PathRewriterTransformer.java 10.6 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.Externalizer
 *  com.day.cq.rewriter.linkchecker.LinkChecker
 *  com.day.text.Text
 *  org.apache.cocoon.xml.sax.AbstractSAXPipe
 *  org.apache.commons.lang.StringUtils
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.rewriter.ProcessingComponentConfiguration
 *  org.apache.sling.rewriter.ProcessingContext
 *  org.apache.sling.rewriter.Transformer
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.wcm.contentsync.impl.rewriter;

import com.day.cq.commons.Externalizer;
import com.day.cq.rewriter.linkchecker.LinkChecker;
import com.day.cq.wcm.contentsync.PathRewriterOptions;
import com.day.cq.wcm.contentsync.impl.rewriter.PathRewriterTransformerConfig;
import com.day.text.Text;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.cocoon.xml.sax.AbstractSAXPipe;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

public class PathRewriterTransformer
extends AbstractSAXPipe
implements Transformer {
    private static final Logger log = LoggerFactory.getLogger(PathRewriterTransformer.class);
    private static final String SCRIPT_TAG = "script";
    private final LinkChecker checker;
    private final Externalizer externalizer;
    private boolean enabled = false;
    private SlingHttpServletRequest request;
    private PathRewriterOptions options;
    private String relativePrefix;
    private PathRewriterTransformerConfig config;
    private boolean insideScript;
    private StringBuffer scriptBuffer;

    public PathRewriterTransformer(LinkChecker checker, Externalizer externalizer, PathRewriterTransformerConfig config) {
        this.checker = checker;
        this.externalizer = externalizer;
        this.config = config;
        this.insideScript = false;
    }

    public void init(ProcessingContext context, ProcessingComponentConfiguration config) throws IOException {
        this.request = context.getRequest();
        this.options = (PathRewriterOptions)this.request.getAttribute("pathRewritingOptions");
        this.enabled = this.options != null;
        this.relativePrefix = this.getRelativePathPrefix(this.request);
        if (this.enabled) {
            log.debug("Rewriting paths for links ({}), clientlibs ({}) and images ({})", new Object[]{this.options.getRewriteMode("links").name(), this.options.getRewriteMode("clientlibs").name(), this.options.getRewriteMode("images").name()});
        }
    }

    public void dispose() {
    }

    public void startElement(String uri, String name, String raw, Attributes a) throws SAXException {
        if (this.enabled) {
            AttributesImpl attrs = new AttributesImpl(a);
            boolean result = false;
            result |= this.internalRewrite(this.config.linksMapping, "links", name, attrs);
            result |= this.internalRewrite(this.config.clientlibsMapping, "clientlibs", name, attrs);
            if (result |= this.internalRewrite(this.config.imagesMapping, "images", name, attrs)) {
                super.startElement(uri, name, raw, (Attributes)attrs);
                return;
            }
            if (name.equals("script") && attrs.getValue("type") != null && attrs.getValue("type").equals("text/javascript")) {
                this.insideScript = true;
                this.scriptBuffer = new StringBuffer();
            }
        }
        super.startElement(uri, name, raw, a);
    }

    private boolean internalRewrite(Map<String, String> mapping, String rewriteOption, String name, AttributesImpl attrs) throws SAXException {
        if (mapping.containsKey(name)) {
            String[] attributesOfInterest = Text.explode((String)mapping.get(name), (int)58);
            boolean targetFound = false;
            for (String attrName : attributesOfInterest) {
                String attrPath = this.findPath(attrName, attrs);
                if (!this.isTargetOfInterest(attrPath)) continue;
                if (this.options.isExternal(rewriteOption)) {
                    this.makeExternal(attrName, attrs);
                } else if (this.options.isRelative(rewriteOption)) {
                    this.makeRelative(attrName, attrs);
                }
                targetFound = true;
            }
            return targetFound;
        }
        return false;
    }

    public void characters(char[] chars, int start, int length) throws SAXException {
        if (this.insideScript) {
            this.scriptBuffer.append(chars, start, length);
        } else {
            super.characters(chars, start, length);
        }
    }

    public void endElement(String uri, String loc, String raw) throws SAXException {
        if (loc.equals("script") && this.insideScript) {
            StringBuffer result = new StringBuffer();
            if (Pattern.compile(".*CQClientLibraryManager.*", 32).matcher(this.scriptBuffer).matches()) {
                Pattern pattern = Pattern.compile(this.config.clientLibraryPattern);
                Matcher matcher = pattern.matcher(this.scriptBuffer);
                while (matcher.find()) {
                    String group = matcher.group(1);
                    if (this.options.isExternal("clientlibs")) {
                        matcher.appendReplacement(result, this.config.clientLibraryReplace.replace("$1", this.externalizer.externalLink(null, "local", group)));
                        continue;
                    }
                    matcher.appendReplacement(result, this.config.clientLibraryReplace.replace("$1", this.relativePrefix + group));
                }
                matcher.appendTail(result);
            } else {
                result = this.scriptBuffer;
            }
            super.characters(result.toString().toCharArray(), 0, result.length());
            this.insideScript = false;
        }
        super.endElement(uri, loc, raw);
    }

    private boolean isTargetOfInterest(String target) {
        return target != null && !this.checker.isSpecial(target) && target.startsWith("/");
    }

    private String getRelativePathPrefix(SlingHttpServletRequest request) {
        return this.getRelativePathPrefix(request.getRequestURI());
    }

    private String getRelativePathPrefix(String uri) {
        String prefix = "";
        int depth = Text.explode((String)uri, (int)47).length;
        prefix = StringUtils.repeat((String)"../", (int)(depth - 1));
        prefix = StringUtils.removeEnd((String)prefix, (String)"/");
        return prefix;
    }

    private String getPathRelativeToParent(String parentPath, String absolutePath) {
        if (StringUtils.isNotBlank((String)absolutePath) && StringUtils.startsWith((String)absolutePath, (String)parentPath)) {
            return Text.getName((String)parentPath) + absolutePath.substring(parentPath.length());
        }
        String prefix = this.relativePrefix;
        if (StringUtils.isNotBlank((String)parentPath)) {
            String[] parentParts = Text.explode((String)parentPath, (int)47);
            String[] absoluteParts = Text.explode((String)absolutePath, (int)47);
            for (int i = 0; i < parentParts.length; ++i) {
                if (i >= absoluteParts.length || parentParts[i].equals(absoluteParts[i])) continue;
                prefix = this.getRelativePathPrefix(this.joinArray(parentParts, '/', i));
                absolutePath = "/" + this.joinArray(absoluteParts, '/', i);
                break;
            }
        }
        return prefix + absolutePath;
    }

    private void makeExternal(String name, AttributesImpl attributes) {
        int index = attributes.getIndex(name);
        String value = this.findPath(name, attributes);
        value = this.externalizer.externalLink(null, "local", value);
        value = this.replacePath(name, attributes, value);
        attributes.setAttribute(index, "", name, name, "String", value);
        log.debug("Attribute \"{}\" rewritten to: {}", (Object)name, (Object)value);
    }

    private void makeRelative(String name, AttributesImpl attributes) {
        int index = attributes.getIndex(name);
        String value = this.findPath(name, attributes);
        value = this.getPathRelativeToParent(this.options.getRelativeParentPath(), value);
        value = this.replacePath(name, attributes, value);
        attributes.setAttribute(index, "", name, name, "String", value);
        log.debug("Attribute \"{}\" rewritten to: {}", (Object)name, (Object)value);
    }

    private String joinArray(String[] array, char separator, int startIndex) {
        StringBuilder value = new StringBuilder();
        for (int j = startIndex; j < array.length; ++j) {
            value.append(array[j]);
            if (j == array.length - 1) continue;
            value.append(separator);
        }
        return value.toString();
    }

    private String findPath(String name, AttributesImpl attrs) {
        String pattern;
        Matcher m;
        Pattern patt;
        String attrValue = attrs.getValue(name);
        if (StringUtils.isNotBlank((String)attrValue) && this.config.patternMapping.containsKey(name) && (m = (patt = Pattern.compile(pattern = this.config.patternMapping.get(name))).matcher(attrValue)).find()) {
            if (m.groupCount() > 0) {
                return m.group(1);
            }
            return m.group(0);
        }
        return attrValue;
    }

    private String replacePath(String name, AttributesImpl attrs, String newPath) {
        if (this.config.patternMapping.containsKey(name)) {
            String attrValue = attrs.getValue(name);
            String pattern = this.config.patternMapping.get(name);
            Pattern patt = Pattern.compile(pattern);
            Matcher m = patt.matcher(attrValue);
            StringBuffer sb = new StringBuffer(attrValue.length());
            if (m.find()) {
                if (m.groupCount() > 0) {
                    m.appendReplacement(sb, Matcher.quoteReplacement(m.group(0).replace(m.group(1), newPath)));
                } else {
                    m.appendReplacement(sb, Matcher.quoteReplacement(newPath));
                }
            }
            m.appendTail(sb);
            return sb.toString();
        }
        return newPath;
    }
}