/**
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.webui.application;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.exoplatform.webui.config.Application;
import org.exoplatform.webui.config.Component;
import org.exoplatform.webui.config.ComponentHandle;
import org.exoplatform.webui.config.Event;
import org.exoplatform.webui.config.EventInterceptor;
import org.exoplatform.webui.config.InitParams;
import org.exoplatform.webui.config.Param;
import org.exoplatform.webui.config.Validator;
import org.exoplatform.webui.config.WebuiConfiguration;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.ComponentConfigs;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.config.annotation.EventInterceptorConfig;
import org.exoplatform.webui.config.annotation.ParamConfig;
import org.exoplatform.webui.config.annotation.ValidatorConfig;
import org.exoplatform.webui.config.metadata.ComponentMetaData;
import org.gatein.common.logging.Logger;
import org.gatein.common.logging.LoggerFactory;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IUnmarshallingContext;
/**
* May 10, 2006
* <p/>
* Manages the ComponentConfig of a list of components.
*
* @see ComponentConfig
*/
public class ConfigurationManager {
/**
* todo (julien) : this map should be synchronized somehow
* <p/>
* The components of which we manage the configuration
*/
// private Map<String, Component> configs_ = new HashMap<String, Component>();
/**
* Minh Hoang TO: First attempt to synchronize the map, we simply replace HashMap with ConcurrentHashMap and default values
* for load factor, initial capacity and concurrentcyLevel
*
* TODO: Need to examine the performance influence in the future for a better synchronizing
*/
private Map<String, Component> configs_ = new ConcurrentHashMap<String, Component>();
/** The logger. */
private final Logger log;
/** . */
private Application application_;
/**
* @param inputStream A stream that links the configuration file
* @throws Exception
*/
public ConfigurationManager(InputStream inputStream) throws Exception {
// Logger first
log = LoggerFactory.getLogger(ConfigurationManager.class);
IBindingFactory bfact = BindingDirectory.getFactory(WebuiConfiguration.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
WebuiConfiguration config = (WebuiConfiguration) uctx.unmarshalDocument(inputStream, null);
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (config.getAnnotationClasses() != null) {
for (String annotationClass : config.getAnnotationClasses()) {
// process annotation and get the Component
Component[] components = annotationToComponents(cl, annotationClass);
setComponentConfigs(components);
}
}
if (config.getComponents() != null) {
for (ComponentMetaData componentMetaData : config.getComponents()) {
String key = componentMetaData.getType();
if (componentMetaData.getId() != null) {
key = key + ":" + componentMetaData.getId();
}
configs_.put(key, new Component(componentMetaData));
}
}
application_ = config.getApplication();
}
/**
* Adds components to the list
*
* @param configs An array of Component
*/
void setComponentConfigs(Component[] configs) {
for (Component component : configs) {
configs_.put(component.getKey(), component);
}
}
/**
* Gets the components of a given class
*
* @param clazz The class of the components
* @return the list of components
*/
public List<Component> getComponentConfig(Class<?> clazz) {
List<Component> configs = new ArrayList<Component>();
Collection<Component> values = configs_.values();
String type = clazz.getName();
for (Component comp : values) {
if (comp.getType().equals(type)) {
configs.add(comp);
}
}
return configs;
}
public Component getComponentConfig(ComponentHandle handle) {
Component component = configs_.get(handle.getKey());
//
if (component == null) {
Class<?> owner = handle.getOwner();
process(owner);
}
//
return configs_.get(handle.getKey());
}
private void process(Class<?> owner) {
if (owner == null) {
throw new NullPointerException("Cannot process a null owner");
}
try {
Component[] components = annotationToComponents(owner);
setComponentConfigs(components);
} catch (Exception e) {
log.error("Could not create component configuration for owner " + owner.getName(), e);
}
}
/**
* Gets a component of a given class and identified by id
*
* @param type The class of the component
* @param id The id of the component
* @return The component
*/
public Component getComponentConfig(Class<?> type, String id) {
String key = type.getName();
if (id != null) {
key = key + ":" + id;
}
//
Component config = configs_.get(key);
if (config != null) {
return config;
}
//
process(type);
//
return configs_.get(key);
}
public Application getApplication() {
return application_;
}
/**
* Gets an array of Component from a ComponentConfig annotation
*
* @param cl the classloader to create the annotation
* @param annClass the annotation class
* @return The array of Component
* @throws Exception
*/
Component[] annotationToComponents(ClassLoader cl, String annClass) throws Exception {
Class<?> clazz = cl.loadClass(annClass);
return annotationToComponents(clazz);
}
/**
* Gets an array of Component from a ComponentConfig annotation
*
* @param clazz The annotation class from which to get the ComponentConfig
* @return The array of Component
* @throws Exception
*/
Component[] annotationToComponents(Class<?> clazz) throws Exception {
ComponentConfig annotation = clazz.getAnnotation(ComponentConfig.class);
if (annotation != null) {
return new Component[] { toComponentConfig(annotation, clazz) };
}
ComponentConfigs annotations = clazz.getAnnotation(ComponentConfigs.class);
if (annotations != null) {
ComponentConfig[] listAnnotations = annotations.value();
Component[] componentConfigs = new Component[listAnnotations.length];
for (int i = 0; i < componentConfigs.length; i++) {
componentConfigs[i] = toComponentConfig(listAnnotations[i], clazz);
}
return componentConfigs;
}
return new Component[] {};
}
private Component toComponentConfig(ComponentConfig annotation, Class<?> clazz) throws Exception {
String template = null;
if (annotation.template().length() > 0) {
template = annotation.template();
}
//
String id = null;
if (annotation.id().length() > 0) {
id = annotation.id();
}
//
Class<?> type = annotation.type() == void.class ? clazz : annotation.type();
//
String lifecycle = null;
if (annotation.lifecycle() != void.class) {
lifecycle = annotation.lifecycle().getName();
}
//
String decorator = null;
if (annotation.decorator().length() > 0) {
decorator = annotation.decorator();
}
//
EventConfig[] eventAnnotations = annotation.events();
ArrayList<Event> events;
if (eventAnnotations.length != 0) {
events = new ArrayList<Event>();
for (EventConfig eventAnnotation : eventAnnotations) {
events.add(toEventConfig(eventAnnotation));
}
} else {
events = new ArrayList<Event>();
}
//
EventInterceptorConfig[] eventInterceptorAnnotations = annotation.eventInterceptors();
ArrayList<EventInterceptor> eventInterceptors;
if (eventInterceptorAnnotations.length != 0) {
eventInterceptors = new ArrayList<EventInterceptor>();
for (EventInterceptorConfig eventAnnotation : eventInterceptorAnnotations) {
eventInterceptors.add(toEventInterceptorConfig(eventAnnotation));
}
} else {
eventInterceptors = new ArrayList<EventInterceptor>();
}
//
ValidatorConfig[] validatorAnnotations = annotation.validators();
ArrayList<Validator> validators;
if (validatorAnnotations.length != 0) {
validators = new ArrayList<Validator>();
for (ValidatorConfig ele : validatorAnnotations) {
validators.add(toValidator(ele));
}
} else {
validators = new ArrayList<Validator>();
}
//
return new Component(clazz, id, type.getName(), lifecycle, template, decorator, toInitParams(annotation.initParams()),
validators, events, eventInterceptors);
}
private Event toEventConfig(EventConfig annotation) {
Event event = new Event();
event.setExecutionPhase(annotation.phase());
event.setConfirm(annotation.confirm());
event.setInitParams(toInitParams(annotation.initParams()));
ArrayList<String> listeners = new ArrayList<String>();
for (Class<?> clazz : annotation.listeners()) {
listeners.add(clazz.getName());
}
if (annotation.name().length() > 0) {
event.setName(annotation.name());
} else if (annotation.listeners().length > 0) {
String name = annotation.listeners()[0].getSimpleName();
int idx = name.indexOf("ActionListener");
if (idx > -1) {
name = name.substring(0, idx);
}
event.setName(name);
}
event.setListeners(listeners);
event.setCsrfCheck(annotation.csrfCheck());
return event;
}
private EventInterceptor toEventInterceptorConfig(EventInterceptorConfig annotation) {
EventInterceptor eventInterceptor = new EventInterceptor();
eventInterceptor.setType(annotation.type().getName());
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, annotation.interceptors());
eventInterceptor.setInterceptors(list);
eventInterceptor.setInitParams(toInitParams(annotation.initParams()));
return eventInterceptor;
}
private Validator toValidator(ValidatorConfig annotation) {
Validator validator = new Validator();
validator.setType(annotation.type().getName());
validator.setInitParams(toInitParams(annotation.initParams()));
return validator;
}
private InitParams toInitParams(ParamConfig[] annotations) {
if (annotations == null || annotations.length < 1) {
return null;
}
ArrayList<Param> listParam = new ArrayList<Param>();
for (ParamConfig ele : annotations) {
Param param = new Param();
param.setName(ele.name());
param.setValue(ele.value());
listParam.add(param);
}
InitParams initParams = new InitParams();
initParams.setParams(listParam);
return initParams;
}
}