View Javadoc

    1   /*
    2    * $Id: Settings.java 478313 2006-11-22 20:35:46Z husted $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    20   */
    21  package org.apache.struts2.config;
    22
    23  import java.util.Iterator;
    24  import java.util.Locale;
    25  import java.util.StringTokenizer;
    26
    27  import org.apache.commons.logging.Log;
    28  import org.apache.commons.logging.LogFactory;
    29  import org.apache.struts2.StrutsConstants;
    30
    31  import com.opensymphony.xwork2.ObjectFactory;
    32  import com.opensymphony.xwork2.util.location.Location;
    33
    34
    35  /***
    36   * Settings retrieves and exposes default values used by the framework.
    37   * An application can override a factory default and provide its own value for a setting.
    38   * <p>
    39   * Implementation of the class is pluggable (the default implementation is {@link DefaultSettings}).
    40   * Pluggability gives applications to ability to customize how settings are retrieved.
    41   * As an example, an application may wish to check some custom property store
    42   * before delegating to the usual configuration and property files.
    43   * <p>
    44   * Key methods:
    45   * <ul>
    46   * <li>{@link #getLocale()}</li>
    47   * <li>{@link #get(String)}</li>
    48   * <li>{@link #set(String, String)}</li>
    49   * <li>{@link #list()}</li>
    50   * </ul>
    51   * <p>
    52   * Key methods for subclasses (plugins):
    53   * <ul>
    54   * <li>{@link #getImpl(String)}</li>
    55   * <li>{@link #setImpl(String, String)}</li>
    56   * <li>{@link #listImpl()}</li>
    57   * <li>{@link #isSetImpl(String)}</li>
    58   * </ul>
    59   */
    60  class Settings {
    61
    62
    63      /***
    64       * A pluggable implementation of Settings,
    65       * provided through the {@link #setInstance} method.
    66       */
    67      static Settings settingsImpl;
    68
    69      /***
    70       * An instance of {@link DefaultSettings}
    71       * to use when another implementation is not provided (plugged in).
    72       */
    73      static Settings defaultImpl;
    74
    75      /***
    76       * An instance of the default locale as specified by the <code>struts.locale</code>  setting.
    77       *
    78       * @see #getLocale
    79       */
    80      static Locale locale;
    81
    82      /***
    83       * The Logging instance for this class.
    84       */
    85      private static final Log LOG = LogFactory.getLog(Settings.class);
    86
    87      /***
    88       * Registers a custom Settings implementation (plugin),
    89       * and resets the cached locale.
    90       * <p>
    91       * This method can only be called once.
    92       *
    93       * @param config a Settings implementation
    94       * @throws IllegalStateException if an error occurs when setting the settings implementation.
    95       */
    96      public static void setInstance(Settings config) throws IllegalStateException {
    97          settingsImpl = config;
    98          locale = null;
    99      }
    100
    101     /***
    102      * Provides the Settings object.
    103      * <p>
    104      * This method will substitute the default instance if another instance is not registered.
    105      *
    106      * @return the Settings object.
    107      */
    108     public static Settings getInstance() {
    109         return (settingsImpl == null) ? getDefaultInstance() : settingsImpl;
    110     }
    111
    112     /***
    113      * Provides the Struts default locale.
    114      * <p>
    115      * This method utilizes the <code>struts.locale</code> setting, which should be given
    116      * as the Java {@link java.util.Locale#toString() toString()} representation of a Locale object
    117      * ("en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr_MAC", and so forth).
    118      * <p>
    119      * If a <code>struts.locale</code> setting is not registered,
    120      * then the default virtual machine locale is substituted and cached.
    121      *
    122      * @return the Struts default locale if specified or the VM default locale.
    123      * @see java.util.Locale#getDefault()
    124      */
    125     public static Locale getLocale() {
    126         if (locale == null) {
    127             try {
    128                 StringTokenizer localeTokens = new StringTokenizer(get(StrutsConstants.STRUTS_LOCALE), "_");
    129                 String lang = null;
    130                 String country = null;
    131
    132                 if (localeTokens.hasMoreTokens()) {
    133                     lang = localeTokens.nextToken();
    134                 }
    135
    136                 if (localeTokens.hasMoreTokens()) {
    137                     country = localeTokens.nextToken();
    138                 }
    139
    140                 locale = new Locale(lang, country);
    141             } catch (Throwable t) {
    142                 // Default
    143                 LOG.warn("Settings: Could not parse struts.locale setting, substituting default VM locale");
    144                 locale = Locale.getDefault();
    145             }
    146         }
    147
    148         return locale;
    149     }
    150
    151     /***
    152      * Determines whether or not a setting has a registered value.
    153      * <p>
    154      * This method is useful for testing for the existance of setting without
    155      * throwing an IllegalArgumentException.
    156      *
    157      * @param name the name of a setting to test.
    158      * @return <code>true</code> if the setting exists and has a value, <code>false</code> otherwise.
    159      */
    160     public static boolean isSet(String name) {
    161         return getInstance().isSetImpl(name);
    162     }
    163
    164     /***
    165      * Provides a setting value as a String.
    166      * <p>
    167      * The method will throw an <code>IllegalArgumentException</code> if an error occurs
    168      * while retrieveing the property or if the property doesn't exist.
    169      *
    170      * @param name the name of the setting to retrieve.
    171      * @return the setting value as a String.
    172      * @throws IllegalArgumentException if an error occurs retrieving the property or the property does not exist.
    173      */
    174     public static String get(String name) throws IllegalArgumentException {
    175         return getInstance().getImpl(name);
    176     }
    177
    178     /***
    179      * Provides the Location of a setting.
    180      * <p>
    181      * The Location is utilized as part of precise error reporting.
    182      * <p>
    183       * This method will throw an <code>IllegalArgumentException</code> if an error occurs
    184      * while retrieving the value or if the setting doesn't exist.
    185      *
    186      * @param name the name of the property to get.
    187      * @return the Location of a property.
    188      * @throws IllegalArgumentException if an error occurs retrieving the property or the property does not exist.
    189      */
    190     public static Location getLocation(String name) throws IllegalArgumentException {
    191         return getInstance().getLocationImpl(name);
    192     }
    193
    194     /***
    195      * Provides an Iterator of all properties names.
    196      *
    197      * @return an Iterator of all properties names.
    198      */
    199     public static Iterator list() {
    200         return getInstance().listImpl();
    201     }
    202
    203     /***
    204      * Implements the {@link #isSet(String)} method.
    205      *
    206      * @param name Identifier for the setting value to change
    207      * @return True if the setting exists and has a value, false otherwise.
    208      * @see #isSet(String)
    209      */
    210     public boolean isSetImpl(String name) {
    211         // this is dumb.. maybe it should just throw an unsupported op like the rest of the *Impl
    212         // methods in this class.
    213         return false;
    214     }
    215
    216     /***
    217      * Registers a value for a setting.
    218      * <p>
    219      * This method raises an exception if an error occurs when setting the value or if the
    220      * settings implementation does not support setting values.
    221      *
    222      * @param name  the name of the setting.
    223      * @param value the value to register for the setting.
    224      * @throws IllegalArgumentException      if an error occurs when setting the value.
    225      * @throws UnsupportedOperationException if the config implementation does not support setting values.
    226      */
    227     public static void set(String name, String value) throws IllegalArgumentException, UnsupportedOperationException {
    228         getInstance().setImpl(name, value);
    229     }
    230
    231     /***
    232      * Implements the {@link #set(String, String)} method.
    233      *
    234      * @param name Identifer for the setting to change.
    235      * @param value The new value for the setting.
    236      * @throws IllegalArgumentException      if an error occurs when setting the value.
    237      * @throws UnsupportedOperationException if the config implementation does not support setting values.
    238      * @see #set(String, String)
    239      */
    240     public void setImpl(String name, String value) throws IllegalArgumentException, UnsupportedOperationException {
    241         throw new UnsupportedOperationException("Settings: This implementation does not support setting a value.");
    242     }
    243
    244     /***
    245      * Implements the {@link #get(String)} method.
    246      *
    247      * @param name The name of the setting value to retreive
    248      * @return The setting value as a String
    249      * @throws IllegalArgumentException if an error occurs when retrieving the value
    250      * @see #get(String)
    251      */
    252     public String getImpl(String name) throws IllegalArgumentException {
    253         return null;
    254     }
    255
    256     /***
    257      * Implements the {@link #getLocation(String)} method.
    258      *
    259      * @param name Name of the setting to locate
    260      * @return The location  of the setting
    261      * @throws IllegalArgumentException if an error occurs when retrieving the value
    262      * @see #getLocation(String)
    263      */
    264     public Location getLocationImpl(String name) throws IllegalArgumentException {
    265         return null;
    266     }
    267
    268     /***
    269      * Implements the {@link #list()} method.
    270      *
    271      * @see #list()
    272      * @return A list of the settings as an iterator
    273      */
    274     public Iterator listImpl() {
    275         throw new UnsupportedOperationException("Settings: This implementation does not support listing the registered settings");
    276     }
    277
    278     /***
    279      * Creates a default Settings object.
    280      * <p>
    281      * A default implementation may be specified by the <code>struts.configuration</code> setting;
    282      * otherwise, this method instantiates {@link DefaultSettings} as the default implementation.
    283      *
    284      * @return A default Settings object.
    285      */
    286     private static Settings getDefaultInstance() {
    287         if (defaultImpl == null) {
    288             // Create bootstrap implementation
    289             defaultImpl = new DefaultSettings();
    290
    291             // Create default implementation
    292             try {
    293                 String className = get(StrutsConstants.STRUTS_CONFIGURATION);
    294
    295                 if (!className.equals(defaultImpl.getClass().getName())) {
    296                     try {
    297                         // singleton instances shouldn't be built accessing request or session-specific context data
    298                         defaultImpl = (Settings) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className), null);
    299                     } catch (Exception e) {
    300                         LOG.error("Settings: Could not instantiate the struts.configuration object, substituting the default implementation.", e);
    301                     }
    302                 }
    303             } catch (IllegalArgumentException ex) {
    304                 // ignore
    305             }
    306         }
    307
    308         return defaultImpl;
    309     }
    310
    311     /***
    312      * Resets the default and any plugin Setting instance to null.
    313      */
    314     public static void reset() {
    315         defaultImpl = null;
    316         settingsImpl = null;
    317     }
    318 }