Coverage Report - org.apache.turbine.services.assemblerbroker.TurbineAssemblerBrokerService
 
Classes in this File Line Coverage Branch Coverage Complexity
TurbineAssemblerBrokerService
86%
70/81
89%
34/38
5,5
 
 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  
 import java.util.concurrent.ConcurrentHashMap;
 30  
 import java.util.concurrent.ConcurrentMap;
 31  
 
 32  
 import org.apache.commons.configuration2.Configuration;
 33  
 import org.apache.logging.log4j.LogManager;
 34  
 import org.apache.logging.log4j.Logger;
 35  
 import org.apache.turbine.Turbine;
 36  
 import org.apache.turbine.TurbineConstants;
 37  
 import org.apache.turbine.annotation.AnnotationProcessor;
 38  
 import org.apache.turbine.modules.Assembler;
 39  
 import org.apache.turbine.modules.Loader;
 40  
 import org.apache.turbine.services.InitializationException;
 41  
 import org.apache.turbine.services.TurbineBaseService;
 42  
 import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
 43  
 import org.apache.turbine.util.TurbineException;
 44  
 
 45  
 /**
 46  
  * TurbineAssemblerBrokerService allows assemblers (like screens,
 47  
  * actions and layouts) to be loaded from one or more AssemblerFactory
 48  
  * classes.  AssemblerFactory classes are registered with this broker
 49  
  * by adding them to the TurbineResources.properties file.
 50  
  *
 51  
  * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
 52  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 53  
  * @version $Id: TurbineAssemblerBrokerService.java 1854688 2019-03-03 10:36:42Z tv $
 54  
  */
 55  102
 public class TurbineAssemblerBrokerService
 56  
         extends TurbineBaseService
 57  
         implements AssemblerBrokerService
 58  
 {
 59  
     /** Logging */
 60  204
     private static Logger log
 61  102
             = LogManager.getLogger(TurbineAssemblerBrokerService.class);
 62  
 
 63  
     /** A structure that holds the registered AssemblerFactories */
 64  102
     private Map<Class<?>, List<?>> factories = null;
 65  
 
 66  
     /** A cache that holds the generated Assemblers */
 67  102
     private ConcurrentMap<String, Assembler> assemblerCache = null;
 68  
 
 69  
     /** A cache that holds the Loaders */
 70  102
     private ConcurrentMap<Class<?>, Loader<? extends Assembler>> loaderCache = null;
 71  
 
 72  
     /** Caching on/off */
 73  
     private boolean isCaching;
 74  
 
 75  
     /**
 76  
      * Get a list of AssemblerFactories of a certain type
 77  
      *
 78  
      * @param type type of Assembler
 79  
      *
 80  
      * @param <T> the type of the assembler
 81  
      *
 82  
      * @return list of AssemblerFactories
 83  
      */
 84  
     @SuppressWarnings("unchecked")
 85  
     private <T extends Assembler> List<AssemblerFactory<T>> getFactoryGroup(Class<T> type)
 86  
     {
 87  2430
         if (!factories.containsKey(type))
 88  
         {
 89  792
             factories.put(type, new ArrayList<AssemblerFactory<T>>());
 90  
         }
 91  2430
         return (List<AssemblerFactory<T>>) factories.get(type);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Utility method to register all factories for a given type.
 96  
      *
 97  
      * @param type type of Assembler
 98  
      * @throws TurbineException if the factory for the given type could not be registered
 99  
      */
 100  
     private void registerFactories(String type)
 101  
         throws TurbineException
 102  
     {
 103  792
         List<Object> names = getConfiguration().getList(type);
 104  
 
 105  792
         log.info("Registering {} {} factories.", Integer.valueOf(names.size()), type);
 106  
 
 107  792
         for (Iterator<Object> it = names.iterator(); it.hasNext(); )
 108  
         {
 109  792
             String factory = (String) it.next();
 110  
             try
 111  
             {
 112  
                 @SuppressWarnings("unchecked")
 113  792
                 AssemblerFactory<? extends Assembler> af =
 114  792
                     (AssemblerFactory<? extends Assembler>) Class.forName(factory).newInstance();
 115  792
                 registerFactory(af);
 116  
             }
 117  
             // these must be passed to the VM
 118  0
             catch (ThreadDeath | 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  792
             }
 129  792
         }
 130  792
     }
 131  
 
 132  
     /**
 133  
      * Initializes the AssemblerBroker and loads the AssemblerFactory
 134  
      * classes registered in TurbineResources.Properties.
 135  
      *
 136  
      * @throws InitializationException if problems occur while registering the factories
 137  
      */
 138  
     @Override
 139  
     public void init()
 140  
         throws InitializationException
 141  
     {
 142  132
         factories = new HashMap<Class<?>, List<?>>();
 143  
 
 144  
         try
 145  
         {
 146  132
             Configuration conf = getConfiguration();
 147  
 
 148  132
             for (Iterator<String> i = conf.getKeys(); i.hasNext();)
 149  
             {
 150  924
                 String type = i.next();
 151  
 
 152  924
                 if (!"classname".equalsIgnoreCase(type))
 153  
                 {
 154  792
                     registerFactories(type);
 155  
                 }
 156  924
             }
 157  
         }
 158  0
         catch (TurbineException e)
 159  
         {
 160  0
             throw new InitializationException(
 161  
                     "AssemblerBrokerService failed to initialize", e);
 162  132
         }
 163  
 
 164  132
         isCaching = Turbine.getConfiguration()
 165  132
             .getBoolean(TurbineConstants.MODULE_CACHE_KEY,
 166  
                         TurbineConstants.MODULE_CACHE_DEFAULT);
 167  
 
 168  132
         if (isCaching)
 169  
         {
 170  48
             int cacheSize = Turbine.getConfiguration()
 171  48
                 .getInt(TurbineConstants.MODULE_CACHE_SIZE_KEY,
 172  
                         TurbineConstants.MODULE_CACHE_SIZE_DEFAULT);
 173  
 
 174  48
             assemblerCache = new ConcurrentHashMap<String, Assembler>(cacheSize);
 175  48
             loaderCache = new ConcurrentHashMap<Class<?>, Loader<? extends Assembler>>(cacheSize);
 176  
         }
 177  
 
 178  132
         setInit(true);
 179  132
     }
 180  
 
 181  
     /**
 182  
      * Register a new AssemblerFactory
 183  
      *
 184  
      * @param factory factory to register
 185  
      *
 186  
      * @param <T> the type of the assembler
 187  
      *
 188  
      */
 189  
     @Override
 190  
     public <T extends Assembler> void registerFactory(AssemblerFactory<T> factory)
 191  
     {
 192  792
         getFactoryGroup(factory.getManagedClass()).add(factory);
 193  792
     }
 194  
 
 195  
     /**
 196  
      * Attempt to retrieve an Assembler of a given type with
 197  
      * a name.  Cycle through all the registered AssemblerFactory
 198  
      * classes of type and return the first non-null assembly
 199  
      * found.  If an assembly was not found return null.
 200  
      *
 201  
      * @param type type of Assembler
 202  
      * @param name name of the requested Assembler
 203  
      *
 204  
      * @param <T> the type of the assembler
 205  
      *
 206  
      * @return an Assembler or null
 207  
      * @throws TurbineException if the assembler could not be loaded
 208  
      */
 209  
     @Override
 210  
     @SuppressWarnings("unchecked")
 211  
     public <T extends Assembler> T getAssembler(Class<T> type, String name)
 212  
         throws TurbineException
 213  
     {
 214  363
         String key = type + ":" + name;
 215  363
         T assembler = null;
 216  
 
 217  363
         if (isCaching && assemblerCache.containsKey(key))
 218  
         {
 219  9
             assembler = (T) assemblerCache.get(key);
 220  9
             log.debug("Found {} in the cache!", key);
 221  
         }
 222  
         else
 223  
         {
 224  354
             log.debug("Loading {}", key);
 225  354
             List<AssemblerFactory<T>> facs = getFactoryGroup(type);
 226  
 
 227  354
             for (Iterator<AssemblerFactory<T>> it = facs.iterator(); (assembler == null) && it.hasNext();)
 228  
             {
 229  354
                 AssemblerFactory<T> fac = it.next();
 230  
 
 231  
                 try
 232  
                 {
 233  354
                     assembler = fac.getAssembler(name);
 234  
                 }
 235  0
                 catch (Exception e)
 236  
                 {
 237  0
                     throw new TurbineException("Failed to load an assembler for "
 238  
                                                + name + " from the "
 239  
                                                + type + " factory "
 240  0
                                                + fac.getClass().getName(), e);
 241  354
                 }
 242  
 
 243  354
                 if (assembler != null)
 244  
                 {
 245  168
                     AnnotationProcessor.process(assembler);
 246  
 
 247  168
                     if (isCaching)
 248  
                     {
 249  33
                         T oldAssembler = (T) assemblerCache.putIfAbsent(key, assembler);
 250  33
                         if (oldAssembler != null)
 251  
                         {
 252  0
                             assembler = oldAssembler;
 253  
                         }
 254  
                     }
 255  
                 }
 256  354
             }
 257  
         }
 258  
 
 259  363
         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  1572
         Loader<T> loader = null;
 276  
 
 277  1572
         if (isCaching && loaderCache.containsKey(type))
 278  
         {
 279  288
             loader = (Loader<T>) loaderCache.get(type);
 280  288
             log.debug("Found {} loader in the cache!", type);
 281  
         }
 282  
         else
 283  
         {
 284  1284
             log.debug("Getting Loader for {}", type);
 285  1284
             List<AssemblerFactory<T>> facs = getFactoryGroup(type);
 286  
 
 287  1284
             for (Iterator<AssemblerFactory<T>> it = facs.iterator(); (loader == null) && it.hasNext();)
 288  
             {
 289  1284
                 AssemblerFactory<T> fac = it.next();
 290  1284
                 loader = fac.getLoader();
 291  1284
             }
 292  
 
 293  1284
             if (isCaching && loader != null)
 294  
             {
 295  240
                 loaderCache.put(type, loader);
 296  
             }
 297  
         }
 298  
 
 299  1572
         if (loader == null)
 300  
         {
 301  0
             log.warn("Loader for {} is null.", type);
 302  
         }
 303  
 
 304  1572
         return loader;
 305  
     }
 306  
 }