View Javadoc

1   /*
2    * $Id: Settings.java 439747 2006-09-03 09:22:46Z mrdon $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts2.config;
19  
20  import java.util.Iterator;
21  import java.util.Locale;
22  import java.util.StringTokenizer;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.struts2.StrutsConstants;
27  
28  import com.opensymphony.xwork2.ObjectFactory;
29  
30  
31  /***
32   * Handles all Struts config properties. Implementation of this class is pluggable (the
33   * default implementation is {@link DefaultSettings}). This gives developers to ability to customize how
34   * Struts properties are set and retrieved. As an example, a developer may wish to check a separate property
35   * store before delegating to the Struts one. <p>
36   * <p/>
37   * Key methods: <ul>
38   * <p/>
39   * <li>{@link #getLocale()}</li>
40   * <li>{@link #get(String)}</li>
41   * <li>{@link #set(String, String)}</li>
42   * <li>{@link #list()}</li></ul>
43   * <p/>
44   * Key methods for subclassers: <ul>
45   * <p/>
46   * <li>{@link #getImpl(String)}</li>
47   * <li>{@link #setImpl(String, String)}</li>
48   * <li>{@link #listImpl()}</li>
49   * <li>{@link #isSetImpl(String)}</li></ul>
50   */
51  public class Settings {
52  
53      static Settings settingsImpl;
54      static Settings defaultImpl;
55      static Locale locale; // Cached locale
56      private static final Log LOG = LogFactory.getLog(Settings.class);
57  
58  
59      /***
60       * Sets the current settings implementation. Can only be called once.
61       *
62       * @param config a Settings implementation
63       * @throws IllegalStateException if an error occurs when setting the settings implementation.
64       */
65      public static void setInstance(Settings config) throws IllegalStateException {
66          settingsImpl = config;
67          locale = null; // Reset cached locale
68      }
69  
70      /***
71       * Gets the current settings implementation.
72       *
73       * @return the current settings implementation.
74       */
75      public static Settings getInstance() {
76          return (settingsImpl == null) ? getDefaultInstance() : settingsImpl;
77      }
78  
79      /***
80       * Returns the Struts locale. Keys off the property <tt>struts.locale</tt> which should be set
81       * as the Java {@link java.util.Locale#toString() toString()} representation of a Locale object (i.e.,
82       * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr_MAC", etc). <p>
83       * <p/>
84       * If no locale is specified then the default VM locale is used ({@link java.util.Locale#getDefault()}).
85       *
86       * @return the Struts locale if specified or the VM default locale.
87       */
88      public static Locale getLocale() {
89          if (locale == null) {
90              try {
91                  StringTokenizer localeTokens = new StringTokenizer(get(StrutsConstants.STRUTS_LOCALE), "_");
92                  String lang = null;
93                  String country = null;
94  
95                  if (localeTokens.hasMoreTokens()) {
96                      lang = localeTokens.nextToken();
97                  }
98  
99                  if (localeTokens.hasMoreTokens()) {
100                     country = localeTokens.nextToken();
101                 }
102 
103                 locale = new Locale(lang, country);
104             } catch (Throwable t) {
105                 // Default
106                 LOG.warn("Setting locale to the default locale");
107                 locale = Locale.getDefault();
108             }
109         }
110 
111         return locale;
112     }
113 
114     /***
115      * Determines whether or not a value has been set. Useful for testing for the existance of parameter without
116      * throwing an IllegalArgumentException.
117      *
118      * @param name the name of the property to test.
119      * @return <tt>true</tt> if the property exists and has a value, <tt>false</tt> otherwise.
120      */
121     public static boolean isSet(String name) {
122         return getInstance().isSetImpl(name);
123     }
124 
125     /***
126      * Returns a property as an Object. This will throw an <tt>IllegalArgumentException</tt> if an error occurs
127      * while retrieveing the property or if the property doesn't exist.
128      *
129      * @param name the name of the property to get.
130      * @return the property as an Object.
131      * @throws IllegalArgumentException if an error occurs retrieveing the property or the property does not exist.
132      */
133     public static String get(String name) throws IllegalArgumentException {
134         String val = getInstance().getImpl(name);
135 
136         return val;
137     }
138 
139     /***
140      * Returns an Iterator of all properties names.
141      *
142      * @return an Iterator of all properties names.
143      */
144     public static Iterator list() {
145         return getInstance().listImpl();
146     }
147 
148     /***
149      * Implementation of the {@link #isSet(String)} method.
150      *
151      * @see #isSet(String)
152      */
153     public boolean isSetImpl(String name) {
154         // this is dumb.. maybe it should just throw an unsupported op like the rest of the *Impl
155         // methods in this class.
156         return false;
157     }
158 
159     /***
160      * Sets a property. Throws an exception if an error occurs when setting the property or if the
161      * Settings implementation does not support setting properties.
162      *
163      * @param name  the name of the property to set.
164      * @param value the property to set.
165      * @throws IllegalArgumentException      if an error occurs when setting the property.
166      * @throws UnsupportedOperationException if the config implementation does not support setting properties.
167      */
168     public static void set(String name, String value) throws IllegalArgumentException, UnsupportedOperationException {
169         getInstance().setImpl(name, value);
170     }
171 
172     /***
173      * Implementation of the {@link #set(String, String)} method.
174      *
175      * @see #set(String, String)
176      */
177     public void setImpl(String name, String value) throws IllegalArgumentException, UnsupportedOperationException {
178         throw new UnsupportedOperationException("This settings does not support updating a setting");
179     }
180 
181     /***
182      * Implementation of the {@link #get(String)} method.
183      *
184      * @see #get(String)
185      */
186     public String getImpl(String aName) throws IllegalArgumentException {
187         return null;
188     }
189 
190     /***
191      * Implementation of the {@link #list()} method.
192      *
193      * @see #list()
194      */
195     public Iterator listImpl() {
196         throw new UnsupportedOperationException("This settings does not support listing the settings");
197     }
198 
199     private static Settings getDefaultInstance() {
200         if (defaultImpl == null) {
201             // Create bootstrap implementation
202             defaultImpl = new DefaultSettings();
203 
204             // Create default implementation
205             try {
206                 String className = get(StrutsConstants.STRUTS_CONFIGURATION);
207 
208                 if (!className.equals(defaultImpl.getClass().getName())) {
209                     try {
210                         // singleton instances shouldn't be built accessing request or session-specific context data
211                         defaultImpl = (Settings) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className), null);
212                     } catch (Exception e) {
213                         LOG.error("Could not instantiate settings", e);
214                     }
215                 }
216             } catch (IllegalArgumentException ex) {
217                 // ignore
218             }
219         }
220 
221         return defaultImpl;
222     }
223 
224     public static void reset() {
225         defaultImpl = null;
226         settingsImpl = null;
227     }
228 }