Package org.mule.util.store

Source Code of org.mule.util.store.QueuePersistenceObjectStore

/*
* $Id: QueuePersistenceObjectStore.java 21762 2011-05-03 01:29:28Z mike.schilling $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/

package org.mule.util.store;

import org.mule.api.MuleContext;
import org.mule.api.MuleRuntimeException;
import org.mule.api.context.MuleContextAware;
import org.mule.api.store.ListableObjectStore;
import org.mule.api.store.ObjectDoesNotExistException;
import org.mule.api.store.ObjectStore;
import org.mule.api.store.ObjectStoreException;
import org.mule.config.i18n.CoreMessages;
import org.mule.config.i18n.Message;
import org.mule.util.FileUtils;
import org.mule.util.SerializationUtils;
import org.mule.util.queue.QueueKey;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.SerializationException;

/**
* <p>
* This is an {@link ObjectStore} implementation that is to be used to persist
* messages on Mule's internal queues. Note that this is a specialized implementation
* of the {@link ObjectStore} interface which hard-codes the location of the
* persistence folder to <code>$MULE_HOME/.mule/queuestore</code>. It also breaks the
* contract defined in the {@link ObjectStore} javadocs as it does not load and
* return the stored object when deleting and entry - the calling code does not care
* about the removed object anyway.
* </p>
* <p>
* This implementation uses <a href=
* "http://download.oracle.com/javase/1.5.0/docs/guide/serialization/spec/serialTOC.html"
* > Java serialization</a> to implement persistence.
* </p>
*/
public class QueuePersistenceObjectStore<T extends Serializable> extends AbstractObjectStore<T>
    implements ListableObjectStore<T>, MuleContextAware
{
    /**
     * The default queueStore directory for persistence
     */
    public static final String DEFAULT_QUEUE_STORE = "queuestore";

    private static final String FILE_EXTENSION = ".msg";

    private MuleContext muleContext;

    /**
     * This is the base directory into which all queues will be persisted
     */
    private File storeDirectory;

    /**
     * Default constructor for Spring.
     */
    public QueuePersistenceObjectStore()
    {
        super();
    }

    public QueuePersistenceObjectStore(MuleContext context)
    {
        super();
        muleContext = context;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isPersistent()
    {
        return true;
    }

    public void open() throws ObjectStoreException
    {
        initStoreDirectory();
        if (!storeDirectory.exists())
        {
            createStoreDirectory(storeDirectory);
        }
    }

    private void initStoreDirectory() throws ObjectStoreException
    {
        try
        {
            String workingDirectory = muleContext.getConfiguration().getWorkingDirectory();
            String path = workingDirectory + File.separator + DEFAULT_QUEUE_STORE;
            storeDirectory = FileUtils.newFile(path);
        }
        catch (MuleRuntimeException mre)
        {
            // FileUtils throws a MuleRuntimeException if something goes wrong when creating the
            // path. To fully conform to the ObjectStore contract we cannot just let it bubble
            // through but rather catch it and re-throw as ObjectStoreException
            throw new ObjectStoreException(mre);
        }
    }

    protected synchronized void createStoreDirectory(File directory) throws ObjectStoreException
    {
        // To support concurrency we need to check if directory exists again inside
        // synchronized method
        if (!directory.exists() && !directory.mkdirs())
        {
            Message message = CoreMessages.failedToCreate("queue store store directory " + directory.getAbsolutePath());
            throw new ObjectStoreException(message);
        }
    }

    public void close() throws ObjectStoreException
    {
        // Nothing to do
    }

    public List<Serializable> allKeys() throws ObjectStoreException
    {
        if (storeDirectory == null)
        {
            return Collections.emptyList();
        }

        return collectAllKeys();
    }

    protected List<Serializable> collectAllKeys() throws ObjectStoreException
    {
        try
        {
            List<Serializable> keys = new ArrayList<Serializable>();
            listStoredFiles(storeDirectory, keys);

            if (logger.isDebugEnabled())
            {
                logger.debug("Restore retrieved " + keys.size() + " objects");
            }

            return keys;
        }
        catch (ClassNotFoundException e)
        {
            String message = String.format("Could not restore from %1s", storeDirectory.getAbsolutePath());
            throw new ObjectStoreException(CoreMessages.createStaticMessage(message));
        }
        catch (IOException e)
        {
            String message = String.format("Could not restore from %1s", storeDirectory.getAbsolutePath());
            throw new ObjectStoreException(CoreMessages.createStaticMessage(message));
        }
    }

    protected void listStoredFiles(File directory, List<Serializable> keys) throws IOException, ClassNotFoundException
    {
        File[] files = directory.listFiles();
        if (files == null)
        {
            return;
        }

        // sort the files so they are in the order in which their ids were generated in store()
        Arrays.sort(files);

        for (int i = 0; i < files.length; i++)
        {
            if (files[i].isDirectory())
            {
                listStoredFiles(files[i], keys);
            }
            else if (files[i].getName().endsWith(FILE_EXTENSION))
            {
                String id = files[i].getCanonicalPath();

                int beginIndex = storeDirectory.getCanonicalPath().length() + 1;
                int length = id.length() - FILE_EXTENSION.length();
                id = id.substring(beginIndex, length);

                String queue = id.substring(0, id.indexOf(File.separator));
                id = id.substring(queue.length() + 1);

                keys.add(new QueueKey(queue, id));
            }
        }
    }

    @Override
    protected boolean doContains(Serializable key) throws ObjectStoreException
    {
        File storeFile = createStoreFile(key);
        return storeFile.exists();
    }

    @Override
    protected void doStore(Serializable key, T value) throws ObjectStoreException
    {
        File outputFile = createStoreFile(key);
        ensureStoreDirectoryExists(outputFile);
        serialize(value, outputFile);
    }

    protected void ensureStoreDirectoryExists(File outputFile) throws ObjectStoreException
    {
        File directory = outputFile.getParentFile();
        if (!directory.exists())
        {
            createStoreDirectory(directory);
        }
    }

    protected void serialize(T value, File outputFile) throws ObjectStoreException
    {
        try
        {
            FileOutputStream out = new FileOutputStream(outputFile);
            SerializationUtils.serialize(value, out);
        }
        catch (SerializationException se)
        {
            throw new ObjectStoreException(se);
        }
        catch (FileNotFoundException fnfe)
        {
            throw new ObjectStoreException(fnfe);
        }
    }

    @Override
    protected T doRetrieve(Serializable key) throws ObjectStoreException
    {
        File file = createStoreFile(key);
        return deserialize(file);
    }

    protected File createStoreFile(Serializable key) throws ObjectStoreException
    {
        QueueKey queueKey = (QueueKey) key;

        String filename = queueKey.id + FILE_EXTENSION;
        String path = queueKey.queueName + File.separator + filename;

        try
        {
            return FileUtils.newFile(storeDirectory, path);
        }
        catch (MuleRuntimeException mre)
        {
            // FileUtils throws a MuleRuntimeException if something goes wrong when creating the
            // path. To fully conform to the ObjectStore contract we cannot just let it bubble
            // through but rather catch it and re-throw as ObjectStoreException
            throw new ObjectStoreException(mre);
        }
    }

    @SuppressWarnings("unchecked")
    protected T deserialize(File file) throws ObjectStoreException
    {
        try
        {
            FileInputStream in = new FileInputStream(file);
            return (T)SerializationUtils.deserialize(in, muleContext);
        }
        catch (SerializationException se)
        {
            throw new ObjectStoreException(se);
        }
        catch (FileNotFoundException fnfe)
        {
            throw new ObjectStoreException(fnfe);
        }
    }

    @Override
    protected T doRemove(Serializable key) throws ObjectStoreException
    {
        File storeFile = createStoreFile(key);
        deleteStoreFile(storeFile);

        // we can safely return null here to avoid loading the message - the calling code
        // discards the returned object anyway (see TransactionalQueueManager#doRemove)
        return null;
    }

    protected void deleteStoreFile(File file) throws ObjectStoreException
    {
        if (file.exists())
        {
            if (!file.delete())
            {
                Message message =
                    CoreMessages.createStaticMessage("Deleting " + file.getAbsolutePath() + " failed");
                throw new ObjectStoreException(message);
            }
        }
        else
        {
            throw new ObjectDoesNotExistException();
        }
    }

    public void setMuleContext(MuleContext context)
    {
        muleContext = context;
    }
}
TOP

Related Classes of org.mule.util.store.QueuePersistenceObjectStore

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.