org.powertac.server.ServerPropertiesService.java Source code

Java tutorial

Introduction

Here is the source code for org.powertac.server.ServerPropertiesService.java

Source

/*
 * Copyright (c) 2011 by the original author
 *
 * 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.powertac.server;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
import java.util.Properties;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;
import org.powertac.common.config.ConfigurationRecorder;
import org.powertac.common.config.Configurator;
import org.powertac.common.interfaces.ServerConfiguration;
import org.powertac.common.interfaces.ServerProperties;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

/**
 * Implementation of the ServerProperties and ServerConfiguration interfaces.
 * @author jcollins
 */
@Service
public class ServerPropertiesService implements ServerProperties, ServerConfiguration, ApplicationContextAware {
    static private Logger log = Logger.getLogger(ServerPropertiesService.class);

    private ApplicationContext context;
    private CompositeConfiguration config;
    private Configurator configurator;
    private ConfigurationPublisher publisher;

    private boolean initialized = false;

    /**
     * Default constructor
     */
    public ServerPropertiesService() {
        super();
        recycle();
    }

    /**
     * Come here to re-configure from scratch. This is not done as an 
     * InitializationService because it has to happen before module
     * initialization happens.
     */
    public void recycle() {
        // set up the config instance
        config = new CompositeConfiguration();
        configurator = new Configurator();
        publisher = new ConfigurationPublisher();
        initialized = false;
    }

    /**
     * Loads the properties from classpath, default config file,
     * and user-specified config file, just in case it's not already been
     * loaded. This is done when properties are first requested, to ensure
     * that the logger has been initialized. Because the CompositeConfiguration
     * treats its config sources in FIFO order, this should be called <i>after</i>
     * any user-specified config is loaded.
     */
    void lazyInit() {
        // only do this once
        if (initialized)
            return;
        initialized = true;

        // find and load the default properties file
        log.info("lazyInit");
        try {
            File defaultProps = new File("config/server.properties");
            if (defaultProps.canRead()) {
                log.debug("adding " + defaultProps.getName());
                config.addConfiguration(new PropertiesConfiguration(defaultProps));
            }
        } catch (Exception e1) {
            log.warn("config/server.properties not found: " + e1.toString());
        }

        // set up the classpath props
        try {
            Resource[] xmlResources = context.getResources("classpath*:config/properties.xml");
            for (Resource xml : xmlResources) {
                if (validXmlResource(xml)) {
                    log.info("loading config from " + xml.getURI());
                    XMLConfiguration xconfig = new XMLConfiguration();
                    xconfig.load(xml.getInputStream());
                    config.addConfiguration(xconfig);
                }
            }
            Resource[] propResources = context.getResources("classpath*:config/*.properties");
            for (Resource prop : propResources) {
                if (validPropResource(prop)) {
                    log.info("loading config from " + prop.getURI());
                    PropertiesConfiguration pconfig = new PropertiesConfiguration();
                    pconfig.load(prop.getInputStream());
                    config.addConfiguration(pconfig);
                }
            }
        } catch (ConfigurationException e) {
            log.error("Error loading configuration: " + e.toString());
        } catch (Exception e) {
            log.error("Error loading configuration: " + e.toString());
        }

        // set up the configurator
        configurator.setConfiguration(config);
    }

    public void setUserConfig(URL userConfigURL) throws ConfigurationException, IOException {
        // then load the user-specified config

        PropertiesConfiguration pconfig = new PropertiesConfiguration();
        pconfig.load(userConfigURL.openStream());
        config.addConfiguration(pconfig);
        log.debug("setUserConfig " + userConfigURL.toExternalForm());
        lazyInit();
    }

    @Override
    public void configureMe(Object target) {
        lazyInit();
        configurator.configureSingleton(target);
    }

    @Override
    public Collection<?> configureInstances(Class<?> target) {
        lazyInit();
        return configurator.configureInstances(target);
    }

    @Override
    public void publishConfiguration(Object target) {
        lazyInit();
        configurator.gatherPublishedConfiguration(target, publisher);
    }

    /**
     * Returns the published configuration as a string
     */
    public Properties getPublishedConfiguration() {
        log.debug("published config: " + publisher.getConfig());
        return publisher.getConfig();
    }

    /* (non-Javadoc)
     * @see org.powertac.common.interfaces.ServerProperties#getProperty(java.lang.String)
     */
    @Override
    public String getProperty(String name) {
        lazyInit();
        return config.getString(name);
    }

    /* (non-Javadoc)
     * @see org.powertac.common.interfaces.ServerProperties#getProperty(java.lang.String, java.lang.String)
     */
    @Override
    public String getProperty(String name, String defaultValue) {
        lazyInit();
        return config.getString(name, defaultValue);
    }

    @Override
    public Integer getIntegerProperty(String name, Integer defaultValue) {
        lazyInit();
        return config.getInteger(name, defaultValue);
    }

    @Override
    public Double getDoubleProperty(String name, Double defaultValue) {
        lazyInit();
        return config.getDouble(name, defaultValue);
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    /**
     * Changes the value of a property (or adds a property).
     */
    public void setProperty(String key, Object value) {
        lazyInit();
        config.setProperty(key, value);
    }

    // -- valid configuration resources --
    private String[] excludedPaths = { ".*/test-classes/.*", ".*/log4j.properties" };

    private boolean validXmlResource(Resource xml) {
        log.debug("resource class: " + xml.getClass().getName());
        try {
            String path = xml.getURI().toString();
            for (String regex : excludedPaths) {
                if (path.matches(regex)) {
                    log.debug("invalid path " + path);
                    return false;
                }
            }
            return true;
        } catch (IOException e) {
            log.error("Should not happen: " + e.toString());
            return false;
        }
    }

    private boolean validPropResource(Resource prop) {
        return validXmlResource(prop);
    }

    // call this to allow test-classes to be included in valid paths
    void allowTestPaths() {
        excludedPaths = new String[] { ".*/log4j.properties" };
    }

    // test support
    Configuration getConfig() {
        return config;
    }

    /**
     * Configuration recorder for publishing config info to brokers
     */
    class ConfigurationPublisher implements ConfigurationRecorder {
        Properties publishedConfig;

        ConfigurationPublisher() {
            publishedConfig = new Properties();
        }

        @Override
        public void recordItem(String key, Object value) {
            publishedConfig.put(key, value);
        }

        Properties getConfig() {
            return publishedConfig;
        }
    }
}