com.bstek.dorado.view.resolver.PackageFileResolver.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.view.resolver.PackageFileResolver.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.view.resolver;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

import com.bstek.dorado.core.Context;
import com.bstek.dorado.core.io.FileResource;
import com.bstek.dorado.core.io.Resource;
import com.bstek.dorado.core.resource.LocaleResolver;
import com.bstek.dorado.util.PathUtils;
import com.bstek.dorado.util.TempFileUtils;
import com.bstek.dorado.view.loader.Package;
import com.bstek.dorado.view.loader.PackagesConfig;
import com.bstek.dorado.view.loader.PackagesConfigManager;
import com.bstek.dorado.view.loader.Pattern;
import com.bstek.dorado.view.output.JsonBuilder;
import com.bstek.dorado.web.DoradoContext;
import com.bstek.dorado.web.WebConfigure;
import com.bstek.dorado.web.resolver.HttpConstants;
import com.bstek.dorado.web.resolver.ResourcesWrapper;
import com.bstek.dorado.web.resolver.WebFileResolver;

/**
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since 2011-1-23
 */
public class PackageFileResolver extends WebFileResolver {
    private static final String NONE_FILE = "(none)";

    protected static final String I18N = "i18n";
    protected static final String I18N_FILE_SUFFIX = ".properties";
    protected static final String LIBRARY_PACKAGE_SUFFIX = ".dpkg";
    protected static final String JAVASCRIPT_SUFFIX = ".js";
    protected static final String STYLESHEET_SUFFIX = ".css";
    protected static final String MIN_JAVASCRIPT_SUFFIX = ".min.js";
    protected static final String MIN_STYLESHEET_SUFFIX = ".min.css";

    private static class I18NResource implements Resource {
        protected Resource adapteeResource;

        public I18NResource(Context context, String packageName, Resource resource) throws IOException {
            if (TempFileUtils.isSupportsTempFile()) {
                File file = TempFileUtils.createTempFile("client-i18n-" + packageName + '-', JAVASCRIPT_SUFFIX);

                FileOutputStream fos = new FileOutputStream(file);
                Writer writer = new OutputStreamWriter(fos);
                try {
                    outputI18N(writer, resource);
                } finally {
                    writer.flush();
                    writer.close();
                    fos.flush();
                    fos.close();
                }

                adapteeResource = new FileResource(file);
            } else {
                adapteeResource = resource;
            }
        }

        /**
         * @param writer
         * @param resource
         * @param fos
         * @throws IOException
         */
        private void outputI18N(Writer writer, Resource resource) throws IOException {
            Properties properties = new Properties();
            properties.load(resource.getInputStream());

            String namespace = properties.getProperty("namespace");
            properties.remove("namespace");
            writer.append("dorado.util.Resource.append(");
            if (StringUtils.isEmpty(namespace)) {
                writer.append("\n");
            } else {
                writer.append("\"").append(StringEscapeUtils.escapeJavaScript(namespace)).append("\",\n");
            }

            JsonBuilder jsonBuilder = new JsonBuilder(writer);
            jsonBuilder.object();
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String value = (String) entry.getValue();
                if (value != null) {
                    jsonBuilder.key((String) entry.getKey());
                    jsonBuilder.beginValue();
                    writer.append('\"').append(StringEscapeUtils.escapeJavaScript(value)).append('\"');
                    jsonBuilder.endValue();
                }
            }
            jsonBuilder.endObject();

            writer.append("\n);");
        }

        public Resource createRelative(String relativePath) throws IOException {
            return adapteeResource.createRelative(relativePath);
        }

        public boolean exists() {
            return adapteeResource.exists();
        }

        public String getDescription() {
            return adapteeResource.getDescription();
        }

        public File getFile() throws IOException {
            return adapteeResource.getFile();
        }

        public String getFilename() {
            return adapteeResource.getFilename();
        }

        public InputStream getInputStream() throws IOException {
            if (TempFileUtils.isSupportsTempFile()) {
                return adapteeResource.getInputStream();
            } else {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                Writer writer = new OutputStreamWriter(baos);
                try {
                    outputI18N(writer, adapteeResource);
                } finally {
                    writer.flush();
                    writer.close();
                    baos.flush();
                    baos.close();
                }

                return new ByteArrayInputStream(baos.toByteArray());
            }
        }

        public String getPath() {
            return adapteeResource.getPath();
        }

        public long getTimestamp() throws IOException {
            return adapteeResource.getTimestamp();
        }

        public URL getURL() throws IOException {
            return adapteeResource.getURL();
        }
    }

    public static class FileInfo {
        private String fileName;
        private String packageName;
        private String fileType;

        public FileInfo(String packageName, String fileName) {
            this.packageName = packageName;
            this.fileName = fileName;
        }

        public FileInfo(String packageName, String fileName, String fileType) {
            this(packageName, fileName);
            this.fileType = fileType;
        }

        public String getFileName() {
            return fileName;
        }

        public String getPackageName() {
            return packageName;
        }

        public String getFileType() {
            return fileType;
        }
    }

    private LocaleResolver localeResolver;
    private Locale defaultLocale;
    private ClientI18NFileRegistry clientI18NFileRegistry;

    private PackagesConfigManager packagesConfigManager;

    public PackageFileResolver() {
        setUseResourcesCache(true);
    }

    /**
     * ????
     */
    public void setLocaleResolver(LocaleResolver localeResolver) {
        this.localeResolver = localeResolver;
    }

    /**
     * ??
     */
    public void setDefaultLocale(Locale defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    public void setClientI18NFileRegistry(ClientI18NFileRegistry clientI18NFileRegistry) {
        this.clientI18NFileRegistry = clientI18NFileRegistry;
    }

    @Override
    protected String getResourceCacheKey(HttpServletRequest request) throws Exception {
        Locale locale = localeResolver.resolveLocale();
        if (locale == null) {
            locale = defaultLocale;
        }
        return getRelativeRequestURI(request) + "|" + locale.toString();
    }

    /**
     * ???
     * 
     * @throws Exception
     */
    protected PackagesConfigManager getPackagesConfigManager() throws Exception {
        if (packagesConfigManager == null) {
            Context context = Context.getCurrent();
            packagesConfigManager = (PackagesConfigManager) context.getServiceBean("packagesConfigManager");
        }
        return packagesConfigManager;
    }

    @Override
    protected ResourcesWrapper createResourcesWrapper(HttpServletRequest request, DoradoContext context)
            throws Exception {
        String packageName = StringUtils.substringAfterLast(request.getRequestURI(), "/");

        String resourcePrefix = getResourcePrefix();
        String resourceSuffix = getUriSuffix(request);
        packageName = packageName.substring(0, packageName.length() - resourceSuffix.length());

        Resource[] resources;
        PackagesConfig packagesConfig = getPackagesConfigManager().getPackagesConfig();
        Map<String, Pattern> patterns = packagesConfig.getPatterns();
        Map<String, Package> packages = packagesConfig.getPackages();

        boolean cacheable = true;
        String[] pkgNames = packageName.split(",");
        List<FileInfo> fileInfos = new ArrayList<FileInfo>();
        for (int i = 0; i < pkgNames.length; i++) {
            String pkgName = pkgNames[i];
            Package pkg = packages.get(pkgName);
            if (pkg == null) {
                throw new FileNotFoundException("Package [" + pkgName + "] not found.");
            }

            if (i == 0) {
                String contentType = pkg.getContentType();
                if (StringUtils.isEmpty(contentType)) {
                    Pattern pattern = patterns.get(pkg.getPattern());
                    if (pattern != null) {
                        resourceSuffix = pattern.getResourceSuffix();
                        contentType = pattern.getContentType();
                    }
                }

                if (StringUtils.isEmpty(resourceSuffix)) {
                    if (HttpConstants.CONTENT_TYPE_CSS.equalsIgnoreCase(contentType)) {
                        resourceSuffix = STYLESHEET_SUFFIX;
                    } else {
                        resourceSuffix = JAVASCRIPT_SUFFIX;
                    }
                }
            }

            if (!pkg.isCacheable()) {
                cacheable = false;
            }

            collectFileInfos(context, fileInfos, pkg, resourcePrefix, resourceSuffix);
        }

        List<Resource> resourceList = new ArrayList<Resource>();
        for (FileInfo fileInfo : fileInfos) {
            Resource[] resourceArray = getResourcesByFileInfo(context, fileInfo, resourcePrefix, resourceSuffix);
            if (resourceArray != null) {
                for (int j = 0; j < resourceArray.length; j++) {
                    resourceList.add(resourceArray[j]);
                }
            }
        }

        resources = new Resource[resourceList.size()];
        resourceList.toArray(resources);

        ResourcesWrapper resourcesWrapper = new ResourcesWrapper(resources,
                getResourceTypeManager().getResourceType(resourceSuffix));
        resourcesWrapper.setCacheable(cacheable);
        return resourcesWrapper;
    }

    private void collectFileInfos(DoradoContext context, List<FileInfo> fileInfos, Package pkg,
            String resourcePrefix, String resourceSuffix) throws Exception {
        String[] fileNameArray = pkg.getFileNames();
        if (fileNameArray != null) {
            for (int j = 0; j < fileNameArray.length; j++) {
                String fileName = StringUtils.trim(fileNameArray[j]);
                if (fileName.indexOf(NONE_FILE) < 0) {
                    fileInfos.add(new FileInfo(pkg.getName(), fileName));
                }
            }
        }

        if (JAVASCRIPT_SUFFIX.equals(resourceSuffix)) {
            ClientI18NFileRegistry.FileInfo fileInfo = clientI18NFileRegistry.getFileInfo(pkg.getName());
            if (fileInfo != null) {
                if (fileInfo.isReplace()) {
                    for (int i = fileInfos.size() - 1; i >= 0; i--) {
                        FileInfo fi = fileInfos.get(i);
                        if (I18N.equals(fi.getFileType())) {
                            fileInfos.remove(i);
                        }
                    }
                }
                fileInfos.add(new FileInfo(pkg.getName(), fileInfo.getPath(), I18N));
            }
        }
    }

    protected Resource[] getResourcesByFileInfo(DoradoContext context, FileInfo fileInfo, String resourcePrefix,
            String resourceSuffix) throws Exception {
        if (JAVASCRIPT_SUFFIX.equals(resourceSuffix)) {
            if (I18N.equals(fileInfo.getFileType())) { // ?
                return getI18NResources(context, fileInfo, resourcePrefix, resourceSuffix);
            } else {
                return getJavaScriptResources(context, fileInfo, resourcePrefix, resourceSuffix);
            }
        } else if (STYLESHEET_SUFFIX.equals(resourceSuffix)) {
            return getStyleSheetResources(context, fileInfo, resourcePrefix, resourceSuffix);

        } else {
            return doGetResourcesByFileName(context, resourcePrefix, fileInfo.getFileName(), resourceSuffix);
        }
    }

    protected Resource[] doGetResourcesByFileName(DoradoContext context, String resourcePrefix, String fileName,
            String resourceSuffix) throws Exception {
        return getResourcesByFileName(context, resourcePrefix, fileName, resourceSuffix);
    }

    protected Resource[] getI18NResources(DoradoContext context, FileInfo fileInfo, String resourcePrefix,
            String resourceSuffix) throws Exception {
        Locale locale = localeResolver.resolveLocale();
        Resource resource = getI18NResource(context, resourcePrefix, fileInfo.getFileName(), resourceSuffix,
                locale);
        Resource[] resources = new Resource[] { new I18NResource(context, fileInfo.getPackageName(), resource) };
        return resources;
    }

    protected final Resource getI18NResource(DoradoContext context, String resourcePrefix, String fileName,
            String resourceSuffix, Locale locale) throws Exception {
        if (locale == null) {
            locale = defaultLocale;
        }

        String localeSuffix = "";
        if (locale != null) {
            String localeString = locale.toString();
            if (StringUtils.isNotEmpty(localeString)) {
                localeSuffix = '.' + localeString;
            }
        }

        return doGetI18NResource(context, resourcePrefix, fileName, localeSuffix);
    }

    protected Resource doGetI18NResource(DoradoContext context, String resourcePrefix, String fileName,
            String localeSuffix) throws Exception, FileNotFoundException {
        Resource[] resources = doGetResourcesByFileName(context, resourcePrefix, fileName,
                localeSuffix + I18N_FILE_SUFFIX);
        if (resources.length == 0 || !resources[0].exists()) {
            resources = null;
        }

        if (resources == null) {
            if (StringUtils.isNotEmpty(localeSuffix)) {
                resources = doGetResourcesByFileName(context, resourcePrefix, fileName, I18N_FILE_SUFFIX);
                if (resources.length == 0 || !resources[0].exists()) {
                    resources = null;
                }

                if (resources == null) {
                    throw new FileNotFoundException("File [" + PathUtils.concatPath(resourcePrefix, fileName)
                            + localeSuffix + I18N_FILE_SUFFIX + "] or ["
                            + PathUtils.concatPath(resourcePrefix, fileName) + I18N_FILE_SUFFIX + "] not found.");
                }
            } else {
                throw new FileNotFoundException("File [" + PathUtils.concatPath(resourcePrefix, fileName)
                        + I18N_FILE_SUFFIX + "] not found.");
            }
        }
        return (resources != null) ? resources[0] : null;
    }

    protected Resource[] getJavaScriptResources(DoradoContext context, FileInfo fileInfo, String resourcePrefix,
            String resourceSuffix) throws Exception {
        boolean useMinJs = WebConfigure.getBoolean("view.useMinifiedJavaScript");
        String fileName = fileInfo.getFileName();
        Resource[] resources = null;
        if (useMinJs) {
            resources = doGetResourcesByFileName(context, resourcePrefix, fileName, MIN_JAVASCRIPT_SUFFIX);
            if (resources.length == 0 || !resources[0].exists()) {
                resources = null;
            }
        }
        if (resources == null) {
            resources = doGetResourcesByFileName(context, resourcePrefix, fileName, resourceSuffix);
        }
        return resources;
    }

    protected Resource[] getStyleSheetResources(DoradoContext context, FileInfo fileInfo, String resourcePrefix,
            String resourceSuffix) throws Exception {
        boolean useMinCss = WebConfigure.getBoolean("view.useMinifiedStyleSheet");
        String fileName = fileInfo.getFileName();
        Resource[] resources = null;
        if (useMinCss) {
            resources = doGetResourcesByFileName(context, resourcePrefix, fileName, MIN_STYLESHEET_SUFFIX);
            if (resources.length == 0 || !resources[0].exists()) {
                resources = null;
            }
        }
        if (resources == null) {
            resources = doGetResourcesByFileName(context, resourcePrefix, fileName, resourceSuffix);
        }
        return resources;
    }
}