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