/** * Copyright (C) 2010 Daniel Manzke <daniel.manzke@googlemail.com> * * 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 de.devsurf.injection.guice.configuration.features; import java.io.File; import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import com.googlecode.rocoto.configuration.readers.PropertiesURLReader; import de.devsurf.injection.guice.configuration.Configuration; import de.devsurf.injection.guice.configuration.Configuration.Type; import de.devsurf.injection.guice.configuration.ConfigurationModule; import de.devsurf.injection.guice.configuration.PathConfig; import de.devsurf.injection.guice.configuration.PropertiesProvider; import de.devsurf.injection.guice.configuration.PropertiesReader; import de.devsurf.injection.guice.install.BindingStage; import de.devsurf.injection.guice.install.bindjob.BindingJob; import de.devsurf.injection.guice.install.bindjob.ConfigurationBindingJob; import de.devsurf.injection.guice.scanner.features.BindingScannerFeature; /** * This class will bind a Properties-Instance or -Provider for each Class * annotated with {@link Configuration}. * * @author Daniel Manzke * */ @Singleton public class ConfigurationFeature extends BindingScannerFeature { Logger _logger = Logger.getLogger(ConfigurationFeature.class.getName()); @Inject private ConfigurationModule module; @Override public BindingStage accept(Class<Object> annotatedClass, Map<String, Annotation> annotations) { if (annotations.containsKey(Configuration.class.getName())) { Configuration config = (Configuration) annotations.get(Configuration.class.getName()); if (Properties.class.isAssignableFrom(config.to())) { return BindingStage.BOOT_BEFORE; } } return BindingStage.IGNORE; } @Override public void process(Class<Object> annotatedClass, Map<String, Annotation> annotations) { Configuration config = (Configuration) annotations.get(Configuration.class.getName()); Named name = config.name(); URL url = null; if (config.alternative().value().length() > 0) { url = findURL(name, config.alternative()); if (url != null) { try { //TODO Use an Executor to test, if the Stream can be opened? //FIXME What happens if Error Page is returned? /* final URL alternativeURL = url; Future<URL> submit = Executors.newSingleThreadExecutor().submit(new Callable<URL>() { @Override public URL call() throws Exception { alternativeURL.openConnection().getInputStream(); return alternativeURL; } }); submit.get(5, TimeUnit.SECONDS); */ url.openStream(); } catch (Exception e) { url = null; } } } if (url == null) { url = findURL(name, config.location()); } if (url == null) { _logger.log(Level.WARNING, "Ignoring Configuration " + name + " in " + config.location() + ", because is couldn't be found in the Classpath."); // TODO Throw an exception if config doesn't exist? return; } if (config.type() == Type.VALUES || config.type() == Type.BOTH) { BindingJob job = new ConfigurationBindingJob(config.name(), url.toString()); if (!tracer.contains(job)) { /* && !(url.toString().startsWith("jar:")) */ _logger.log(Level.INFO, "Trying to bind \"" + url.toString() + "\" to rocoto Module."); module.addConfigurationReader(new PropertiesURLReader(url, url.toString().endsWith(".xml"))); //TODO do we need protocol handling? file:/, ... tracer.add(job); } } if (config.type() == Type.CONFIGURATION || config.type() == Type.BOTH) { boolean isXML; String path = url.toString(); if (path.endsWith(".xml")) { isXML = true; } else if (path.endsWith(".properties")) { isXML = false; } else { _logger.log(Level.WARNING, "Ignoring Configuration " + name + " in " + path + ", because is doesn't end with .xml or .properties."); // TODO Throw an exception if config has another format? return; } Named named = null; if (name.value().length() > 0) { named = name; } if (!config.lazy()) { Properties properties; try { properties = new PropertiesReader(url, isXML).readNative(); } catch (Exception e) { _logger.log(Level.WARNING, "Configuration " + name + " in " + url + ", couldn't be loaded: " + e.getMessage(), e); return; } bindInstance(properties, Properties.class, named, null); } else { Provider<Properties> provider = new PropertiesProvider(url, isXML); bindProvider(provider, Properties.class, named, Singleton.class); } } } private URL findURL(Named name, PathConfig config) { URL url = null; String path = resolver.resolve(config.value()); switch (config.type()) { case FILE: File file = new File(path); if (!file.exists()) { _logger.log(Level.WARNING, "Ignoring Configuration " + name + " in " + path + ". In the Path " + file.getAbsolutePath() + " no Configuration was found."); return null; } if (file.isFile()) { try { url = file.toURI().toURL(); } catch (MalformedURLException e) { _logger.log(Level.WARNING, "Ignoring Configuration " + name + " in " + path + ". It has an illegal URL-Format.", e); return null; } } /* * else if (file.isDirectory()) { for (File entry : * file.listFiles()) { try { url = entry.toURI().toURL(); } catch * (MalformedURLException e) { _logger.log(Level.WARNING, * "Ignoring Configuration " + name + " in " + path + * ". It has an illegal URL-Format.", e); return null; } } } */ break; case URL: try { url = new URL(path); } catch (MalformedURLException e) { _logger.log(Level.WARNING, "Ignoring Configuration " + name + " in " + path + ". It has an illegal URL-Format.", e); return null; } break; case CLASSPATH: default: url = this.getClass().getResource(path); break; } return url; } }