/*
* 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.config;
import static org.kaleidofoundry.core.env.model.EnvironmentConstants.CONFIGURATIONS_PROPERTY_SEPARATOR;
import static org.kaleidofoundry.core.env.model.EnvironmentConstants.CONFIGURATIONS_PROPERTY_VALUE_SEPARATOR;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.StringTokenizer;
import org.kaleidofoundry.core.config.ConfigurationConstants.Extension;
import org.kaleidofoundry.core.context.ProviderException;
import org.kaleidofoundry.core.context.RuntimeContext;
import org.kaleidofoundry.core.lang.annotation.NotNull;
import org.kaleidofoundry.core.store.ResourceException;
import org.kaleidofoundry.core.util.StringHelper;
/**
* Configuration factory provider
* <p>
* <b>How to declare the configuration to load ?</b> <br/>
* <br/>
* Define the following java environment variable {@link ConfigurationConstants#CONFIGURATIONS_PROPERTY} like this :
* <p>
* <code>
* -Dkaleido.configurations=configurationName01=configurationUri01,configurationName02=configurationUri02,...
* </code>
* </p>
* <p>
* <b>Example :</b> <br/>
* <code>
* java -Dkaleido.configurations=datasource=classpath:/datasource.properties,otherResource=http:/host/path/otherResource;... ...
* </code>
* </p>
* </p>
*
* @author jraduget
* @see ConfigurationProvider delegate configuration creation & registry
*/
public abstract class ConfigurationFactory {
// does default init Configurations have occurred
private static boolean INIT_LOADED = false;
/**
* main configuration registry instance (shared between providers instances)
*/
static final ConfigurationRegistry REGISTRY = new ConfigurationRegistry();
/**
* configuration provider used by the factory
*/
static final ConfigurationProvider CONFIGURATION_PROVIDER = new ConfigurationProvider(Configuration.class);
/**
* Create / Load / Register all configurations, that have been declared via java system environment <br/>
* <br/>
* If load have already be called, it does nothing more.
*
* @param configurations configurationName01=configurationUri01,configurationName02=configurationUri02,...
* @throws ResourceException
* @see ConfigurationConstants#CONFIGURATIONS_PROPERTY
*/
public static synchronized final void init(final String configurations) throws ResourceException {
if (!INIT_LOADED) {
final StringTokenizer strConfigToken = new StringTokenizer(configurations, CONFIGURATIONS_PROPERTY_SEPARATOR);
while (strConfigToken.hasMoreTokens()) {
final String configItemStr = strConfigToken.nextToken().trim();
final String[] configItem = StringHelper.split(configItemStr, CONFIGURATIONS_PROPERTY_VALUE_SEPARATOR);
// named declaration
if (configItem.length == 2) {
provides(configItem[0].trim(), configItem[1].trim());
}
// anonymous declaration
else if (configItem.length == 1) {
provides(configItem[0].trim(), configItem[0].trim());
}
}
// Init is successful
INIT_LOADED = true;
}
}
/**
* Unload / Unregister / Destroy all registered configurations
*
* @throws ResourceException
*/
public static synchronized final void unregisterAll() throws ResourceException {
for (final Configuration configuration : getRegistry().values()) {
if (configuration.isLoaded()) {
configuration.unload();
}
getRegistry().remove(configuration.getName());
}
INIT_LOADED = false;
}
/**
* Unload / Unregister / Destroy the given configuration
*
* @param configName
* @throws ResourceException
* @throws ConfigurationNotFoundException
*/
public static final void unregister(@NotNull final String configName) throws ConfigurationNotFoundException, ResourceException {
final Configuration configToDestroy = getRegistry().get(configName);
if (configToDestroy != null) {
if (configToDestroy.isLoaded()) {
configToDestroy.unload();
}
getRegistry().remove(configName);
} else {
throw new ConfigurationNotFoundException(configName);
}
}
/**
* does configuration is registered
*
* @param config
* @return <code>true|false</code>
*/
public static boolean isRegistered(final String config) {
return ConfigurationFactory.getRegistry().containsKey(config);
}
/**
* @return shortcut to main configuration registry stored in {@link ConfigurationProvider}
*/
public static final ConfigurationRegistry getRegistry() {
return REGISTRY;
}
/**
* Provides a new configuration instance
* <p>
* To known what is the configuration format, it scans the resource path URI extension :
* <ul>
* <li>.properties,</li>
* <li>.xmlproperties,</li>
* <li>.xml,</li>
* <li>.javasystem,</li>
* <li>.mainargs,</li>
* <li>.osenv,</li>
* <li>...</li>
* </ul>
* <br/>
* a default enumeration of the handle extensions can be found at {@link Extension}<br/>
* </p>
* <br/>
* <p>
* To known the configuration store to use, it scans the scheme of the URI :
* <ul>
* <li>file:/,</li>
* <li>http://,</li>
* <li>ftp://,</li>
* <li>classpath:/,</li>
* <li>webapp:/,</li>
* <li>jpa://,</li>
* <li>jdbc://,</li>
* </ul>
* </p>
* <br/>
* <b>Configuration is loaded before to be provided.</b> <br/>
*
* @param runtimeContext see {@link ConfigurationContextBuilder} informations for common context properties, and specific implementation
* class
* if needed
* @return configuration instance (loaded) which map to the resourceURI
* @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException},
* {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException})
* @see Configuration
*/
public static Configuration provides(final RuntimeContext<Configuration> runtimeContext) {
return CONFIGURATION_PROVIDER.provides(runtimeContext);
}
/**
* Provides a new configuration instance
* <p>
* To known what is the configuration format, it scans the resource path URI extension :
* <ul>
* <li>.properties,</li>
* <li>.xmlproperties,</li>
* <li>.xml,</li>
* <li>.javasystem,</li>
* <li>.mainargs,</li>
* <li>.osenv,</li>
* <li>...</li>
* </ul>
* <br/>
* a default enumeration of the handle extensions can be found at {@link Extension}<br/>
* </p>
* <br/>
* <p>
* To known the configuration store to use, it scans the scheme of the URI :
* <ul>
* <li>file:/,</li>
* <li>http://,</li>
* <li>ftp://,</li>
* <li>classpath:/,</li>
* <li>webapp:/,</li>
* <li>jpa://,</li>
* <li>jdbc://,</li>
* </ul>
* </p>
* <br/>
* <b>Configuration is loaded before to be provided.</b> <br/>
*
* @param name configuration name (unique identifier)
* @param resourceURI
* @return configuration instance (loaded) which map to the resourceURI
* @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException},
* {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException})
* @see Configuration
*/
public static Configuration provides(@NotNull final String name, @NotNull final String resourceURI) {
return CONFIGURATION_PROVIDER.provides(name, resourceURI);
}
/**
* Provides a new configuration instance
* <p>
* To known what is the configuration format, it scans the resource path URI extension :
* <ul>
* <li>.properties,</li>
* <li>.xmlproperties,</li>
* <li>.xml,</li>
* <li>.javasystem,</li>
* <li>.mainargs,</li>
* <li>.osenv,</li>
* <li>...</li>
* </ul>
* <br/>
* a default enumeration of the handle extensions can be found at {@link Extension}<br/>
* </p>
* <br/>
* <p>
* To known the configuration store to use, it scans the scheme of the URI :
* <ul>
* <li>file:/,</li>
* <li>http://,</li>
* <li>ftp://,</li>
* <li>classpath:/,</li>
* <li>webapp:/,</li>
* <li>jpa://,</li>
* <li>jdbc://,</li>
* </ul>
* </p>
* <br/>
* <b>Configuration is loaded before to be provided.</b> <br/>
*
* @param name configuration name (unique identifier)
* @param resourceURI configuration resource URI
* @param runtimeContext see {@link ConfigurationContextBuilder} informations for common context properties, and specific implementation
* class
* if needed
* @return configuration instance (loaded) which map to the resourceURI
* @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException},
* {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException})
* @see Configuration
*/
public static Configuration provides(@NotNull final String name, @NotNull final String resourceURI,
@NotNull final RuntimeContext<Configuration> runtimeContext) {
return CONFIGURATION_PROVIDER.provides(name, resourceURI, runtimeContext);
}
/**
* Provides a new configuration instance
* <p>
* To known what is the configuration format, it scans the resource path URI extension :
* <ul>
* <li>.properties,</li>
* <li>.xmlproperties,</li>
* <li>.xml,</li>
* <li>.javasystem,</li>
* <li>.mainargs,</li>
* <li>.osenv,</li>
* <li>...</li>
* </ul>
* <br/>
* a default enumeration of the handle extensions can be found at {@link Extension}<br/>
* </p>
* <br/>
* <p>
* To known the configuration store to use, it scans the scheme of the URI :
* <ul>
* <li>file:/,</li>
* <li>http://,</li>
* <li>ftp://,</li>
* <li>classpath:/,</li>
* <li>webapp:/,</li>
* <li>jpa://,</li>
* <li>jdbc://,</li>
* </ul>
* </p>
* <br/>
* <b>Configuration is loaded before to be provided.</b> <br/>
*
* @param name configuration name (unique identifier)
* @param resourceURI configuration resource URI
* @param runtimeContext see {@link ConfigurationContextBuilder} informations for common context properties, and specific implementation
* class
* if needed
* @return configuration instance (loaded) which map to the resourceURI
* @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException},
* {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException})
* @see Configuration
*/
public static Configuration provides(@NotNull final String name, @NotNull final URI resourceURI, @NotNull final RuntimeContext<Configuration> runtimeContext) {
return CONFIGURATION_PROVIDER.provides(name, resourceURI, runtimeContext);
}
/**
* Provides a new configuration instance exposing the java system properties
*
* @return a convenient {@link Configuration} accessor to java {@link System#getProperties()} through {@link Configuration} interface
*/
public static Configuration javaSystemConfiguration() {
return ConfigurationFactory.provides("javaSystem", "memory:/internal/configuration.osenv");
}
/**
* Provides a new configuration instance exposing the OS environment variables
*
* @return a convenient {@link Configuration} accessor to OS environment variables through {@link Configuration} interface
*/
public static Configuration osEnvironmentConfiguration() {
return ConfigurationFactory.provides("osEnvironment", "memory:/internal/configuration.javasystem");
}
}