Package org.apache.muse.core

Source Code of org.apache.muse.core.AbstractFilePersistence$FileNumberFilter

/*=============================================================================*
*  Copyright 2006 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.muse.core;

import java.io.File;
import java.io.FileFilter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.apache.muse.util.messages.Messages;
import org.apache.muse.util.messages.MessagesFactory;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.addressing.soap.SoapFault;

/**
*
* AbstractFilePersistence is an abstract component that provides generic
* resource-state-to-file utilities without specifying the format of the XML
* that goes into the files. It can be used by resources or capabilities that
* wish to save state to disk and reload that state the next time the
* application is initialized.
*
* @author Dan Jemiolo (danj)
*
*/

public abstract class AbstractFilePersistence implements Persistence
{   
    //
    // Used to look up all exception messages
    //
    private static Messages _MESSAGES = MessagesFactory.get(AbstractFilePersistence.class);
   
    //
    // N -> EPR of resource whose state (or partial state) is being saved. here,
    // N is a monotonically-increasing integer
    //
    private Map _fileNumbersByEPR = new HashMap();
   
    //
    // maps to the <persistence><location/></persistence> element in muse.xml.
    // here, "location" is the directory that contains sub-directories with
    // the state/partial-state of resource instances
    //
    private String _location = null;
   
    //
    // provides access to all of the resource instances that exist at runtime
    // so we can add and compare to that set
    //
    private ResourceManager _manager = null;
   
    //
    // name-value pairs specified with <init-param/>
    //
    private Map _parameters = null;
   
    /**
     *
     * Creates the proper file name for the given resource instance and then
     * delegates creation of the file's contents to the abstract method of
     * the same name.
     *
     * @param epr
     * @param resource
     *
     * @see #getNextFileNumber()
     * @see #createResourceFile(EndpointReference, Resource, File)
     *
     */
    protected void createResourceFile(EndpointReference epr, Resource resource)
        throws SoapFault
    {
        int nextNumber = getNextFileNumber();
        String nextFileName = getNextFileName(nextNumber);
        File resourceTypeDir = getResourceTypeDirectory(resource.getContextPath());
        File resourceFile = new File(resourceTypeDir, nextFileName);
       
        createResourceFile(epr, resource, resourceFile);
       
        getFileNumbersByEPR().put(epr, new Integer(nextNumber));
    }
   
    /**
     *
     * This method should be overridden by concrete file-based persistence
     * classes to create the given file and fill it with the appropriate
     * XML content. Classes that are only interested in the serialization of
     * a certain capability's data can use the Resource object to get access
     * to said capability.
     *
     * @param epr
     *        The EPR that maps to the given Resource in the ResourceManager.
     *       
     * @param resource
     *        The resource instance whose state is being persisted.
     *       
     * @param resourceFile
     *        The File object that represents the yet-to-be-created XML file
     *        that will contain the content generated by this method. The
     *        implementation of this method must be sure to create the File
     *        on disk somehow.
     *       
     * @throws SoapFault
     *         <ul>
     *         <li>If there is an error generating the proper content for the
     *         persistence file.</li>
     *         <li>If there is an I/O error while reading or writing to the
     *         file system.</li>        
     *         </ul>
     *
     */
    protected abstract void createResourceFile(EndpointReference epr, Resource resource, File resourceFile)
        throws SoapFault;
   
    /**
     *
     * Finds the file associated with the given resource EPR and removes it
     * from the file system. This method should be called when a resource is
     * destroyed (gone forever), but not when it is merely shutdown (because
     * of server reboot, etc.).
     *
     * @param epr
     *        The EPR of the resource that has been permanently destroyed.
     *
     */
    protected void destroyResourceFile(EndpointReference epr)
        throws SoapFault
    {
        Integer fileNumber = (Integer)getFileNumbersByEPR().get(epr);
        FileNumberFilter filter = new FileNumberFilter(fileNumber);
       
        String contextPath = getContextPath(epr);
        File resourceTypeDir = getResourceTypeDirectory(contextPath);
        File[] results = resourceTypeDir.listFiles(filter);
       
        //
        // make sure we're not trying to delete state that doesn't exist,
        // which won't cause an immediate error but may point to problems
        // in the persistence impl
        //
        if (results.length == 0)
        {
            Object[] filler = { "\n\n" + epr };
            throw new SoapFault(_MESSAGES.get("NoFileForEPR", filler));
        }
       
        results[0].delete();
        getFileNumbersByEPR().remove(epr);
    }
   
    /**
     *
     * @param epr
     *
     * @return The last token after the last slash in the EPR's address. That
     *         is, for an EPR with address http://example.com/my-resource,
     *         the method returns 'my-resource'.
     *
     */
    protected String getContextPath(EndpointReference epr)
    {
        String addressPath = epr.getAddress().getPath();
        int slash = addressPath.lastIndexOf('/');       
        return addressPath.substring(slash + 1);
    }
   
    /**
     *
     * @param fileName
     *
     * @return The number at the end of the file name, before the suffix. That
     *         is, for a file named 'my-file-14.xml', the method returns 14.
     *
     */
    protected Integer getFileNumber(String fileName)
    {
        int underscore = fileName.lastIndexOf('-');
        int extension = fileName.lastIndexOf('.');
        String numberString = fileName.substring(underscore + 1, extension);
        return new Integer(numberString);
    }
   
    protected Map getFileNumbersByEPR()
    {
        return _fileNumbersByEPR;
    }
   
    /**
     *
     * @return The common string that will start all files created by the
     *         persistence implementation. This string will have the next
     *         file number appended to it in order to create unique file names.
     *        
     * @see #getNextFileNumber()
     *
     */
    protected abstract String getFilePrefix();
   
    public String getInitializationParameter(String name)
    {
        return (String)getInitializationParameters().get(name);
    }

    public Map getInitializationParameters()
    {
        return _parameters;
    }
   
    /**
     *
     * @param fileNumber
     *
     * @return A string of the following format: {file-prefix}{file-number}.xml
     *
     */
    protected String getNextFileName(int fileNumber)
    {
        return getFilePrefix() + fileNumber + ".xml";
    }
   
    /**
     *
     * @return The next number that is available for creation of unique file
     *         names; this number is determined by taking the largest number
     *         currently used and incrementing it by one. The method does not
     *         attempt to reuse numbers in 'gaps' caused by deletions (that is,
     *         if numbers 1, 2, 5, and 6 are used, the method returns 7, not 3).
     *
     */
    protected int getNextFileNumber()
    {
        if (getFileNumbersByEPR().isEmpty())
            return 1;
       
        //
        // create a binary tree of numbers, pick the last one (= largest)
        //
        TreeSet sortedNumbers = new TreeSet(getFileNumbersByEPR().values());
        Integer largest = (Integer)sortedNumbers.last();
        return largest.intValue() + 1;
    }
   
    /**
     *
     * @return The File directory that was specified as the persistence location
     *         in muse.xml. The directory may not exist, so use File.exists()
     *         and/or File.mkdirs() to prevent I/O errors.
     *
     */
    protected File getPersistenceDirectory()
    {
        String path = getPersistenceLocation();
       
        if (path == null)
            throw new RuntimeException(_MESSAGES.get("NoPersistenceLocation"));
       
        File workingDir = getResourceManager().getEnvironment().getRealDirectory();
        return new File(workingDir, path);
    }
   
    public String getPersistenceLocation()
    {
        return _location;
    }
       
    public ResourceManager getResourceManager()
    {
        return _manager;
    }
   
    /**
     *
     * @param contextPath
     *
     * @return Returns a directory for a given resource type, under the
     *         specified persistence location. The name of the directory
     *         is the context path provided. If the directory does not
     *         exist, this method will create it before returning the
     *         File object.
     *        
     * @see #getPersistenceDirectory()
     * @see File#mkdirs()
     *
     */
    protected File getResourceTypeDirectory(String contextPath)
    {
        File dir = new File(getPersistenceDirectory(), contextPath);
       
        if (!dir.exists())
            dir.mkdirs();
       
        return dir;
    }
   
    /**
     *
     * This implementation re-loads all saved instances of the resource types
     * found in the ResourceManager. It delegates the actual reloading work
     * to reloadResources(String, File).
     *
     * @see #reloadResources(String, File)
     *
     */
    public void reload()
        throws SoapFault
    {
        Iterator i = getResourceManager().getResourceContextPaths().iterator();
       
        while (i.hasNext())
        {
            String contextPath = (String)i.next();
            File resourceTypeDir = getResourceTypeDirectory(contextPath);
            reloadResources(contextPath, resourceTypeDir);
        }
    }
   
    /**
     *
     * This method should be overridden by concrete file-based persistence
     * classes to update a resource instance with the saved data from the
     * XML fragment. The resource instance may be created by this method, or
     * it may exist prior to invocation.
     *
     * @param contextPath
     *        The context path of the instance's resource type.
     *       
     * @param resourceXML
     *        The persisted data that must be reloaded.
     *
     * @return The Resource instance whose state (or part of it) has been
     *         reloaded from XML. The Resource may have already existed
     *         prior to the method being called, and simply had one of its
     *         capabilities updated with saved data; it may also have been
     *         created by the method and initialized right before return.
     *
     */
    protected abstract Resource reloadResource(String contextPath, Element resourceXML)
        throws SoapFault;
   
    /**
     *
     * This method finds all of the files in the resource type's persistence
     * directory and reloads them one at a time. It delegates the reloading of
     * individual resource instances to reloadResource(String, Element).
     *
     * @param contextPath
     * @param resourceTypeDir
     *
     * @see #reloadResource(String, Element)
     *
     */
    protected void reloadResources(String contextPath, File resourceTypeDir)
        throws SoapFault
    {
        File[] resourceFiles = resourceTypeDir.listFiles(new ResourceFileFilter());
       
        for (int n = 0; n < resourceFiles.length; ++n)
        {
            Document xmlDoc = null;
           
            try
            {
                xmlDoc = XmlUtils.createDocument(resourceFiles[n]);
            }
           
            catch (Throwable error)
            {
                throw new RuntimeException(error.getMessage(), error);
            }
           
            Element root = XmlUtils.getFirstElement(xmlDoc);
            Resource resource = reloadResource(contextPath, root);
           
            String fileName = resourceFiles[n].getName();
            Integer fileNumber = getFileNumber(fileName);
           
            getFileNumbersByEPR().put(resource.getEndpointReference(), fileNumber);
        }
    }

    public void setInitializationParameters(Map parameters)
    {
        _parameters = parameters;
    }

    public void setPersistenceLocation(String location)
    {
        _location = location;
    }
   
    public void setResourceManager(ResourceManager manager)
    {
        _manager = manager;
    }
   
    /**
     *
     * FileNumberFilter finds files that end with a given number (excluding
     * the file suffix).
     *
     * @author Dan Jemiolo (danj)
     *
     */
    private class FileNumberFilter implements FileFilter
    {
        private Integer _fileNumber = null;
       
        public FileNumberFilter(Integer fileNumber)
        {
            _fileNumber = fileNumber;
        }
       
        public boolean accept(File file)
        {
            return file.getName().indexOf("-" + _fileNumber + ".xml") >= 0;
        }
    }
   
    /**
     *
     * ResourceFileFilter finds files that start with the value returned by
     * getFilePrefix().
     *
     * @author Dan Jemiolo (danj)
     *
     */
    private class ResourceFileFilter implements FileFilter
    {
        public boolean accept(File file)
        {
            return file.getName().startsWith(getFilePrefix());
        }
    }
}
TOP

Related Classes of org.apache.muse.core.AbstractFilePersistence$FileNumberFilter

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.