HtmlConsoleResponse.java 7.75 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.jcr.vault.fs.api.ProgressTrackerListener
 *  com.day.jcr.vault.fs.api.ProgressTrackerListener$Mode
 *  com.day.jcr.vault.util.HtmlProgressListener
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.commons.lang3.StringEscapeUtils
 *  org.apache.sling.xss.XSSAPI
 */
package com.day.crx.packaging.impl.response;

import com.day.crx.packaging.impl.response.BaseResponse;
import com.day.crx.packaging.impl.response.Response;
import com.day.jcr.vault.fs.api.ProgressTrackerListener;
import com.day.jcr.vault.util.HtmlProgressListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.sling.xss.XSSAPI;

public class HtmlConsoleResponse
extends BaseResponse {
    protected Session session;
    private final XSSAPI xssapi;
    protected PrintWriter out;
    protected HtmlProgressListener htmlProgressListener;

    public HtmlConsoleResponse(Session session, XSSAPI xssapi) {
        this.session = session;
        this.xssapi = xssapi;
    }

    @Override
    public void init() throws IOException {
        this.getServletResponse().setContentType("text/html; charset=utf-8");
        this.out = this.getServletResponse().getWriter();
        this.htmlProgressListener = new HtmlProgressListener((Writer)this.out);
        this.out.print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">\n<html><head>\n    <style type=\"text/css\">\n        body {\n            background-color: white;\n            font-family: verdana, arial, sans-serif;\n            font-size: 12px;\n            white-space: nowrap;\n        }\n        div {\n            font-family: courier, monospace;\n            font-size: 11px;\n        }\n    </style>\n    <script type=\"text/javascript\">\n        function onStatus(pid, stat, p, max, msg) {\n            window.parent.cqPackageShareClient.onStatus(pid, stat, p, max, msg);\n            window.scrollTo(0, 1000000);\n        }\n    </script></head>\n<body>");
    }

    @Override
    public void start(String title) throws IOException {
        this.startTimer();
        this.out.printf("<h2>%s</h2><div>", this.encode(title));
        this.out.flush();
    }

    @Override
    public /* varargs */ void log(String msg, Object ... args) {
        this.out.printf(msg + "<br>", this.encode(args));
        this.out.flush();
    }

    @Override
    public void success(String message, String longMessage) throws IOException {
        this.setSuccess(true, message, null);
        if (longMessage == null) {
            longMessage = message;
        }
        this.out.printf("</div><br>%s in %sms.<br>", this.encode(longMessage), this.getElapsedTime());
        this.writeScroll();
    }

    @Override
    public void error(String message, Throwable t) throws IOException {
        this.setSuccess(false, message, t);
        this.out.print("<br><span class=\"error\">Error during processing.</span><br>");
        this.out.println("<code><pre>");
        StringWriter error = new StringWriter();
        t.printStackTrace(new PrintWriter(error));
        this.out.print(this.encode(error.toString()));
        this.out.print("</pre></code>");
        this.writeScroll();
    }

    @Override
    public void onError(ProgressTrackerListener.Mode mode, String path, Exception e) {
        this.htmlProgressListener.onError(mode, path, e);
        if (mode.equals((Object)ProgressTrackerListener.Mode.PATHS) && path.startsWith("/libs/")) {
            String appsPath = "/apps/" + path.substring("/libs/".length());
            try {
                if (this.session.itemExists(appsPath)) {
                    this.log("Warning: the file %1$s in this package is overlaid by %2$s. %1$s will not be active. Ignore this message if this behaviour is intended.", path, appsPath);
                }
            }
            catch (RepositoryException ignored) {
                // empty catch block
            }
        }
    }

    @Override
    public void onMessage(ProgressTrackerListener.Mode mode, String action, String path) {
        this.htmlProgressListener.onMessage(mode, action, path);
        this.checkOverlay(mode, action, path);
    }

    @Override
    public Response.ShareTracker getTracker(String status, String pid) {
        return new HtmlShareTracker(this.out, status, pid);
    }

    @Override
    public void send() throws IOException {
        this.out.print("</body></html>");
        this.out.flush();
    }

    protected void checkOverlay(ProgressTrackerListener.Mode mode, String action, String path) {
        if (path.startsWith("/libs/")) {
            String appsPath = "/apps/" + path.substring("/libs/".length());
            try {
                if (this.session.itemExists(appsPath)) {
                    this.log("Warning: the file %1$s in this package is overlaid by %2$s. %1$s will not be active. Ignore this message if this behaviour is intended.", path, appsPath);
                }
            }
            catch (RepositoryException ignored) {
                // empty catch block
            }
        }
    }

    protected void writeScroll() {
        this.out.println("<script type=\"text/javascript\">");
        this.out.println("window.scrollTo(0, 1000000);");
        this.out.println("</script>");
        this.out.flush();
    }

    Object[] encode(Object[] args) {
        if (args == null || args.length == 0) {
            return args;
        }
        Object[] result = new Object[args.length];
        for (int i = 0; i < args.length; ++i) {
            Object arg = args[i];
            result[i] = arg instanceof String ? this.encode((String)arg) : arg;
        }
        return result;
    }

    String encode(String arg) {
        return this.xssapi.encodeForHTML(arg);
    }

    public class HtmlShareTracker
    implements Response.ShareTracker {
        private final PrintWriter out;
        private String status;
        private String callback;
        private final String pid;
        private long lastPing;

        public HtmlShareTracker(PrintWriter out, String status, String pid) {
            this.callback = "onStatus";
            this.lastPing = 0;
            this.out = out;
            this.status = status;
            this.pid = pid;
        }

        @Override
        public void onStatus(String status) {
        }

        public void setCallback(String callback) {
            this.callback = callback;
        }

        @Override
        public void onProgress(long progress, long max) {
            long now = System.currentTimeMillis();
            if (now - this.lastPing > 100) {
                this.out.printf("%d / %d<br>%n", progress, max);
                if (this.status != null) {
                    this.sendStatus(this.status, progress, max, "");
                } else {
                    HtmlConsoleResponse.this.writeScroll();
                }
                this.lastPing = now;
            }
        }

        @Override
        public void message(String status, String msg) {
            this.sendStatus(status, 0, 0, msg);
        }

        private void sendStatus(String status, long progress, long max, String msg) {
            this.status = status;
            if (msg == null) {
                msg = "";
            } else {
                StringEscapeUtils.escapeEcmaScript((String)msg);
            }
            this.out.println("<script>");
            this.out.printf("%s('%s', '%s', '%d', '%d', '%s');%n", this.callback, this.pid, status, progress, max, msg);
            this.out.println("</script>");
            this.out.flush();
        }
    }

}