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,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  819
         if (!factories.containsKey(type))
 87  
         {
 88  258
             factories.put(type, new ArrayList<AssemblerFactory<T>>());
 89  
         }
 90  819
         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  166
         String key = type + ":" + name;
 219  166
         T assembler = null;
 220  
 
 221  166
         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  160
             log.debug("Loading " + key);
 229  160
             List<AssemblerFactory<T>> facs = getFactoryGroup(type);
 230  
 
 231  160
             for (Iterator<AssemblerFactory<T>> it = facs.iterator(); (assembler == null) && it.hasNext();)
 232  
             {
 233  160
                 AssemblerFactory<T> fac = it.next();
 234  
 
 235  
                 try
 236  
                 {
 237  160
                     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  160
                 }
 246  
 
 247  160
                 if (assembler != null)
 248  
                 {
 249  98
                     AnnotationProcessor.process(assembler);
 250  
 
 251  98
                     if (isCaching)
 252  
                     {
 253  15
                         assemblerCache.put(key, assembler);
 254  
                     }
 255  
                 }
 256  160
             }
 257  
         }
 258  
 
 259  166
         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  
 }