/*
* Copyright 2008-2014 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 org.kaleidofoundry.core.plugin;
import static org.kaleidofoundry.core.plugin.PluginConstants.PACKAGE_STANDARD;
import java.util.Set;
import org.kaleidofoundry.core.plugin.model.Plugin;
import org.kaleidofoundry.core.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This factory will load and handle a global registry of :<br/>
* <ul>
* <li>plugin declare interface {@link Declare} - {@link PluginRegistry}</li>
* <li>plugin declare class implementation {@link Declare} - {@link PluginImplementationRegistry}</li>
* </ul>
* <p>
* 1. The registries are loaded statically, during first factory call<br/>
* 2. During this load, it scan and introspect all annotation plugin interface /implementation {@link Declare}<br/>
* 3. It can be reloaded (synchronized way) at each time.
* </p>
*
* @author jraduget
*/
public final class PluginFactory {
private static final PluginRegistry INTERFACE_REGISTRY = new PluginRegistry();
private static final PluginImplementationRegistry IMPLEMENTATION_REGISTRY = new PluginImplementationRegistry();
private static final Logger LOGGER = LoggerFactory.getLogger(PluginFactory.class);
static {
loadPluginInspector();
}
/*
* init static factory plugin load
*/
private static void loadPluginInspector() throws PluginRegistryException {
INTERFACE_REGISTRY.clear();
IMPLEMENTATION_REGISTRY.clear();
final PluginInspector pluginInspector = new PluginInspector();
Set<Plugin<?>> plugins = null;
Set<Plugin<?>> pluginImpls = null;
Set<PluginRegistryException> errors = null;
// inspect @Declare
plugins = pluginInspector.loadPluginMetaData();
pluginImpls = pluginInspector.loadPluginImplementationMetaData();
// print load processing messages
for (final String message : pluginInspector.getEchoMessages()) {
LOGGER.info(message);
}
// check declaration coherence
errors = pluginInspector.checkDeclarations();
// all right, registered them
if (errors.isEmpty()) {
for (final Plugin<?> p : plugins) {
INTERFACE_REGISTRY.put(p.getName(), p);
}
for (final Plugin<?> p : pluginImpls) {
IMPLEMENTATION_REGISTRY.put(p.getName(), p);
}
} else {
// process multiple errors
final StringBuilder errorMessage = new StringBuilder();
for (final PluginRegistryException pre : errors) {
LOGGER.error(pre.getMessage());
errorMessage.append("\t").append(pre.getMessage()).append("\n");
}
throw new PluginRegistryException("plugin.error.load.declare.all", new String[] { errorMessage.toString() });
}
}
/**
* @return plugin interface registry
*/
public final static PluginRegistry getInterfaceRegistry() {
return INTERFACE_REGISTRY;
}
/**
* @return plugin implementations registry
*/
public final static PluginImplementationRegistry getImplementationRegistry() {
return IMPLEMENTATION_REGISTRY;
}
/**
* @throws PluginRegistryException
*/
public final static synchronized void reload() throws PluginRegistryException {
loadPluginInspector();
}
/**
* helper method, used to create a new plugin instance, using {@link Declare} annotation meta-data
*
* @param declarePlugin
* @param annotatedClass
* @return new plugin instance
*/
static <T> Plugin<T> create(final Declare declarePlugin, final Class<? extends T> annotatedClass) {
String annotatedClassVersion = annotatedClass.getPackage().getImplementationVersion() != null ? annotatedClass.getPackage().getImplementationVersion()
: annotatedClass.getPackage().getSpecificationVersion();
final Plugin<T> plugin = new Plugin<T>(declarePlugin.value(), annotatedClass.getPackage().getName().contains(PACKAGE_STANDARD), annotatedClass,
declarePlugin.description(), !StringHelper.isEmpty(declarePlugin.version()) ? declarePlugin.version() : annotatedClassVersion, declarePlugin.enable());
return plugin;
}
}