Package org.apache.ace.repository.impl

Source Code of org.apache.ace.repository.impl.RepositoryFactory

/*
* 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.ace.repository.impl;

import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_BASE_DIR;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_CUSTOMER;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_FILE_EXTENSION;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_INITIAL_CONTENT;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_LIMIT;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_MASTER;
import static org.apache.ace.repository.RepositoryConstants.REPOSITORY_NAME;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Dictionary;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.ace.repository.Repository;
import org.apache.ace.repository.RepositoryReplication;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.BundleContext;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.log.LogService;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
import org.osgi.service.prefs.PreferencesService;

/**
* A <code>ManagedServiceFactory</code> responsible for creating a (<code>Replication</code>)<code>Repository</code>
* instance for each valid configuration that is received from the <code>ConfigurationAdmin</code>.
*/
public class RepositoryFactory implements ManagedServiceFactory {

    private final ConcurrentMap<String, Component> m_instances = new ConcurrentHashMap<String, Component>();
    private final DependencyManager m_manager;

    /* injected by dependency manager */
    private volatile LogService m_log;
    private volatile BundleContext m_context;
    private volatile PreferencesService m_prefsService;

    private File m_tempDir;

    public RepositoryFactory(DependencyManager manager) {
        m_manager = manager;
    }

    public void deleted(String pid) {
        // remove repository service...
        Component service = m_instances.remove(pid);
        if (service != null) {
            File repoDir = ((RepositoryImpl) service.getService()).getDir();

            m_manager.remove(service);

            // remove persisted data...
            deleteRepositoryStore(pid, repoDir);
            deleteRepositoryPrefs(pid);
        }
    }

    @Override
    public String getName() {
        return "RepositoryFactory";
    }

    public void init() {
        m_tempDir = ensureDirectoryAvailable(m_context.getDataFile("tmp"));
    }

    /**
     * Creates a new instance if the supplied dictionary contains a valid configuration. A configuration is valid if
     * <code>RepositoryConstants.REPOSITORY_NAME</code> and <code>RepositoryConstants.REPOSITORY_CUSTOMER</code>
     * properties are present, not empty and the combination of the two is unique in respect to other previously created
     * instances. Finally a property <code>RepositoryConstants.REPOSITORY_MASTER</code> should be present and be either
     * <code>true</code> or <code>false</code>.
     *
     * @param pid
     *            A unique identifier for the instance, generated by <code>ConfigurationAdmin</code> normally.
     * @param dict
     *            The configuration properties for the instance, see description above.
     * @throws ConfigurationException
     *             If any of the above explanation fails <b>or</b>when there is an internal error creating the
     *             repository.
     */
    public void updated(String pid, Dictionary dict) throws ConfigurationException {
        String customer = (String) dict.get(REPOSITORY_CUSTOMER);
        if ((customer == null) || "".equals(customer)) {
            throw new ConfigurationException(REPOSITORY_CUSTOMER, "Repository customer has to be specified.");
        }

        String name = (String) dict.get(REPOSITORY_NAME);
        if ((name == null) || "".equals(name)) {
            throw new ConfigurationException(REPOSITORY_NAME, "Repository name has to be specified.");
        }

        String master = (String) dict.get(REPOSITORY_MASTER);
        if (!("false".equalsIgnoreCase(master.trim()) || "true".equalsIgnoreCase(master.trim()))) {
            throw new ConfigurationException(REPOSITORY_MASTER, "Have to specify whether the repository is the master or a slave.");
        }
        boolean isMaster = Boolean.parseBoolean(master);

        String fileExtension = (String) dict.get(REPOSITORY_FILE_EXTENSION);
        if ((fileExtension == null) || "".equals(fileExtension.trim())) {
            fileExtension = "";
        }

        String baseDirName = (String) dict.get(REPOSITORY_BASE_DIR);
        File baseDir;
        if (baseDirName == null || "".equals(baseDirName.trim())) {
            baseDir = m_context.getDataFile("repos");
        }
        else {
            baseDir = new File(baseDirName);
        }

        String limit = (String) dict.get(REPOSITORY_LIMIT);
        long limitValue = Long.MAX_VALUE;
        if (limit != null) {
            try {
                limitValue = Long.parseLong(limit);
            }
            catch (NumberFormatException nfe) {
                throw new ConfigurationException(REPOSITORY_LIMIT, "Limit has to be a number, was: " + limit);
            }
            if (limitValue < 1) {
                throw new ConfigurationException(REPOSITORY_LIMIT, "Limit has to be at least 1, was " + limit);
            }
        }

        String initialContents = (String) dict.get(REPOSITORY_INITIAL_CONTENT);

        Component service = m_manager.createComponent()
            .setInterface(new String[] { RepositoryReplication.class.getName(), Repository.class.getName() }, dict)
            .setImplementation(createRepositoryStore(pid, baseDir, isMaster, limitValue, fileExtension, initialContents))
            .add(m_manager.createServiceDependency().setService(LogService.class).setRequired(false));

        Component oldService = m_instances.putIfAbsent(pid, service);
        if (oldService == null) {
            // new instance...
            createRepositoryPrefs(pid, customer, name);

            m_manager.add(service);
        }
        else {
            // update existing instance...
            RepositoryImpl store = (RepositoryImpl) oldService.getService();

            // be a little pedantic about the ignored properties...
            if (!baseDir.equals(store.getDir())) {
                m_log.log(LogService.LOG_WARNING, "Cannot update base directory of repository from " + store.getDir() + " to " + baseDir);
            }
            if (!fileExtension.equals(store.getFileExtension())) {
                m_log.log(LogService.LOG_WARNING, "Cannot update file extension of repository from " + store.getFileExtension() + " to " + fileExtension);
            }

            store.updated(isMaster, limitValue);
        }
    }

    private void createRepositoryPrefs(String pid, String customer, String name) throws ConfigurationException {
        Preferences systemPrefs = m_prefsService.getSystemPreferences();

        String[] nodes;
        try {
            nodes = systemPrefs.childrenNames();
        }
        catch (BackingStoreException e) {
            throw new ConfigurationException(null, "Internal error while validating configuration.");
        }
        for (String nodeName : nodes) {
            if (pid.equals(nodeName)) {
                // avoid failing on our own node (in case we're updating)...
                continue;
            }

            Preferences prefs = systemPrefs.node(nodeName);
            String repoName = prefs.get(REPOSITORY_NAME, "");
            String repoCustomer = prefs.get(REPOSITORY_CUSTOMER, "");

            if (name.equalsIgnoreCase(repoName) && name.equalsIgnoreCase(repoCustomer)) {
                throw new ConfigurationException(null, "Name and customer combination already exists");
            }
        }

        Preferences node = systemPrefs.node(pid);
        node.put(REPOSITORY_NAME, name);
        node.put(REPOSITORY_CUSTOMER, customer);
    }

    private RepositoryImpl createRepositoryStore(String pid, File baseDir, boolean isMaster, long limitValue, String fileExtension, String initialContents) {
        File dir = ensureDirectoryAvailable(new File(baseDir, pid));
        RepositoryImpl store = new RepositoryImpl(dir, m_tempDir, fileExtension, isMaster, limitValue);
        if ((initialContents != null) && isMaster) {
            try {
                // Do not even try to commit initial contents for existing repositories...
                if (store.getRange().getHigh() == 0L) {
                    store.commit(new ByteArrayInputStream(initialContents.getBytes()), 0L);
                }
            }
            catch (IOException e) {
                m_log.log(LogService.LOG_ERROR, "Unable to set initial contents of the repository.", e);
            }
        }
        return store;
    }

    private void deleteRepositoryPrefs(String pid) {
        try {
            Preferences prefs = m_prefsService.getSystemPreferences();

            prefs.node(pid).removeNode();
            prefs.sync();
        }
        catch (BackingStoreException e) {
            // Not much we can do
        }
    }

    private void deleteRepositoryStore(String pid, File repoDir) {
        if (repoDir.exists() && repoDir.isDirectory()) {
            File[] files = repoDir.listFiles();
            for (int i = 0; (files != null) && (i < files.length); i++) {
                files[i].delete();
            }
            if (!repoDir.delete()) {
                m_log.log(LogService.LOG_WARNING, "Unable to clean up files in " + repoDir.getAbsolutePath() + " after removing repository!");
            }
        }
    }

    private File ensureDirectoryAvailable(File dir) {
        if (dir == null) {
            throw new IllegalArgumentException("Unable to use file system!");
        }
        if (dir.exists() && dir.isFile()) {
            dir.delete();
        }
        if (!dir.exists() && !dir.mkdirs()) {
            throw new IllegalArgumentException("Unable to create directory: " + dir.getAbsolutePath() + "!");
        }
        return dir;
    }
}
TOP

Related Classes of org.apache.ace.repository.impl.RepositoryFactory

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.