Package org.apache.marmotta.platform.core.services.config

Source Code of org.apache.marmotta.platform.core.services.config.ConfigurationServiceImpl

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.marmotta.platform.core.services.config;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Any;
import javax.inject.Inject;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.servlet.ServletContext;

import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.marmotta.platform.core.api.config.ConfigurationService;
import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
import org.apache.marmotta.platform.core.events.ConfigurationServiceInitEvent;
import org.apache.marmotta.platform.core.util.FallbackConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.common.io.Resources;

/**
* This service offers access to the system configuration of the LMF and takes care of initialising the system
* properly on startup.
*
* @author Sebastian Schaffert
* @author Sergio Fernández
*
*/
@ApplicationScoped
public class ConfigurationServiceImpl implements ConfigurationService {

    private String home;

    private static Logger log = LoggerFactory.getLogger(ConfigurationService.class);

    private String configFileName, metaFileName;

    /**
     * The configuration wrapper, loads first the stored configuration and then all stored configuration options
     */
    private CompositeConfiguration config;

    /**
     * The backend for storing configuration values, usually ${marmotta.home}/system-config.properties
     */
    private Configuration saveConfiguration;

    /**
     * The backend for storing metadata about configuration values, usually ${marmotta.home}/system-meta.properties
     */
    private Configuration saveMetadata;

    /**
     * The metadata about the configuration options
     */
    private CompositeConfiguration configDescriptions;

    private HashMap<String, Boolean> runtimeFlags;

    @Inject
    @Any
    private Event<ConfigurationChangedEvent> configurationEvent;

    @Inject
    @Any
    private Event<ConfigurationServiceInitEvent> configurationInitEvent;

    private int serverPort        = 0;
    //private String serverContext;
    private String serverName     = null;

    private boolean                          initialising;
    private boolean                          initialised = false;

    private ServletContext                   servletContext;


    /**
     * A lock to ensure proper concurrent access to the configuration. The system requests a write lock in case a
     * setXXX() method is called and a read lock in case a getXXX() method is called.
     */
    private ReadWriteLock lock;


    public ConfigurationServiceImpl() {
        runtimeFlags = new HashMap<String, Boolean>();
        lock = new ReentrantReadWriteLock();
    }

    /**
     * Initialise the ConfigurationService. Takes the marmotta.home system property from the servlet
     * init parameters
     * (web.xml) as bootstrap home. In case a system-config.properties file is found in this
     * directory, the
     * configuration is then loaded from this file. In case a system-config.properties file does not
     * yet exist,
     * the method loads bootstrap settings from the resource default-config.properties in the
     * classpath (in the
     * standard bundling, the file is in the kiwi-core-XXX.jar archive). After loading the
     * configuration, the
     * service initialises the plugin subsystem and the SOLR home directory by unpacking the default
     * configuration
     * if the SOLR configuration does not yet exist.
     * @param override
     */
    @Override
    public void initialize(String home, Configuration override) {
        lock.writeLock().lock();
        try {
            initialising = true;

            log.info("Apache Marmotta Configuration Service starting up ...");

            if(isTomcat7()) {
                log.info("Apache Marmotta running on Apache Tomcat 7.x");
            } else if(isTomcat6()) {
                log.info("Apache Marmotta running on Apache Tomcat <= 6.x");
            } else if(isJetty7()) {
                log.info("Apache Marmotta running on Jetty 7.x");
            } else if(isJetty6()) {
                log.info("Apache Marmotta running on Jetty <= 6.x");
            } else {
                log.info("Apache Marmotta running on an unknown servlet container");
            }

            setHome(home);

            if (getHome() != null) {
                File f1 = new File(getHome());
                if (!f1.exists()) {
                    f1.mkdirs();
                }
                // ensure directory for user configuration files
                File f2 = new File(getHome() + File.separator + "config");
                if(!f2.exists()) {
                    f2.mkdirs();
                }

                // ensure directory for logging messages
                File f3 = new File(getHome() + File.separator + "log");
                if(!f3.exists()) {
                    f3.mkdirs();
                }
            }

            // the save configuration will be in the  home directory
            try {
                if (getHome() != null) {
                    configFileName = getHome() + File.separator + "system-config.properties";
                    metaFileName = getHome() + File.separator + "system-meta.properties";

                    File configFile = new File(configFileName);
                    if (!configFile.exists()) {
                        log.info("creating system configuration in configuration file {}", configFile.getAbsolutePath());
                    } else {
                        log.info("reading system configuration from existing configuration file {}", configFile.getAbsolutePath());
                    }
                    saveConfiguration = new PropertiesConfiguration(configFile);


                    File metaFile = new File(metaFileName);
                    if (!metaFile.exists()) {
                        log.info("creating system configuration metadata in configuration file {}", metaFile.getAbsolutePath());
                    } else {
                        log.info("reading system configuration metadata from existing configuration file {}", metaFile.getAbsolutePath());
                    }
                    saveMetadata = new PropertiesConfiguration(metaFile);

                } else {
                    log.error("error while initialising configuration: no marmotta.home property given; creating memory-only configuration");
                    saveConfiguration = new MapConfiguration(new HashMap<String, Object>());
                    saveMetadata      = new MapConfiguration(new HashMap<String, Object>());
                }
            } catch (Exception e) {
                log.error("error while initialising configuration file {}: {}; creating memory-only configuration", configFileName, e.getMessage());
                saveConfiguration = new MapConfiguration(new HashMap<String, Object>());
                saveMetadata      = new MapConfiguration(new HashMap<String, Object>());
            }
            config = new FallbackConfiguration();
            config.addConfiguration(saveConfiguration,true);

            // load all default-config.properties

            try {
                Enumeration<URL> configs = this.getClass().getClassLoader().getResources("config-defaults.properties");
                while(configs.hasMoreElements()) {
                    URL url = configs.nextElement();
                    config.addConfiguration(new PropertiesConfiguration(url));
                }

            } catch (IOException e) {
                log.error("I/O error while loading default configurations",e);
            } catch (ConfigurationException e) {
                log.error("configuration error while loading default configurations",e);
            }

            // legacy support (to be removed)
            try {
                Enumeration<URL> configs = this.getClass().getClassLoader().getResources("default-config.properties");
                while(configs.hasMoreElements()) {
                    URL url = configs.nextElement();
                    config.addConfiguration(new PropertiesConfiguration(url));
                    log.warn("found legacy configuration file {}; should be replaced with per-module configuration!",url);
                }

            } catch (IOException e) {
                log.error("I/O error while loading default configurations",e);
            } catch (ConfigurationException e) {
                log.error("configuration error while loading default configurations",e);
            }


            // create the configuration that is responsible for getting metadata about configuration keys in the main
            // configuration; since the keys will be different, we store changes also to the main save configuration
            configDescriptions = new FallbackConfiguration();
            configDescriptions.addConfiguration(saveMetadata,true);
            try {
                Enumeration<URL> configs = this.getClass().getClassLoader().getResources("config-descriptions.properties");
                while(configs.hasMoreElements()) {
                    URL url = configs.nextElement();
                    configDescriptions.addConfiguration(new PropertiesConfiguration(url));
                }

            } catch (IOException e) {
                log.error("I/O error while loading configuration descriptions",e);
            } catch (ConfigurationException e) {
                log.error("configuration error while loading configuration descriptions",e);
            }

            // setup home if it is given as system property,
            // the bootstrap configuration is overwritten
            if (getHome() != null) {
                config.setProperty("marmotta.home", getHome());
                config.setProperty("solr.home", getHome() + File.separator + "solr");
            }

            // in case override configuration is given, change all settings in the configuration accordingly
            if(override != null) {
                for (Iterator<String> it = override.getKeys(); it.hasNext();) {
                    String key = it.next();

                    config.setProperty(key, override.getProperty(key));
                }
            }

            save();

            // configuration service is now ready to use
            initialised = true;


            // this should maybe move to the KiWiPreStartupFilter ...
            initLoggingConfiguration();
            initDatabaseConfiguration();

            save();

            log.info("Apache Marmotta Configuration Service: initialisation completed");

            configurationInitEvent.fire(new ConfigurationServiceInitEvent());

            initialising = false;
        } finally {
            lock.writeLock().unlock();
        }

    }

    /**
     * Initialise the Apache Marmotta Logging Configuration.
     * <ul>
     * <li>if the logback.xml file does not yet exist, create it based on the logback-template.xml resource</li>
     * <li>reiniaialise the logging framework using the logback.xml file from Apache Marmotta Home, overwriting the basic logging configured on startup</li>
     * <li>in case debug.enabled = true, set the root logger level to debug, otherwise set it to info</li>
     * </ul>
     */
    private void initLoggingConfiguration() {
        File log_configuration = new File(getWorkDir() + File.separator + "logback.xml");

        if(!log_configuration.exists()) {
            // create new logging configuration from template
            URL url_template = ConfigurationService.class.getResource(config.getString("logging.template", "/logback-template.xml"));

            if (url_template != null) {
                try {
                    Files.copy(Resources.newInputStreamSupplier(url_template), log_configuration);
                } catch (IOException e) {
                    log.error("could not create logging configuration; reverting to bootstrap logging", e);
                }
            } else {
                log.error("could not find logging template; reverting to bootstrap logging");
            }
        }

        log.warn("LOGGING: Switching to Apache Marmotta logging configuration; further output will be found in {}/log/*.log", getWorkDir());
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(context);
            context.reset();
            configurator.doConfigure(log_configuration);
        } catch (JoranException e) {
            StatusPrinter.printInCaseOfErrorsOrWarnings(context);
        }

        // set root logger level
        ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
        if(getBooleanConfiguration("debug.enabled",false)) {
            rootLogger.setLevel(Level.DEBUG);
        } else {
            rootLogger.setLevel(Level.INFO);
        }

    }

    private void initDatabaseConfiguration() {
        if (!config.getBoolean("kiwi.setup.database")) {
            log.info("SETUP: Setting up initial Apache Marmotta database configuration ...");
            String db_type = config.getString("database.type", "h2");
            config.setProperty("database.h2.url", "jdbc:h2:" + getWorkDir() + "/db/lmf;MVCC=true;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=10");
            if (db_type.equals("h2")) {
                config.setProperty("database.url", "jdbc:h2:" + getWorkDir() + "/db/lmf;MVCC=true;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=10");
                config.setProperty("database.user", "sa");
                config.setProperty("database.password", "sa");
                config.setProperty("database.mode", "create");
            }
            config.setProperty("kiwi.setup.database", true);
        }
    }

    @PreDestroy
    public void shutdown() {
        log.info("shutting down configuration service");
    }

    /**
     * Pass the servlet context over to the configuration service to provide runtime information about
     * the environment to the rest of the system.
     *
     * @param context
     */
    @Override
    public void setServletContext(ServletContext context) {
        this.servletContext = context;
    }


    /**
     * Get the servlet context used when initialising the system
     *
     * @return
     */
    @Override
    public ServletContext getServletContext() {
        return servletContext;
    }

    /**
     * Get the base URI out of the current request. The base URI
     * is used e.g. to generate URIs of internal content items
     *
     * @see org.apache.marmotta.platform.core.api.config.ConfigurationService#getBaseUri()
     */

    @Override
    public String getBaseUri() {
        return getStringConfiguration("kiwi.context");
    }

    /**
     * Get the base path of the system, which is the relative path from the server host.
     * For example, in the case of http://localhost:8080/LMF, /LMF would be returned as the path.
     *
     * @return a String representing the path
     */
    @Override
    public String getPath() {
        return getStringConfiguration("kiwi.path");
    }

    /**
     * Get the server uri of the system, i.e. a uri that when entered in the browser accesses the
     * server that runs the KiWi (and SOLR) applications. Can be used to compute the paths of
     * other applications relative to the current application. Computed like the base uri.
     *
     * @see ConfigurationService#getServerUri()
     */
    @Override
    public String getServerUri() {
        String serverUrl = getStringConfiguration("kiwi.host");

        if (serverUrl.endsWith("/"))
            return serverUrl;
        else
            return serverUrl + "/";
    }

    /**
     * List all configuration keys defined for the system configuration of KiWi.
     *
     * @return
     */
    @Override
    public List<String> listConfigurationKeys() {
        lock.readLock().lock();
        try {
            List<String> keys = new LinkedList<String>();
            for (Iterator<String> it = config.getKeys(); it.hasNext();) {
                keys.add(it.next());
            }
            return keys;
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * List all configuration keys defined for the system configuration of KiWi having prefix.
     *
     * @param prefix the prefix of keys that should be returned
     * @return
     */
    @Override
    public List<String> listConfigurationKeys(String prefix) {
        lock.readLock().lock();
        try {
            List<String> keys = new LinkedList<String>();
            for (Iterator<String> it = config.getKeys(prefix); it.hasNext();) {
                keys.add(it.next());
            }
            return keys;
        } finally {
            lock.readLock().unlock();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#isConfigurationSet(java.lang.String)
     */
    @Override
    public boolean isConfigurationSet(String key) {
        lock.readLock().lock();
        try {
            return config.containsKey(key);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Get the configuration for the given key. If there is no such configuration, a new one is
     * created with empty value (returns null).
     *
     * @param key unique configuration key for lookup
     * @return a configuration object with either the configured value or null as value
     */
    @Override
    public Object getConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getProperty(key);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Return the comment for the configuration with the given key as string. If there is no such
     * configuration, null is returned
     *
     * @param key unique configuration key for lookup
     * @return a string describing the configuration option or null if no comment was given
     */
    @Override
    public String getComment(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return configDescriptions.getString(key + ".description");
        } finally {
            lock.readLock().unlock();
        }

    }

    /**
     * Return the type for the configuration with the given key as string. If there is no such
     * configuration, null is returned
     * @param key unique configuration key for lookup
     * @return  a string describing the type for key or DEFAULT_TYPE (String) if no type was given
     */
    @Override
    public String getType(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            String s = configDescriptions.getString(key+".type");
            return s!=null?s: String.class.getName();
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Set the configuration "key" to the string value "value".
     *
     * @param key
     * @param value
     */
    @Override
    public void setConfiguration(String key, Object value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }

        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    /**
     * Set type for a configuration key
     *
     * @param key key for configuration fields
     * @param type type for configuratino field
     */
    @Override
    public void setType(String key, String type) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            configDescriptions.setProperty(key+".type",type);
            save();
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * Set type for a configuration key
     *
     * @param key key for configuration fields
     * @param description type for configuratino field
     */
    @Override
    public void setComment(String key, String description) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            configDescriptions.setProperty(key+".description",description);
            save();
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     *
     *
     */
    @Override
    public String getStringConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
            }
            String result = config.getString(key);
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
            }
            return result;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public String getStringConfiguration(String key, String defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
            }
            String result = config.getString(key, defaultValue);
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
            }
            return result;
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public double getDoubleConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getDouble(key, 0.0);
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public double getDoubleConfiguration(String key, double defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getDouble(key, defaultValue);
        } finally {
            lock.readLock().unlock();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#setDoubleConfiguration(java.lang.String, double)
     */
    @Override
    public void setDoubleConfiguration(String key, double value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }

        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    @Override
    public int getIntConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised, "ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getInt(key, 0);
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public int getIntConfiguration(String key, int defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getInt(key, defaultValue);
        } finally {
            lock.readLock().unlock();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#setIntConfiguration(java.lang.String, int)
     */
    @Override
    public void setIntConfiguration(String key, int value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }

        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }


    /**
     * Get the configuration for the given key. If there is no such configuration, 0 is returned
     *
     * @param key unique configuration key for lookup
     * @return a int value with either the configured value or 0
     */
    @Override
    public long getLongConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised, "ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getLong(key, 0);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Get the configuration for the given key. If there is no such configuration, a new one is
     * created using the provided defaultValue as double value.
     *
     * @param key          unique configuration key for lookup
     * @param defaultValue default value if configuration not found
     * @return a configuration object with either the configured value or defaultValue
     */
    @Override
    public long getLongConfiguration(String key, long defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getLong(key, defaultValue);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * Set the system configuration with the given key to the given int value.
     *
     * @param key
     * @param value
     */
    @Override
    public void setLongConfiguration(String key, long value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }

        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    @Override
    public boolean getBooleanConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getBoolean(key, false);
        } finally {
            lock.readLock().unlock();
        }

    }

    @Override
    public boolean getBooleanConfiguration(String key, boolean defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getBoolean(key, defaultValue);
        } finally {
            lock.readLock().unlock();
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#setIntConfiguration(java.lang.String, int)
     */
    @Override
    public void setBooleanConfiguration(String key, boolean value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }


        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#getListConfiguration(java.lang.String)
     */
    @Override
    public Properties getPropertiesConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            return config.getProperties(key);
        } finally {
            lock.readLock().unlock();
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#getListConfiguration(java.lang.String)
     */
    @Override
    public List<String> getListConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            String[] result = config.getStringArray(key);

            if (result.length == 1 && "".equals(result[0].trim())) return Collections.emptyList();

            return Lists.newArrayList(result);
        } finally {
            lock.readLock().unlock();
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#getListConfiguration(java.lang.String,
     * java.util.List)
     */
    @Override
    public List<String> getListConfiguration(String key, List<String> defaultValue) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.readLock().lock();
        try {
            if (config.containsKey(key)) {
                String[] values = config.getStringArray(key);
                if (values.length > 0) return Lists.newArrayList(values);
                else
                    return Lists.newArrayList();
            } else
                return defaultValue;
        } finally {
            lock.readLock().unlock();
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see kiwi.api.config.ConfigurationService#setListConfiguration(java.lang.String,
     * java.util.List)
     */
    @Override
    public void setListConfiguration(String key, List<String> value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, value);
            save();
        } finally {
            lock.writeLock().unlock();
        }


        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    @Override
    public void removeConfiguration(String key) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.clearProperty(key);
            configDescriptions.clearProperty(key+".type");
            configDescriptions.clearProperty(key+".description");
        } finally {
            lock.writeLock().unlock();
        }

    }

    @Override
    public void setConfiguration(String key, String value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
            }
            config.setProperty(key, value);
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
            }
            save();
        } finally {
            lock.writeLock().unlock();
        }


        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    /**
     * Set a configuration value without firing an event. This is in rare cases needed to avoid
     * propagation of events.
     *
     * @param key
     * @param value
     */
    @Override
    public void setConfigurationWithoutEvent(String key, Object value) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
            }
            config.setProperty(key, value);
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
            }
            save();
        } finally {
            lock.writeLock().unlock();
        }

    }


    @Override
    public void setConfigurations(Map<String, ?> values) {
        Preconditions.checkNotNull(values);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
            }
            for (Map.Entry<String, ?> entry : values.entrySet()) {
                config.setProperty(entry.getKey(), entry.getValue());
            }
            if (config instanceof AbstractConfiguration) {
                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
            }
            save();
        } finally {
            lock.writeLock().unlock();
        }


        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(values.keySet()));
        }
    }

    @Override
    public void setConfiguration(String key, List<String> values) {
        Preconditions.checkNotNull(key);
        Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");

        lock.writeLock().lock();
        try {
            config.setProperty(key, values);
            save();
        } finally {
            lock.writeLock().unlock();
        }


        if (!initialising) {
            configurationEvent.fire(new ConfigurationChangedEvent(key));
        }
    }

    /**
     * The work directory for marmotta, where all applications will create their own subdirectories
     */

    @Override
    @Deprecated
    public String getWorkDir() {
        return getHome();
    }

    protected void save() {
        if(saveConfiguration instanceof PropertiesConfiguration) {
            try {
                ((PropertiesConfiguration)saveConfiguration).save();
            } catch (ConfigurationException e) {
                log.error("could not save system configuration: #0", e.getMessage());
            }
        }

        if(saveMetadata instanceof PropertiesConfiguration) {
            try {
                ((PropertiesConfiguration)saveMetadata).save();
            } catch (ConfigurationException e) {
                log.error("could not save system metadata: #0", e.getMessage());
            }
        }
    }

    /**
     * Return the value of the runtime flag passed as argument.
     *
     * @param flag
     * @return
     */
    @Override
    public boolean getRuntimeFlag(String flag) {
        if (runtimeFlags.get(flag) != null)
            return runtimeFlags.get(flag);
        else
            return false;
    }

    /**
     * Set a flag at runtime that is discarded on system shutdown; used e.g. to indicate that
     * certain
     * processes have already been carried out.
     *
     * @param value
     */
    @Override
    public void setRuntimeFlag(String flag, boolean value) {
        runtimeFlags.put(flag, value);
    }

    /**
     * Set the LMF_HOME value to the correct path. Used during the initialization process.
     *
     * @param home
     */
    @Override
    @Deprecated
    public void setLMFHome(String home) {
        log.warn("ConfigurationService.setLMFHome() is deprecated, consider call directly ConfigurationService.setHome()");
        this.setHome(home);
    }

    /**
     * Set the home value to the correct path. Used during the initialization process.
     *
     * @param home
     */
    @Override
    public void setHome(String home) {
        this.home = home;
    }

    /**
     * Return the value of the LMF_HOME setting. Used during the initialization process.
     *
     * @return
     */
    @Override
    @Deprecated
    public String getLMFHome() {
        log.warn("ConfigurationService.getLMFHome() is deprecated, consider call directly ConfigurationService.getHome()");
        return getHome();
    }

    /**
     * Return the value of the home setting. Used during the initialization process.
     *
     * @return
     */
    @Override
    public String getHome() {
        return home;
    }

    /**
     * Get the base context URI
     *
     * @return base context
     */
    @Override
    public String getBaseContext() {
        return getBaseUri() + CONTEXT_PATH + "/";
    }

    /**
     * Return the context used for storing system information.
     *
     * @return a KiWiUriResource representing the system knowledge space
     */
    @Override
    public String getSystemContext() {
        return getBaseUri() + CONTEXT_PATH + CONTEXT_SYSTEM;
    }

    /**
     * Get the uri of the inferred context
     *
     * @return uri of this inferred context
     */
    @Override
    public String getInferredContext() {
        return getBaseUri() + CONTEXT_PATH + "/" + CONTEXT_INFERRED;
    }

    /**
     * Get the uri of the default context
     *
     * @return
     */
    @Override
    public String getDefaultContext() {
        return getBaseUri() + CONTEXT_PATH + "/" + CONTEXT_DEFAULT;
    }

    /**
     * Get the uri of the context used for caching linked data
     *
     * @return
     */
    @Override
    public String getCacheContext() {
        return getBaseUri() + CONTEXT_PATH + "/" + CONTEXT_CACHE;
    }

    @Override
    public String getEnhancerContex() {
        return getBaseUri() + CONTEXT_PATH + "/" + CONTEXT_ENHANCEMENT;
    }

    /**
     * Get a string describing the type and version of the application server running the LMF.
     *
     * @return
     */
    @Override
    public String getServerInfo() {
        if(isTomcat7())
            return "Apache Tomcat 7.x";
        else if(isTomcat6())
            return "Apache Tomcat <= 6.x";
        else if(isJetty7())
            return "Jetty 7.x";
        else if(isJetty6()) return "Jetty 6.x";
        else
            return "Unknown Servlet Container";

    }


    /**
     * Try figuring out on which port the server is running ...
     */
    @Override
    public int getServerPort() {

        if(serverPort == 0) {

            if(isTomcat6()) {
                // tomcat <= 6.x
                try {
                    Object server = Class.forName("org.apache.catalina.ServerFactory").getMethod("getServer").invoke(null);
                    Object service = Array.get(server.getClass().getMethod("findServices").invoke(server),0);
                    Object connector = Array.get(service.getClass().getMethod("findConnectors").invoke(service),0);

                    int port = (Integer)connector.getClass().getMethod("getPort").invoke(connector);
                    log.info("Tomcat <= 6.x detected, server port: {}",port);
                    serverPort = port;
                } catch (Exception e) {
                }
            } else if(isTomcat7()) {
                // tomcat 7.x
                try {
                    MBeanServer mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
                    ObjectName name = new ObjectName("Catalina", "type", "Server");
                    Object server = mBeanServer.getAttribute(name, "managedResource");

                    Object service = Array.get(server.getClass().getMethod("findServices").invoke(server),0);
                    Object connector = Array.get(service.getClass().getMethod("findConnectors").invoke(service),0);

                    int port = (Integer)connector.getClass().getMethod("getPort").invoke(connector);
                    log.info("Tomcat 7.x detected, server port: {}",port);
                    serverPort = port;
                } catch (Exception e) {
                }
            } else {

                log.warn("not running on Tomcat, could not determine server port, returning default of 8080");
                serverPort = 8080;
            }
        }

        return serverPort;

    }

    /**
     * Try figuring out the local name of the server
     * @return
     */
    @Override
    public String getServerName() {
        if(serverName == null) {
            try {
                serverName = java.net.InetAddress.getLocalHost().getHostName();
            } catch (UnknownHostException e) {
                serverName = "localhost";
            }
        }
        return serverName;

    }

    /**
     * Return the context path of this application
     * @return
     */
    @Override
    public String getServerContext() {
        return servletContext.getContextPath();
    }


    /**
     * Shutdown the application server running this web application; tries to determine the kind of server we are
     * running under and send the proper shutdown signal before exiting with System.exit
     */
    @Override
    public void performServerShutdown() {
        try{
            MBeanServer server = (MBeanServer)Class.forName("org.apache.catalina.mbeans.MBeanUtils").getMethod("createServer").invoke(null);
            ObjectName name;
            if(isTomcat6()) {
                // Tomcat 6.x
                name = new ObjectName("Catalina:type=Service,serviceName=Catalina");
                server.invoke(name, "stop", new Object[0], new String[0]);
                log.warn("shutting down Apache Tomcat server on user request");
            } else if(isTomcat7()) {
                // Tomcat 7.x
                name = new ObjectName("Catalina", "type", "Service");
                server.invoke(name, "stop", new Object[0], new String[0]);
                log.warn("shutting down Apache Tomcat server on user request");
            }
        } catch (Exception ex) {
            log.error("shutting down other servers than Apache Tomcat is not supported",ex);
        }

        // ensure complete shutdown
        System.exit(0);

    }

    /**
     * Return true if Jetty 6.x is detected; tests for presence of class org.mortbay.jetty.Server
     * @return
     */
    @Override
    public boolean isJetty6() {
        try {
            Class.forName("org.mortbay.jetty.Server");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }


    /**
     * Return true if Jetty 7.x is detected; tests for presence of class org.eclipse.jetty.server.Server
     * @return
     */
    @Override
    public boolean isJetty7() {
        try {
            Class.forName("org.eclipse.jetty.server.Server");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }


    /**
     * Return true if Tomcat 6.x is detected; tests for presence of class org.apache.catalina.ServerFactory
     * @return
     */
    @Override
    public boolean isTomcat6() {
        try {
            Class.forName("org.apache.catalina.ServerFactory");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }


    /**
     * Return true if Tomcat 7.x is detected; tests for presence of class org.apache.catalina.CatalinaFactory
     * @return
     */
    @Override
    public boolean isTomcat7() {
        try {
            Class.forName("org.apache.catalina.CatalinaFactory");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

}
TOP

Related Classes of org.apache.marmotta.platform.core.services.config.ConfigurationServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.