001: /*
002: * $Id: Settings.java 478313 2006-11-22 20:35:46Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.config;
022:
023: import java.util.Iterator;
024: import java.util.Locale;
025: import java.util.StringTokenizer;
026:
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.struts2.StrutsConstants;
030:
031: import com.opensymphony.xwork2.ObjectFactory;
032: import com.opensymphony.xwork2.util.location.Location;
033:
034: /**
035: * Settings retrieves and exposes default values used by the framework.
036: * An application can override a factory default and provide its own value for a setting.
037: * <p>
038: * Implementation of the class is pluggable (the default implementation is {@link DefaultSettings}).
039: * Pluggability gives applications to ability to customize how settings are retrieved.
040: * As an example, an application may wish to check some custom property store
041: * before delegating to the usual configuration and property files.
042: * <p>
043: * Key methods:
044: * <ul>
045: * <li>{@link #getLocale()}</li>
046: * <li>{@link #get(String)}</li>
047: * <li>{@link #set(String, String)}</li>
048: * <li>{@link #list()}</li>
049: * </ul>
050: * <p>
051: * Key methods for subclasses (plugins):
052: * <ul>
053: * <li>{@link #getImpl(String)}</li>
054: * <li>{@link #setImpl(String, String)}</li>
055: * <li>{@link #listImpl()}</li>
056: * <li>{@link #isSetImpl(String)}</li>
057: * </ul>
058: */
059: class Settings {
060:
061: /**
062: * A pluggable implementation of Settings,
063: * provided through the {@link #setInstance} method.
064: */
065: static Settings settingsImpl;
066:
067: /**
068: * An instance of {@link DefaultSettings}
069: * to use when another implementation is not provided (plugged in).
070: */
071: static Settings defaultImpl;
072:
073: /**
074: * An instance of the default locale as specified by the <code>struts.locale</code> setting.
075: *
076: * @see #getLocale
077: */
078: static Locale locale;
079:
080: /**
081: * The Logging instance for this class.
082: */
083: private static final Log LOG = LogFactory.getLog(Settings.class);
084:
085: /**
086: * Registers a custom Settings implementation (plugin),
087: * and resets the cached locale.
088: * <p>
089: * This method can only be called once.
090: *
091: * @param config a Settings implementation
092: * @throws IllegalStateException if an error occurs when setting the settings implementation.
093: */
094: public static void setInstance(Settings config)
095: throws IllegalStateException {
096: settingsImpl = config;
097: locale = null;
098: }
099:
100: /**
101: * Provides the Settings object.
102: * <p>
103: * This method will substitute the default instance if another instance is not registered.
104: *
105: * @return the Settings object.
106: */
107: public static Settings getInstance() {
108: return (settingsImpl == null) ? getDefaultInstance()
109: : 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(
129: get(StrutsConstants.STRUTS_LOCALE), "_");
130: String lang = null;
131: String country = null;
132:
133: if (localeTokens.hasMoreTokens()) {
134: lang = localeTokens.nextToken();
135: }
136:
137: if (localeTokens.hasMoreTokens()) {
138: country = localeTokens.nextToken();
139: }
140:
141: locale = new Locale(lang, country);
142: } catch (Throwable t) {
143: // Default
144: LOG
145: .warn("Settings: Could not parse struts.locale setting, substituting default VM locale");
146: locale = Locale.getDefault();
147: }
148: }
149:
150: return locale;
151: }
152:
153: /**
154: * Determines whether or not a setting has a registered value.
155: * <p>
156: * This method is useful for testing for the existance of setting without
157: * throwing an IllegalArgumentException.
158: *
159: * @param name the name of a setting to test.
160: * @return <code>true</code> if the setting exists and has a value, <code>false</code> otherwise.
161: */
162: public static boolean isSet(String name) {
163: return getInstance().isSetImpl(name);
164: }
165:
166: /**
167: * Provides a setting value as a String.
168: * <p>
169: * The method will throw an <code>IllegalArgumentException</code> if an error occurs
170: * while retrieveing the property or if the property doesn't exist.
171: *
172: * @param name the name of the setting to retrieve.
173: * @return the setting value as a String.
174: * @throws IllegalArgumentException if an error occurs retrieving the property or the property does not exist.
175: */
176: public static String get(String name)
177: throws IllegalArgumentException {
178: return getInstance().getImpl(name);
179: }
180:
181: /**
182: * Provides the Location of a setting.
183: * <p>
184: * The Location is utilized as part of precise error reporting.
185: * <p>
186: * This method will throw an <code>IllegalArgumentException</code> if an error occurs
187: * while retrieving the value or if the setting doesn't exist.
188: *
189: * @param name the name of the property to get.
190: * @return the Location of a property.
191: * @throws IllegalArgumentException if an error occurs retrieving the property or the property does not exist.
192: */
193: public static Location getLocation(String name)
194: throws IllegalArgumentException {
195: return getInstance().getLocationImpl(name);
196: }
197:
198: /**
199: * Provides an Iterator of all properties names.
200: *
201: * @return an Iterator of all properties names.
202: */
203: public static Iterator list() {
204: return getInstance().listImpl();
205: }
206:
207: /**
208: * Implements the {@link #isSet(String)} method.
209: *
210: * @param name Identifier for the setting value to change
211: * @return True if the setting exists and has a value, false otherwise.
212: * @see #isSet(String)
213: */
214: public boolean isSetImpl(String name) {
215: // this is dumb.. maybe it should just throw an unsupported op like the rest of the *Impl
216: // methods in this class.
217: return false;
218: }
219:
220: /**
221: * Registers a value for a setting.
222: * <p>
223: * This method raises an exception if an error occurs when setting the value or if the
224: * settings implementation does not support setting values.
225: *
226: * @param name the name of the setting.
227: * @param value the value to register for the setting.
228: * @throws IllegalArgumentException if an error occurs when setting the value.
229: * @throws UnsupportedOperationException if the config implementation does not support setting values.
230: */
231: public static void set(String name, String value)
232: throws IllegalArgumentException,
233: UnsupportedOperationException {
234: getInstance().setImpl(name, value);
235: }
236:
237: /**
238: * Implements the {@link #set(String, String)} method.
239: *
240: * @param name Identifer for the setting to change.
241: * @param value The new value for the setting.
242: * @throws IllegalArgumentException if an error occurs when setting the value.
243: * @throws UnsupportedOperationException if the config implementation does not support setting values.
244: * @see #set(String, String)
245: */
246: public void setImpl(String name, String value)
247: throws IllegalArgumentException,
248: UnsupportedOperationException {
249: throw new UnsupportedOperationException(
250: "Settings: This implementation does not support setting a value.");
251: }
252:
253: /**
254: * Implements the {@link #get(String)} method.
255: *
256: * @param name The name of the setting value to retreive
257: * @return The setting value as a String
258: * @throws IllegalArgumentException if an error occurs when retrieving the value
259: * @see #get(String)
260: */
261: public String getImpl(String name) throws IllegalArgumentException {
262: return null;
263: }
264:
265: /**
266: * Implements the {@link #getLocation(String)} method.
267: *
268: * @param name Name of the setting to locate
269: * @return The location of the setting
270: * @throws IllegalArgumentException if an error occurs when retrieving the value
271: * @see #getLocation(String)
272: */
273: public Location getLocationImpl(String name)
274: throws IllegalArgumentException {
275: return null;
276: }
277:
278: /**
279: * Implements the {@link #list()} method.
280: *
281: * @see #list()
282: * @return A list of the settings as an iterator
283: */
284: public Iterator listImpl() {
285: throw new UnsupportedOperationException(
286: "Settings: This implementation does not support listing the registered settings");
287: }
288:
289: /**
290: * Creates a default Settings object.
291: * <p>
292: * A default implementation may be specified by the <code>struts.configuration</code> setting;
293: * otherwise, this method instantiates {@link DefaultSettings} as the default implementation.
294: *
295: * @return A default Settings object.
296: */
297: private static Settings getDefaultInstance() {
298: if (defaultImpl == null) {
299: // Create bootstrap implementation
300: defaultImpl = new DefaultSettings();
301:
302: // Create default implementation
303: try {
304: String className = get(StrutsConstants.STRUTS_CONFIGURATION);
305:
306: if (!className.equals(defaultImpl.getClass().getName())) {
307: try {
308: // singleton instances shouldn't be built accessing request or session-specific context data
309: defaultImpl = (Settings) ObjectFactory
310: .getObjectFactory()
311: .buildBean(
312: Thread
313: .currentThread()
314: .getContextClassLoader()
315: .loadClass(className),
316: null);
317: } catch (Exception e) {
318: LOG
319: .error(
320: "Settings: Could not instantiate the struts.configuration object, substituting the default implementation.",
321: e);
322: }
323: }
324: } catch (IllegalArgumentException ex) {
325: // ignore
326: }
327: }
328:
329: return defaultImpl;
330: }
331:
332: /**
333: * Resets the default and any plugin Setting instance to null.
334: */
335: public static void reset() {
336: defaultImpl = null;
337: settingsImpl = null;
338: }
339: }
|