001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: SystemProperties.java,v 1.21 2009/10/12 17:55:06 alanchu Exp $ 026 * 027 */ 028 029/* 030 * Portions Copyrighted 2010-2014 ForgeRock, AS. 031 */ 032package com.iplanet.am.util; 033 034import com.iplanet.sso.SSOToken; 035import com.sun.identity.common.AttributeStruct; 036import com.sun.identity.common.PropertiesFinder; 037import com.sun.identity.common.configuration.ServerConfiguration; 038import com.sun.identity.security.AdminTokenAction; 039import com.sun.identity.shared.Constants; 040import com.sun.identity.sm.SMSEntry; 041import org.forgerock.openam.cts.api.CoreTokenConstants; 042import org.forgerock.openam.utils.CollectionUtils; 043 044import java.io.ByteArrayOutputStream; 045import java.io.FileInputStream; 046import java.io.IOException; 047import java.io.PrintStream; 048import java.net.InetAddress; 049import java.security.AccessController; 050import java.util.Collections; 051import java.util.Enumeration; 052import java.util.HashMap; 053import java.util.HashSet; 054import java.util.Iterator; 055import java.util.Map; 056import java.util.MissingResourceException; 057import java.util.Properties; 058import java.util.ResourceBundle; 059import java.util.Set; 060import java.util.concurrent.locks.ReentrantReadWriteLock; 061 062/** 063 * This class provides functionality that allows single-point-of-access to all 064 * related system properties. 065 * <p> 066 * The system properties can be set in couple of ways: programmatically by 067 * calling the <code>initializeProperties</code> method, or can be statically 068 * loaded at startup from a file named: 069 * <code>AMConfig.[class,properties]</code>. 070 * Setting the properties through the API takes precedence and will replace the 071 * properties loaded via file. For statically loading the properties via a file, 072 * this class tries to first find a class, <code>AMConfig.class</code>, and 073 * then a file, <code>AMConfig.properties</code> in the CLASSPATH accessible 074 * to this code. The <code>AMConfig.class</code> takes precedence over the 075 * flat file <code>AMConfig.properties</code>. 076 * <p> 077 * If multiple servers are running, each may have their own configuration file. 078 * The naming convention for such scenarios is 079 * <code>AMConfig-<serverName></code>. 080 * @supported.all.api 081 */ 082public class SystemProperties { 083 private static String instanceName; 084 private static ReentrantReadWriteLock rwLock = new 085 ReentrantReadWriteLock(); 086 private static Map attributeMap = new HashMap(); 087 private static boolean sitemonitorDisabled = false; 088 private final static String TRUE = "true"; 089 /** Regular expression pattern for a sequence of 1 or more white space characters. */ 090 private static final String WHITESPACE = "\\s+"; 091 092 static { 093 initAttributeMapping(); 094 } 095 096 private static void initAttributeMapping() { 097 try { 098 ResourceBundle rb = ResourceBundle.getBundle("serverAttributeMap"); 099 for (Enumeration e = rb.getKeys(); e.hasMoreElements(); ) { 100 String propertyName = (String)e.nextElement(); 101 attributeMap.put(propertyName, new AttributeStruct( 102 rb.getString(propertyName))); 103 } 104 } catch(java.util.MissingResourceException mse) { 105 // No Resource Bundle Found, Continue. 106 // Could be in Test Mode. 107 } 108 } 109 110 111 private static Properties props; 112 113 private static long lastModified; 114 115 private static String initError; 116 117 private static String initSecondaryError; 118 119 private static final String SERVER_NAME_PROPERTY = "server.name"; 120 121 private static final String CONFIG_NAME_PROPERTY = "amconfig"; 122 123 private static final String AMCONFIG_FILE_NAME = "AMConfig"; 124 125 /** 126 * Runtime flag to be set, in order to override the path of the 127 * configuration file. 128 */ 129 public static final String CONFIG_PATH = "com.iplanet.services.configpath"; 130 131 /** 132 * Default name of the configuration file. 133 */ 134 public static final String CONFIG_FILE_NAME = "serverconfig.xml"; 135 136 /** 137 * New configuration file extension 138 */ 139 public static final String PROPERTIES = "properties"; 140 141 public static final String NEWCONFDIR = "NEW_CONF_DIR"; 142 143 private static Map mapTagswap = new HashMap(); 144 private static Map tagswapValues; 145 146 /** 147 * Initialization to load the properties file for config information before 148 * anything else starts. 149 */ 150 static { 151 mapTagswap.put("%SERVER_PORT%", Constants.AM_SERVER_PORT); 152 mapTagswap.put("%SERVER_URI%", Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR); 153 mapTagswap.put("%SERVER_HOST%", Constants.AM_SERVER_HOST); 154 mapTagswap.put("%SERVER_PROTO%", Constants.AM_SERVER_PROTOCOL); 155 mapTagswap.put("%BASE_DIR%", CONFIG_PATH); 156 mapTagswap.put("%SESSION_ROOT_SUFFIX%", 157 CoreTokenConstants.SYS_PROPERTY_SESSION_HA_REPOSITORY_ROOT_SUFFIX); 158 mapTagswap.put("%SESSION_STORE_TYPE%", 159 CoreTokenConstants.SYS_PROPERTY_SESSION_HA_REPOSITORY_TYPE); 160 161 try { 162 // Initialize properties 163 props = new Properties(); 164 165 // Load properties from file 166 String serverName = System.getProperty(SERVER_NAME_PROPERTY); 167 String configName = System.getProperty(CONFIG_NAME_PROPERTY, 168 AMCONFIG_FILE_NAME); 169 String fname = null; 170 FileInputStream fis = null; 171 if (serverName != null) { 172 serverName = serverName.replace('.', '_'); 173 fname = configName + "-" + serverName; 174 } else { 175 fname = configName; 176 } 177 initializeProperties(fname); 178 179 // Get the location of the new configuration file in case 180 // of single war deployment 181 try { 182 String newConfigFileLoc = props 183 .getProperty(Constants.AM_NEW_CONFIGFILE_PATH); 184 if ((newConfigFileLoc != null) && 185 (newConfigFileLoc.length() > 0) && 186 !newConfigFileLoc.equals(NEWCONFDIR) 187 ) { 188 String hostName = InetAddress.getLocalHost().getHostName() 189 .toLowerCase(); 190 String serverURI = props.getProperty( 191 Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR); 192 serverURI = serverURI.replace('/', '_').toLowerCase(); 193 StringBuilder fileName = new StringBuilder(); 194 fileName.append(newConfigFileLoc).append("/").append( 195 AMCONFIG_FILE_NAME).append(serverURI).append( 196 hostName).append( 197 props.getProperty(Constants.AM_SERVER_PORT)) 198 .append(".").append(PROPERTIES); 199 Properties modProp = new Properties(); 200 try { 201 fis = new FileInputStream(fileName.toString()); 202 modProp.load(fis); 203 props.putAll(modProp); 204 } catch (IOException ioe) { 205 StringBuilder fileNameOrig = new StringBuilder(); 206 fileNameOrig.append(newConfigFileLoc).append("/") 207 .append(AMCONFIG_FILE_NAME).append(".").append( 208 PROPERTIES); 209 try { 210 fis = new FileInputStream(fileNameOrig.toString()); 211 modProp.load(fis); 212 props.putAll(modProp); 213 } catch (IOException ioexp) { 214 saveException(ioexp); 215 } 216 } finally { 217 if (fis != null) { 218 fis.close(); 219 } 220 } 221 } 222 } catch (Exception ex) { 223 saveException(ex); 224 } 225 } catch (MissingResourceException e) { 226 // Can't print the message to debug due to dependency 227 // Save it as a String and provide when requested. 228 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 229 e.printStackTrace(new PrintStream(baos)); 230 initError = baos.toString(); 231 try { 232 baos.close(); 233 } catch (IOException ioe) { 234 // Should not happend, ignore the exception 235 } 236 } 237 sitemonitorDisabled = Boolean.valueOf(getProp( 238 Constants.SITEMONITOR_DISABLED, "false")).booleanValue(); 239 } 240 241 /** 242 * Helper function to handle associated exceptions during initialization of 243 * properties using external properties file in a single war deployment. 244 */ 245 static void saveException(Exception ex) { 246 // Save it as a String and provide when requested. 247 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 248 ex.printStackTrace(new PrintStream(baos)); 249 initSecondaryError = baos.toString(); 250 try { 251 baos.close(); 252 } catch (IOException ioe) { 253 // Should not happend, ignore the exception 254 } 255 } 256 257 /** 258 * This method lets you query for a system property whose value is same as 259 * <code>String</code> key. The method first tries to read the property 260 * from java.lang.System followed by a lookup in the config file. 261 * 262 * @param key 263 * type <code>String</code>, the key whose value one is 264 * looking for. 265 * @return the value if the key exists; otherwise returns <code>null</code> 266 */ 267 public static String get(String key) { 268 rwLock.readLock().lock(); 269 270 try { 271 String answer = null; 272 273 // look up values in SMS services only if in server mode. 274 if (isServerMode() || sitemonitorDisabled) { 275 AttributeStruct ast = (AttributeStruct) attributeMap.get(key); 276 if (ast != null) { 277 answer = PropertiesFinder.getProperty(key, ast); 278 } 279 } 280 281 if (answer == null) { 282 answer = getProp(key); 283 284 if ((answer != null) && (tagswapValues != null)) { 285 Set set = new HashSet(); 286 set.addAll(tagswapValues.keySet()); 287 288 for (Iterator i = set.iterator(); i.hasNext();) { 289 String k = (String) i.next(); 290 String val = (String) tagswapValues.get(k); 291 292 if (k.equals("%SERVER_URI%")) { 293 if ((val != null) && (val.length() > 0)) { 294 if (val.charAt(0) == '/') { 295 answer = answer.replaceAll("/%SERVER_URI%", 296 val); 297 String lessSlash = val.substring(1); 298 answer = answer.replaceAll("%SERVER_URI%", 299 lessSlash); 300 } else { 301 answer = answer.replaceAll(k, val); 302 } 303 } 304 } else { 305 answer = answer.replaceAll(k, val); 306 } 307 } 308 309 if (answer.indexOf("%ROOT_SUFFIX%") != -1) { 310 answer = answer.replaceAll("%ROOT_SUFFIX%", 311 SMSEntry.getAMSdkBaseDN()); 312 } 313 } 314 } 315 316 317 return (answer); 318 } finally { 319 rwLock.readLock().unlock(); 320 } 321 } 322 323 private static String getProp(String key, String def) { 324 String value = getProp(key); 325 return ((value == null) ? def : value); 326 } 327 328 private static String getProp(String key) { 329 String answer = System.getProperty(key); 330 if (answer == null) { 331 answer = props.getProperty(key); 332 } 333 return answer; 334 } 335 336 /** 337 * This method lets you query for a system property whose value is same as 338 * <code>String</code> key. 339 * 340 * @param key the key whose value one is looking for. 341 * @param def the default value if the key does not exist. 342 * @return the value if the key exists; otherwise returns default value. 343 */ 344 public static String get(String key, String def) { 345 String value = get(key); 346 return ((value == null) ? def : value); 347 } 348 349 /** 350 * Returns the property value as a boolean 351 * 352 * @param key the key whose value one is looking for. 353 * @return the boolean value if the key exists; otherwise returns false 354 */ 355 public static boolean getAsBoolean(String key) { 356 String value = get(key); 357 358 if (value == null) 359 return false; 360 361 return (value.equalsIgnoreCase(TRUE) ? true : false); 362 } 363 364 /** 365 * Returns the property value as a boolean 366 * 367 * @param key 368 * @param defaultValue value if key is not found. 369 * @return the boolean value if the key exists; otherwise the default value 370 */ 371 public static boolean getAsBoolean(String key, boolean defaultValue) { 372 String value = get(key); 373 374 if (value == null) 375 { return defaultValue; } 376 377 return (value.equalsIgnoreCase(TRUE) ? true : false); 378 } 379 380 /** 381 * @param key The System Property key to lookup. 382 * @param defaultValue If the property was not set, or could not be parsed to an int. 383 * @return Either the defaultValue, or the numeric value assigned to the System Property. 384 */ 385 public static int getAsInt(String key, int defaultValue) { 386 String value = get(key); 387 388 if (value == null) { 389 return defaultValue; 390 } 391 try { 392 return Integer.parseInt(value); 393 } catch (NumberFormatException e) { 394 return defaultValue; 395 } 396 } 397 398 /** 399 * @param key The System Property key to lookup. 400 * @param defaultValue If the property was not set, or could not be parsed to a long. 401 * @return Either the defaultValue, or the numeric value assigned to the System Property. 402 */ 403 public static long getAsLong(String key, long defaultValue) { 404 String value = get(key); 405 406 if (value == null) { 407 return defaultValue; 408 } 409 try { 410 return Long.parseLong(value); 411 } catch (NumberFormatException e) { 412 return defaultValue; 413 } 414 } 415 416 /** 417 * Parses a system property as a set of strings by splitting the value on the given delimiter expression. 418 * 419 * @param key The System Property key to lookup. 420 * @param delimiterRegex The regular expression to use to split the value into elements in the set. 421 * @param defaultValue The default set to return if the property does not exist. 422 * @return the value of the property parsed as a set of strings. 423 */ 424 public static Set<String> getAsSet(String key, String delimiterRegex, Set<String> defaultValue) { 425 String value = get(key); 426 if (value == null || value.trim().isEmpty()) { 427 return defaultValue; 428 } 429 return CollectionUtils.asSet(value.split(delimiterRegex)); 430 } 431 432 /** 433 * Parses a system property as a set of strings by splitting the value on the given delimiter expression. 434 * 435 * @param key The System Property key to lookup. 436 * @param delimiterRegex The regular expression to use to split the value into elements in the set. 437 * @return the value of the property parsed as a set of strings or an empty set if no match is found. 438 */ 439 public static Set<String> getAsSet(String key, String delimiterRegex) { 440 return getAsSet(key, delimiterRegex, Collections.<String>emptySet()); 441 } 442 443 /** 444 * Parses a system property as a set of strings by splitting the value on white space characters. 445 * 446 * @param key The System Property key to lookup. 447 * @return the value of the property parsed as a set of strings or an empty set if no match is found. 448 */ 449 public static Set<String> getAsSet(String key) { 450 return getAsSet(key, WHITESPACE); 451 } 452 453 /** 454 * Returns all the properties defined and their values. 455 * 456 * @return Properties object with all the key value pairs. 457 */ 458 public static Properties getProperties() { 459 rwLock.readLock().lock(); 460 try { 461 Properties properties = new Properties(); 462 properties.putAll(props); 463 return properties; 464 } finally { 465 rwLock.readLock().unlock(); 466 } 467 } 468 469 /** 470 * This method lets you get all the properties defined and their values. The 471 * method first tries to load the properties from java.lang.System followed 472 * by a lookup in the config file. 473 * 474 * @return Properties object with all the key value pairs. 475 * 476 */ 477 public static Properties getAll() { 478 rwLock.readLock().lock(); 479 480 try { 481 Properties properties = new Properties(); 482 properties.putAll(props); 483 // Iterate over the System Properties & add them in result obj 484 Iterator it = System.getProperties().entrySet().iterator(); 485 while (it.hasNext()) { 486 Map.Entry entry = (Map.Entry) it.next(); 487 String key = (String) entry.getKey(); 488 String val = (String) entry.getValue(); 489 if ((key != null) && (key.length() > 0)) { 490 properties.setProperty(key, val); 491 } 492 } 493 return properties; 494 } finally { 495 rwLock.readLock().unlock(); 496 } 497 } 498 499 /** 500 * This method lets you query for all the platform properties defined and 501 * their values. Returns a Properties object with all the key value pairs. 502 * 503 * @deprecated use <code>getAll()</code> 504 * 505 * @return the platform properties 506 */ 507 public static Properties getPlatform() { 508 return getAll(); 509 } 510 511 private static void updateTagswapMap(Properties properties) { 512 tagswapValues = new HashMap(); 513 for (Iterator i = mapTagswap.keySet().iterator(); i.hasNext(); ) { 514 String key = (String)i.next(); 515 String rgKey = (String)mapTagswap.get(key); 516 String val = System.getProperty(rgKey); 517 if (val == null) { 518 val = (String)properties.get(rgKey); 519 } 520 tagswapValues.put(key, val); 521 } 522 } 523 524 /** 525 * Initializes properties bundle from the <code>file<code> 526 * passed. 527 * 528 * @param file type <code>String</code>, file name for the resource bundle 529 * @exception MissingResourceException 530 */ 531 public static void initializeProperties(String file) 532 throws MissingResourceException { 533 rwLock.writeLock().lock(); 534 try { 535 ResourceBundle bundle = ResourceBundle.getBundle(file); 536 // Copy the properties to props 537 Enumeration e = bundle.getKeys(); 538 Properties newProps = new Properties(); 539 newProps.putAll(props); 540 while (e.hasMoreElements()) { 541 String key = (String) e.nextElement(); 542 newProps.put(key, bundle.getString(key)); 543 } 544 // Reset the last modified time 545 props = newProps; 546 updateTagswapMap(props); 547 lastModified = System.currentTimeMillis(); 548 } finally { 549 rwLock.writeLock().unlock(); 550 } 551 } 552 553 public static void initializeProperties(Properties properties){ 554 initializeProperties(properties, false); 555 } 556 557 /** 558 * Initializes the properties to be used by OpenSSO. Ideally this 559 * must be called first before any other method is called within OpenSSO 560 * Enterprise. This method provides a programmatic way to set the 561 * properties, and will override similar properties if loaded for a 562 * properties file. 563 * 564 * @param properties properties for OpenSSO 565 * @param reset <code>true</code> to reset existing properties. 566 */ 567 public static void initializeProperties( 568 Properties properties, 569 boolean reset) 570 { 571 initializeProperties(properties, reset, false); 572 } 573 574 /** 575 * Initializes the properties to be used by OpenSSO. Ideally this 576 * must be called first before any other method is called within OpenSSO 577 * Enterprise. This method provides a programmatic way to set the 578 * properties, and will override similar properties if loaded for a 579 * properties file. 580 * 581 * @param properties properties for OpenSSO. 582 * @param reset <code>true</code> to reset existing properties. 583 * @param withDefaults <code>true</code> to include default properties. 584 */ 585 public static void initializeProperties( 586 Properties properties, 587 boolean reset, 588 boolean withDefaults) { 589 Properties defaultProp = null; 590 if (withDefaults) { 591 SSOToken appToken = (SSOToken) AccessController.doPrivileged( 592 AdminTokenAction.getInstance()); 593 defaultProp = ServerConfiguration.getDefaults(appToken); 594 } 595 596 rwLock.writeLock().lock(); 597 598 try { 599 Properties newProps = new Properties(); 600 if (defaultProp != null) { 601 newProps.putAll(defaultProp); 602 } 603 604 605 if (!reset) { 606 newProps.putAll(props); 607 } 608 609 newProps.putAll(properties); 610 props = newProps; 611 updateTagswapMap(props); 612 lastModified = System.currentTimeMillis(); 613 } finally { 614 rwLock.writeLock().unlock(); 615 } 616 } 617 618 /** 619 * Initializes the property to be used by OpenSSO. Ideally this 620 * must be called first before any other method is called within OpenSSO 621 * Enterprise. 622 * This method provides a programmatic way to set a specific property, and 623 * will override similar property if loaded for a properties file. 624 * 625 * @param propertyName property name. 626 * @param propertyValue property value. 627 */ 628 public static void initializeProperties( 629 String propertyName, 630 String propertyValue 631 ) { 632 rwLock.writeLock().lock(); 633 634 try { 635 Properties newProps = new Properties(); 636 newProps.putAll(props); 637 newProps.put(propertyName, propertyValue); 638 props = newProps; 639 updateTagswapMap(props); 640 lastModified = System.currentTimeMillis(); 641 } finally { 642 rwLock.writeLock().unlock(); 643 } 644 } 645 646 /** 647 * Returns a counter for last modification. The counter is incremented if 648 * the properties are changed by calling the following method 649 * <code>initializeProperties</code>. This is a convenience methods for 650 * applications to track changes to OpenSSO properties. 651 * 652 * @return counter of the last modification 653 */ 654 public static long lastModified() { 655 return (lastModified); 656 } 657 658 /** 659 * Returns error messages during initialization, else <code>null</code>. 660 * 661 * @return error messages during initialization 662 */ 663 public static String getInitializationError() { 664 return (initError); 665 } 666 667 /** 668 * Returns error messages during initialization using the single war 669 * deployment, else <code>null</code>. 670 * 671 * @return error messages during initialization of AM as single war 672 */ 673 public static String getSecondaryInitializationError() { 674 return (initSecondaryError); 675 } 676 677 /** 678 * Sets the server instance name of which properties are retrieved 679 * to initialized this object. 680 * 681 * @param name Server instance name. 682 */ 683 public static void setServerInstanceName(String name) { 684 instanceName = name; 685 } 686 687 /** 688 * Returns the server instance name of which properties are retrieved 689 * to initialized this object. 690 * 691 * @return Server instance name. 692 */ 693 public static String getServerInstanceName() { 694 return instanceName; 695 } 696 697 /** 698 * Returns <code>true</code> if instance is running in server mode. 699 * 700 * @return <code>true</code> if instance is running in server mode. 701 */ 702 public static boolean isServerMode() { 703 // use getProp and not get method to avoid infinite loop 704 return Boolean.valueOf(getProp( 705 Constants.SERVER_MODE, "false")).booleanValue(); 706 } 707 708 /** 709 * Returns the property name to service attribute schema name mapping. 710 * 711 * @return Property name to service attribute schema name mapping. 712 */ 713 public static Map getAttributeMap() { 714 rwLock.readLock().lock(); 715 try { 716 return attributeMap; 717 } finally { 718 rwLock.readLock().unlock(); 719 } 720 } 721}
Copyright © 2010-2017, ForgeRock All Rights Reserved.