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-&lt;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.