Package org.jboss.seam.wiki.core.ui

Source Code of org.jboss.seam.wiki.core.ui.WikiPluginThemeResource

/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.wiki.core.ui;

import static org.jboss.seam.ScopeType.APPLICATION;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.Expressions;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.util.Resources;
import org.jboss.seam.web.ConditionalAbstractResource;
import org.jboss.seam.wiki.core.plugin.PluginRegistry;
import org.jboss.seam.wiki.core.plugin.metamodel.Plugin;
import org.jboss.seam.wiki.core.plugin.metamodel.PluginModule;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Serves files from the classpath, from a Plugin theme package.
* <p>
* This means that any web request can get any file out of that package. So don't put
* anything into a plugins theme directory that you don't want people to GET.
* </p>
* <p>
* It is primarily used for serving up plugin CSS and image files. It can also interpolate
* EL expressions in certain resources, configured with <tt>interpolatedResourcesExtensions</tt>.
* The default is to parse resources with <tt>css</tt> extension. A <tt>PluginModule</tt> instance
* is always available as variable <tt>currentPluginModule</tt>, which allows direct access to metadata
* and path information such as <tt>imagePath</tt> and <tt>styleSheetPath</tt>.
* </p>
*
* @author Christian Bauer
*/
@Scope(APPLICATION)
@Name("wikiPluginThemeResource")
@BypassInterceptors
public class WikiPluginThemeResource extends ConditionalAbstractResource {

    private Log log = Logging.getLog(WikiPluginThemeResource.class);

    private static final Pattern EL_PATTERN = Pattern.compile("#" + Pattern.quote("{") + "(.*)" + Pattern.quote("}"));

    // Resources URIs end with /<pluginKey/<pluginModuleKey>/<themeResourceName>.<themeResourceExtension>
    public static Pattern PLUGIN_RESOURCE_PATTERN =
            Pattern.compile("^/(" + Plugin.KEY_PATTERN + ")/(" + Plugin.KEY_PATTERN + ")/(.+?)\\.([a-z]+)$");

    // Resources that are interpolated, i.e. which are text files that contain EL expressions
    private String[] interpolatedResourcesExtensions = new String[]{"css"};

    private Map<String, String> mimeTypesExtensions = new HashMap() {{
        put("css", "text/css");
        put("txt", "text/plain");
        put("js", "text/javascript");
        put("png", "image/png");
        put("jpg", "image/jpg");
        put("jpeg", "image/jpeg");
        put("gif", "image/gif");
        put("swf", "application/x-shockwave-flash");
        put("flv", "video/x-flv");
    }};

    @Override
    public String getResourcePath() {
        return Plugin.REGISTER_SEAM_RESOURCE_THEME;
    }

    @Override
    public void getResource(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {

        // Wrap this, we need an ApplicationContext
        new ContextualHttpServletRequest(request) {
            @Override
            public void process() throws IOException {
                doWork(request, response);
            }
        }.run();

    }

    public String[] getInterpolatedResourcesExtensions() {
        return interpolatedResourcesExtensions;
    }

    public void setInterpolatedResourcesExtensions(String[] interpolatedResourcesExtensions) {
        this.interpolatedResourcesExtensions = interpolatedResourcesExtensions;
    }

    public void doWork(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        String pathInfo = request.getPathInfo().substring(getResourcePath().length());

        String pluginKey = null;
        String pluginModuleKey = null;
        String themeResourceName = null;
        String themeResourceExtension = null;

        Matcher matcher = PLUGIN_RESOURCE_PATTERN.matcher(pathInfo);
        if (matcher.find()) {
            pluginKey = matcher.group(1);
            pluginModuleKey = matcher.group(2);
            themeResourceName = matcher.group(3);
            themeResourceExtension = matcher.group(4);
            log.debug("request for resource,"
                    + " plugin key '" + pluginKey + "'"
                    + " plugin module key '" + pluginModuleKey + "'"
                    + " theme resource name '" + themeResourceName + "'"
                    + " theme resource ext '" + themeResourceExtension + "'"
            );
        }
        if (pluginKey == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Plugin key not found");
            return;
        }
        if (pluginModuleKey == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Plugin module key not found");
            return;
        }
        if (themeResourceName == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Resource name not found");
            return;
        }

        PluginRegistry registry = PluginRegistry.instance();
        Plugin plugin = registry.getPlugin(pluginKey);
        if (plugin == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Plugin not found in registry: " + pluginKey);
            return;
        }
        PluginModule pluginModule = plugin.getModuleByKey(pluginModuleKey);
        if (pluginModule == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Plugin module not found: " + pluginKey+"."+pluginModuleKey);
            return;
        }

        org.jboss.seam.contexts.Contexts.getEventContext().set("currentPluginModule", pluginModule);

        String resourcePath = plugin.getPackageThemePath() + "/" + themeResourceName + "." + themeResourceExtension;
        InputStream in = Resources.getResourceAsStream(resourcePath, getServletContext());

        if (in != null) {

            boolean isInterpolated = false;
            for (String interpolatedResourcesExtension : interpolatedResourcesExtensions) {
                if (interpolatedResourcesExtension.equals(themeResourceExtension)) {
                    isInterpolated = true;
                    break;
                }
            }

            String contentType = mimeTypesExtensions.get(themeResourceExtension);

            if (isInterpolated) {

                if (contentType == null) {
                    contentType = "text/plain";
                }
                response.setContentType(contentType);

                CharSequence textFile = readFile(in);
                textFile = parseEL(textFile);

                String entityTag = createEntityTag(textFile.toString(), false);
                Long lastModified = getLastModifiedTimestamp(resourcePath);

                if (!sendConditional(request, response, entityTag, lastModified)) {
                    log.debug("serving interpolated resource: " + resourcePath);
                    OutputStreamWriter outStream = new OutputStreamWriter(selectOutputStream(request, response));
                    outStream.write(textFile.toString());
                    outStream.close();
                }
            } else {
                log.debug("serving resource: " + resourcePath);

                if (contentType == null) {
                    contentType = "application/octet-stream";
                }
                response.setContentType(contentType);

                // We can't produce an entity tag because we stream the bytes through (or not, through the gzip wrapper)
                if (!sendConditional(request, response, null, getLastModifiedTimestamp(resourcePath))) {
                    OutputStream outStream = selectOutputStream(request, response);
                    byte[] buffer = new byte[1024];
                    int read = in.read(buffer);
                    while (read != -1) {
                        outStream.write(buffer, 0, read);
                        read = in.read(buffer);
                    }
                    outStream.close();
                }
            }
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, resourcePath);
        }

    }

    private CharSequence readFile(InputStream inputStream) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder css = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            css.append(line);
            css.append("\n");
        }
        inputStream.close();
        return css;
    }

    // Resolve any EL value binding expression present in text resource
    // This should be Interpolator.interpolate, but it seems to break on CSS
    private CharSequence parseEL(CharSequence string) {
        StringBuffer parsed = new StringBuffer(string.length());
        Matcher matcher =
                EL_PATTERN.matcher(string);

        while (matcher.find()) {
            String result = Expressions.instance().createValueExpression(
                "#{" + matcher.group(1) + "}", String.class
            ).getValue();
            if (result != null) {
                matcher.appendReplacement(parsed, result);
            } else {
                matcher.appendReplacement(parsed, "");
            }
        }
        matcher.appendTail(parsed);
        return parsed;
    }

}
TOP

Related Classes of org.jboss.seam.wiki.core.ui.WikiPluginThemeResource

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.