com.bstek.dorado.web.resolver.AbstractWebFileResolver.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.web.resolver.AbstractWebFileResolver.java

Source

/*
 * This file is part of Dorado 7.x (http://dorado7.bsdn.org).
 * 
 * Copyright (c) 2002-2012 BSTEK Corp. All rights reserved.
 * 
 * This file is dual-licensed under the AGPLv3 (http://www.gnu.org/licenses/agpl-3.0.html) 
 * and BSDN commercial (http://www.bsdn.org/licenses) licenses.
 * 
 * If you are unsure which license is appropriate for your use, please contact the sales department
 * at http://www.bstek.com/contact.
 */

package com.bstek.dorado.web.resolver;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.servlet.ModelAndView;

import com.bstek.dorado.core.io.Resource;
import com.bstek.dorado.web.DoradoContext;

public abstract class AbstractWebFileResolver extends AbstractResolver
        implements BeanFactoryAware, InitializingBean {
    private static Log logger = LogFactory.getLog(WebFileResolver.class);

    private static final int BUFFER_SIZE = 1024 * 2;
    private static final int ONE_SECOND = 1000;
    private static final int MIN_RETRIEVE_LAST_MODIFIED_INTERVAL = ONE_SECOND * 10;
    private static final SimpleTimeZone GMT_TIME_ZONE = new SimpleTimeZone(0, "GMT");

    private static final ResourcesWrapper FILE_NOT_FOUND_RESOURCES_WRAPPER = new ResourcesWrapper(
            HttpServletResponse.SC_NOT_FOUND);
    private static final ResourcesWrapper FORBIDDEN_RESOURCES_WRAPPER = new ResourcesWrapper(
            HttpServletResponse.SC_FORBIDDEN);

    private BeanFactory beanFactory;
    private ResourceTypeManager resourceTypeManager;
    private Map<String, ResourcesWrapper> resourcesCache = new Hashtable<String, ResourcesWrapper>();
    private boolean useResourcesCache;
    private boolean checkResourceType;

    protected ResourceTypeManager getResourceTypeManager() {
        return resourceTypeManager;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void afterPropertiesSet() throws Exception {
        resourceTypeManager = (ResourceTypeManager) beanFactory.getBean("dorado.resourceTypeManager");
    }

    protected String getResourceExtName(String path) {
        int i = path.lastIndexOf(".");
        if (i > 0 && i < path.length() - 1) {
            return path.substring(i).toLowerCase();
        }
        return "";
    }

    protected String getUriSuffix(HttpServletRequest request) {
        return getResourceExtName(request.getRequestURI());
    }

    protected boolean shouldCompress(ResourcesWrapper resourcesWrapper) {
        ResourceType resourceType = resourcesWrapper.getResourceType();
        return (resourceType != null) ? resourceType.isCompressible() : false;
    }

    public boolean isUseResourcesCache() {
        return useResourcesCache;
    }

    public void setUseResourcesCache(boolean useResourcesCache) {
        this.useResourcesCache = useResourcesCache;
    }

    public boolean isCheckResourceType() {
        return checkResourceType;
    }

    public void setCheckResourceType(boolean checkResourceType) {
        this.checkResourceType = checkResourceType;
    }

    protected String getContentType(ResourcesWrapper resourcesWrapper) {
        ResourceType resourceType = resourcesWrapper.getResourceType();
        return (resourceType != null) ? resourceType.getContentType() : HttpConstants.CONTENT_TYPE_OCTET_STREAM;
    }

    protected OutputStream getOutputStream(HttpServletRequest request, HttpServletResponse response,
            ResourcesWrapper resourcesWrapper) throws IOException {
        int encodingType = 0;
        String encoding = request.getHeader(HttpConstants.ACCEPT_ENCODING);
        if (encoding != null) {
            encodingType = (encoding.indexOf(HttpConstants.GZIP) >= 0) ? 1
                    : (encoding.indexOf(HttpConstants.COMPRESS) >= 0 ? 2 : 0);
        }

        OutputStream out = response.getOutputStream();
        if (encodingType > 0 && shouldCompress(resourcesWrapper)) {
            try {
                if (encodingType == 1) {
                    response.setHeader(HttpConstants.CONTENT_ENCODING, HttpConstants.GZIP);
                    out = new GZIPOutputStream(out);
                } else if (encodingType == 2) {
                    response.setHeader(HttpConstants.CONTENT_ENCODING, HttpConstants.COMPRESS);
                    out = new ZipOutputStream(out);
                }
            } catch (IOException e) {
                // do nothing
            }
        }
        return out;
    }

    protected void outputFile(OutputStream out, Resource resource) throws IOException {
        InputStream in = resource.getInputStream();
        try {
            byte[] buffer = new byte[BUFFER_SIZE];
            int len = in.read(buffer);
            while (len != -1) {
                out.write(buffer, 0, len);
                len = in.read(buffer);
            }
        } catch (IOException e) {
            // do nothing
        } finally {
            in.close();
        }
    }

    protected ResourcesWrapper getResourcesWrapper(HttpServletRequest request, DoradoContext context)
            throws Exception {
        String cacheKey = getResourceCacheKey(request);
        ResourcesWrapper resourcesWrapper = null;
        boolean useResourcesCache = isUseResourcesCache();
        if (useResourcesCache && cacheKey != null) {
            resourcesWrapper = resourcesCache.get(cacheKey);
        }
        if (resourcesWrapper != null) {
            if (resourcesWrapper.isReloadable() && System.currentTimeMillis()
                    - resourcesWrapper.getLastAccessed() > MIN_RETRIEVE_LAST_MODIFIED_INTERVAL) {
                resourcesWrapper.updateLastModified();
            }
            resourcesWrapper.updateLastAccessed();
        } else {
            try {
                resourcesWrapper = createResourcesWrapper(request, context);
                if (checkResourceType && resourcesWrapper.getResourceType() == null) {
                    resourcesWrapper = FORBIDDEN_RESOURCES_WRAPPER;
                } else {
                    Resource[] resources = resourcesWrapper.getResources();
                    if (resources != null && resources.length > 0) {
                        for (int i = 0; i < resources.length; i++) {
                            Resource resource = resources[i];
                            if (!resource.exists()) {
                                throw new FileNotFoundException(resource + " does not exist.");
                            }
                        }
                    }
                }

                if (useResourcesCache && cacheKey != null && resourcesWrapper.isCacheable()) {
                    resourcesCache.put(cacheKey, resourcesWrapper);
                }
            } catch (FileNotFoundException e) {
                logger.error(e, e);
                resourcesWrapper = FILE_NOT_FOUND_RESOURCES_WRAPPER;
            } catch (IllegalAccessException e) {
                logger.error(e, e);
                resourcesWrapper = FORBIDDEN_RESOURCES_WRAPPER;
            }
        }
        if (resourcesWrapper == null) {
            resourcesWrapper = FILE_NOT_FOUND_RESOURCES_WRAPPER;
        }
        return resourcesWrapper;
    }

    protected String getResourceCacheKey(HttpServletRequest request) throws Exception {
        return getRelativeRequestURI(request);
    }

    protected ResourcesWrapper createResourcesWrapper(HttpServletRequest request, DoradoContext context)
            throws Exception {
        String path = getRelativeRequestURI(request);
        String resourceSuffix = getUriSuffix(request);
        Resource[] resources = context.getResources(path);
        return new ResourcesWrapper(resources, getResourceTypeManager().getResourceType(resourceSuffix));
    }

    @Override
    protected ModelAndView doHandleRequest(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        DoradoContext context = DoradoContext.getCurrent();
        ResourcesWrapper resourcesWrapper = getResourcesWrapper(request, context);
        outputResourcesWrapper(resourcesWrapper, request, response);
        return null;
    }

    protected void outputResourcesWrapper(ResourcesWrapper resourcesWrapper, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        if (resourcesWrapper.getHttpStatus() != 0) {
            response.setStatus(resourcesWrapper.getHttpStatus());
        } else {
            // ?Client??-1
            long cachedLastModified = request.getDateHeader(HttpConstants.IF_MODIFIED_SINCE);

            // ?Server??
            long lastModified = resourcesWrapper.getLastModified();

            // ?Client
            if (lastModified != 0 && cachedLastModified != 0
                    && Math.abs(lastModified - cachedLastModified) < ONE_SECOND) {
                // ?Server???Client
                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            } else {
                String contentType = getContentType(resourcesWrapper);
                response.setContentType(contentType);

                // Client??
                SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
                dateFormat.setTimeZone(GMT_TIME_ZONE);

                response.addHeader(HttpConstants.LAST_MODIFIED, dateFormat.format(new Date(lastModified)));

                Resource[] resources = resourcesWrapper.getResources();
                OutputStream out = getOutputStream(request, response, resourcesWrapper);
                try {
                    for (int i = 0; i < resources.length; i++) {
                        if (i > 0 && contentType.contains("text")) {
                            out.write("\n".getBytes(response.getCharacterEncoding()));
                        }
                        outputFile(out, resources[i]);
                    }
                } finally {
                    try {
                        out.close();
                    } catch (IOException e) {
                        // do nothing
                    }
                }
            }
        }
    }
}