View Javadoc

1   package org.apache.turbine.services.assemblerbroker;
2   
3   
4   /*
5    * Licensed to the Apache Software Foundation (ASF) under one
6    * or more contributor license agreements.  See the NOTICE file
7    * distributed with this work for additional information
8    * regarding copyright ownership.  The ASF licenses this file
9    * to you under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License.  You may obtain a copy of the License at
12   *
13   *   http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on an
17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied.  See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21   */
22  
23  
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Vector;
29  
30  import org.apache.commons.collections.map.LRUMap;
31  import org.apache.commons.configuration.Configuration;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.turbine.Turbine;
35  import org.apache.turbine.TurbineConstants;
36  import org.apache.turbine.modules.Assembler;
37  import org.apache.turbine.modules.Loader;
38  import org.apache.turbine.services.InitializationException;
39  import org.apache.turbine.services.TurbineBaseService;
40  import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
41  import org.apache.turbine.util.TurbineException;
42  
43  /**
44   * TurbineAssemblerBrokerService allows assemblers (like screens,
45   * actions and layouts) to be loaded from one or more AssemblerFactory
46   * classes.  AssemblerFactory classes are registered with this broker
47   * by adding them to the TurbineResources.properties file.
48   *
49   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
50   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
51   * @version $Id: TurbineAssemblerBrokerService.java 1078552 2011-03-06 19:58:46Z tv $
52   */
53  public class TurbineAssemblerBrokerService
54          extends TurbineBaseService
55          implements AssemblerBrokerService
56  {
57      /** Logging */
58      private static Log log
59              = LogFactory.getLog(TurbineAssemblerBrokerService.class);
60  
61      /** A structure that holds the registered AssemblerFactories */
62      private Map<String, List<AssemblerFactory>> factories = null;
63  
64      /** A cache that holds the generated Assemblers */
65      private Map<String, Assembler> assemblerCache = null;
66  
67      /** A cache that holds the Loaders */
68      private Map<String, Loader> loaderCache = null;
69  
70      /** Caching on/off */
71      private boolean isCaching;
72  
73      /**
74       * Get a list of AssemblerFactories of a certain type
75       *
76       * @param type type of Assembler
77       * @return list of AssemblerFactories
78       */
79      private List<AssemblerFactory> getFactoryGroup(String type)
80      {
81          if (!factories.containsKey(type))
82          {
83              factories.put(type, new Vector<AssemblerFactory>());
84          }
85          return factories.get(type);
86      }
87  
88      /**
89       * Utiltiy method to register all factories for a given type.
90       *
91       * @param type type of Assembler
92       * @throws TurbineException
93       */
94      private void registerFactories(String type)
95          throws TurbineException
96      {
97          List names = getConfiguration().getList(type);
98  
99          log.info("Registering " + names.size() + " " + type + " factories.");
100 
101         for (Iterator it = names.iterator(); it.hasNext(); )
102         {
103             String factory = (String) it.next();
104             try
105             {
106                 Object o = Class.forName(factory).newInstance();
107                 registerFactory(type, (AssemblerFactory) o);
108             }
109             // these must be passed to the VM
110             catch (ThreadDeath e)
111             {
112                 throw e;
113             }
114             catch (OutOfMemoryError e)
115             {
116                 throw e;
117             }
118             // when using Class.forName(), NoClassDefFoundErrors are likely
119             // to happen (missing jar files)
120             catch (Throwable t)
121             {
122                 throw new TurbineException("Failed registering " + type
123                         + " factory: " + factory, t);
124             }
125         }
126     }
127 
128     /**
129      * Initializes the AssemblerBroker and loads the AssemblerFactory
130      * classes registered in TurbineResources.Properties.
131      *
132      * @throws InitializationException
133      */
134     @SuppressWarnings("unchecked") // as long as commons-collections does not use generics
135     @Override
136     public void init()
137         throws InitializationException
138     {
139         factories = new HashMap<String, List<AssemblerFactory>>();
140 
141         try
142         {
143             Configuration conf = getConfiguration();
144 
145             for (Iterator i = conf.getKeys(); i.hasNext();)
146             {
147                 String type = (String)i.next();
148 
149                 if (!"classname".equalsIgnoreCase(type))
150                 {
151                     registerFactories(type);
152                 }
153             }
154         }
155         catch (TurbineException e)
156         {
157             throw new InitializationException(
158                     "AssemblerBrokerService failed to initialize", e);
159         }
160 
161         isCaching = Turbine.getConfiguration()
162             .getBoolean(TurbineConstants.MODULE_CACHE_KEY,
163                         TurbineConstants.MODULE_CACHE_DEFAULT);
164 
165         if (isCaching)
166         {
167             int cacheSize = Turbine.getConfiguration()
168                 .getInt(TurbineConstants.MODULE_CACHE_SIZE_KEY,
169                         TurbineConstants.MODULE_CACHE_SIZE_DEFAULT);
170 
171             assemblerCache = new LRUMap(cacheSize);
172             loaderCache = new LRUMap(cacheSize);
173         }
174 
175         setInit(true);
176     }
177 
178     /**
179      * Register a new AssemblerFactory under a certain type
180      *
181      * @param type type of Assembler
182      * @param factory factory to register
183      */
184     public void registerFactory(String type, AssemblerFactory factory)
185     {
186         getFactoryGroup(type).add(factory);
187     }
188 
189     /**
190      * Attempt to retrieve an Assembler of a given type with
191      * a name.  Cycle through all the registered AssemblerFactory
192      * classes of type and return the first non-null assembly
193      * found.  If an assembly was not found return null.
194      *
195      * @param type type of Assembler
196      * @param name name of the requested Assembler
197      * @return an Assembler or null
198      * @throws TurbineException
199      */
200     public Assembler getAssembler(String type, String name)
201         throws TurbineException
202     {
203         String key = type + ":" + name;
204         Assembler assembler = null;
205 
206         if (isCaching && assemblerCache.containsKey(key))
207         {
208             assembler = assemblerCache.get(key);
209             log.debug("Found " + key + " in the cache!");
210         }
211         else
212         {
213             log.debug("Loading " + key);
214             List<AssemblerFactory> facs = getFactoryGroup(type);
215 
216             for (Iterator<AssemblerFactory> it = facs.iterator(); (assembler == null) && it.hasNext();)
217             {
218                 AssemblerFactory fac = it.next();
219 
220                 try
221                 {
222                     assembler = fac.getAssembler(name);
223                 }
224                 catch (Exception e)
225                 {
226                     throw new TurbineException("Failed to load an assembler for "
227                                                + name + " from the "
228                                                + type + " factory "
229                                                + fac.getClass().getName(), e);
230                 }
231 
232                 if (isCaching && assembler != null)
233                 {
234                     assemblerCache.put(key, assembler);
235                 }
236             }
237         }
238 
239         return assembler;
240     }
241 
242     /**
243      * Get a Loader for the given assembler type
244      *
245      * @param type The Type of the Assembler
246      * @return A Loader instance for the requested type
247      */
248     public Loader getLoader(String type)
249     {
250         Loader loader = null;
251 
252         if (isCaching && loaderCache.containsKey(type))
253         {
254             loader = loaderCache.get(type);
255             log.debug("Found " + type + " loader in the cache!");
256         }
257         else
258         {
259             log.debug("Getting Loader for " + type);
260             List facs = getFactoryGroup(type);
261 
262             for (Iterator it = facs.iterator(); (loader == null) && it.hasNext();)
263             {
264                 AssemblerFactory fac = (AssemblerFactory) it.next();
265 
266                 loader = fac.getLoader();
267             }
268 
269             if (isCaching && loader != null)
270             {
271                 loaderCache.put(type, loader);
272             }
273         }
274 
275         if (loader == null)
276         {
277             log.warn("Loader for " + type + " is null.");
278         }
279 
280         return loader;
281     }
282 }