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 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  
 }