View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  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,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.jsieve;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.util.Map;
25  import java.util.Properties;
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.ConcurrentMap;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.xml.sax.SAXException;
32  
33  /**
34   * <p>
35   * <code>ConfigurationManager</code> parses the XML statements
36   * in the Sieve configuration file and translates them to Java objects.
37   * </p>
38   * <p>
39   * The Sieve configuration is read from 3 properties files
40   * </p>
41   * <ul>
42   * <li><code>org/apache/jsieve/commandsmap.properties</code></li>
43   * <li><code>org/apache/jsieve/testsmap.properties</code></li>
44   * <li><code>org/apache/jsieve/comparatorsmap.properties</code></li>
45   * </ul>
46   * <p>They are located by searching the classpath of the current ClassLoader.
47   * </p>
48   * <h4>Thread Safety</h4>
49   * <p>
50   * Each configuration manager instance may be safely accessed by concurrent threads.
51   * </p>
52   * <p>
53   * The managers constructed by 
54   * </p>
55   * <ul>
56   * <li>{@link #getCommandManager()}</li> 
57   * <li>{@link #getComparatorManager()}</li>
58   * <li>{@link #getTestManager()}</li>
59   * </ul>
60   * <p>
61   * and the {@link SieveFactory} built by
62   * </p>
63   * <ul>
64   * <li>{@link #build()}</li>
65   * </ul>
66   * <p>
67   * may be safely shared by multiple threads.
68   * </p>
69   */
70  public class ConfigurationManager {
71  
72      private static final int DEFAULT_INITIAL_CONCURRENCY_LEVEL = 8;
73  
74      private static final String COMMANDSMAP_PROPERTIES = "org/apache/jsieve/commandsmap.properties";
75  
76      private static final String TESTSMAP_PROPERTIES = "org/apache/jsieve/testsmap.properties";
77  
78      private static final String COMPARATORSMAP_PROPERTIES = "org/apache/jsieve/comparatorsmap.properties";
79  
80      /**
81       * A Map of the Command names and their associated class names.
82       */
83      private ConcurrentMap<String, String> fieldCommandMap;
84  
85      /**
86       * A Map of the Test names and their associated class names.
87       */
88      private ConcurrentMap<String, String> fieldTestMap;
89  
90      /**
91       * A Map of the Comparator names and their associated class names.
92       */
93      private ConcurrentMap<String, String> fieldComparatorMap;
94      
95      /**
96       * The initial size for the {@link ConcurrentHashMap} concurrency level.
97       */
98      private int initialConcurrencyLevel = DEFAULT_INITIAL_CONCURRENCY_LEVEL;
99  
100     private static final Log LOG = LogFactory.getLog("org.apache.jsieve");
101 
102     private Log log = LOG;
103     
104     /**
105      * Constructor for ConfigurationManager.
106      * 
107      * @throws SieveConfigurationException
108      */
109     public ConfigurationManager() throws SieveConfigurationException {
110         super();
111         try {
112             parse();
113         } catch (SAXException e) {
114             if (log.isErrorEnabled())
115                 log.error("Exception processing Configuration: ", e);
116             throw new SieveConfigurationException(e);
117         } catch (IOException e) {
118             if (log.isErrorEnabled())
119                 log.error("Exception processing Configuration: ", e);
120             throw new SieveConfigurationException(e);
121         }
122     }
123 
124     /**
125      * Gets the current initial size for the {@link ConcurrentHashMap} concurrency level.
126      * @return number of concurrent threads estimated for initial sizing
127      */
128     public int getInitialConcurrencyLevel() {
129         return initialConcurrencyLevel;
130     }
131 
132     /**
133      * Sets the current initial size for the {@link ConcurrentHashMap} concurrency level.
134      * @param initialConcurrencyLevel number of concurrent threads estimated for initial sizing
135      */
136     public void setInitialConcurrencyLevel(int initialConcurrencyLevel) {
137         this.initialConcurrencyLevel = initialConcurrencyLevel;
138     }
139 
140 
141 
142     /**
143      * <p>
144      * Method getConfigStream answers an InputStream over the Sieve
145      * configuration file. It is located by searching the classpath of the
146      * current ClassLoader.
147      * </p>
148      * <p>
149      * The context classloader is searched first. If a suitably named resource
150      * is found then this is returned. Otherwise, the classloader used to load
151      * this class is searched for the resource.
152      * </p>
153      * 
154      * @return InputStream
155      * @throws IOException
156      */
157     private InputStream getConfigStream(String configName) throws IOException {
158         InputStream stream = null;
159         // Context classloader is usually right in a JEE evironment
160         final ClassLoader contextClassLoader = Thread.currentThread()
161                 .getContextClassLoader();
162         if (contextClassLoader != null) {
163             stream = contextClassLoader.getResourceAsStream(configName);
164         }
165 
166         // Sometimes context classloader will not be set conventionally
167         // So, try class classloader
168         if (null == stream) {
169             stream = ConfigurationManager.class.getClassLoader()
170                     .getResourceAsStream(configName);
171         }
172 
173         if (null == stream)
174             throw new IOException("Resource \"" + configName + "\" not found");
175         return stream;
176     }
177 
178     /**
179      * Method getCommandMap answers a Map of Command names and their associated
180      * class names, lazily initialized if required.
181      * 
182      * @return Map not null
183      */
184     public ConcurrentMap<String, String> getCommandMap() {
185         if (null == fieldCommandMap) {
186             fieldCommandMap = new ConcurrentHashMap<String, String>();
187         }
188         return fieldCommandMap;
189     }
190 
191     /**
192      * Method getTestMap answers a Map of Test names and their associated class
193      * names, lazily initialized if required.
194      * 
195      * @return Map not null
196      */
197     public ConcurrentMap<String, String> getTestMap() {
198         if (null == fieldTestMap) {
199             fieldTestMap = new ConcurrentHashMap<String, String>();
200         }
201         return fieldTestMap;
202     }
203 
204     /**
205      * Method getComparatorMap answers a Map of Comparator names and their
206      * associated class names, lazily initialized if required.
207      * 
208      * @return Map not null
209      */
210     public ConcurrentMap<String, String> getComparatorMap() {
211         if (null == fieldComparatorMap) {
212             fieldComparatorMap = new ConcurrentHashMap<String, String>();
213         }
214         return fieldComparatorMap;
215     }
216 
217     /**
218      * Method parse uses the Digester to parse the XML statements in the Sieve
219      * configuration file into Java objects.
220      * 
221      * @throws SAXException
222      * @throws IOException
223      */
224     private void parse() throws SAXException, IOException {
225         setCommandMap(loadConfiguration(COMMANDSMAP_PROPERTIES));
226         setTestMap(loadConfiguration(TESTSMAP_PROPERTIES));
227         setComparatorMap(loadConfiguration(COMPARATORSMAP_PROPERTIES));
228     }
229 
230     private ConcurrentMap<String,String> loadConfiguration(final String name) throws IOException {
231         final Properties properties = loadProperties(name);
232         final ConcurrentMap<String, String> result = 
233             new ConcurrentHashMap<String, String>(properties.size(), 1.0f, initialConcurrencyLevel);
234         for (final Map.Entry<Object, Object> entry: properties.entrySet()) {
235             result.put(entry.getKey().toString(), entry.getValue().toString());
236         }
237         return result;
238     }
239     
240     private Properties loadProperties(final String name) throws IOException {
241         final InputStream is = getConfigStream(name);
242         final Properties p = new Properties();
243         p.load(is);
244         return p;
245     }
246 
247     /**
248      * Sets the commandMap.
249      * 
250      * @param commandMap
251      *            The commandMap to set
252      */
253     private void setCommandMap(ConcurrentMap<String, String> commandMap) {
254         fieldCommandMap = commandMap;
255     }
256 
257     /**
258      * Sets the testMap.
259      * 
260      * @param testMap
261      *            The testMap to set
262      */
263     private void setTestMap(ConcurrentMap<String, String> testMap) {
264         fieldTestMap = testMap;
265     }
266 
267     /**
268      * Sets the comparatorMap.
269      * 
270      * @param comparatorMap
271      *            The comparatorMap to set
272      */
273     private void setComparatorMap(ConcurrentMap<String, String> comparatorMap) {
274         fieldComparatorMap = comparatorMap;
275     }
276 
277     public ComparatorManager getComparatorManager() {
278         return new ComparatorManagerImpl(fieldComparatorMap);
279     }
280 
281     public CommandManager getCommandManager() {
282         return new CommandManagerImpl(fieldCommandMap);
283     }
284 
285     public TestManager getTestManager() {
286         return new TestManagerImpl(fieldTestMap);
287     }
288 
289     public Log getLog() {
290         return log;
291     }
292     
293     public void setLog(Log log) {
294         this.log = log;
295     }
296 
297     public SieveFactory build() {
298         return new SieveFactory(getCommandManager(), getComparatorManager(),
299                 getTestManager(), getLog());
300     }
301 }