/*
* 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);
}
}