/*
* 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.container.xml;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Jul 19, 2004
*
* @author: Tuan Nguyen
* @version: $Id: Configuration.java 5799 2006-05-28 17:55:42Z geaz $
*/
public class Configuration implements Cloneable
{
public static final String KERNEL_CONFIGURATION_1_0_URI = "http://www.exoplaform.org/xml/ns/kernel_1_0.xsd";
private static final Log LOG = ExoLogger.getLogger("exo.kernel.container.Configuration");
/**
* We need this thread local to be able to detect the normal objects from the components while serializing the configuration
*/
private static final ThreadLocal<Configuration> CURRENT_CONFIG_TO_SERIALIZE = new ThreadLocal<Configuration>();
private Map<String, ContainerLifecyclePlugin> containerLifecyclePlugin_ =
new HashMap<String, ContainerLifecyclePlugin>();
private Map<String, ComponentLifecyclePlugin> componentLifecyclePlugin_ =
new HashMap<String, ComponentLifecyclePlugin>();
private Map<String, Component> component_ = new HashMap<String, Component>();
private Map<String, ExternalComponentPlugins> externalComponentPlugins_ =
new HashMap<String, ExternalComponentPlugins>();
private List<String> imports_;
private List<String> removeConfiguration_;
private int currentSize;
private int currentHash;
public Collection<ContainerLifecyclePlugin> getContainerLifecyclePlugins()
{
List<ContainerLifecyclePlugin> plugins =
new ArrayList<ContainerLifecyclePlugin>(containerLifecyclePlugin_.values());
Collections.sort(plugins);
return plugins;
}
public void addContainerLifecyclePlugin(ContainerLifecyclePlugin plugin)
{
String key = plugin.getType();
containerLifecyclePlugin_.put(key, plugin);
}
public Iterator<ContainerLifecyclePlugin> getContainerLifecyclePluginIterator()
{
return getContainerLifecyclePlugins().iterator();
}
public boolean hasContainerLifecyclePlugin()
{
return containerLifecyclePlugin_.size() > 0;
}
public Collection<ComponentLifecyclePlugin> getComponentLifecyclePlugins()
{
return componentLifecyclePlugin_.values();
}
public void addComponentLifecyclePlugin(Object object)
{
ComponentLifecyclePlugin plugin = (ComponentLifecyclePlugin)object;
String key = plugin.getType();
componentLifecyclePlugin_.put(key, plugin);
}
public Iterator<ComponentLifecyclePlugin> getComponentLifecyclePluginIterator()
{
return componentLifecyclePlugin_.values().iterator();
}
public boolean hasComponentLifecyclePlugin()
{
return componentLifecyclePlugin_.size() > 0;
}
public Component getComponent(String s)
{
return component_.get(s);
}
public void addComponent(Component comp)
{
String key = comp.getKey();
if (key == null)
{
key = comp.getType();
comp.setKey(key);
}
component_.put(key, comp);
}
public Collection<Component> getComponents()
{
return component_.values();
}
public Iterator<Component> getComponentIterator()
{
return component_.values().iterator();
}
public boolean hasComponent()
{
return component_.size() > 0;
}
public ExternalComponentPlugins getExternalComponentPlugins(String s)
{
return externalComponentPlugins_.get(s);
}
public void addExternalComponentPlugins(ExternalComponentPlugins eps)
{
// Retrieve potential existing external component
// plugins with same target component.
String targetComponent = eps.getTargetComponent();
ExternalComponentPlugins foundExternalComponentPlugins =
(ExternalComponentPlugins)externalComponentPlugins_.get(targetComponent);
if (foundExternalComponentPlugins == null)
{
// No external component plugins found. Create a new entry.
externalComponentPlugins_.put(targetComponent, eps);
}
else
{
// Found external component plugins. Add the specified one.
foundExternalComponentPlugins.merge(eps);
}
}
public Iterator<ExternalComponentPlugins> getExternalComponentPluginsIterator()
{
return externalComponentPlugins_.values().iterator();
}
public boolean hasExternalComponentPlugins()
{
return externalComponentPlugins_.size() > 0;
}
public void addImport(String url)
{
if (imports_ == null)
imports_ = new ArrayList<String>();
imports_.add(url);
}
public List<String> getImports()
{
return imports_;
}
public void addRemoveConfiguration(String type)
{
if (removeConfiguration_ == null)
removeConfiguration_ = new ArrayList<String>();
removeConfiguration_.add(type);
}
public List<String> getRemoveConfiguration()
{
return removeConfiguration_;
}
public void removeConfiguration(String type)
{
component_.remove(type);
}
// -------------------------end new mapping configuration--------------------
public void mergeConfiguration(Configuration other)
{
component_.putAll(other.component_);
componentLifecyclePlugin_.putAll(other.componentLifecyclePlugin_);
containerLifecyclePlugin_.putAll(other.containerLifecyclePlugin_);
// merge the external plugins
Iterator<ExternalComponentPlugins> i = other.externalComponentPlugins_.values().iterator();
while (i.hasNext())
{
addExternalComponentPlugins(i.next());
}
if (other.getRemoveConfiguration() == null)
return;
if (removeConfiguration_ == null)
removeConfiguration_ = new ArrayList<String>();
removeConfiguration_.addAll(other.getRemoveConfiguration());
}
/**
* Merge all the given configurations and return a safe copy of the result
* @param configs the list of configurations to merge ordered by priority, the second
* configuration will override the configuration of the first one and so on.
* @return the merged configuration
*/
public static Configuration merge(Configuration... configs)
{
if (configs == null || configs.length == 0)
{
return null;
}
Configuration result = null;
for (Configuration conf : configs)
{
if (conf == null)
{
// Ignore the null configuration
continue;
}
else if (result == null)
{
// Initialize with the clone of the first non null configuration
result = (Configuration)conf.clone();
}
else
{
// The merge the current configuration with this new configuration
result.mergeConfiguration(conf);
}
}
return result;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected Object clone()
{
try
{
Configuration conf = (Configuration)super.clone();
conf.component_ = (Map<String, Component>)((HashMap<String, Component>)component_).clone();
conf.componentLifecyclePlugin_ =
(Map<String, ComponentLifecyclePlugin>)((HashMap<String, ComponentLifecyclePlugin>)componentLifecyclePlugin_)
.clone();
conf.containerLifecyclePlugin_ =
(Map<String, ContainerLifecyclePlugin>)((HashMap<String, ContainerLifecyclePlugin>)containerLifecyclePlugin_)
.clone();
conf.externalComponentPlugins_ =
(Map<String, ExternalComponentPlugins>)((HashMap<String, ExternalComponentPlugins>)externalComponentPlugins_)
.clone();
if (imports_ != null)
{
conf.imports_ = (List<String>)((ArrayList<String>)imports_).clone();
}
if (removeConfiguration_ != null)
{
conf.removeConfiguration_ = (List<String>)((ArrayList<String>)removeConfiguration_).clone();
}
return conf;
}
catch (CloneNotSupportedException e)
{
throw new AssertionError("Could not clone the configuration");
}
}
/**
* Indicates whether or not the given key has been registered has a component within the current
* configuration if and only if we have a configuration currently defined. If no configuration
* has been defined it will always return <code>false</code>
*/
public static boolean hasComponent(String key)
{
Configuration config = CURRENT_CONFIG_TO_SERIALIZE.get();
if (config == null)
return false;
return config.getComponent(key) != null;
}
/**
* Dumps the configuration in XML format into the given {@link Writer}
*/
public void toXML(Writer w)
{
try
{
CURRENT_CONFIG_TO_SERIALIZE.set(this);
IBindingFactory bfact = BindingDirectory.getFactory(Configuration.class);
IMarshallingContext mctx = bfact.createMarshallingContext();
mctx.setIndent(2);
mctx.marshalDocument(this, "UTF-8", null, w);
}
catch (Exception e)
{
LOG.warn("Couldn't dump the runtime configuration in XML Format", e);
}
finally
{
CURRENT_CONFIG_TO_SERIALIZE.remove();
}
}
/**
* Dumps the configuration in XML format into a {@link StringWriter} and
* returns the content
*/
public String toXML()
{
StringWriter sw = new StringWriter();
try
{
toXML(sw);
}
catch (Exception e)
{
LOG.warn("Cannot convert the configuration to XML format", e);
return null;
}
finally
{
try
{
sw.close();
}
catch (IOException ignore)
{
if (LOG.isTraceEnabled())
{
LOG.trace("An exception occurred: " + ignore.getMessage());
}
}
}
return sw.toString();
}
/**
* This will keep the current state of the configuration like its size and hash
*/
public void keepCurrentState()
{
String xml = toXML();
if (xml != null)
{
this.currentSize = xml.length();
this.currentHash = xml.hashCode();
}
}
/**
* @return the currentSize
*/
public int getCurrentSize()
{
return currentSize;
}
/**
* @return the currentHash
*/
public int getCurrentHash()
{
return currentHash;
}
}