ninja.utils.ImplFromPropertiesFactory Maven / Gradle / Ivy
/**
* Copyright (C) 2012-2016 the original author or authors.
*
* 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 ninja.utils;
import com.google.inject.Injector;
import org.slf4j.Logger;
import java.util.concurrent.atomic.AtomicReference;
/**
* An abstract provider that determines which implementation to load based on
* the value of key in {@link NinjaProperties} (aka application.conf).
*
* If this variable is set then the implementation class is loaded for subclasses
* to use in their own implementation of Provider.get().
*/
public class ImplFromPropertiesFactory {
private final Injector injector;
private final NinjaProperties ninjaProperties;
private final String propertyName;
private final Class extends T> targetClass;
private final String defaultClassName;
private final Logger logger;
private final AtomicReference> implementationClassRef;
/**
* Tries to load implementation class defined as a property in NinjaProperties
* or will fallback to loading the default implementation class or nothing
* if its not set.
*
* @param injector The guice injector
* @param ninjaProperties The ninja properties
* @param propertyName The name of the configuration property key
* @param targetClass The target implementation class (e.g. ninja.Cache)
* @param defaultClassName The default implementation class or null if
* a default doesn't exist. A string is used here to not require
* an implementation class to be on the classpath.
* @param deferResolveUntilGet If false then the implementation class will
* be resolved in the constructor. If true then the resolution will
* be deferred until getImplementation() or create() is called.
* @param logger The logger to use for info and errors
*/
public ImplFromPropertiesFactory(Injector injector,
NinjaProperties ninjaProperties,
String propertyName,
Class extends T> targetClass,
String defaultClassName,
boolean deferResolveUntilGet,
Logger logger) {
this.injector = injector;
this.ninjaProperties = ninjaProperties;
this.propertyName = propertyName;
this.targetClass = targetClass;
this.defaultClassName = defaultClassName;
this.logger = logger;
this.implementationClassRef = new AtomicReference<>();
if (!deferResolveUntilGet) {
this.implementationClassRef.set(resolveImplementationClass());
}
}
public T create() {
return this.injector
.getInstance(getImplementationClass());
}
public Class extends T> getImplementationClass() {
Class extends T> implementationClass = this.implementationClassRef.get();
if (implementationClass != null) {
return implementationClass;
}
// first one wins in case multiple threads get here...
this.implementationClassRef.compareAndSet(null, resolveImplementationClass());
return this.implementationClassRef.get();
}
private Class extends T> resolveImplementationClass() {
String implementationClassName = ninjaProperties.get(propertyName);
Class extends T> implementationClass = null;
if (implementationClassName != null) {
// resolve or throw exception
implementationClass
= resolveClass(implementationClassName,
targetClass,
propertyName,
true);
logger.info("Using {} as implementation for {}", implementationClassName, targetClass.getCanonicalName());
} else {
if (defaultClassName != null) {
// resolve or throw exception
implementationClass
= resolveClass(defaultClassName,
targetClass,
propertyName,
false);
logger.info("Using {} as default implementation for {}", defaultClassName, targetClass.getCanonicalName());
}
}
return implementationClass;
}
private Class extends T> resolveClass(String className, Class extends T> targetClass, String propertyName, boolean viaConfiguration) {
// more descriptive error message
String message = (viaConfiguration
? "in configuration " + propertyName : "as default for configuration " + propertyName);
try {
Class> resolvedClass = Class.forName(className);
return resolvedClass.asSubclass(targetClass);
} catch (ClassNotFoundException e) {
throw new RuntimeException(
"Class defined " + message + " not found (" + className + ")", e);
} catch (ClassCastException e) {
throw new RuntimeException(
"Class defined " + message + " is not an instance of ("
+ targetClass + ")", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy