Package org.jahia.services.render.filter

Source Code of org.jahia.services.render.filter.StaticAssetsFilter$AssetsScriptContext

/**
* This file is part of Jahia, next-generation open source CMS:
* Jahia's next-generation, open source CMS stems from a widely acknowledged vision
* of enterprise application convergence - web, search, document, social and portal -
* unified by the simplicity of web content management.
*
* For more information, please visit http://www.jahia.com.
*
* Copyright (C) 2002-2011 Jahia Solutions Group SA. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* As a special exception to the terms and conditions of version 2.0 of
* the GPL (or any later version), you may redistribute this Program in connection
* with Free/Libre and Open Source Software ("FLOSS") applications as described
* in Jahia's FLOSS exception. You should have received a copy of the text
* describing the FLOSS exception, and it is also available here:
* http://www.jahia.com/license
*
* Commercial and Supported Versions of the program (dual licensing):
* alternatively, commercial and supported versions of the program may be used
* in accordance with the terms and conditions contained in a separate
* written agreement between you and Jahia Solutions Group SA.
*
* If you are unsure which license is appropriate for your use,
* please contact the sales department at sales@jahia.com.
*/

package org.jahia.services.render.filter;

import net.htmlparser.jericho.*;
import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.collections.Factory;
import org.apache.commons.collections.FastHashMap;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.NOPTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.LazySortedMap;
import org.apache.commons.collections.map.TransformedSortedMap;
import org.apache.commons.lang.StringUtils;
import org.jahia.services.content.nodetypes.ConstraintsHelper;
import org.jahia.services.render.RenderContext;
import org.jahia.services.render.Resource;
import org.jahia.services.render.SetFactory;
import org.jahia.services.render.filter.cache.AggregateCacheFilter;
import org.jahia.services.templates.JahiaTemplateManagerService.TemplatePackageRedeployedEvent;
import org.jahia.utils.ScriptEngineUtils;
import org.jahia.utils.WebUtils;
import org.jahia.utils.i18n.JahiaResourceBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.SimpleScriptContext;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URLDecoder;
import java.util.*;
import java.util.regex.Pattern;

/**
* Render filter that "injects" the static assets into the HEAD section of the
* rendered HTML document.
*
* @author Sergiy Shyrkov
*/
public class StaticAssetsFilter extends AbstractFilter implements ApplicationListener<ApplicationEvent> {


    private static final Transformer LOW_CASE_TRANSFORMER = new Transformer() {
        public Object transform(Object input) {
            return input != null ? input.toString().toLowerCase() : null;
        }
    };

    private static final FastHashMap RANK;
    static {
        RANK = new FastHashMap();
        RANK.put("css", Integer.valueOf(1));
        RANK.put("inlinecss", Integer.valueOf(2));
        RANK.put("javascript", Integer.valueOf(3));
        RANK.put("inlinejavascript", Integer.valueOf(4));
        RANK.put("inline", Integer.valueOf(5));
        RANK.put("unknown", Integer.valueOf(6));
        RANK.setFast(true);
    }

    @SuppressWarnings("unchecked")
    private static final Comparator<String> ASSET_COMPARATOR = ComparatorUtils
            .transformedComparator(null, new Transformer() {
                public Object transform(Object input) {
                    Integer rank = null;
                    if (input != null) {
                        rank = (Integer) RANK.get(input.toString());
                    }

                    return rank != null ? rank : RANK.get("unknown");
                }
            });


    class AssetsScriptContext extends SimpleScriptContext {
        private Writer writer = null;

        /**
         * {@inheritDoc}
         */
        @Override
        public Writer getWriter() {
            if (writer == null) {
                writer = new StringWriter();
            }
            return writer;
        }
    }
   
    private static Logger logger = LoggerFactory.getLogger(StaticAssetsFilter.class);
   
    private String ajaxResolvedTemplate;

    private String ajaxTemplate;
    private String ajaxTemplateExtension;
    private String resolvedTemplate;

    private ScriptEngineUtils scriptEngineUtils;

    private String template;
    private String templateExtension;

    private static final Pattern CLEANUP_RESOURCE_REGEXP = Pattern.compile(
            "<jahia:resource .*/>");


    @Override
    public String execute(String previousOut, RenderContext renderContext, Resource resource, RenderChain chain)
            throws Exception {
        String out = previousOut;

        Source source = new Source(previousOut);

        @SuppressWarnings("unchecked")
        Map<String, Set<String>> assets = LazySortedMap.decorate(
                TransformedSortedMap.decorate(new TreeMap<String, Set<String>>(ASSET_COMPARATOR), LOW_CASE_TRANSFORMER, NOPTransformer.INSTANCE), new SetFactory());

        @SuppressWarnings("unchecked")
        Map<String, Map<String, String>> assetsOptions = LazyMap.decorate(
                new HashMap<String, Map<String, Object>>(), new Factory() {
                    public Object create() {
                        return new HashMap<String, Object>();
                    }
                });

        List<StartTag> esiResourceTags = source.getAllStartTags("jahia:resource");
        Set<String> keys = new HashSet<String>();
        for (StartTag esiResourceTag : esiResourceTags) {
            String type = esiResourceTag.getAttributeValue("type");
            String path = esiResourceTag.getAttributeValue("path");
            path = URLDecoder.decode(path, "UTF-8");
            Boolean insert = Boolean.parseBoolean(esiResourceTag.getAttributeValue("insert"));
            String resourceS = esiResourceTag.getAttributeValue("resource");
            String title = esiResourceTag.getAttributeValue("title");
            String key = esiResourceTag.getAttributeValue("key");
            Set<String> stringSet = assets.get(type);
            if (stringSet == null) {
                stringSet = new LinkedHashSet<String>();
            }
            if (insert) {
                LinkedHashSet<String> my = new LinkedHashSet<String>();
                my.add(path);
                my.addAll(stringSet);
                stringSet = my;
            } else {
                if ("".equals(key) || !keys.contains(key)) {
                    stringSet.add(path);
                    keys.add(key);
                }
            }
            assets.put(type, stringSet);
            if (title != null && !"".equals(title.trim())) {
                Map<String, String> stringMap = assetsOptions.get(resourceS);
                if (stringMap == null) {
                    stringMap = new HashMap<String, String>();
                    assetsOptions.put(resourceS, stringMap);
                }
                stringMap.put("title", title);
            }
        }

        renderContext.getRequest().setAttribute("staticAssets", assets);
        renderContext.getRequest().setAttribute("staticAssetsOptions", assetsOptions);

        OutputDocument outputDocument = new OutputDocument(source);

        if (renderContext.isAjaxRequest()) {
            String templateContent = getAjaxResolvedTemplate();
            if (templateContent != null) {
                Element element = source.getFirstElement();
                final EndTag tag = element != null ? element.getEndTag() : null;
                ScriptEngine scriptEngine = scriptEngineUtils.scriptEngine(ajaxTemplateExtension);
                ScriptContext scriptContext = new AssetsScriptContext();
                final Bindings bindings = scriptEngine.createBindings();
                bindings.put("renderContext", renderContext);
                bindings.put("resource", resource);
                scriptContext.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
                // The following binding is necessary for Javascript, which doesn't offer a console by default.
                bindings.put("out", new PrintWriter(scriptContext.getWriter()));
                scriptEngine.eval(templateContent, scriptContext);
                StringWriter writer = (StringWriter) scriptContext.getWriter();
                final String staticsAsset = writer.toString();

                if (StringUtils.isNotBlank(staticsAsset)) {
                    if (tag != null) {
                        outputDocument.replace(tag.getBegin(), tag.getBegin() + 1, "\n" + staticsAsset + "\n<");
                        out = outputDocument.toString();
                    } else {
                        out = previousOut + "\n" + staticsAsset;
                    }
                }
            }
        } else if (resource.getContextConfiguration().equals("page")) {
            if (renderContext.isEditMode()) {
                // Add static div for edit mode
                List<Element> bodyElementList = source.getAllElements(HTMLElementName.BODY);
                Set<String> javascript = assets.get("javascript");
                if (javascript == null) {
                    assets.put("javascript", (javascript = new HashSet<String>()));
                }
                javascript.add(renderContext.getRequest().getContextPath() + "/modules/assets/javascript/jquery.min.js");
                javascript.add(renderContext.getRequest().getContextPath() + "/modules/assets/javascript/jquery.Jcrop.js");

                if (bodyElementList.size() > 0) {
                    Element bodyElement = bodyElementList.get(bodyElementList.size() - 1);

                    EndTag bodyEndTag = bodyElement.getEndTag();
                    outputDocument.replace(bodyEndTag.getBegin(), bodyEndTag.getBegin() + 1, "</div><");

                    bodyElement = bodyElementList.get(0);

                    StartTag bodyStartTag = bodyElement.getStartTag();
                    outputDocument.replace(bodyStartTag.getEnd(), bodyStartTag.getEnd(), "\n" +
                                                                                         "<div class=\"jahia-template-gxt editmode-gxt\" jahiatype=\"editmode\" id=\"editmode\"" +
                                                                                         " config=\"" +
                                                                                         renderContext.getEditModeConfigName() +
                                                                                         "\"" + " path=\"" +
                                                                                         resource.getNode().getPath() +
                                                                                         "\" locale=\"" +
                                                                                         resource.getLocale() + "\"" +
                                                                                         " template=\"" +
                                                                                         resource.getResolvedTemplate() +
                                                                                         "\"" + " nodetypes=\"" +
                                                                                         ConstraintsHelper.getConstraints(
                                                                                                 renderContext.getMainResource().getNode()) +
                                                                                         "\"" + ">");
                }
            }
            List<Element> headElementList = source.getAllElements(HTMLElementName.HEAD);
            for (Element element : headElementList) {
                String templateContent = getResolvedTemplate();
                if (templateContent != null) {
                    final EndTag headEndTag = element.getEndTag();
                    ScriptEngine scriptEngine = scriptEngineUtils.scriptEngine(templateExtension);
                    ScriptContext scriptContext = new AssetsScriptContext();
                    final Bindings bindings = scriptEngine.createBindings();
                    bindings.put("renderContext", renderContext);
                    bindings.put("resource", resource);
                    bindings.put("contextPath", renderContext.getRequest().getContextPath());
                    scriptContext.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
                    // The following binding is necessary for Javascript, which doesn't offer a console by default.
                    bindings.put("out", new PrintWriter(scriptContext.getWriter()));
                    scriptEngine.eval(templateContent, scriptContext);
                    StringWriter writer = (StringWriter) scriptContext.getWriter();
                    final String staticsAsset = writer.toString();

                    if (StringUtils.isNotBlank(staticsAsset)) {
                        outputDocument.replace(headEndTag.getBegin(), headEndTag.getBegin() + 1,
                                "\n" + AggregateCacheFilter.removeEsiTags(staticsAsset) + "\n<");
                    }
                }
                String header = renderContext.getRequest().getHeader("user-agent");
                if (header!=null && header.contains("MSIE")) {
                    int idx = element.getBegin() + element.toString().indexOf(">");
                    String str = ">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\">";
                    outputDocument.replace(idx,idx + 1,str);
                }
                if (renderContext.isContributionMode() || renderContext.isPreviewMode()) {
                    for (Element title : element.getAllElements(HTMLElementName.TITLE)) {
                        int idx = title.getBegin() + title.toString().indexOf(">");
                        String str = renderContext.isContributionMode()?JahiaResourceBundle.getJahiaInternalResource("label.contribute",renderContext.getUILocale()):
                                JahiaResourceBundle.getJahiaInternalResource("label.preview",renderContext.getUILocale());
                        str = "> " + str  + " - ";
                        outputDocument.replace(idx, idx + 1,str);
                    }
                }

            }
            out = outputDocument.toString();
        }

        out = CLEANUP_RESOURCE_REGEXP.matcher(out).replaceAll("");
        return out.trim();
    }

    protected String getAjaxResolvedTemplate() throws IOException {
        if (ajaxResolvedTemplate == null) {
            ajaxResolvedTemplate = WebUtils.getResourceAsString(ajaxTemplate);
            if (ajaxResolvedTemplate == null) {
                logger.warn("Unable to lookup template at {}", ajaxTemplate);
            }
        }
        return ajaxResolvedTemplate;
    }

    protected String getResolvedTemplate() throws IOException {
        if (resolvedTemplate == null) {
            resolvedTemplate = WebUtils.getResourceAsString(template);
            if (resolvedTemplate == null) {
                logger.warn("Unable to lookup template at {}", template);
            }
        }
        return resolvedTemplate;
    }

    public void setAjaxTemplate(String ajaxTemplate) {
        this.ajaxTemplate = ajaxTemplate;
        if (ajaxTemplate != null) {
            ajaxTemplateExtension = StringUtils.substringAfterLast(ajaxTemplate, ".");
        }
    }

    public void setScriptEngineUtils(ScriptEngineUtils scriptEngineUtils) {
        this.scriptEngineUtils = scriptEngineUtils;
    }

    public void setTemplate(String template) {
        this.template = template;
        if (template != null) {
            templateExtension = StringUtils.substringAfterLast(template, ".");
        }
    }

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof TemplatePackageRedeployedEvent) {
            ajaxResolvedTemplate = null;
            resolvedTemplate = null;
        }
    }
}
TOP

Related Classes of org.jahia.services.render.filter.StaticAssetsFilter$AssetsScriptContext

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.