diff --git a/Configuration/lib/isaac-configuration-1.0.10-SNAPSHOT_dependency.jar b/Configuration/lib/isaac-configuration-1.0.10-SNAPSHOT_dependency.jar deleted file mode 100644 index 1fdbb07..0000000 Binary files a/Configuration/lib/isaac-configuration-1.0.10-SNAPSHOT_dependency.jar and /dev/null differ diff --git a/Configuration/lib_ori/isaac-configuration-1.0.10-SNAPSHOT.jar b/Configuration/lib_ori/isaac-configuration-1.0.10-SNAPSHOT.jar deleted file mode 100644 index f207482..0000000 Binary files a/Configuration/lib_ori/isaac-configuration-1.0.10-SNAPSHOT.jar and /dev/null differ diff --git a/Configuration/src/com/dotmarketing/plugin/business/PluginAPIImpl.java b/Configuration/src/com/dotmarketing/plugin/business/PluginAPIImpl.java index ee5ad3d..9e25545 100644 --- a/Configuration/src/com/dotmarketing/plugin/business/PluginAPIImpl.java +++ b/Configuration/src/com/dotmarketing/plugin/business/PluginAPIImpl.java @@ -13,8 +13,8 @@ import java.util.List; import java.util.NoSuchElementException; +import nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.ConfigurationService; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; import nl.isaac.dotcms.plugin.configuration.exception.ConfigurationNotFoundException; diff --git a/Configuration/src/nl/isaac/comp/configuration/CombinedConfigurationWrapper.java b/Configuration/src/nl/isaac/comp/configuration/CombinedConfigurationWrapper.java new file mode 100644 index 0000000..8531fde --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/CombinedConfigurationWrapper.java @@ -0,0 +1,457 @@ +package nl.isaac.comp.configuration; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.AbstractConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.CombinedConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.Configuration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.HierarchicalConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.HierarchicalConfiguration.Node; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.SubnodeConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.event.ConfigurationErrorListener; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.event.ConfigurationEvent; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.event.ConfigurationListener; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.interpol.ConfigurationInterpolator; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNode; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ExpressionEngine; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.NodeCombiner; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.lang.text.StrSubstitutor; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.logging.Log; + + +/** + * A wrapper class for {@link CombinedConfiguration} + * @author jan-willem + * + */ +public class CombinedConfigurationWrapper implements Configuration { + + private final CombinedConfiguration configuration; + + public CombinedConfigurationWrapper(CombinedConfiguration configuration) { + this.configuration = configuration; + } + + /** + * Returns the delegated instance which was passed to {@link #HierarchicalConfigurationWrapper(HierarchicalConfiguration)} + * @return + */ + public CombinedConfiguration getDelegate() { + return configuration; + } + + public void addConfiguration(AbstractConfiguration config, String name, + String at) { + configuration.addConfiguration(config, name, at); + } + + public void addConfiguration(AbstractConfiguration config, String name) { + configuration.addConfiguration(config, name); + } + + public void addConfiguration(AbstractConfiguration config) { + configuration.addConfiguration(config); + } + + public void addConfigurationListener(ConfigurationListener l) { + configuration.addConfigurationListener(l); + } + + public void addErrorListener(ConfigurationErrorListener l) { + configuration.addErrorListener(l); + } + + public void addErrorLogListener() { + configuration.addErrorLogListener(); + } + + public void addNodes(String key, Collection nodes) { + configuration.addNodes(key, nodes); + } + + public void addProperty(String key, Object value) { + configuration.addProperty(key, value); + } + + public void append(Configuration c) { + configuration.append(c); + } + + public void clear() { + configuration.clear(); + } + + public void clearConfigurationListeners() { + configuration.clearConfigurationListeners(); + } + + public void clearErrorListeners() { + configuration.clearErrorListeners(); + } + + public void clearProperty(String key) { + configuration.clearProperty(key); + } + + public void clearTree(String key) { + configuration.clearTree(key); + } + + public Object clone() { + return configuration.clone(); + } + + public SubnodeConfiguration configurationAt(String key, + boolean supportUpdates) { + return configuration.configurationAt(key, supportUpdates); + } + + public SubnodeConfiguration configurationAt(String key) { + return configuration.configurationAt(key); + } + + public void configurationChanged(ConfigurationEvent event) { + configuration.configurationChanged(event); + } + + public List configurationsAt(String key) { + return configuration.configurationsAt(key); + } + + public boolean containsKey(String key) { + return configuration.containsKey(key); + } + + public void copy(Configuration c) { + configuration.copy(c); + } + + public boolean equals(Object obj) { + return configuration.equals(obj); + } + + public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { + return configuration.getBigDecimal(key, defaultValue); + } + + public BigDecimal getBigDecimal(String key) { + return configuration.getBigDecimal(key); + } + + public BigInteger getBigInteger(String key, BigInteger defaultValue) { + return configuration.getBigInteger(key, defaultValue); + } + + public BigInteger getBigInteger(String key) { + return configuration.getBigInteger(key); + } + + public boolean getBoolean(String key, boolean defaultValue) { + return configuration.getBoolean(key, defaultValue); + } + + public Boolean getBoolean(String key, Boolean defaultValue) { + return configuration.getBoolean(key, defaultValue); + } + + public boolean getBoolean(String key) { + return configuration.getBoolean(key); + } + + public byte getByte(String key, byte defaultValue) { + return configuration.getByte(key, defaultValue); + } + + public Byte getByte(String key, Byte defaultValue) { + return configuration.getByte(key, defaultValue); + } + + public byte getByte(String key) { + return configuration.getByte(key); + } + + public Configuration getConfiguration(int index) { + return configuration.getConfiguration(index); + } + + public Configuration getConfiguration(String name) { + return configuration.getConfiguration(name); + } + + public Collection getConfigurationListeners() { + return configuration.getConfigurationListeners(); + } + + public Set getConfigurationNames() { + return configuration.getConfigurationNames(); + } + + public ExpressionEngine getConversionExpressionEngine() { + return configuration.getConversionExpressionEngine(); + } + + public double getDouble(String key, double defaultValue) { + return configuration.getDouble(key, defaultValue); + } + + public Double getDouble(String key, Double defaultValue) { + return configuration.getDouble(key, defaultValue); + } + + public double getDouble(String key) { + return configuration.getDouble(key); + } + + public Collection getErrorListeners() { + return configuration.getErrorListeners(); + } + + public ExpressionEngine getExpressionEngine() { + return configuration.getExpressionEngine(); + } + + public float getFloat(String key, float defaultValue) { + return configuration.getFloat(key, defaultValue); + } + + public Float getFloat(String key, Float defaultValue) { + return configuration.getFloat(key, defaultValue); + } + + public float getFloat(String key) { + return configuration.getFloat(key); + } + + public int getInt(String key, int defaultValue) { + return configuration.getInt(key, defaultValue); + } + + public int getInt(String key) { + return configuration.getInt(key); + } + + public Integer getInteger(String key, Integer defaultValue) { + return configuration.getInteger(key, defaultValue); + } + + public ConfigurationInterpolator getInterpolator() { + return configuration.getInterpolator(); + } + + public Iterator getKeys() { + return configuration.getKeys(); + } + + public Iterator getKeys(String prefix) { + return configuration.getKeys(prefix); + } + + public List getList(String key, List defaultValue) { + return configuration.getList(key, defaultValue); + } + + public List getList(String key) { + return configuration.getList(key); + } + + public char getListDelimiter() { + return configuration.getListDelimiter(); + } + + public Log getLogger() { + return configuration.getLogger(); + } + + public long getLong(String key, long defaultValue) { + return configuration.getLong(key, defaultValue); + } + + public Long getLong(String key, Long defaultValue) { + return configuration.getLong(key, defaultValue); + } + + public long getLong(String key) { + return configuration.getLong(key); + } + + public int getMaxIndex(String key) { + return configuration.getMaxIndex(key); + } + + public NodeCombiner getNodeCombiner() { + return configuration.getNodeCombiner(); + } + + public int getNumberOfConfigurations() { + return configuration.getNumberOfConfigurations(); + } + + public Properties getProperties(String key, Properties defaults) { + return configuration.getProperties(key, defaults); + } + + public Properties getProperties(String key) { + return configuration.getProperties(key); + } + + public Object getProperty(String key) { + return configuration.getProperty(key); + } + + public Node getRoot() { + return configuration.getRoot(); + } + + public ConfigurationNode getRootNode() { + return configuration.getRootNode(); + } + + public short getShort(String key, short defaultValue) { + return configuration.getShort(key, defaultValue); + } + + public Short getShort(String key, Short defaultValue) { + return configuration.getShort(key, defaultValue); + } + + public short getShort(String key) { + return configuration.getShort(key); + } + + public Configuration getSource(String key) { + return configuration.getSource(key); + } + + public String getString(String key, String defaultValue) { + return configuration.getString(key, defaultValue); + } + + public String getString(String key) { + return configuration.getString(key); + } + + public String[] getStringArray(String key) { + return configuration.getStringArray(key); + } + + public StrSubstitutor getSubstitutor() { + return configuration.getSubstitutor(); + } + + public int hashCode() { + return configuration.hashCode(); + } + + public Configuration interpolatedConfiguration() { + return configuration.interpolatedConfiguration(); + } + + public void invalidate() { + configuration.invalidate(); + } + + public boolean isDelimiterParsingDisabled() { + return configuration.isDelimiterParsingDisabled(); + } + + public boolean isDetailEvents() { + return configuration.isDetailEvents(); + } + + public boolean isEmpty() { + return configuration.isEmpty(); + } + + public boolean isForceReloadCheck() { + return configuration.isForceReloadCheck(); + } + + public boolean isThrowExceptionOnMissing() { + return configuration.isThrowExceptionOnMissing(); + } + + public boolean removeConfiguration(Configuration config) { + return configuration.removeConfiguration(config); + } + + public Configuration removeConfiguration(String name) { + return configuration.removeConfiguration(name); + } + + public Configuration removeConfigurationAt(int index) { + return configuration.removeConfigurationAt(index); + } + + public boolean removeConfigurationListener(ConfigurationListener l) { + return configuration.removeConfigurationListener(l); + } + + public boolean removeErrorListener(ConfigurationErrorListener l) { + return configuration.removeErrorListener(l); + } + + public void setConversionExpressionEngine( + ExpressionEngine conversionExpressionEngine) { + configuration.setConversionExpressionEngine(conversionExpressionEngine); + } + + public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled) { + configuration.setDelimiterParsingDisabled(delimiterParsingDisabled); + } + + public void setDetailEvents(boolean enable) { + configuration.setDetailEvents(enable); + } + + public void setExpressionEngine(ExpressionEngine expressionEngine) { + configuration.setExpressionEngine(expressionEngine); + } + + public void setForceReloadCheck(boolean forceReloadCheck) { + configuration.setForceReloadCheck(forceReloadCheck); + } + + public void setListDelimiter(char listDelimiter) { + configuration.setListDelimiter(listDelimiter); + } + + public void setLogger(Log log) { + configuration.setLogger(log); + } + + public void setNodeCombiner(NodeCombiner nodeCombiner) { + configuration.setNodeCombiner(nodeCombiner); + } + + public void setProperty(String key, Object value) { + configuration.setProperty(key, value); + } + + public void setRoot(Node node) { + configuration.setRoot(node); + } + + public void setRootNode(ConfigurationNode rootNode) { + configuration.setRootNode(rootNode); + } + + public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing) { + configuration.setThrowExceptionOnMissing(throwExceptionOnMissing); + } + + public Configuration subset(String prefix) { + return configuration.subset(prefix); + } + + public String toString() { + return configuration.toString(); + } + + +} diff --git a/Configuration/src/nl/isaac/comp/configuration/ConfigurationFactory.java b/Configuration/src/nl/isaac/comp/configuration/ConfigurationFactory.java new file mode 100644 index 0000000..7a25146 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/ConfigurationFactory.java @@ -0,0 +1,117 @@ +package nl.isaac.comp.configuration; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.AbstractConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.CombinedConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.FileConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.lang.exception.ExceptionUtils; + +import org.xml.sax.SAXParseException; + +import com.dotmarketing.util.Logger; + +/** + * A factory class with useful methods to load configurations + * @author jan-willem + * + */ +public class ConfigurationFactory { + + private ConfigurationFactory() { + } + + /** + * Convenient method for initializing a {@link CustomConfiguration} Object.
+ * Usage example:
+ *
+	 *    CustomConfiguration config = ConfigurationFactory.newConfiguration(MyConfigService.class.getClassLoader(), "META-INF/config.xml");
+	 *    return new MyConfigPojo(config);
+	 * 
+ * In addition, each additional xml configuration location is parsed and added to the resulting configuration as well. + * @param cl, the classLoader where config.xml is found + * @param configXmlLocation + * @param additionalXmlLocations + * @return + * @throws ConfigurationException + */ + public static CustomConfiguration newConfiguration(ClassLoader cl, String configXmlLocation, String... additionalXmlLocations) throws ConfigurationException { + + try { + + CustomConfigurationBuilder configurationBuilder = new CustomConfigurationBuilder(cl, configXmlLocation); + CombinedConfiguration config = configurationBuilder.getConfiguration(true); + + if (additionalXmlLocations != null && additionalXmlLocations.length > 0) { + + // this is a reference to the latest configuration loaded + // by adding the loaded configuration to the new configuration, previous loaded variables + // can be used in the new configuration and in config.xml's + AbstractConfiguration parentConfig = (AbstractConfiguration) config.clone(); + + for (String additionalXmlLocation : additionalXmlLocations) { + + CustomConfigurationBuilder additionalConfigurationBuilder = new CustomConfigurationBuilder(cl, additionalXmlLocation); + + CombinedConfiguration additionalConfig = additionalConfigurationBuilder.getConfiguration(true, parentConfig); + + config.addConfiguration(additionalConfig); + + parentConfig = (AbstractConfiguration) additionalConfig.clone(); + } + } + + // wrap it with a helper that contains convenient methods + return new CustomConfiguration(config); + + } catch (ConfigurationException e) { + + Throwable rootCause = ExceptionUtils.getRootCause(e); + + if (rootCause instanceof SAXParseException) { + + /* + * When an SAXParseException is thrown, create a new Exception that gives all known problems in one message + * instead of several exceptions + */ + Throwable cause2 = null; + + int indexOfCause1 = ExceptionUtils.indexOfThrowable(e, SAXParseException.class); + if (indexOfCause1 > 0) { + int indexOfCause2 = ExceptionUtils.indexOfThrowable(e, ConfigurationException.class, indexOfCause1 - 1); + if (indexOfCause2 >= 0) { + cause2 = ExceptionUtils.getThrowables(e)[indexOfCause2]; + } + } + + SAXParseException spe = (SAXParseException) rootCause; + String message = "Error parsing configuration, line=" + spe.getLineNumber() + ", column=" + spe.getColumnNumber(); + if (cause2 != null) { + message = cause2.getMessage() + ". " + message; + } + throw new ConfigurationException(message + ". " + rootCause.getMessage(), e.getCause()); + } + throw e; + } + } + + public static CustomConfiguration newConfiguration(ClassLoader cl, boolean logConfigurationDetails, String configXmlLocation, String... additionalXmlLocations) throws ConfigurationException { + + CustomConfiguration result = newConfiguration(cl, configXmlLocation, additionalXmlLocations); + logConfigurationDetails(result); + + return result; + } + + protected static void logConfigurationDetails(CustomConfiguration configuration) { + + StringBuffer configFiles = new StringBuffer(); + for (FileConfiguration cf : configuration.getLoadedFileConfigurations()) { + if (cf.getFile() != null) { + configFiles.append("\n\t").append(cf.getFile()); + } + } + + Logger.debug(ConfigurationFactory.class, "Used configuration files:" + configFiles.toString()); + Logger.debug(ConfigurationFactory.class, "Configuration result:\n" + configuration.toStringTree(true)); + } +} diff --git a/Configuration/src/nl/isaac/comp/configuration/CustomConfiguration.java b/Configuration/src/nl/isaac/comp/configuration/CustomConfiguration.java new file mode 100644 index 0000000..464b665 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/CustomConfiguration.java @@ -0,0 +1,244 @@ +package nl.isaac.comp.configuration; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import nl.isaac.comp.configuration.visitor.ToStringMultiLineVisitor; +import nl.isaac.comp.configuration.visitor.ToStringSingleLineVisitor; +import nl.isaac.comp.configuration.visitor.ToStringTreeVisitor; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.CombinedConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.Configuration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.FileConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.HierarchicalConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNodeVisitor; + + + +/** + * A ISAAC configuration class with additional helper methods compared to {@link CombinedConfiguration}
+ * Also, {@link #setThrowExceptionOnMissing(boolean)} is set to true which means exceptions are thrown by default when a property does not exist. + * This ensures a valid existing configuration file. + * @author jan-willem + * + */ +public class CustomConfiguration extends CombinedConfigurationWrapper { + + public CustomConfiguration(CombinedConfiguration configuration) { + super(configuration); + + // by default setThrowExceptionOnMissing is false. + // for ISAAC related projects this is on all the times + setThrowExceptionOnMissing(true); + } + + /** + * Get the configured file and converts it to a {@link File}.
+ * Uses {@link Configuration#getString(String)} internally + * @param key + * @return + * @throws IllegalArgumentException is the file does not exist + */ + public File getFile(String key) { + + String value = getString(key); + File f = new File(value); + + if (f.exists() && !f.isFile()) { + throw new IllegalArgumentException("'" + key + "' resolves to '" + value + "' which is not a file"); + } + + return f; + } + + /** + * Get the configured file, converts it to a {@link File} and checks if it exists.
+ * Uses {@link Configuration#getString(String)} internally + * @param key + * @return + * @throws IllegalArgumentException is the file does not exist + */ + public File getExistingFile(String key) { + + String value = getString(key); + File f = new File(value); + + if (!f.isFile()) { + throw new IllegalArgumentException("'" + key + "' resolves to '" + value + "' which is not a valid file"); + } + + return f; + } + + /** + * Get the configured directory and converts it to a {@link File}.
+ * Uses {@link Configuration#getString(String)} internally + * @param key + * @return + * @throws IllegalArgumentException is the resolved directory does exists but is not a directory + */ + public File getDirectory(String key) throws IllegalArgumentException { + + String value = getString(key); + File f = new File(value); + + if (f.exists() && !f.isDirectory()) { + throw new IllegalArgumentException("'" + key + "' resolves to '" + value + "' which is not a directory"); + } + + return f; + } + + /** + * Get the configured directory, converts it to a {@link File} and checks if it exists.
+ * Uses {@link Configuration#getString(String)} internally + * @param key + * @return + * @throws IllegalArgumentException is the directory does not exist + */ + public File getExistingDirectory(String key) throws IllegalArgumentException { + + String value = getString(key); + File f = new File(value); + + if (!f.isDirectory()) { + throw new IllegalArgumentException("'" + key + "' resolves to '" + value + "' which is not a valid directory"); + } + + return f; + } + + /** + * Get the configured String value and converts it to the provided enum type + * @param enumClass + * @param key + * @return + * @throws IllegalArgumentException if the value is not a valid enum type + */ + public > T getEnum(Class enumType, String key) throws IllegalArgumentException { + + String value = getString(key); + + T res = Enum.valueOf(enumType, value); + + return res; + } + + /** + * Get the configured String value and converts it to the provided enum type. If the string is not set + * defaultValue is returned + * @param enumType + * @param key + * @param defaultValue + * @return + * @throws IllegalArgumentException if the value is not null and not a valid enum type + */ + public > T getEnum(Class enumType, String key, T defaultValue) throws IllegalArgumentException { + + String value = getString(key, null); + T res = defaultValue; + if (value != null) { + res = Enum.valueOf(enumType, value); + } + + return res; + } + + /** + * Returns a list of FileConfiguration's (in order) that the combined configuration was loaded from + * @return + */ + public List getLoadedFileConfigurations() { + + List result = new ArrayList(); + processLoadedConfigurationFiles(result, getDelegate()); + + return result; + } + + protected void processLoadedConfigurationFiles(List result, CombinedConfiguration configuration) { + + for (int i = 0; i < configuration.getNumberOfConfigurations(); i++) { + Configuration c = configuration.getConfiguration(i); + + if (c instanceof FileConfiguration) { + FileConfiguration fc = (FileConfiguration) c; + result.add(fc); + } else if (c instanceof CombinedConfiguration) { + processLoadedConfigurationFiles(result, (CombinedConfiguration) c); + } + + } + } + + /** + * @see {@link #visit(ConfigurationNodeVisitor, boolean)} + * @param visitor + * @param interpolate when set, a interpolated copy of the configuration is used + */ + private void visit(ConfigurationNodeVisitor visitor, boolean interpolate) { + + if (interpolate) { + + HierarchicalConfiguration hc = (HierarchicalConfiguration) interpolatedConfiguration(); + hc.getRootNode().visit(visitor); + } else { + getRootNode().visit(visitor); + } + } + + /** + * Returns the entire non-interpolated configuration as a tree representation. + * @return + */ + public String toStringTree() { + + return toStringTree(false); + } + + /** + * Returns the entire configuration as a tree representation + * @param interpolate when set, the interpolated result is printed + * @return + */ + public String toStringTree(boolean interpolate) { + + ConfigurationNodeVisitor visitor = new ToStringTreeVisitor(); + visit(visitor, interpolate); + + return visitor.toString(); + } + + /** + * Returns the entire non-interpolated configuration as a multiline representation. + * @return + */ + public String toStringMultiLine() { + + return toStringMultiLine(false); + } + + /** + * Returns the entire configuration as a multiline representation + * @param interpolate when set, the interpolated result is printed + * @return + */ + public String toStringMultiLine(boolean interpolate) { + + ConfigurationNodeVisitor visitor = new ToStringMultiLineVisitor(); + getRootNode().visit(visitor); + + return visitor.toString(); + } + + @Override + public String toString() { + + ConfigurationNodeVisitor visitor = new ToStringSingleLineVisitor(); + getRootNode().visit(visitor); + + return visitor.toString(); + } + + +} diff --git a/Configuration/src/nl/isaac/comp/configuration/CustomConfigurationBuilder.java b/Configuration/src/nl/isaac/comp/configuration/CustomConfigurationBuilder.java new file mode 100644 index 0000000..f504164 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/CustomConfigurationBuilder.java @@ -0,0 +1,187 @@ +package nl.isaac.comp.configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import nl.isaac.comp.configuration.interpolator.EnvironmentLookup; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.AbstractConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.CombinedConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.Configuration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.DefaultConfigurationBuilder; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.event.ConfigurationErrorEvent; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.event.ConfigurationErrorListener; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.interpol.ConfigurationInterpolator; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.logging.LogFactory; + +import com.dotmarketing.util.Logger; + + + + + +/** + * Wrapper for DefaultConfigurationBuilder for the Apache Commons Configuration framework. The only reason is to + * disable the default error listeners + * @author jan-willem + * + */ +@SuppressWarnings("serial") +public class CustomConfigurationBuilder extends DefaultConfigurationBuilder { + + private static final ConfigurationProvider INLINE_ROPERTIES_PROVIDER = new InlinePropertiesConfigurationProvider(); + + /** + * There is a problem when redeploying jboss applications and loading configurations from a jar file. + * The work around this problem we use this flag to prevent apache commons configuration from loading url's + * on calling {@link #getConfiguration(true)} + */ + public boolean loadedOnInstantiation = false; + + /** + * The parent configuration to use while loading config.xml. When set, variables from this configuration + * can be used in config.xml + */ + private AbstractConfiguration parentConfigurationWhileParsing; + + static { + ConfigurationInterpolator.registerGlobalLookup("env", new EnvironmentLookup()); + } + + public CustomConfigurationBuilder() { + + super(); + + // set the logger of the class we are extending to it's original value + // this to prevent non interesting debug logging from apache-commons-configuration + setLogger(LogFactory.getLog(DefaultConfigurationBuilder.class)); + + // Remove the default logger, it prints an exception when an optional log does not exist. + // Add a customer error listener if you want to catch messages + super.clearErrorListeners(); + + super.addErrorListener(new ConfigurationErrorListener() { + public void configurationError(ConfigurationErrorEvent event) { + String message = "" + event.getType() + " : "; + if (event.getCause() != null) { + message += event.getCause().getMessage(); + } + if (event.getType() == DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL) { + // make the log message more friendly + message = message.replace("Cannot locate configuration source", "Looking for optional configuration file:"); + Logger.debug(this,"LOAD_OPTIONAL: " + message); + } else { + Logger.info(this,message); + } + } + }); + + super.addConfigurationProvider("inlineproperties", INLINE_ROPERTIES_PROVIDER); + } + + /** + * @see DefaultConfigurationBuilder#DefaultConfigurationBuilder(URL) + */ + public CustomConfigurationBuilder(URL url) throws ConfigurationException { + this(); + setURL(url); + } + + /** + * Load's the configuration from the specified resource + * + * @param cl, the classloader which is able to find the specified resource + * @param resource, the resource to load + * @throws ConfigurationException, @see {@link DefaultConfigurationBuilder#getConfiguration(boolean)} + */ + public CustomConfigurationBuilder(ClassLoader cl, String resource) throws ConfigurationException { + this(); + + InputStream is = cl.getResourceAsStream(resource); + + if (is == null) throw new ConfigurationException("Unable to locate resource '" + resource + "'"); + + try { + try { + load(is); + + loadedOnInstantiation = true; + + } finally { + is.close(); + } + } catch (IOException e) { + throw new ConfigurationException(e); + } + } + + /** + * Creates the resulting combined configuration. This method is called by + * getConfiguration(). It checks whether the + * header section of the configuration definition file + * contains a result element. If this is the case, it will be + * used to initialize the properties of the newly created configuration + * object. + * + * @return the resulting configuration object + * @throws ConfigurationException if an error occurs + */ + @Override + protected CombinedConfiguration createResultConfiguration() throws ConfigurationException { + + CombinedConfiguration result = super.createResultConfiguration(); + + if (parentConfigurationWhileParsing != null) { + result.addConfiguration(parentConfigurationWhileParsing); + } + + return result; + } + + @Override + public CombinedConfiguration getConfiguration(boolean load) throws ConfigurationException { + + return getConfiguration(load, null); + } + + /** + * @see #getConfiguration(boolean) + * @param load + * @param parentConfigurationWhileParsing the configuration to use while processing config.xml. The configuration is not part of the actual configuration when loaded + * @return + * @throws ConfigurationException + */ + public CombinedConfiguration getConfiguration(boolean load, AbstractConfiguration parentConfigurationWhileParsing) throws ConfigurationException { + + if (load && loadedOnInstantiation) { + load = false; + } + + if (parentConfigurationWhileParsing != null) { + + // this is used in createResultConfiguration(); + this.parentConfigurationWhileParsing = parentConfigurationWhileParsing; + } + + CombinedConfiguration combinedConfiguration = super.getConfiguration(load); + + if (parentConfigurationWhileParsing != null) { + + // and remove the configuration again since we only used it for parsing + combinedConfiguration.removeConfiguration(parentConfigurationWhileParsing); + } + + return combinedConfiguration; + } + + /** + * @see #getConfiguration(boolean, AbstractConfiguration) + * @param parentConfigurationWhileParsing the configuration to use while processing config.xml. The configuration is not part of the actual configuration when loaded + * @return + * @throws ConfigurationException + */ + public Configuration getConfiguration(AbstractConfiguration parentConfigurationWhileParsing) throws ConfigurationException { + return getConfiguration(true, parentConfigurationWhileParsing); + } +} diff --git a/Configuration/src/nl/isaac/comp/configuration/InlinePropertiesConfigurationProvider.java b/Configuration/src/nl/isaac/comp/configuration/InlinePropertiesConfigurationProvider.java new file mode 100644 index 0000000..c46f736 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/InlinePropertiesConfigurationProvider.java @@ -0,0 +1,61 @@ +package nl.isaac.comp.configuration; + +import java.util.List; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.AbstractConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.DefaultConfigurationBuilder.ConfigurationDeclaration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.DefaultConfigurationBuilder.ConfigurationProvider; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.PropertiesConfiguration; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNode; + + + +/** + * A specialized provider implementation that deals with inline property + * configurations. + */ +public class InlinePropertiesConfigurationProvider extends ConfigurationProvider { + + /** + * Creates a new instance of InlineConfigurationProvider. + */ + public InlinePropertiesConfigurationProvider() { + super(PropertiesConfiguration.class); + } + + /** + * Creates the configuration. After that load() will be + * called. If this configuration is marked as optional, exceptions will + * be ignored. + * + * @param decl the declaration + * @return the new configuration + * @throws Exception if an error occurs + */ + public AbstractConfiguration getConfiguration(ConfigurationDeclaration decl) throws Exception { + + PropertiesConfiguration config = new PropertiesConfiguration(); + + for (Object o : decl.getNode().getChildren()) { + + ConfigurationNode node = (ConfigurationNode) o; + + if (node.getName().equals("property")) { + + List keys = node.getAttributes("key"); + + if (keys.size() != 1) throw new RuntimeException(InlinePropertiesConfigurationProvider.class.getSimpleName() + ": missing 'key' attribute"); + String key = (String) ((ConfigurationNode) keys.get(0)).getValue(); + Object value = node.getValue(); + + if (value != null) { + config.addProperty(key, value); + } + } + } + + return config; + } + +} + diff --git a/Configuration/src/nl/isaac/comp/configuration/interpolator/EnvironmentLookup.java b/Configuration/src/nl/isaac/comp/configuration/interpolator/EnvironmentLookup.java new file mode 100644 index 0000000..593bab2 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/interpolator/EnvironmentLookup.java @@ -0,0 +1,17 @@ +package nl.isaac.comp.configuration.interpolator; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.lang.text.StrLookup; + +/** + * Lookup implementation for environment settings using the "env:" prefix + * @author jan-willem + * + */ +public class EnvironmentLookup extends StrLookup { + + @Override + public String lookup(String key) { + return System.getenv(key); + } + +} diff --git a/Configuration/src/nl/isaac/comp/configuration/types/EnvironmentType.java b/Configuration/src/nl/isaac/comp/configuration/types/EnvironmentType.java new file mode 100644 index 0000000..7f92169 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/types/EnvironmentType.java @@ -0,0 +1,43 @@ +package nl.isaac.comp.configuration.types; + +/** + * This enum specifies the environment the application is running in. It should be used in all applications + * @author jan-willem + * + */ +public enum EnvironmentType { + + /** + * Local development workstation (e.g. Eclipse) + */ + LOCAL(true), + + /** + * Development environment (non development machine) + */ + DEV(true), + + /** + * UAT environment + */ + UAT(true), + + /** + * Production environment + */ + PROD(false); + + private final boolean isTestEnvironment; + + private EnvironmentType(boolean isTestEnvironment) { + this.isTestEnvironment = isTestEnvironment; + } + + /** + * Returns true if this is not a production environment + * @return + */ + public boolean isTestEnvironment() { + return isTestEnvironment; + } +} diff --git a/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringMultiLineVisitor.java b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringMultiLineVisitor.java new file mode 100644 index 0000000..050734d --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringMultiLineVisitor.java @@ -0,0 +1,55 @@ +package nl.isaac.comp.configuration.visitor; + +import java.util.Stack; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNode; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNodeVisitor; + + + +public class ToStringMultiLineVisitor implements ConfigurationNodeVisitor { + + private Stack parentStack = new Stack(); + private StringBuffer buf = new StringBuffer(); + + public ToStringMultiLineVisitor() { + } + + public void visitBeforeChildren(ConfigurationNode node) { + + if (node.getName() != null) { + + parentStack.add(node.getName()); + + if (node.getChildrenCount() == 0) { + buf.append("\n"); + + for (int i = 0; i < parentStack.size() - 1; i++) { + buf.append(parentStack.get(i)).append("."); + } + } + + buf.append(parentStack.peek()); + + if (node.getChildrenCount() == 0) { + buf.append(" = ").append(node.getValue()); + } + } + } + + public void visitAfterChildren(ConfigurationNode node) { + + if (!parentStack.isEmpty()) { + parentStack.pop(); + } + } + + public boolean terminate() { + return false; + } + + @Override + public String toString() { + return buf.toString(); + } +} diff --git a/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringSingleLineVisitor.java b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringSingleLineVisitor.java new file mode 100644 index 0000000..4fb453e --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringSingleLineVisitor.java @@ -0,0 +1,49 @@ +package nl.isaac.comp.configuration.visitor; + +import java.util.Stack; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNode; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNodeVisitor; + +public class ToStringSingleLineVisitor implements ConfigurationNodeVisitor { + + private Stack parentStack = new Stack(); + private StringBuffer buf = new StringBuffer(); + + public ToStringSingleLineVisitor() { + } + + public void visitBeforeChildren(ConfigurationNode node) { + + if (node.getName() != null) { + + parentStack.add(node.getName()); + + if (node.getChildrenCount() == 0) { + buf.append(", "); + } + + buf.append(parentStack.peek()); + + if (node.getChildrenCount() == 0) { + buf.append(" = ").append(node.getValue()); + } + } + } + + public void visitAfterChildren(ConfigurationNode node) { + + if (!parentStack.isEmpty()) { + parentStack.pop(); + } + } + + public boolean terminate() { + return false; + } + + @Override + public String toString() { + return buf.toString(); + } +} diff --git a/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringTreeVisitor.java b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringTreeVisitor.java new file mode 100644 index 0000000..64216e3 --- /dev/null +++ b/Configuration/src/nl/isaac/comp/configuration/visitor/ToStringTreeVisitor.java @@ -0,0 +1,59 @@ +package nl.isaac.comp.configuration.visitor; + +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNode; +import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.tree.ConfigurationNodeVisitor; + + +public class ToStringTreeVisitor implements ConfigurationNodeVisitor { + + private StringBuffer buf = new StringBuffer(); + private int level = -1; + private boolean addNewLine = false; + + public ToStringTreeVisitor() { + } + + public void visitBeforeChildren(ConfigurationNode node) { + + if (node.getName() != null) { + + level++; + + if (addNewLine) { + buf.append("\n"); + for (int i = 0; i < level; i++) { + buf.append("\t"); + } + addNewLine = false; + } + + if (level > 0) { + buf.append("."); + } + + buf.append(node.getName()); + + if (node.getChildrenCount() == 0) { + buf.append(" = ").append(node.getValue()); + addNewLine = true; + } + + if (node.getChildrenCount() > 1) { + addNewLine = true; + } + } + } + + public void visitAfterChildren(ConfigurationNode node) { + level--; + } + + public boolean terminate() { + return false; + } + + @Override + public String toString() { + return buf.toString(); + } +} diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationFactory.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationFactory.java index 06932ee..6b2d7e1 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationFactory.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationFactory.java @@ -11,8 +11,8 @@ import java.util.Collections; import java.util.Map; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfigurationBuilder; +import nl.isaac.comp.configuration.CustomConfiguration; +import nl.isaac.comp.configuration.CustomConfigurationBuilder; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.DefaultConfigurationBuilder.ConfigurationProvider; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.FileConfiguration; diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationService.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationService.java index 04cb312..b218c02 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationService.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/ConfigurationService.java @@ -12,8 +12,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.types.EnvironmentType; +import nl.isaac.comp.configuration.CustomConfiguration; +import nl.isaac.comp.configuration.types.EnvironmentType; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.DefaultConfigurationBuilder.ConfigurationProvider; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.lang.text.StrLookup; diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/util/EmptyConfiguration.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/util/EmptyConfiguration.java index addf22f..b75ad7a 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/util/EmptyConfiguration.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/util/EmptyConfiguration.java @@ -8,7 +8,7 @@ * @copyright Copyright (c) 2011 ISAAC Software Solutions B.V. (http://www.isaac.nl) */ -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; +import nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.CombinedConfiguration; public class EmptyConfiguration extends CustomConfiguration{ diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationMap.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationMap.java index 2b002b4..b14e7bd 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationMap.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationMap.java @@ -10,7 +10,7 @@ import java.util.Iterator; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; +import nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.util.BasicMap; import com.dotmarketing.util.Logger; diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationViewTool.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationViewTool.java index c3727d1..9d6ab3d 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationViewTool.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/ConfigurationViewTool.java @@ -17,8 +17,8 @@ import javax.servlet.http.HttpServletRequest; +import nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.ConfigurationService; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; import nl.isaac.dotcms.plugin.configuration.filter.RequestStoringFilter; import nl.isaac.dotcms.plugin.configuration.util.BasicMap; diff --git a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/portlet/admin/ConfigurationAdminViewTool.java b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/portlet/admin/ConfigurationAdminViewTool.java index 1d4ae4a..480adfc 100644 --- a/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/portlet/admin/ConfigurationAdminViewTool.java +++ b/Configuration/src/nl/isaac/dotcms/plugin/configuration/viewtool/portlet/admin/ConfigurationAdminViewTool.java @@ -13,8 +13,8 @@ import javax.servlet.http.HttpServletRequest; +import nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.ConfigurationService; -import nl.isaac.dotcms.plugin.configuration.dependencies.nl.isaac.comp.configuration.CustomConfiguration; import nl.isaac.dotcms.plugin.configuration.dependencies.org.apache.commons.configuration.ConfigurationException; import org.apache.velocity.tools.view.tools.ViewTool;