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