| /* |
| * Copyright (C) 2010 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.clearsilver; |
| |
| import java.lang.reflect.Constructor; |
| import java.util.concurrent.locks.ReadWriteLock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * This class holds static methods for getting and setting the CS and HDF |
| * factory used throughout the Java Clearsilver Framework. |
| * Clients are <strong>strongly encouraged</strong> to not use this class, and |
| * instead directly inject {@link ClearsilverFactory} into the classes that |
| * need to create {@link HDF} and {@link CS} instances. |
| * For now, projects should set the {@link ClearsilverFactory} in FactoryLoader |
| * and use the singleton accessor {@link #getClearsilverFactory()} if proper |
| * dependency injection is not easy to implement. |
| * <p> |
| * Allows the default implementation to be the original JNI version without |
| * requiring users that don't want to use the JNI version to have to link |
| * it in. The ClearsilverFactory object to use can be either passed into the |
| * {@link #setClearsilverFactory} method or the class name can be specified |
| * in the Java property {@code org.clearsilver.defaultClearsilverFactory}. |
| */ |
| public final class FactoryLoader { |
| private static final Logger logger = |
| Logger.getLogger(FactoryLoader.class.getName()); |
| |
| private static final String DEFAULT_CS_FACTORY_CLASS_PROPERTY_NAME = |
| "org.clearsilver.defaultClearsilverFactory"; |
| private static final String DEFAULT_CS_FACTORY_CLASS_NAME = |
| "org.clearsilver.jni.JniClearsilverFactory"; |
| |
| // ClearsilverFactory to be used when constructing objects. Allows |
| // applications to subclass the CS and HDF objects used in Java Clearsilver |
| private static ClearsilverFactory clearsilverFactory = null; |
| |
| // Read/Write lock for global factory pointer. |
| private static final ReadWriteLock factoryLock = new ReentrantReadWriteLock(); |
| |
| // Getters and setters |
| /** |
| * Get the {@link org.clearsilver.ClearsilverFactory} object to be used by |
| * disparate parts of the application. |
| */ |
| public static ClearsilverFactory getClearsilverFactory() { |
| factoryLock.readLock().lock(); |
| if (clearsilverFactory == null) { |
| factoryLock.readLock().unlock(); |
| factoryLock.writeLock().lock(); |
| try { |
| if (clearsilverFactory == null) { |
| clearsilverFactory = newDefaultClearsilverFactory(); |
| } |
| factoryLock.readLock().lock(); |
| } finally { |
| factoryLock.writeLock().unlock(); |
| } |
| } |
| ClearsilverFactory returned = clearsilverFactory; |
| factoryLock.readLock().unlock(); |
| return returned; |
| } |
| |
| /** |
| * Set the {@link org.clearsilver.ClearsilverFactory} to be used by |
| * the application. If parameter is {@code null}, then the default factory |
| * implementation will be used the next time {@link #getClearsilverFactory()} |
| * is called. |
| * |
| * @return the previous factory (may return {@code null}) |
| */ |
| public static ClearsilverFactory setClearsilverFactory( |
| ClearsilverFactory clearsilverFactory) { |
| factoryLock.writeLock().lock(); |
| try { |
| ClearsilverFactory previousFactory = FactoryLoader.clearsilverFactory; |
| FactoryLoader.clearsilverFactory = clearsilverFactory; |
| return previousFactory; |
| } finally { |
| factoryLock.writeLock().unlock(); |
| } |
| } |
| |
| private static ClearsilverFactory newDefaultClearsilverFactory() { |
| String factoryClassName = |
| System.getProperty(DEFAULT_CS_FACTORY_CLASS_PROPERTY_NAME, |
| DEFAULT_CS_FACTORY_CLASS_NAME); |
| try { |
| ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
| Class<ClearsilverFactory> clazz = |
| loadClass(factoryClassName, classLoader); |
| Constructor<ClearsilverFactory> constructor = clazz.getConstructor(); |
| return constructor.newInstance(); |
| } catch (Exception e) { |
| String errMsg = "Unable to load default ClearsilverFactory class: \"" + |
| factoryClassName + "\""; |
| logger.log(Level.SEVERE, errMsg, e); |
| throw new RuntimeException(errMsg, e); |
| } |
| } |
| |
| private static Class<ClearsilverFactory> loadClass(String className, |
| ClassLoader classLoader) throws ClassNotFoundException { |
| return (Class<ClearsilverFactory>) Class.forName(className, true, |
| classLoader); |
| } |
| } |