org.webdavaccess.LocalFileSystemStorage.java Source code

Java tutorial

Introduction

Here is the source code for org.webdavaccess.LocalFileSystemStorage.java

Source

/*
 *
 * 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.webdavaccess;

import java.io.InputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;

import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.webdavaccess.exceptions.WebdavException;

/**
 * Reference Implementation of IWebdavStorage
 * 
 * @author joa
 * @author re
 * @author lubosp
 */
public class LocalFileSystemStorage implements IWebdavStorage {

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

    private static final String ROOTPATH_PARAMETER = "rootpath";
    private static final String DEBUG_PARAMETER = "storeDebug";

    private static final int MAX_PROPERTIES_CACHE_SIZE = 5000;
    private static final String CUSTOM_PROPERTIES_STORAGE = ".properties";
    private static final String PROPERTIES_STORAGE_PATH_SEPARATOR = "|";

    private static int BUF_SIZE = 50000;
    private static File root = null;
    private static int debug = -1;

    private String servletName;

    private MRUCache mPropertiesCache;

    public void begin(HttpServletRequest req, Hashtable parameters, String defaultStorageLocation)
            throws WebdavException {
        if (debug == -1) {
            String debugString = (String) parameters.get(DEBUG_PARAMETER);
            if (debugString == null) {
                debug = 0;
            } else {
                debug = Integer.parseInt(debugString);
            }
        }
        if (debug == 1)
            log.debug("LocalFileSystemStore.begin()");

        if (root == null) {

            String rootPath = (String) parameters.get(ROOTPATH_PARAMETER);
            if (rootPath != null) {
                try {
                    InitialContext context = new InitialContext();
                    Context environment = (Context) context.lookup("java:comp/env");
                    rootPath = (String) environment.lookup(rootPath);
                } catch (Exception ex) {
                    // Not an context env. use the original as root
                }
            }
            if (rootPath == null && defaultStorageLocation != null) {
                rootPath = defaultStorageLocation;
            }

            if (rootPath == null) {
                throw new WebdavException("missing parameter: " + ROOTPATH_PARAMETER);
            }

            root = new File(rootPath);
            if (!root.exists()) {
                if (!root.mkdirs()) {
                    throw new WebdavException(
                            ROOTPATH_PARAMETER + ": " + root + " does not exist and could not be created");
                }
            }

            servletName = req.getServletPath();
        }

        mPropertiesCache = new MRUCache(MAX_PROPERTIES_CACHE_SIZE);

    }

    public void commit() throws WebdavException {
        // do nothing
        if (debug == 1)
            log.debug("LocalFileSystemStore.commit() - do nothing");
    }

    public void rollback() throws WebdavException {
        // do nothing
        if (debug == 1)
            log.debug("LocalFileSystemStore.rollback() - do nothing");

    }

    public boolean objectExists(String uri) throws WebdavException {
        uri = normalize(uri);
        File file = new File(root, uri);
        if (debug == 1)
            log.debug("LocalFileSystemStore.objectExists(" + uri + ")=" + file.exists());
        return file.exists();
    }

    public boolean isFolder(String uri) throws WebdavException {
        uri = normalize(uri);
        File file = new File(root, uri);
        if (debug == 1)
            log.debug("LocalFileSystemStore.isFolder(" + uri + ")=" + file.isDirectory());
        return file.exists() && file.isDirectory();
    }

    public boolean isResource(String uri) throws WebdavException {
        uri = normalize(uri);
        File file = new File(root, uri);
        if (debug == 1)
            log.debug("LocalFileSystemStore.isResource(" + uri + ") " + file.isFile());
        return file.exists() && file.isFile();
    }

    public String getResourceName(String uri) {
        uri = normalize(uri);
        File file = new File(root, uri);
        if (file.isDirectory())
            return uri;
        int idx = file.getAbsolutePath().lastIndexOf(File.separatorChar);
        if (idx < 0)
            return uri;
        String name = file.getAbsolutePath().substring(idx + 1);
        if (debug == 1)
            log.debug("LocalFileSystemStore.getResourceName(" + uri + ") " + name);
        return name;
    }

    /**
     * @throws IOException
     *             if the folder cannot be created
     */
    public void createFolder(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.createFolder(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        if (!file.mkdir())
            throw new WebdavException("cannot create folder: " + uri);
    }

    /**
     * @throws IOException
     *             if the resource cannot be created
     */
    public void createResource(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.createResource(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        try {
            if (!file.createNewFile())
                throw new WebdavException("cannot create file: " + uri);
        } catch (IOException e) {
            throw new WebdavException(e);
        }
    }

    /**
     * @throws IOException
     *             if the resource cannot be created
     */
    public void copyResource(String src, String dest) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.createResource(" + dest + ")");
        dest = normalize(dest);
        File file = new File(root, dest);
        try {
            if (!file.createNewFile())
                throw new WebdavException("cannot create file: " + dest);
        } catch (IOException e) {
            throw new WebdavException(e);
        }
        src = normalize(src);
        setResourceContent(dest, getResourceContent(src), null, null);

        // copy properties from src to dest
        copyCustomProperties(src, dest);
    }

    /**
     * tries to save the given InputStream to the file at path "uri". content
     * type and character encoding are ignored
     */
    public void setResourceContent(String uri, InputStream is, String contentType, String characterEncoding)
            throws WebdavException {

        if (debug == 1)
            log.debug("LocalFileSystemStore.setResourceContent(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        try {
            OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
            try {
                int read = -1;
                byte[] copyBuffer = new byte[BUF_SIZE];

                while ((read = is.read(copyBuffer, 0, copyBuffer.length)) != -1) {
                    os.write(copyBuffer, 0, read);
                }
            } finally {
                try {
                    is.close();
                } finally {
                    os.close();
                }
            }
        } catch (IOException e) {
            throw new WebdavException(e);
        }
    }

    /**
     * @return the lastModified Date
     */
    public Date getLastModified(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.getLastModified(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        return new Date(file.lastModified());
    }

    /**
     * @return the lastModified date of the file, java.io.file does not support
     *         a creation date
     */
    public Date getCreationDate(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.getCreationDate(" + uri + ")");
        // return creation date if available else last modified
        uri = normalize(uri);
        File file = new File(root, uri);
        return new Date(file.lastModified());
    }

    /**
     * @return a (possibly empty) list of children, or <code>null</code> if
     *         the uri points to a file
     */
    public String[] getChildrenNames(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.getChildrenNames(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        if (file.isDirectory()) {

            File[] children = file.listFiles();
            List childList = new ArrayList();
            for (int i = 0; i < children.length; i++) {
                String name = children[i].getName();
                if (!CUSTOM_PROPERTIES_STORAGE.equals(name))
                    childList.add(name);
            }
            String[] childrenNames = new String[childList.size()];
            childrenNames = (String[]) childList.toArray(childrenNames);
            return childrenNames;
        } else {
            return null;
        }

    }

    /**
     * @return an input stream to the specified resource
     */
    public InputStream getResourceContent(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.getResourceContent(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);

        InputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(file));
        } catch (IOException e) {
            throw new WebdavException(e);
        }
        return in;
    }

    /**
     * @return the size of the file
     */
    public long getResourceLength(String uri) throws WebdavException {
        if (debug == 1)
            log.debug("LocalFileSystemStore.getResourceLength(" + uri + ")");
        uri = normalize(uri);
        File file = new File(root, uri);
        return file.length();
    }

    /**
     * @throws IOException
     *             if the deletion failed
     * 
     */
    public void removeObject(String uri) throws WebdavException {
        uri = normalize(uri);
        File file = new File(root, uri);
        boolean success = file.delete();
        // delete properties
        deleteProperties(uri, null);
        if (debug == 1)
            log.debug("LocalFileSystemStore.removeObject(" + uri + ")=" + success);
        if (!success) {
            throw new WebdavException("cannot delete object: " + uri);
        }

    }

    // Normalize uri
    private String normalize(String uri) {
        if (uri.startsWith(servletName))
            return uri.substring(servletName.length());
        else
            return uri;
    }

    // Get properties file for resourceUri
    private File getPropertiesFile(String resourceUri) {
        File file = new File(root, resourceUri);
        file = file.getParentFile();
        if (file == null)
            return null;
        return new File(file.getAbsoluteFile() + File.separator + CUSTOM_PROPERTIES_STORAGE);
    }

    private String getResourcePropertyKey(String resourceUri, String key) {
        return resourceUri + PROPERTIES_STORAGE_PATH_SEPARATOR + key;
    }

    private boolean isResourceProperty(String uri, String key) {
        return key.startsWith(uri + PROPERTIES_STORAGE_PATH_SEPARATOR);
    }

    private String getPropertyKey(String uri, String key) {
        return key.substring(uri.length() + PROPERTIES_STORAGE_PATH_SEPARATOR.length());
    }

    // Save custom properties
    private void saveCustomProperties(Properties newProperties, String resourceUri) {
        if (newProperties == null || newProperties.size() == 0)
            return;

        resourceUri = normalize(resourceUri);
        File file = getPropertiesFile(resourceUri);
        if (file == null)
            return;
        Properties persisted = new Properties();
        // Properties file exists, load it so we can add new properties
        if (file.exists()) {
            InputStream in = null;
            try {
                in = new FileInputStream(file);
                persisted.loadFromXML(in);
            } catch (Exception e) {
                log.warn("Failed to get properties from cache for " + resourceUri);
                return;
            } finally {
                if (in != null)
                    try {
                        in.close();
                    } catch (Exception e) {
                    }
            }
        }
        // Add new properties with key format of: resourceUri + "|" + key
        Enumeration en = newProperties.keys();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            persisted.setProperty(getResourcePropertyKey(resourceUri, key), newProperties.getProperty(key));
        }
        // Store the updates properties
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            persisted.storeToXML(os, "");
        } catch (Exception e) {
            log.warn("Failed to store properties for " + resourceUri);
        } finally {
            if (os != null)
                try {
                    os.close();
                } catch (Exception e) {
                }
        }
    }

    // Get properties for given uri
    private Properties getPropertiesFor(String uri) {
        uri = normalize(uri);
        File file = getPropertiesFile(uri);
        if (file == null || !file.exists()) {
            return null;
        }
        InputStream in = null;
        Properties persisted = new Properties();
        try {
            in = new FileInputStream(file);
            persisted.loadFromXML(in);
        } catch (Exception e) {
            log.warn("Failed to get properties from cache for " + uri);
            return null;
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (Exception e) {
                }
        }
        Enumeration en = persisted.keys();
        Properties props = new Properties();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            if (isResourceProperty(uri, key)) {
                String newKey = getPropertyKey(uri, key);
                props.setProperty(newKey, persisted.getProperty(key));
            }
        }
        return (props.size() == 0) ? null : props;
    }

    /**
     * Set custom properties for given resource
     * 
     * @param resourceUri URI of the resource
     * @param properties to set
     */
    public void setCustomProperties(String resourceUri, Properties newProperties) {
        if (newProperties == null || newProperties.size() == 0)
            return;

        resourceUri = normalize(resourceUri);
        if (resourceUri.endsWith("/" + CUSTOM_PROPERTIES_STORAGE))
            return;

        Properties props = (Properties) mPropertiesCache.get(resourceUri);
        if (props == null) {
            // Get them from persistent storage
            props = getPropertiesFor(resourceUri);
            if (props == null)
                props = new Properties();
        }

        props.putAll(newProperties);
        // Save in cache
        try {
            mPropertiesCache.put(resourceUri, props);
        } catch (Exception e) {
            log.warn("Failed to put properties into cache for " + resourceUri);
        }
        // Write them to the persistent storage
        saveCustomProperties(props, resourceUri);
    }

    /* (non-Javadoc)
     */
    public void removeCustomProperties(String resourceUri, Properties properties) {
        if (properties == null || properties.size() == 0)
            return;
        deleteProperties(resourceUri, properties);
    }

    /**
     * Get custom properties for given resource
     * 
     * @param resourceUri URI of the resource
     */
    public Properties getCustomProperties(String resourceUri) {
        resourceUri = normalize(resourceUri);
        // Try cache first
        Properties props = (Properties) mPropertiesCache.get(resourceUri);
        if (props != null) {
            return props;
        }
        // Get them from persistent storage
        try {
            props = getPropertiesFor(resourceUri);
            if (props == null)
                return new Properties();
            // Put them to the cache
            mPropertiesCache.put(resourceUri, props);
        } catch (Exception e) {
            log.warn("Failed to put properties into cache for " + resourceUri);
        }

        return props;
    }

    /**
     * Delete properties for given resource
     * 
     * @param resourceUri for which to delete properties
     */
    public void deleteProperties(String resourceUri, Properties propertiesToDelete) {
        resourceUri = normalize(resourceUri);
        // Try cache first
        Properties props = (Properties) mPropertiesCache.get(resourceUri);
        if (props != null)
            mPropertiesCache.remove(resourceUri);
        File file = getPropertiesFile(resourceUri);
        if (file == null || !file.exists()) {
            return;
        }
        InputStream in = null;
        Properties persisted = new Properties();
        try {
            in = new FileInputStream(file);
            persisted.loadFromXML(in);
        } catch (Exception e) {
            log.warn("Failed to get properties from cache for " + resourceUri);
            return;
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (Exception e) {
                }
        }
        boolean changed = false;
        Enumeration en = persisted.keys();
        HashMap toRemove = new HashMap();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            if (isResourceProperty(resourceUri, key)) {
                if (propertiesToDelete != null) {
                    String newKey = getPropertyKey(resourceUri, key);
                    if (propertiesToDelete.getProperty(newKey) != null)
                        toRemove.put(key, persisted.getProperty(key));
                } else {
                    toRemove.put(key, persisted.getProperty(key));
                }
            }
        }
        changed = !toRemove.isEmpty();
        for (Iterator it = toRemove.keySet().iterator(); it.hasNext();) {
            String key = (String) it.next();
            persisted.remove(key);
        }
        if (changed) {
            // Store the updates properties
            OutputStream os = null;
            try {
                os = new FileOutputStream(file);
                persisted.storeToXML(os, "");
            } catch (Exception e) {
                log.warn("Failed to store properties for " + resourceUri);
            } finally {
                if (os != null)
                    try {
                        os.close();
                    } catch (Exception e) {
                    }
            }
        }
    }

    /**
     * Copy properties from src to dest
     * 
     * @param srcUri to copy from
     * @param destUri to copy to
     */
    public void copyCustomProperties(String srcUri, String destUri) {
        Properties props = getCustomProperties(srcUri);
        setCustomProperties(destUri, props);
    }

}