##### Coverage Report - org.apache.turbine.services.assemblerbroker.TurbineAssemblerBrokerService

Classes in this File | Line Coverage | Branch Coverage | Complexity
TurbineAssemblerBrokerService |
85% | 65/76
91% | 33/36
| 5.666666666666667;5,667

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