com.webpagebytes.cms.local.WPBLocalFileStorage.java Source code

Java tutorial

Introduction

Here is the source code for com.webpagebytes.cms.local.WPBLocalFileStorage.java

Source

/*
 *   Copyright 2014 Webpagebytes
 *
 * 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 com.webpagebytes.cms.local;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.CRC32;

import javax.xml.bind.DatatypeConverter;

import org.apache.commons.io.IOUtils;

import com.webpagebytes.cms.WPBFileInfo;
import com.webpagebytes.cms.WPBFilePath;
import com.webpagebytes.cms.WPBFileStorage;
import com.webpagebytes.cms.engine.WPBDefaultCloudFileInfo;
import com.webpagebytes.cms.utility.CmsBase64Utility;
import com.webpagebytes.cms.utility.CmsConfiguration;
import com.webpagebytes.cms.utility.CmsConfigurationFactory;
import com.webpagebytes.cms.utility.CmsConfiguration.WPBSECTION;

public class WPBLocalFileStorage implements WPBFileStorage {
    private static final String publicDataFolder = "public";
    private static final String privateDataFolder = "private";
    private static final String publicMetaFolder = "public_meta";
    private static final String privateMetaFolder = "private_meta";
    private String dataDirectory;
    private String basePublicUrlPath;
    private boolean isInitialized;
    private static final Logger log = Logger.getLogger(WPBLocalFileStorage.class.getName());

    public WPBLocalFileStorage() {
        try {
            initialize(true);
        } catch (Exception e) {
            log.log(Level.SEVERE, "Cannot initialize WBLocalCloudFileStorage for " + dataDirectory, e);
        }
    }

    public WPBLocalFileStorage(String dataDirectory, String basePublicUrlPath) {

        this.dataDirectory = dataDirectory;

        if (!basePublicUrlPath.endsWith("/")) {
            basePublicUrlPath = basePublicUrlPath + "/";
        }
        this.basePublicUrlPath = basePublicUrlPath;
        try {
            initialize(false);
        } catch (Exception e) {
            // log the exception here
            log.log(Level.SEVERE, "Cannot initialize WBLocalCloudFileStorage for " + dataDirectory, e);
        }
    }

    public String getDataDir() {
        return dataDirectory;
    }

    public boolean isInitialized() {
        return isInitialized;
    }

    private String getPathPublicDataDir() {
        return dataDirectory + File.separator + publicDataFolder;
    }

    private String getPathPrivateDataDir() {
        return dataDirectory + File.separator + privateDataFolder;
    }

    private String getPathPublicMetaDir() {
        return dataDirectory + File.separator + publicMetaFolder;
    }

    private String getPathPrivateMetaDir() {
        return dataDirectory + File.separator + privateMetaFolder;
    }

    private void initializeFileStorage(String dataDirectory) throws IOException, FileNotFoundException {
        File fileBaseData = new File(dataDirectory);
        if (!fileBaseData.exists() || !fileBaseData.isDirectory()) {
            throw new FileNotFoundException();
        }

        File publicDataDir = new File(getPathPublicDataDir());
        if (!publicDataDir.exists()) {
            log.log(Level.INFO, "Create public dir for WBLocalCloudFileStorage " + publicDataDir.getAbsolutePath());
            if (false == publicDataDir.mkdir()) {
                throw new IOException("Cannot create dir: " + publicDataDir.getPath());
            }
        }

        File privateDataDir = new File(getPathPrivateDataDir());
        if (!privateDataDir.exists()) {
            log.log(Level.INFO,
                    "Create private dir for WBLocalCloudFileStorage " + privateDataDir.getAbsolutePath());
            if (false == privateDataDir.mkdir()) {
                throw new IOException("Cannot create dir: " + privateDataDir.getPath());
            }
        }

        File publicMetaDir = new File(getPathPublicMetaDir());
        if (!publicMetaDir.exists()) {
            log.log(Level.INFO,
                    "Create public meta dir for WBLocalCloudFileStorage " + publicMetaDir.getAbsolutePath());
            if (false == publicMetaDir.mkdir()) {
                throw new IOException("Cannot create dir: " + publicMetaDir.getPath());
            }
        }

        File privateMetaDir = new File(getPathPrivateMetaDir());
        if (!privateMetaDir.exists()) {
            log.log(Level.INFO,
                    "Create private meta dir for WBLocalCloudFileStorage " + privateMetaDir.getAbsolutePath());
            if (false == privateMetaDir.mkdir()) {
                throw new IOException("Cannot create dir: " + privateMetaDir.getPath());
            }
        }

        isInitialized = true;

    }

    private void initialize(boolean paramsFromConfig) throws IOException, FileNotFoundException {
        if (paramsFromConfig) {
            CmsConfiguration config = CmsConfigurationFactory.getConfiguration();
            Map<String, String> params = config.getSectionParams(WPBSECTION.SECTION_FILESTORAGE);

            dataDirectory = params.get("dataDirectory");
            basePublicUrlPath = params.get("basePublicUrlPath");

            if (!basePublicUrlPath.endsWith("/")) {
                basePublicUrlPath = basePublicUrlPath + "/";
            }
        }

        log.log(Level.INFO, "Initialize for WBLocalCloudFileStorage with dir: " + dataDirectory);

        initializeFileStorage(dataDirectory);
    }

    /*
     * sanitizeCloudFilePath will return a safe path that can be part of a file name
     * The path will be converted to base64  
     */
    private String sanitizeCloudFilePath(String path) {
        return CmsBase64Utility.toBase64(path.getBytes(Charset.forName("UTF-8")));
    }

    private String getLocalFullDataPath(WPBFilePath file) {
        if (file.getBucket().equals(publicDataFolder)) {
            return getPathPublicDataDir() + File.separator + sanitizeCloudFilePath(file.getPath());
        }
        if (file.getBucket().equals(privateDataFolder)) {
            return getPathPrivateDataDir() + File.separator + sanitizeCloudFilePath(file.getPath());
        }
        return null;
    }

    private String getLocalFullMetaPath(WPBFilePath file) {
        if (file.getBucket().equals(publicDataFolder)) {
            return getPathPublicMetaDir() + File.separator + sanitizeCloudFilePath(file.getPath());
        }
        if (file.getBucket().equals(privateDataFolder)) {
            return getPathPrivateMetaDir() + File.separator + sanitizeCloudFilePath(file.getPath());
        }
        return null;
    }

    private OutputStream createStorageOutputStream(String path) throws IOException {
        if (new File(path).exists()) {
            throw new IOException("file already exists");
        }
        return new FileOutputStream(path);
    }

    private InputStream createStorageInputStream(String path) throws IOException {

        return new FileInputStream(path);
    }

    private void storeFileProperties(Properties props, String filePath) throws IOException {
        FileOutputStream os = new FileOutputStream(filePath);
        props.storeToXML(os, "", "UTF-8");
        IOUtils.closeQuietly(os);
    }

    private Properties getFileProperties(String filePath) throws IOException {
        Properties props = new Properties();
        FileInputStream fis = null;
        fis = new FileInputStream(filePath);
        props.loadFromXML(fis);
        return props;
    }

    private boolean checkIfFileExists(String filePath) throws IOException {
        return new File(filePath).exists();
    }

    public void storeFile(InputStream is, WPBFilePath file) throws IOException {
        String fullFilePath = getLocalFullDataPath(file);
        OutputStream fos = createStorageOutputStream(fullFilePath);
        byte[] buffer = new byte[4096];
        CRC32 crc = new CRC32();
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            IOUtils.closeQuietly(fos);
            throw new IOException("Cannot calculate md5 to store the file", e);
        }

        int count = 0;
        int size = 0;
        while ((count = is.read(buffer)) != -1) {
            size += count;
            fos.write(buffer, 0, count);
            crc.update(buffer, 0, count);
            md.update(buffer, 0, count);
        }

        IOUtils.closeQuietly(fos);

        Properties props = new Properties();
        props.put("path", file.getPath());
        props.put("contentType", "application/octet-stream");
        props.put("crc32", String.valueOf(crc.getValue()));
        props.put("md5", DatatypeConverter.printBase64Binary(md.digest()));
        props.put("creationTime",
                String.valueOf(Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime().getTime()));
        props.put("size", String.valueOf(size));

        String metaPath = getLocalFullMetaPath(file);
        storeFileProperties(props, metaPath);

    }

    public WPBFileInfo getFileInfo(WPBFilePath file) {
        String metaPath = getLocalFullMetaPath(file);
        String dataPath = getLocalFullDataPath(file);
        Properties props = new Properties();
        try {
            props = getFileProperties(metaPath);

            String contentType = props.getProperty("contentType");
            int size = Integer.valueOf(props.getProperty("size"));
            String md5 = props.getProperty("md5");
            long crc32 = Long.valueOf(props.getProperty("crc32"));
            long creationTime = Long.valueOf(props.getProperty("creationTime"));

            boolean fileExists = checkIfFileExists(dataPath);
            WPBFileInfo fileInfo = new WPBDefaultCloudFileInfo(file, contentType, fileExists, size, md5, crc32,
                    creationTime);
            props.remove("path");
            props.remove("contentType");
            props.remove("size");
            props.remove("md5");
            props.remove("crc32");
            props.remove("creationTime");
            props.remove("filePath");
            // add the custom properties of the file
            for (Object key : props.keySet()) {
                String strKey = (String) key;
                fileInfo.setProperty(strKey, props.getProperty(strKey));
            }
            return fileInfo;
        } catch (Exception e) {
            return null;
        }

    }

    public boolean deleteFile(WPBFilePath file) throws IOException {
        String filePath = getLocalFullDataPath(file);
        File dataFile = new File(filePath);
        boolean del1 = true;
        if (dataFile.exists()) {
            del1 = dataFile.delete();
        }
        String metaPath = getLocalFullMetaPath(file);
        File metaFile = new File(metaPath);
        boolean del2 = true;
        if (metaFile.exists()) {
            del2 = metaFile.delete();
        }
        return del1 && del2;

    }

    public InputStream getFileContent(WPBFilePath file) throws IOException {
        String fullFilePath = getLocalFullDataPath(file);
        if (!checkIfFileExists(fullFilePath)) {
            throw new IOException("file does not exists");
        }
        return createStorageInputStream(fullFilePath);
    }

    public void updateContentType(WPBFilePath file, String contentType) throws IOException {
        String fullFilePath = getLocalFullDataPath(file);
        if (!checkIfFileExists(fullFilePath)) {
            throw new IOException("file does not exists");
        }

        String metaPath = getLocalFullMetaPath(file);
        Properties props = getFileProperties(metaPath);

        props.put("contentType", contentType);

        storeFileProperties(props, metaPath);
    }

    public void updateFileCustomProperties(WPBFilePath file, Map<String, String> customProps) throws IOException {
        String fullFilePath = getLocalFullDataPath(file);
        if (!checkIfFileExists(fullFilePath)) {
            throw new IOException("file does not already exists");
        }

        String metaPath = getLocalFullMetaPath(file);
        Properties props = getFileProperties(metaPath);

        customProps.remove("path");
        customProps.remove("contentType");
        customProps.remove("size");
        customProps.remove("md5");
        customProps.remove("crc32");
        customProps.remove("creationTime");
        customProps.remove("filePath");

        props.putAll(customProps);

        storeFileProperties(props, metaPath);
    }

    public String getPublicFileUrl(WPBFilePath file) {
        String partialPath = file.getBucket() + "/" + sanitizeCloudFilePath(file.getPath());
        return basePublicUrlPath + partialPath;
    }

}