/* * 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.config.ConfigurationConstants.ConfigurationPluginName; import static org.kaleidofoundry.core.config.ConfigurationContextBuilder.FileStoreUri; import static org.kaleidofoundry.core.config.ConfigurationContextBuilder.Name; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.Set; import org.kaleidofoundry.core.context.AbstractProviderService; import org.kaleidofoundry.core.context.Context; import org.kaleidofoundry.core.context.EmptyContextParameterException; import org.kaleidofoundry.core.context.ProviderException; import org.kaleidofoundry.core.context.ProviderService; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.plugin.PluginFactory; import org.kaleidofoundry.core.plugin.model.Plugin; import org.kaleidofoundry.core.store.FileStoreProvider; import org.kaleidofoundry.core.store.ResourceException; import org.kaleidofoundry.core.util.StringHelper; /** * Configuration provider instance (creation + registry) <br/> * <ul> * <li>It can be manually used by developer via {@link ConfigurationFactory}</li> * <li>or</li> * <li>It will be used automatically by annotation processor (AOP AspectJ, Guice, Spring) which will handle {@link Context} annotation at * runtime</li> * </ul> * * @author jraduget */ public class ConfigurationProvider extends AbstractProviderService<Configuration> implements ProviderService<Configuration> { /** * @param genericClass */ public ConfigurationProvider(final Class<Configuration> genericClass) { super(genericClass); } /** * @return main configuration registry instance (shared between providers instances) */ @Override public final ConfigurationRegistry getRegistry() { return ConfigurationFactory.REGISTRY; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.context.Provider#_provides(org.kaleidofoundry.core.context.RuntimeContext) */ @Override public Configuration _provides(@NotNull final RuntimeContext<Configuration> runtimeContext) throws ProviderException { String name = runtimeContext.getString(Name); final String resourceUri = runtimeContext.getString(FileStoreUri); if (StringHelper.isEmpty(name)) { name = runtimeContext.getName(); } if (StringHelper.isEmpty(name)) { throw new EmptyContextParameterException(Name, runtimeContext); } if (StringHelper.isEmpty(resourceUri)) { throw new EmptyContextParameterException(FileStoreUri, runtimeContext); } return provides(name, resourceUri != null ? URI.create(FileStoreProvider.buildFullResourceURi(resourceUri)) : null, runtimeContext); } /** * @see ConfigurationFactory#provides(String, String) * @param name * @param resourceURI * @return configuration instance * @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException}, * {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException}) */ public Configuration provides(@NotNull final String name, @NotNull final String resourceURI) throws ProviderException { return provides(name, resourceURI, new RuntimeContext<Configuration>(name, Configuration.class)); } /** * @see ConfigurationFactory#provides(String, String, RuntimeContext) * @param name * @param resourceURI * @param runtimeContext * @return configuration instance * @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException}, * {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException}) */ public Configuration provides(@NotNull final String name, @NotNull final String resourceURI, @NotNull final RuntimeContext<Configuration> runtimeContext) throws ProviderException { String fullResourceUri = FileStoreProvider.buildFullResourceURi(resourceURI); return provides(name, resourceURI != null ? URI.create(fullResourceUri) : null, runtimeContext); } /** * @see ConfigurationFactory#provides(String, URI, RuntimeContext) * @param name * @param resourceURI * @param runtimeContext * @return configuration instance * @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException}, * {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException}) */ public Configuration provides(@NotNull final String name, @NotNull final URI resourceURI, @NotNull final RuntimeContext<Configuration> runtimeContext) throws ProviderException { final Configuration configuration = getRegistry().get(name); try { if (configuration == null) { Configuration newInstance; // create it newInstance = create(name, resourceURI, runtimeContext); // load it newInstance.load(); // register it getRegistry().put(name, newInstance); return newInstance; } else { if (!configuration.isLoaded()) { configuration.load(); } // re-check uri coherence ? return configuration; } } catch (final ResourceException ste) { throw new ProviderException(ste); } } /** * @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 new configuration instance which map to the resourceURI * @throws ProviderException encapsulate class implementation constructor call error (like {@link NoSuchMethodException}, * {@link InstantiationException}, {@link IllegalAccessException}, {@link InvocationTargetException}) * @see Configuration */ private Configuration create(@NotNull final String name, @NotNull final URI resourceURI, @NotNull final RuntimeContext<Configuration> runtimeContext) throws ProviderException { final Set<Plugin<Configuration>> pluginImpls = PluginFactory.getImplementationRegistry().findByInterface(Configuration.class); // scan each @Declare store implementation, to get one which handle the uri scheme for (final Plugin<Configuration> pi : pluginImpls) { final Class<? extends Configuration> impl = pi.getAnnotatedClass(); try { final Declare declarePlugin = impl.getAnnotation(Declare.class); final String uriPath = resourceURI.getPath().toLowerCase(); final String pluginConfigExtention = declarePlugin.value().replace(ConfigurationPluginName, "").toLowerCase(); if (uriPath.endsWith(pluginConfigExtention)) { final Constructor<? extends Configuration> constructor = impl.getConstructor(String.class, String.class, RuntimeContext.class); return constructor.newInstance(name, resourceURI.toString(), runtimeContext); } } catch (final NoSuchMethodException e) { throw new ProviderException("context.provider.error.NoSuchConstructorException", impl.getName(), "String name, String resourceUri, RuntimeContext<Configuration> context"); } catch (final InstantiationException e) { throw new ProviderException("context.provider.error.InstantiationException", impl.getName(), e.getMessage()); } catch (final IllegalAccessException e) { throw new ProviderException("context.provider.error.IllegalAccessException", impl.getName(), "String name, String resourceUri, RuntimeContext<Configuration> context"); } catch (final InvocationTargetException e) { if (e.getCause() instanceof ResourceException) { throw new ProviderException(e.getCause()); } else { throw new ProviderException("context.provider.error.InvocationTargetException", e.getCause(), impl.getName(), "String name, String resourceUri, RuntimeContext<Configuration> context"); } } } throw new ProviderException(new ResourceException("store.uri.notmanaged.illegal", resourceURI.toString())); } }