Package org.wso2.carbon.mediation.initializer.persistence

Source Code of org.wso2.carbon.mediation.initializer.persistence.MediationPersistenceManager$PersistenceRequest

/*
*  Copyright (c) 2005-2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. 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.wso2.carbon.mediation.initializer.persistence;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.config.SynapseConfiguration;
import org.apache.synapse.config.xml.MultiXMLConfigurationSerializer;
import org.apache.synapse.config.xml.XMLConfigurationSerializer;
import org.wso2.carbon.mediation.initializer.RegistryBasedSynapseConfigSerializer;
import org.wso2.carbon.mediation.initializer.ServiceBusConstants;
import org.wso2.carbon.registry.core.session.UserRegistry;

import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
* Manages all persistence activities related to mediation configuration. Takes care
* of saving configurations to the file system, registry and updating such configurations
* as and when necessary. All the mediation components (proxy services, sequences etc)
* should use this implementation to handle their persistence requirements. This class
* does not immediately carry out persistence requests. Requests are first queued up and
* then executed as batch jobs. Therefore admin services which initiate persistence
* requests does not have to 'wait' for disk and network I/O often associated with
* persistence activities. This improves the UI response times and system usability
* in a great deal.
*/
@SuppressWarnings({"UnusedDeclaration"})
public class MediationPersistenceManager {

    private static final Log log = LogFactory.getLog(MediationPersistenceManager.class);

    private UserRegistry registry;
    private boolean initialized = false;
    private String configPath;
    private boolean flatFileMode;   
    private SynapseConfiguration synapseConfiguration;
    private String configName;

    /** Queue to hold persistence requests - Make sure all accesses are synchronized */
    private final LinkedList<PersistenceRequest> requestQueue = new LinkedList<PersistenceRequest>();

    private MediationPersistenceWorker worker;
    private boolean acceptRequests;
    private long interval = 5000L;

    private Map<Integer, AbstractStore> dataStores;

    /**
     * Initialize the mediation persistence manager instance and start accepting
     * and processing persistence requests. Persistence requests are carried out
     * on the local file system and if required on the registry as well.
     *
     * @param registry The UserRegistry instance to be used for persistence or null
     * @param configPath Path to the file/directory where configuration should be saved in
     * @param synapseConfiguration synapse configuration to be used
     * @param interval The wait time for the mediation persistence worker thread
     * @param configName Name of the configuration to be used
     */
    public MediationPersistenceManager(UserRegistry registry, String configPath,
                     SynapseConfiguration synapseConfiguration,
                     long interval, String configName) {

        if (initialized) {
            log.warn("Mediation persistence manager is already initialized");
            return;
        }

        if (configPath == null) {
            log.warn("Synapse configuration location is not provided - Unable to initialize " +
                    "the mediation persistence manager.");
            return;
        }

        if (log.isDebugEnabled()) {
            log.debug("Initializing the mediation persistence manager");
        }

        this.registry = registry;
        this.configPath = configPath;       
        this.synapseConfiguration = synapseConfiguration;
        this.configName = configName;
        if (interval > 0) {
            this.interval = interval;
        } else {
            log.warn("Invalid interval value " + interval + " for the mediation persistence " +
                    "worker, Using defaults");
        }

        File file = new File(configPath);
        flatFileMode = file.exists() && file.isFile();

        initDataStores();
       
        worker = new MediationPersistenceWorker();
        worker.start();

        // and we are ready to launch....
        acceptRequests = true;
        initialized = true;
    }

    private void initDataStores() {
        dataStores = new HashMap<Integer, AbstractStore>();
        dataStores.put(ServiceBusConstants.ITEM_TYPE_PROXY_SERVICE,
                new ProxyServiceStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_SEQUENCE,
                new SequenceStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_ENDPOINT,
                new EndpointStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_TASK,
                new StartupStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_EVENT_SRC,
                new EventSourceStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_ENTRY,
                new LocalEntryStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_REGISTRY,
                new SynapseRegistryStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_EXECUTOR,
                new ExecutorStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_TEMPLATE,
                new TemplateStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_TEMPLATE_ENDPOINTS,
                new EndpointTemplateStore(configPath, registry, configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_MESSAGE_STORE,
                new MessageStoreStore(configPath,registry,configName));
        dataStores.put(ServiceBusConstants.ITEM_TYPE_MESSAGE_PROCESSOR,
                new MessageProcessorStore(configPath,registry,configName));
    }

    public void destroy() {
        if (!initialized) {
            return;
        }

        // Stop accepting any more persistence requests
        acceptRequests = false;

        if (log.isDebugEnabled()) {
            log.debug("Shutting down mediation persistence manager");
        }

        // Wait till the jobs already in the queue are done
        while (!requestQueue.isEmpty()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignore) { }
        }

        // Halt the persistence worker thread
        worker.proceed = false;
        if (worker.isAlive()) {
            // If the worker is asleep, wake him up
            worker.interrupt();
        }
        initialized = false;
    }

    public boolean isInitialized() {
        return initialized;
    }

    /**
     * Save changes made to a particular item of the mediation configuration. Changes are
     * saved to the local file system and if required to the registry as well. Types of
     * supported mediation configuration items are defined in ServiceBusConstants. If the
     * item to be saved should be written to its own configuration file, the file name
     * attribute must be set on the item (in the SynapseConfiguration). Leaving the file
     * name as null will cause the item to be persisted into the top level synapse.xml
     * file.
     *
     * @param name Name/ID of the configuration item
     * @param itemType type of the configuration item
     */
    public void saveItem(String name, int itemType) {
        if (!initialized || !acceptRequests) {
            log.warn("Mediation persistence manager is either not initialized or not in the " +
                    "'accepting' mode. Ignoring the save request.");
            return;
        }

        if (itemType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            saveFullConfiguration(false);
            return;
        }

        PersistenceRequest request = new PersistenceRequest(name, itemType, true);
        synchronized (requestQueue) {
            addToQueue(request);
        }
    }

    /**
     * Delete a particular item in the saved mediation configuration. Item is removed from the
     * local file system and if required to the registry as well. Types of
     * supported mediation configuration items are defined in ServiceBusConstants.
     *
     * @param name Name/ID of the configuration item
     * @param fileName Name of the file where the item is currently saved in
     * @param itemType Type of the configuration item
     */
    public void deleteItem(String name, String fileName, int itemType) {
        if (!initialized || !acceptRequests) {
            log.warn("Mediation persistence manager is either not initialized or not in the " +
                    "'accepting' mode. Ignoring the delete request.");
            return;
        }

        if (itemType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            return;
        }

        PersistenceRequest request = new PersistenceRequest(name, fileName, itemType, false);
        synchronized (requestQueue) {
            addToQueue(request);
        }
    }

    /**
     * Save the specified item to the registry only. This method accepts request if and only
     * if registry persistence is enabled for mediation configuration items. It is not
     * recommended to use this method unless it is required to save something to the registry
     * only. To save an item properly one must use the saveItem method.
     *
     * @param name Name/ID of the configuration item
     * @param itemType Type of the configuration item
     */
    public void saveItemToRegistry(String name, int itemType) {
        if (!initialized || !acceptRequests) {
            log.warn("Mediation persistence manager is either not initialized or not in the " +
                    "'accepting' mode. Ignoring the save request.");
            return;
        }

        if (registry == null) {
            if (log.isDebugEnabled()) {
                log.debug("Registry persistence is disabled for mediation configuration. " +
                        "Ignoring the persistence request for " + name);
            }
            return;
        }

        if (itemType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            saveFullConfiguration(true);
            return;
        }

        PersistenceRequest request = new PersistenceRequest(name, itemType, true);
        request.registryOnly = true;

        synchronized (requestQueue) {
            addToQueue(request);
        }
    }

    /**
     * Delete the specified item from the registry only. This method accepts request if and only
     * if registry persistence is enabled for mediation configuration items. It is not
     * recommended to use this method unless it is required to delete something from the registry
     * only. To delete an item properly one must use the deleteItem method.
     *
     * @param name Name/ID of the configuration item
     * @param itemType Type of the configuration item
     */
    public void deleteItemFromRegistry(String name, int itemType) {
        if (!initialized || !acceptRequests) {
            log.warn("Mediation persistence manager is either not initialized or not in the " +
                    "'accepting' mode. Ignoring the delete request.");
            return;
        }

        if (registry == null) {
            if (log.isDebugEnabled()) {
                log.debug("Registry persistence is disabled for mediation configuration. " +
                        "Ignoring the persistence request for " + name);
            }
            return;
        }

        if (itemType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            return;
        }

        PersistenceRequest request = new PersistenceRequest(name, null, itemType, false);
        request.registryOnly = true;
        synchronized (requestQueue) {
            addToQueue(request);
        }
    }

    /**
     * This method ensures that only the latest persistence request for a particular object
     * will remain in the request queue. This helps reduce I/O overhead during persistence
     * operations by merging multiple save requests to one and giving delete requests priority
     * over save requests.
     *
     * @param request The latest request to be added to queue
     */
    private void addToQueue(PersistenceRequest request) {

        int i = 0;
        boolean matchFound = false;
        for (; i < requestQueue.size(); i++) {
            PersistenceRequest oldRequest = requestQueue.get(i);
            if (oldRequest.subjectType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
                // if a request to save the full configuration is already in the queue
                // we can ignore the current request - Configuration will get saved
                // to the disk anyway
                return;
            }

            if (oldRequest.subjectType == request.subjectType &&
                    oldRequest.subjectId.equals(request.subjectId)) {
                matchFound = true;
                break;
            }
        }

        if (matchFound) {
            // If an older request was found for the same item overwrite it
            requestQueue.remove(i);
            requestQueue.add(i, request);
        } else {
            // Otherwise add the current request to the tail of the queue
            requestQueue.offer(request);
        }
    }

    /**
     * Make a request to save the complete mediation configuration (the entire
     * SynapseConfiguration) to be saved to the file system and the registry.
     * This will remove all the existing requests already in the job queue and add
     * a single new entry.
     *
     * @param registryOnly Whether or not to save the configuration to the registry only
     */
    public void saveFullConfiguration(boolean registryOnly) {
        if (log.isDebugEnabled()) {
            log.debug("Received request to save full mediation configuration");
        }

        PersistenceRequest request = new PersistenceRequest(null,
                ServiceBusConstants.ITEM_TYPE_FULL_CONFIG, true);
        request.registryOnly = registryOnly;
        synchronized (requestQueue) {
            requestQueue.clear();
            requestQueue.offer(request);
        }
    }

    private void handleException(String msg, Throwable t) {
        log.error(msg, t);
        throw new ServiceBusPersistenceException(msg, t);
    }

    private class MediationPersistenceWorker extends Thread {

        boolean proceed = true;

        public void run() {
            if (log.isDebugEnabled()) {
                log.debug("Starting the mediation persistence worker thread");
            }

            while (proceed) {
                PersistenceRequest request;

                synchronized (requestQueue) {
                   request = requestQueue.poll();
                }

                if (request == null) {
                    try {
                        sleep(interval);
                    } catch (InterruptedException ignore) {
                        // This condition could occur only during system shutdown.
                        // We can safely ignore this.
                    }

                    // Simply go to the next iteration
                    continue;
                }

                try {
                    //SynapseConfiguration config = synapseConfiguration;
                    if (request.registryOnly && registry != null) {
                        if (request.save) {
                            persistElementToRegistry(synapseConfiguration, request);
                        } else {
                            deleteElementFromRegistry(request);
                        }
                    } else {
                        if (flatFileMode) {
                            saveToFlatFile(synapseConfiguration);
                        } else if (request.save) {
                            persistElement(synapseConfiguration, request);
                        } else {
                            deleteElement(synapseConfiguration, request);
                        }
                    }

                } catch (Throwable t) {
                    // Just log the error and continue
                    // DO NOT throw the error since that will kill the worker thread
                    log.error("Error while saving mediation configuration changes", t);
                }
            }

            if (log.isDebugEnabled()) {
                log.debug("Stopping the mediation persistence worker thread");
            }
        }
    }

    private void persistElement(SynapseConfiguration config, PersistenceRequest request) {
        if (request.subjectType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            saveFullConfiguration(config);
        } else {
            AbstractStore dataStore = dataStores.get(request.subjectType);
            dataStore.save(request.subjectId, config);
        }
    }

    private void deleteElement(SynapseConfiguration config, PersistenceRequest request) {
        AbstractStore dataStore = dataStores.get(request.subjectType);
        dataStore.delete(request.subjectId, request.fileName, config);
    }

    private void persistElementToRegistry(SynapseConfiguration config, PersistenceRequest request) {
        if (request.subjectType == ServiceBusConstants.ITEM_TYPE_FULL_CONFIG) {
            if (log.isDebugEnabled()) {
                log.debug("Serializing full mediation configuration to the registry");
            }

            RegistryBasedSynapseConfigSerializer registrySerializer =
                    new RegistryBasedSynapseConfigSerializer(registry, configName);
            registrySerializer.serializeConfiguration(config);

        } else {
            AbstractStore dataStore = dataStores.get(request.subjectType);
            dataStore.saveItemToRegistry(request.subjectId, config);
        }
    }

    private void deleteElementFromRegistry(PersistenceRequest request) {
        AbstractStore dataStore = dataStores.get(request.subjectType);
        dataStore.deleteItemFromRegistry(request.subjectId);
    }

    @SuppressWarnings({"ResultOfMethodCallIgnored"})
    private void saveToFlatFile(SynapseConfiguration config) throws IOException,
            XMLStreamException {

        File outputFile = new File(configPath);
        if (!outputFile.exists()) {
            outputFile.createNewFile();
        }

        FileOutputStream fos = new FileOutputStream(outputFile);
        XMLConfigurationSerializer.serializeConfiguration(config, fos);
        fos.flush();
        fos.close();
    }

    private void saveFullConfiguration(SynapseConfiguration config) {
        if (log.isDebugEnabled()) {
            log.debug("Serializing full mediation configuration to the file system");
        }

        MultiXMLConfigurationSerializer serializer = new MultiXMLConfigurationSerializer(configPath);
        serializer.serialize(config);

        if (registry != null) {
            if (log.isDebugEnabled()) {
                log.debug("Serializing full mediation configuration to the registry");   
            }

            RegistryBasedSynapseConfigSerializer registrySerializer =
                    new RegistryBasedSynapseConfigSerializer(registry, configName);
            registrySerializer.serializeConfiguration(config);
        }
    }

    /**
     * Bean to store details of a persistence request
     */
    private class PersistenceRequest {

        private boolean save;
        private int subjectType;
        private String subjectId;
        private String fileName;
        private boolean registryOnly;

        public PersistenceRequest(String subjectId, int subjectType, boolean save) {
            this.save = save;
            this.subjectId = subjectId;
            this.subjectType = subjectType;
        }

        public PersistenceRequest(String subjectId, String fileName, int subjectType, boolean save) {
            this.save = save;
            this.subjectId = subjectId;
            this.subjectType = subjectType;
            this.fileName = fileName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            PersistenceRequest pr = (PersistenceRequest) o;
            return pr.subjectType == this.subjectType &&
                    pr.save == this.save &&
                    pr.subjectId.equals(this.subjectId);
        }

        @Override
        public int hashCode() {
            int result = (save ? 1 : 0);
            result = 31 * result + subjectType;
            result = 31 * result + (subjectId != null ? subjectId.hashCode() : 0);
            return result;
        }
    }

}
TOP

Related Classes of org.wso2.carbon.mediation.initializer.persistence.MediationPersistenceManager$PersistenceRequest

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.