1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
212
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
289 defaultImpl = new DefaultSettings();
290
291
292 try {
293 String className = get(StrutsConstants.STRUTS_CONFIGURATION);
294
295 if (!className.equals(defaultImpl.getClass().getName())) {
296 try {
297
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
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 }