• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.clearsilver;
18 
19 import java.lang.reflect.Constructor;
20 import java.util.concurrent.locks.ReadWriteLock;
21 import java.util.concurrent.locks.ReentrantReadWriteLock;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
24 
25 /**
26  * This class holds static methods for getting and setting the CS and HDF
27  * factory used throughout the Java Clearsilver Framework.
28  * Clients are <strong>strongly encouraged</strong> to not use this class, and
29  * instead directly inject {@link ClearsilverFactory} into the classes that
30  * need to create {@link HDF} and {@link CS} instances.
31  * For now, projects should set the {@link ClearsilverFactory} in FactoryLoader
32  * and use the singleton accessor {@link #getClearsilverFactory()} if proper
33  * dependency injection is not easy to implement.
34  * <p>
35  * Allows the default implementation to be the original JNI version without
36  * requiring users that don't want to use the JNI version to have to link
37  * it in.  The ClearsilverFactory object to use can be either passed into the
38  * {@link #setClearsilverFactory} method or the class name can be specified
39  * in the Java property {@code  org.clearsilver.defaultClearsilverFactory}.
40  */
41 public final class FactoryLoader {
42   private static final Logger logger =
43       Logger.getLogger(FactoryLoader.class.getName());
44 
45   private static final String DEFAULT_CS_FACTORY_CLASS_PROPERTY_NAME =
46       "org.clearsilver.defaultClearsilverFactory";
47   private static final String DEFAULT_CS_FACTORY_CLASS_NAME =
48       "org.clearsilver.jni.JniClearsilverFactory";
49 
50   // ClearsilverFactory to be used when constructing objects.  Allows
51   // applications to subclass the CS and HDF objects used in Java Clearsilver
52   private static ClearsilverFactory clearsilverFactory = null;
53 
54   // Read/Write lock for global factory pointer.
55   private static final ReadWriteLock factoryLock = new ReentrantReadWriteLock();
56 
57   // Getters and setters
58   /**
59    * Get the {@link org.clearsilver.ClearsilverFactory} object to be used by
60    * disparate parts of the application.
61    */
getClearsilverFactory()62   public static ClearsilverFactory getClearsilverFactory() {
63     factoryLock.readLock().lock();
64     if (clearsilverFactory == null) {
65       factoryLock.readLock().unlock();
66       factoryLock.writeLock().lock();
67       try {
68         if (clearsilverFactory == null) {
69           clearsilverFactory = newDefaultClearsilverFactory();
70         }
71         factoryLock.readLock().lock();
72       } finally {
73         factoryLock.writeLock().unlock();
74       }
75     }
76     ClearsilverFactory returned = clearsilverFactory;
77     factoryLock.readLock().unlock();
78     return returned;
79   }
80 
81   /**
82    * Set the {@link org.clearsilver.ClearsilverFactory} to be used by
83    * the application. If parameter is {@code null}, then the default factory
84    * implementation will be used the next time {@link #getClearsilverFactory()}
85    * is called.
86    *
87    * @return the previous factory (may return {@code null})
88    */
setClearsilverFactory( ClearsilverFactory clearsilverFactory)89   public static ClearsilverFactory setClearsilverFactory(
90       ClearsilverFactory clearsilverFactory) {
91     factoryLock.writeLock().lock();
92     try {
93       ClearsilverFactory previousFactory = FactoryLoader.clearsilverFactory;
94       FactoryLoader.clearsilverFactory = clearsilverFactory;
95       return previousFactory;
96     } finally {
97       factoryLock.writeLock().unlock();
98     }
99   }
100 
newDefaultClearsilverFactory()101   private static ClearsilverFactory newDefaultClearsilverFactory() {
102     String factoryClassName =
103         System.getProperty(DEFAULT_CS_FACTORY_CLASS_PROPERTY_NAME,
104             DEFAULT_CS_FACTORY_CLASS_NAME);
105     try {
106       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
107       Class<ClearsilverFactory> clazz =
108           loadClass(factoryClassName, classLoader);
109       Constructor<ClearsilverFactory> constructor = clazz.getConstructor();
110       return constructor.newInstance();
111     } catch (Exception e) {
112       String errMsg = "Unable to load default ClearsilverFactory class: \"" +
113           factoryClassName + "\"";
114       logger.log(Level.SEVERE, errMsg, e);
115       throw new RuntimeException(errMsg, e);
116     }
117   }
118 
loadClass(String className, ClassLoader classLoader)119   private static Class<ClearsilverFactory> loadClass(String className,
120       ClassLoader classLoader) throws ClassNotFoundException {
121     return (Class<ClearsilverFactory>) Class.forName(className, true,
122         classLoader);
123   }
124 }
125