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 }