Coverage Report - javax.faces.FactoryFinder
 
Classes in this File Line Coverage Branch Coverage Complexity
FactoryFinder
0%
0/111
0%
0/32
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package javax.faces;
 20  
 
 21  
 
 22  
 import javax.faces.application.ApplicationFactory;
 23  
 import javax.faces.context.FacesContextFactory;
 24  
 import javax.faces.lifecycle.LifecycleFactory;
 25  
 import javax.faces.render.RenderKitFactory;
 26  
 import java.lang.reflect.Constructor;
 27  
 import java.lang.reflect.InvocationTargetException;
 28  
 import java.util.*;
 29  
 
 30  
 /**
 31  
  * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
 32  
  *
 33  
  * @author Manfred Geiler (latest modification by $Author: skitching $)
 34  
  * @version $Revision: 676298 $ $Date: 2008-07-13 05:31:48 -0500 (Sun, 13 Jul 2008) $
 35  
  */
 36  
 public final class FactoryFinder
 37  
 {
 38  
     public static final String APPLICATION_FACTORY = "javax.faces.application.ApplicationFactory";
 39  
     public static final String FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory";
 40  
     public static final String LIFECYCLE_FACTORY = "javax.faces.lifecycle.LifecycleFactory";
 41  
     public static final String RENDER_KIT_FACTORY = "javax.faces.render.RenderKitFactory";
 42  
 
 43  
     /**
 44  
      * used as a monitor for itself and _factories.
 45  
      * Maps in this map are used as monitors for themselves and the corresponding maps in _factories.
 46  
      */
 47  0
     private static Map<ClassLoader, Map> _registeredFactoryNames = new HashMap<ClassLoader, Map>();
 48  
     /**
 49  
      * Maps from classLoader to another map, the container (i.e. Tomcat) will create a class loader for
 50  
      * each web app that it controls (typically anyway) and that class loader is used as the key.
 51  
      *
 52  
      * The secondary map maps the factory name (i.e. FactoryFinder.APPLICATION_FACTORY) to actual instances
 53  
      * that are created via getFactory. The instances will be of the class specified in the setFactory method
 54  
      * for the factory name, i.e. FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MyFactory.class).
 55  
      */
 56  0
     private static Map<ClassLoader, Map> _factories = new HashMap<ClassLoader, Map>();
 57  
 
 58  0
     private static final Set<String> VALID_FACTORY_NAMES = new HashSet<String>();
 59  0
     private static final Map<String, Class> ABSTRACT_FACTORY_CLASSES = new HashMap<String, Class>();
 60  
     static {
 61  0
         VALID_FACTORY_NAMES.add(APPLICATION_FACTORY);
 62  0
         VALID_FACTORY_NAMES.add(FACES_CONTEXT_FACTORY);
 63  0
         VALID_FACTORY_NAMES.add(LIFECYCLE_FACTORY);
 64  0
         VALID_FACTORY_NAMES.add(RENDER_KIT_FACTORY);
 65  
 
 66  0
         ABSTRACT_FACTORY_CLASSES.put(APPLICATION_FACTORY, ApplicationFactory.class);
 67  0
         ABSTRACT_FACTORY_CLASSES.put(FACES_CONTEXT_FACTORY, FacesContextFactory.class);
 68  0
         ABSTRACT_FACTORY_CLASSES.put(LIFECYCLE_FACTORY, LifecycleFactory.class);
 69  0
         ABSTRACT_FACTORY_CLASSES.put(RENDER_KIT_FACTORY, RenderKitFactory.class);
 70  0
     }
 71  
 
 72  
 
 73  
   // avoid instantiation
 74  0
   FactoryFinder() {
 75  0
   }
 76  
 
 77  
   public static Object getFactory(String factoryName)
 78  
             throws FacesException
 79  
     {
 80  0
         if(factoryName == null)
 81  0
             throw new NullPointerException("factoryName may not be null");
 82  
 
 83  0
         ClassLoader classLoader = getClassLoader();
 84  
 
 85  
         //This code must be synchronized because this could cause a problem when
 86  
         //using update feature each time of myfaces (org.apache.myfaces.CONFIG_REFRESH_PERIOD)
 87  
         //In this moment, a concurrency problem could happen
 88  0
         Map factoryClassNames = null;
 89  0
         Map<String, Object> factoryMap = null;
 90  
         
 91  0
         synchronized(_registeredFactoryNames)
 92  
         {
 93  0
             factoryClassNames = _registeredFactoryNames.get(classLoader);
 94  
 
 95  0
             if (factoryClassNames == null)
 96  
             {
 97  0
                 String message = "No Factories configured for this Application. This happens if the faces-initialization "+
 98  
                     "does not work at all - make sure that you properly include all configuration settings necessary for a basic faces application " +
 99  
                     "and that all the necessary libs are included. Also check the logging output of your web application and your container for any exceptions!" +
 100  
                     "\nIf you did that and find nothing, the mistake might be due to the fact that you use some special web-containers which "+
 101  
                     "do not support registering context-listeners via TLD files and " +
 102  
                     "a context listener is not setup in your web.xml.\n" +
 103  
                     "A typical config looks like this;\n<listener>\n" +
 104  
                     "  <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>\n" +
 105  
                     "</listener>\n";
 106  0
                 throw new IllegalStateException(message);
 107  
             }
 108  
 
 109  0
             if (! factoryClassNames.containsKey(factoryName))
 110  
             {
 111  0
                 throw new IllegalArgumentException("no factory " + factoryName + " configured for this application.");
 112  
             }
 113  
 
 114  0
             factoryMap = _factories.get(classLoader);
 115  
 
 116  0
             if (factoryMap == null)
 117  
             {
 118  0
                 factoryMap = new HashMap<String, Object>();
 119  0
                 _factories.put(classLoader, factoryMap);
 120  
             }
 121  0
         }
 122  
         
 123  0
         List classNames = null;
 124  0
         Object factory = null;
 125  0
         synchronized (factoryClassNames)
 126  
         {
 127  0
             factory = factoryMap.get(factoryName);
 128  0
             if (factory != null)
 129  
             {
 130  0
                 return factory;
 131  
             }
 132  0
             classNames = (List) factoryClassNames.get(factoryName);
 133  0
         }
 134  
         
 135  
         //release lock while calling out
 136  0
         factory = newFactoryInstance(ABSTRACT_FACTORY_CLASSES.get(factoryName), classNames.iterator(), classLoader);
 137  
         
 138  0
         synchronized (factoryClassNames)
 139  
         {
 140  
             //check if someone else already installed the factory
 141  0
             if (factoryMap.get(factoryName) == null)
 142  
             {
 143  0
                 factoryMap.put(factoryName, factory);
 144  
             }            
 145  0
         }
 146  0
         return factory;
 147  
     }
 148  
 
 149  
 
 150  
     private static Object newFactoryInstance(Class interfaceClass, Iterator classNamesIterator, ClassLoader classLoader)
 151  
     {
 152  
         try
 153  
         {
 154  0
             Object current = null;
 155  
 
 156  0
             while (classNamesIterator.hasNext())
 157  
             {
 158  0
                 String implClassName = (String) classNamesIterator.next();
 159  0
                 Class implClass = classLoader.loadClass(implClassName);
 160  
 
 161  
                 // check, if class is of expected interface type
 162  0
                 if (!interfaceClass.isAssignableFrom(implClass))
 163  
                 {
 164  0
                     throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
 165  
                 }
 166  
 
 167  0
                 if (current == null)
 168  
                 {
 169  
                     // nothing to decorate
 170  0
                     current = implClass.newInstance();
 171  
                 } else
 172  
                 {
 173  
                     // let's check if class supports the decorator pattern
 174  
                     try
 175  
                     {
 176  0
                         Constructor delegationConstructor = implClass.getConstructor(new Class[]{interfaceClass});
 177  
                         // impl class supports decorator pattern,
 178  
                         try
 179  
                         {
 180  
                             // create new decorator wrapping current
 181  0
                             current = delegationConstructor.newInstance(new Object[]{current});
 182  0
                         } catch (InstantiationException e)
 183  
                         {
 184  0
                             throw new FacesException(e);
 185  0
                         } catch (IllegalAccessException e)
 186  
                         {
 187  0
                             throw new FacesException(e);
 188  0
                         } catch (InvocationTargetException e)
 189  
                         {
 190  0
                             throw new FacesException(e);
 191  0
                         }
 192  0
                     } catch (NoSuchMethodException e)
 193  
                     {
 194  
                         // no decorator pattern support
 195  0
                         current = implClass.newInstance();
 196  0
                     }
 197  
                 }
 198  0
             }
 199  
 
 200  0
             return current;
 201  0
         } catch (ClassNotFoundException e)
 202  
         {
 203  0
             throw new FacesException(e);
 204  0
         } catch (InstantiationException e)
 205  
         {
 206  0
             throw new FacesException(e);
 207  0
         } catch (IllegalAccessException e)
 208  
         {
 209  0
             throw new FacesException(e);
 210  
         }
 211  
     }
 212  
 
 213  
 
 214  
     public static void setFactory(String factoryName,
 215  
                                   String implName)
 216  
     {
 217  0
         checkFactoryName(factoryName);
 218  
 
 219  0
         ClassLoader classLoader = getClassLoader();
 220  0
         Map<String, List> factoryClassNames = null;
 221  0
         synchronized(_registeredFactoryNames)
 222  
         {
 223  0
             Map factories = _factories.get(classLoader);
 224  
 
 225  0
             if (factories != null && factories.containsKey(factoryName)) {
 226  
                 // Javadoc says ... This method has no effect if getFactory() has already been
 227  
                 // called looking for a factory for this factoryName.
 228  0
                 return;
 229  
             }
 230  
 
 231  0
             factoryClassNames = _registeredFactoryNames.get(classLoader);
 232  
 
 233  0
             if (factoryClassNames == null)
 234  
             {
 235  0
                 factoryClassNames = new HashMap<String, List>();
 236  0
                 _registeredFactoryNames.put(classLoader, factoryClassNames);
 237  
             }
 238  0
         }
 239  0
         synchronized (factoryClassNames)
 240  
         {
 241  0
             List<String> classNameList = factoryClassNames.get(factoryName);
 242  
 
 243  0
             if (classNameList == null) 
 244  
             {
 245  0
                 classNameList = new ArrayList<String>();
 246  0
                 factoryClassNames.put(factoryName, classNameList);
 247  
             }
 248  0
             classNameList.add(implName);
 249  0
         }
 250  0
     }
 251  
 
 252  
 
 253  
     public static void releaseFactories()
 254  
             throws FacesException
 255  
     {
 256  0
         ClassLoader classLoader = getClassLoader();
 257  
 
 258  
         //This code must be synchronized
 259  0
         synchronized(_registeredFactoryNames)
 260  
         {
 261  0
             _factories.remove(classLoader);            
 262  
             
 263  
             // _registeredFactoryNames has as value type Map<String,List> and this must
 264  
             //be cleaned before release (for gc).
 265  0
             Map factoryClassNames = (Map) _registeredFactoryNames.get(classLoader);
 266  0
             if (factoryClassNames != null) factoryClassNames.clear();
 267  0
             _registeredFactoryNames.remove(classLoader);
 268  0
         }
 269  0
     }
 270  
 
 271  
     private static void checkFactoryName(String factoryName)
 272  
     {
 273  0
         if (! VALID_FACTORY_NAMES.contains(factoryName))
 274  
         {
 275  0
             throw new IllegalArgumentException("factoryName '" + factoryName + "'");
 276  
         }
 277  0
     }
 278  
 
 279  
 
 280  
     private static ClassLoader getClassLoader()
 281  
     {
 282  
         try
 283  
         {
 284  0
             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 285  0
             if (classLoader == null)
 286  
             {
 287  0
                 throw new FacesException("web application class loader cannot be identified", null);
 288  
             }
 289  0
             return classLoader;
 290  
         }
 291  0
         catch (Exception e)
 292  
         {
 293  0
             throw new FacesException("web application class loader cannot be identified", e);
 294  
         }
 295  
     }
 296  
 }