Package org.apache.geronimo.system.configuration

Source Code of org.apache.geronimo.system.configuration.LocalConfigStore

/**
*
* Copyright 2003-2004 The Apache Software Foundation
*
*  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.apache.geronimo.system.configuration;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.gbean.GBeanData;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.management.State;
import org.apache.geronimo.kernel.config.Configuration;
import org.apache.geronimo.kernel.config.ConfigurationStore;
import org.apache.geronimo.kernel.config.InvalidConfigException;
import org.apache.geronimo.kernel.config.NoSuchConfigException;
import org.apache.geronimo.kernel.config.ConfigurationData;
import org.apache.geronimo.kernel.config.ConfigurationInfo;
import org.apache.geronimo.kernel.config.ConfigurationModuleType;
import org.apache.geronimo.kernel.config.ManageableAttributeStore;
import org.apache.geronimo.system.serverinfo.ServerInfo;

/**
* Implementation of ConfigurationStore using the local filesystem.
*
* @version $Rev: 278940 $ $Date: 2005-09-06 02:20:51 -0600 (Tue, 06 Sep 2005) $
*/
public class LocalConfigStore implements ConfigurationStore, GBeanLifecycle {
    private static final String INDEX_NAME = "index.properties";
    private static final String BACKUP_NAME = "index.backup";
    private final Kernel kernel;
    private final ObjectName objectName;
    private final URI root;
    private final ManageableAttributeStore attributeStore;
    private final ServerInfo serverInfo;
    private final Properties index = new Properties();
    private final Log log;
    private File rootDir;
    private int maxId;

    /**
     * Constructor is only used for direct testing with out a kernel.
     */
    public LocalConfigStore(File rootDir) {
        kernel = null;
        objectName = null;
        serverInfo = null;
        this.root = null;
        this.attributeStore = null;
        this.rootDir = rootDir;
        log = LogFactory.getLog("LocalConfigStore:"+rootDir.getName());
    }

    public LocalConfigStore(Kernel kernel, String objectName, URI root, ServerInfo serverInfo, ManageableAttributeStore attributeStore) throws MalformedObjectNameException {
        this.kernel = kernel;
        this.objectName = new ObjectName(objectName);
        this.root = root;
        this.serverInfo = serverInfo;
        this.attributeStore = attributeStore;
        log = LogFactory.getLog("LocalConfigStore:"+root.toString());
    }

    public String getObjectName() {
        return objectName.toString();
    }

    public synchronized void doStart() throws FileNotFoundException, IOException {
        // resolve the root dir if not alredy resolved
        if (rootDir == null) {
            if (serverInfo == null) {
                rootDir = new File(root);
            } else {
                rootDir = new File(serverInfo.resolve(root));
            }
            if (!rootDir.isDirectory()) {
                throw new FileNotFoundException("Store root does not exist or is not a directory: " + rootDir);
            }
        }

        index.clear();
        File indexfile = new File(rootDir, INDEX_NAME);
        try {
            index.load(new BufferedInputStream(new FileInputStream(indexfile)));
            for (Iterator i = index.values().iterator(); i.hasNext();) {
                String id = (String) i.next();
                maxId = Math.max(maxId, Integer.parseInt(id));
            }
        } catch (FileNotFoundException e) {
            maxId = 0;
        }
    }

    public void doStop() {
    }

    public void doFail() {
    }

    private void saveIndex() throws IOException {
        // todo provide a backout mechanism
        File indexFile = new File(rootDir, INDEX_NAME);
        File backupFile = new File(rootDir, BACKUP_NAME);
        if (backupFile.exists()) {
            backupFile.delete();
        }
        indexFile.renameTo(backupFile);

        FileOutputStream fos = new FileOutputStream(indexFile);
        try {
            BufferedOutputStream os = new BufferedOutputStream(fos);
            index.store(os, null);
            os.close();
            fos = null;
        } catch (IOException e) {
            if (fos != null) {
                fos.close();
            }
            indexFile.delete();
            backupFile.renameTo(indexFile);
            throw e;
        }
    }

    public File createNewConfigurationDir() {
        // loop until we find a directory that doesn't alredy exist
        // this can happen when a deployment fails (leaving an bad directory)
        // and the server reboots without saving out the index.propreties file
        // the is rare but we should check for it
        File configurationDir;
        do {
            String newId;
            synchronized (this) {
                newId = Integer.toString(++maxId);
            }
            configurationDir = new File(rootDir, newId);
        } while (configurationDir.exists());
        configurationDir.mkdir();
        return configurationDir;
    }

    public URI install(URL source) throws IOException, InvalidConfigException {
        File configurationDir = createNewConfigurationDir();

        InputStream is = source.openStream();
        try {
            unpack(configurationDir, is);
        } catch (IOException e) {
            delete(configurationDir);
            throw e;
        } finally {
            is.close();
        }

        URI configId;
        try {
            GBeanData config = loadConfig(configurationDir);
            configId = (URI) config.getAttribute("id");
            index.setProperty(configId.toString(), configurationDir.getName());
        } catch (Exception e) {
            delete(configurationDir);
            throw new InvalidConfigException("Unable to get ID from downloaded configuration", e);
        }

        synchronized (this) {
            saveIndex();
        }

        log.info("Installed configuration " + configId + " in location " + configurationDir.getName());
        return configId;
    }

    public void install(ConfigurationData configurationData, File source) throws IOException, InvalidConfigException {
        if (!source.isDirectory()) {
            throw new InvalidConfigException("Source must be a directory: source=" + source);
        }
        if (!source.getParentFile().equals(rootDir)) {
            throw new InvalidConfigException("Source must be within the config store: source=" + source + ", configStoreDir=" + rootDir);
        }

        ExecutableConfigurationUtil.writeConfiguration(configurationData, source);

        // update the index
        synchronized (this) {
            index.setProperty(configurationData.getId().toString(), source.getName());
            saveIndex();
        }

        log.info("Installed configuration " + configurationData.getId() + " in location " + source.getName());
    }

    public void uninstall(URI configID) throws NoSuchConfigException, IOException {
        String id = configID.toString();
        File configDir;
        synchronized(this) {
            String storeID = index.getProperty(id);
            if (storeID == null) {
                throw new NoSuchConfigException();
            }
            configDir = new File(rootDir, storeID);
            File tempDir = new File(rootDir, storeID + ".tmp");
            if (configDir.renameTo(tempDir)) {
                configDir = tempDir;
            }
            index.remove(id);
            saveIndex();
        }
        log.info("Uninstalled configuration " + configID);
        delete(configDir);
    }

    public synchronized ObjectName loadConfiguration(URI configId) throws NoSuchConfigException, IOException, InvalidConfigException {
        GBeanData config = loadConfig(getRoot(configId));

        ObjectName name;
        try {
            name = Configuration.getConfigurationObjectName(configId);
        } catch (MalformedObjectNameException e) {
            throw new InvalidConfigException("Cannot convert id to ObjectName: ", e);
        }
        config.setName(name);
        ObjectName pattern;
        try {
            pattern = attributeStore == null ? null : new ObjectName(attributeStore.getObjectName());
        } catch (MalformedObjectNameException e) {
            throw new InvalidConfigException("Invalid ObjectName for AttributeStore: " + attributeStore.getObjectName());
        }
        config.setReferencePattern("AttributeStore", pattern);

        try {
            kernel.loadGBean(config, Configuration.class.getClassLoader());
        } catch (Exception e) {
            throw new InvalidConfigException("Unable to register configuration", e);
        }

        try {
            kernel.setAttribute(name, "baseURL", getRoot(configId).toURL());
        } catch (Exception e) {
            try {
                kernel.unloadGBean(name);
            } catch (Exception ignored) {
                // ignore
            }
            throw new InvalidConfigException("Cannot set baseURL", e);
        }
        log.info("Loaded Configuration " + name);

        return name;
    }

    public synchronized void updateConfiguration(ConfigurationData configurationData) throws NoSuchConfigException, Exception {
        File root = getRoot(configurationData.getId());
        File stateFile = new File(root, "META-INF/state.ser");
        try {
            FileOutputStream fos = new FileOutputStream(stateFile);
            ObjectOutputStream oos;
            try {
                oos = new ObjectOutputStream(fos);
                GBeanData configurationGBeanData = ExecutableConfigurationUtil.getConfigurationGBeanData(configurationData);
                configurationGBeanData.writeExternal(oos);
                oos.flush();
            } finally {
                fos.close();
            }
        } catch (Exception e) {
            log.error("state store failed", e);
            stateFile.delete();
            throw e;
        }
    }

    public List listConfigurations() {
        List configs;
        synchronized (this) {
            configs = new ArrayList(index.size());
            for (Iterator i = index.keySet().iterator(); i.hasNext();) {
                URI configId = URI.create((String) i.next());
                try {
                    ObjectName configName = Configuration.getConfigurationObjectName(configId);
                    State state;
                    if (kernel.isLoaded(configName)) {
                        try {
                            state = State.fromInt(kernel.getGBeanState(configName));
                        } catch (Exception e) {
                            state = null;
                        }
                    } else {
                        // If the configuration is not loaded by the kernel
                        // and defined by the store, then it is stopped.
                        state = State.STOPPED;
                    }

                    GBeanData bean = loadConfig(getRoot(configId));
                    ConfigurationModuleType type = (ConfigurationModuleType) bean.getAttribute("type");

                    configs.add(new ConfigurationInfo(objectName, configId, state, type));
                } catch (Exception e) {
                    // bad configuration in store - ignored for this purpose
                    log.info("Unable get configuration info for configuration " + configId, e);
                }
            }
        }
        return configs;
    }

    public synchronized boolean containsConfiguration(URI configID) {
        return index.getProperty(configID.toString()) != null;
    }

    private synchronized File getRoot(URI configID) throws NoSuchConfigException {
        String id = index.getProperty(configID.toString());
        if (id == null) {
            throw new NoSuchConfigException("No such config: " + configID);
        }
        return new File(rootDir, id);
    }

    private GBeanData loadConfig(File configRoot) throws IOException, InvalidConfigException {
        File file = new File(configRoot, "META-INF/state.ser");
        if (!file.isFile()) {
            file = new File(configRoot, "META-INF/config.ser");
            if (!file.isFile()) {
                throw new InvalidConfigException("Configuration does not contain a META-INF/config.ser file");
            }
        }

        FileInputStream fis = new FileInputStream(file);
        try {
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
            GBeanData config = new GBeanData();
            try {
                config.readExternal(ois);
            } catch (ClassNotFoundException e) {
                //TODO more informative exceptions
                throw new InvalidConfigException("Unable to read attribute ", e);
            } catch (Exception e) {
                throw new InvalidConfigException("Unable to set attribute ", e);
            }
            config.setReferencePattern("ConfigurationStore", objectName);
            return config;
        } finally {
            fis.close();
        }
    }

    public static void unpack(File to, InputStream from) throws IOException {
        ZipInputStream zis = new ZipInputStream(from);
        try {
            ZipEntry entry;
            byte[] buffer = new byte[4096];
            while ((entry = zis.getNextEntry()) != null) {
                File out = new File(to, entry.getName());
                if (entry.isDirectory()) {
                    out.mkdirs();
                } else {
                    if (!entry.getName().equals("META-INF/startup-jar")) {
                        out.getParentFile().mkdirs();
                        OutputStream os = new FileOutputStream(out);
                        try {
                            int count;
                            while ((count = zis.read(buffer)) > 0) {
                                os.write(buffer, 0, count);
                            }
                        } finally {
                            os.close();
                        }
                        zis.closeEntry();
                    }
                }
            }
        } catch (IOException e) {
            delete(to);
            throw e;
        }
    }

    private static void delete(File root) throws IOException {
        File[] files = root.listFiles();
        if ( null == files ) {
            return;
        }
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            if (file.isDirectory()) {
                delete(file);
            } else {
                if (!file.delete()) {
                    file.deleteOnExit();
                };
            }
        }
        root.delete();
    }

    public static final GBeanInfo GBEAN_INFO;

    static {
        GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(LocalConfigStore.class, "ConfigurationStore"); //NameFactory.CONFIGURATION_STORE

        infoFactory.addAttribute("kernel", Kernel.class, false);
        infoFactory.addAttribute("objectName", String.class, false);
        infoFactory.addAttribute("root", URI.class, true);
        infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
        infoFactory.addReference("AttributeStore", ManageableAttributeStore.class, "AttributeStore");
        infoFactory.addInterface(ConfigurationStore.class);

        infoFactory.setConstructor(new String[]{"kernel", "objectName", "root", "ServerInfo", "AttributeStore"});

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }
}
TOP

Related Classes of org.apache.geronimo.system.configuration.LocalConfigStore

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.