S7ImageServerRenderer.java 12.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.cq.dam.dm.delivery.api.ImageDelivery
 *  com.adobe.cq.dam.dm.process.api.PTiffRendition
 *  com.adobe.cq.gfx.Instructions
 *  com.adobe.cq.gfx.Layer
 *  com.adobe.cq.gfx.Plan
 *  com.adobe.cq.gfx.Renderer
 *  com.day.cq.commons.Externalizer
 *  com.day.cq.dam.api.Asset
 *  javax.jcr.Credentials
 *  javax.jcr.Session
 *  javax.jcr.SimpleCredentials
 *  javax.servlet.ServletException
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceMetadata
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.engine.SlingRequestProcessor
 *  org.osgi.service.component.ComponentContext
 *  org.osgi.service.component.annotations.Activate
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.dam.s7imaging.impl.gfx;

import com.adobe.cq.dam.dm.delivery.api.ImageDelivery;
import com.adobe.cq.dam.dm.process.api.PTiffRendition;
import com.adobe.cq.dam.s7imaging.impl.gfx.LoopbackConfig;
import com.adobe.cq.dam.s7imaging.impl.gfx.Request;
import com.adobe.cq.dam.s7imaging.impl.gfx.Response;
import com.adobe.cq.gfx.Instructions;
import com.adobe.cq.gfx.Layer;
import com.adobe.cq.gfx.Plan;
import com.adobe.cq.gfx.Renderer;
import com.day.cq.commons.Externalizer;
import com.day.cq.dam.api.Asset;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.Credentials;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.engine.SlingRequestProcessor;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
@Component
@Property(name="service.ranking", intValue={1000})
public class S7ImageServerRenderer
implements Renderer {
    private final Logger log = LoggerFactory.getLogger(S7ImageServerRenderer.class);
    @Reference
    private ResourceResolverFactory resolverFactory;
    @Reference
    private SlingRequestProcessor sling;
    @Reference
    private Externalizer externalizer;
    @Reference
    private ImageDelivery imageDelivery;
    private URL loopbackUrl;

    @Activate
    public void activate(ComponentContext ctx) {
        this.loopbackUrl = LoopbackConfig.createLoopbackUrl(ctx, this.externalizer);
        if (this.loopbackUrl != null) {
            this.log.info("loopbackUrl: {}", (Object)this.loopbackUrl);
        } else {
            this.log.warn("loopbackUrl: not configured");
        }
    }

    private boolean accepts(Plan plan, ResourceResolver resolver) {
        if (!this.imageDelivery.isEnabled()) {
            this.log.debug("Denying rendering because Dynamic Media is not enabled");
            return false;
        }
        if (this.loopbackUrl == null) {
            this.log.warn("Local CQ HTTP service port not configured. Configure the self domain in the Externalizer to fully enable Dynamic Media.");
            return false;
        }
        return this.referencesOnlyAssetsWithPtiffs(plan, resolver);
    }

    public InputStream render(Plan plan, ResourceResolver resolver) throws Exception {
        if (!this.accepts(plan, resolver)) {
            return null;
        }
        String path = (String)plan.layer(0).get("src", String.class);
        if (path == null) {
            return null;
        }
        String queryString = S7ImageServerRenderer.modifiersToQueryString(plan);
        this.log.debug("rendering {}", (Object)path);
        this.log.debug("modifiers {}", (Object)queryString);
        try {
            Pipe pipe = new Pipe();
            final Request request = new Request(this.loopbackUrl, "/is/image" + path, queryString);
            final Response response = new Response(pipe, path, queryString, this.log);
            Session session = (Session)resolver.adaptTo(Session.class);
            final Session clonedSession = session.impersonate((Credentials)new SimpleCredentials(session.getUserID(), new char[0]));
            final ResourceResolver clonedResolver = this.resolverFactory.getResourceResolver((Map)new HashMap<String, Object>(){});
            new Thread(new Runnable(){

                /*
                 * WARNING - Removed try catching itself - possible behaviour change.
                 */
                @Override
                public void run() {
                    try {
                        S7ImageServerRenderer.this.sling.processRequest(request, (HttpServletResponse)response, clonedResolver);
                    }
                    catch (ServletException e) {
                        S7ImageServerRenderer.this.log.error("PlatformServer request failed", (Throwable)e);
                    }
                    catch (IOException e) {
                        S7ImageServerRenderer.this.log.error("PlatformServer request failed", (Throwable)e);
                    }
                    finally {
                        response.close();
                        clonedResolver.close();
                        clonedSession.logout();
                    }
                }
            }).start();
            return pipe.inputStream();
        }
        catch (LoginException e) {
            throw new Exception("Could not clone resource resolver for rendering asset " + path, (Throwable)e);
        }
    }

    private static String modifiersToQueryString(Plan plan) {
        StringBuilder builder = new StringBuilder();
        for (String key3 : plan.view().keySet()) {
            S7ImageServerRenderer.appendKeyValuePair(builder, key3, (String)plan.view().get(key3, String.class));
        }
        for (int i = 0; i < plan.layers().size(); ++i) {
            Layer layer = (Layer)plan.layers().get(i);
            if (layer.size() == 0 || layer.size() == 1 && layer.containsKey((Object)"src")) continue;
            S7ImageServerRenderer.appendKeyValuePair(builder, "layer", Integer.toString(i));
            for (String key2 : layer.keySet()) {
                if (i == 0 && "src".equals(key2)) continue;
                S7ImageServerRenderer.appendKeyValuePair(builder, key2, (String)layer.get(key2, String.class));
            }
        }
        if (plan.composition().size() > 0) {
            S7ImageServerRenderer.appendKeyValuePair(builder, "layer", "comp");
            for (String key3 : plan.composition().keySet()) {
                S7ImageServerRenderer.appendKeyValuePair(builder, key3, (String)plan.composition().get(key3, String.class));
            }
        }
        return builder.toString();
    }

    private static void appendKeyValuePair(StringBuilder builder, String key, String value) {
        if (builder.length() > 0) {
            builder.append("&");
        }
        builder.append(key).append("=").append(value);
    }

    private static /* varargs */ boolean referencesOnlyCertainMimeTypes(Plan plan, ResourceResolver resolver, String ... mimeTypePatterns) {
        for (String mimeType : S7ImageServerRenderer.getMimeTypesFromSourcesInPlan(plan, resolver)) {
            if (mimeType == null || S7ImageServerRenderer.mimeTypeMatches(mimeType, mimeTypePatterns)) continue;
            return false;
        }
        return true;
    }

    private boolean referencesOnlyAssetsWithPtiffs(Plan plan, ResourceResolver resolver) {
        for (Resource resource : S7ImageServerRenderer.getSourcesReferencedInPlan(plan, resolver)) {
            Asset asset = (Asset)resource.adaptTo(Asset.class);
            if (this.imageDelivery.getPTiffRendition(asset) != null) continue;
            return false;
        }
        return true;
    }

    private static List<String> getMimeTypesFromSourcesInPlan(Plan plan, ResourceResolver resolver) {
        ArrayList<String> result = new ArrayList<String>(plan.layers().size());
        for (Resource resource : S7ImageServerRenderer.getSourcesReferencedInPlan(plan, resolver)) {
            Asset asset = (Asset)resource.adaptTo(Asset.class);
            if (asset != null) {
                result.add(asset.getMimeType());
                continue;
            }
            result.add(resource.getResourceMetadata().getContentType());
        }
        return result;
    }

    private static /* varargs */ boolean mimeTypeMatches(String mimeType, String ... patterns) {
        for (String pattern : patterns) {
            if (!(pattern.endsWith("*") ? mimeType.startsWith(StringUtils.removeEnd((String)pattern, (String)"*")) : mimeType.equals(pattern))) continue;
            return true;
        }
        return false;
    }

    private static List<Resource> getSourcesReferencedInPlan(Plan plan, ResourceResolver resolver) {
        ArrayList<Resource> result = new ArrayList<Resource>(plan.layers().size());
        for (Layer layer : plan.layers()) {
            Resource resource = resolver.getResource((String)layer.get("src", (Object)""));
            if (resource == null) continue;
            result.add(resource);
        }
        return result;
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }

    protected void bindSling(SlingRequestProcessor slingRequestProcessor) {
        this.sling = slingRequestProcessor;
    }

    protected void unbindSling(SlingRequestProcessor slingRequestProcessor) {
        if (this.sling == slingRequestProcessor) {
            this.sling = null;
        }
    }

    protected void bindExternalizer(Externalizer externalizer) {
        this.externalizer = externalizer;
    }

    protected void unbindExternalizer(Externalizer externalizer) {
        if (this.externalizer == externalizer) {
            this.externalizer = null;
        }
    }

    protected void bindImageDelivery(ImageDelivery imageDelivery) {
        this.imageDelivery = imageDelivery;
    }

    protected void unbindImageDelivery(ImageDelivery imageDelivery) {
        if (this.imageDelivery == imageDelivery) {
            this.imageDelivery = null;
        }
    }

    public class Pipe {
        private PipedInputStream in;
        private PipedOutputStream out;
        private volatile IOException exception;

        public Pipe() {
            this.in = new PipedInputStream(S7ImageServerRenderer.this){
                final /* synthetic */ S7ImageServerRenderer val$this$0;

                @Override
                public synchronized int read() throws IOException {
                    if (Pipe.this.exception != null) {
                        throw Pipe.this.exception;
                    }
                    int b = super.read();
                    if (Pipe.this.exception != null) {
                        throw Pipe.this.exception;
                    }
                    return b;
                }
            };
            try {
                this.out = new PipedOutputStream(this.in);
            }
            catch (IOException e) {
                S7ImageServerRenderer.this.log.error("freshly created piped streams cannot be connected (unexpected)", (Throwable)e);
            }
        }

        public PipedInputStream inputStream() {
            return this.in;
        }

        public PipedOutputStream outputStream() {
            return this.out;
        }

        public void sendException(IOException ioe) {
            this.exception = ioe;
        }

        public void close() {
            try {
                this.out.close();
            }
            catch (IOException e) {
                S7ImageServerRenderer.this.log.error("Could not close pipe from PlatformServerServlet outputstream", (Throwable)e);
            }
        }

    }

}