RepositoryCheckPlugin.java 13.6 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.xss.XSSAPI
 *  javax.jcr.Binary
 *  javax.jcr.Credentials
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.PathNotFoundException
 *  javax.jcr.Property
 *  javax.jcr.PropertyIterator
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.SimpleCredentials
 *  javax.jcr.Value
 *  javax.jcr.Workspace
 *  javax.jcr.nodetype.PropertyDefinition
 *  javax.servlet.Servlet
 *  javax.servlet.ServletException
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  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.felix.webconsole.AbstractWebConsolePlugin
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.repositorychecker.impl;

import com.adobe.granite.xss.XSSAPI;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.text.MessageFormat;
import javax.jcr.Binary;
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Value;
import javax.jcr.Workspace;
import javax.jcr.nodetype.PropertyDefinition;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.felix.webconsole.AbstractWebConsolePlugin;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@Service(value={Servlet.class})
public class RepositoryCheckPlugin
extends AbstractWebConsolePlugin {
    private static final Logger log = LoggerFactory.getLogger(RepositoryCheckPlugin.class);
    @Property(name="felix.webconsole.label")
    private static final String LABEL = "repositorycheck";
    @Property(name="felix.webconsole.title")
    private static final String TITLE = "Repository Check";
    private static final String RESOURCE_PREFIX = "/repositorycheck/";
    @Reference
    private SlingRepository repository;
    @Reference
    private XSSAPI xssApi;

    public String getLabel() {
        return "repositorycheck";
    }

    public String getTitle() {
        return "Repository Check";
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        this.doGet(req, res);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    protected void renderContent(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        Form form = new Form(req);
        PrintWriter pw = res.getWriter();
        Session session = null;
        try {
            pw.println("<form method='POST'>");
            pw.println("<div><label>Workspace <select name='workspace' required='true'>");
            session = this.repository.loginAdministrative(form.workspace);
            for (String w : session.getWorkspace().getAccessibleWorkspaceNames()) {
                if (w.equals(form.workspace)) {
                    pw.println("<option selected='true'>" + this.xssApi.encodeForHTML(w) + "</option>");
                    continue;
                }
                pw.println("<option>" + this.xssApi.encodeForHTML(w) + "</option>");
            }
            pw.println("</select></label></div>");
            pw.println("<div><label>Check nodes below <input name='path' value='" + this.xssApi.encodeForHTMLAttr(form.path) + "' required='true' /></label></div>");
            pw.println("<hr />");
            pw.println("<div><label><input name='traversal' type='checkbox'" + (form.traversal ? " checked='true'" : "") + " /> Traversal check</label></div>");
            pw.println("<div><label><input name='fixinconsistencies' type='checkbox'" + (form.fixInconsistencies ? " checked='true'" : "") + " /> Fix inconsistencies</label></div>");
            pw.println("<div><label><input name='log' type='checkbox'" + (form.log ? " checked='true'" : "") + " /> Log each node</label></div>");
            pw.println("<hr />");
            pw.println("<div><label><input name='datastoreconsistency' type='checkbox'" + (form.dsConsistency ? " checked='true'" : "") + " /> Data store consistency check</label></div>");
            pw.println("<div><input type='submit' value='Run' /></div>");
            pw.println("</form>");
            if ("POST".equals(req.getMethod())) {
                this.start(req, res, session, form);
            }
        }
        catch (RepositoryException e) {
            log.error("Error occur getting available workspaces", (Throwable)e);
            res.sendError(500, e.getMessage());
        }
        finally {
            if (session != null) {
                session.logout();
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void start(HttpServletRequest req, HttpServletResponse res, Session oSession, Form form) throws IOException {
        PrintWriter pw = res.getWriter();
        pw.println("<div class='results'>");
        Session session = null;
        try {
            Stats s;
            SimpleCredentials sc = new SimpleCredentials(oSession.getUserID(), "".toCharArray());
            if (form.fixInconsistencies) {
                sc.setAttribute("org.apache.jackrabbit.autoFixCorruptions", (Object)"true");
            }
            session = oSession.impersonate((Credentials)sc);
            Node rootNode = null;
            try {
                rootNode = session.getNode(form.path);
            }
            catch (PathNotFoundException e) {
                // empty catch block
            }
            if (form.traversal && rootNode != null) {
                pw.println("<p>Performing traversal check...</p>");
                if (form.fixInconsistencies) {
                    pw.println("<p>Automatically fixing inconsistencies (see log file for details)...</p>");
                }
                s = new Stats();
                s.calcSize = true;
                long t1 = System.currentTimeMillis();
                this.traverse(pw, rootNode, s, form.log);
                long t = System.currentTimeMillis() - t1;
                pw.println(MessageFormat.format("<p>Traversed {0} nodes, {1} properties in {2} ms</p>", String.valueOf(s.numNodes), String.valueOf(s.numProps), String.valueOf(t)));
                pw.println("<p>" + s.sizeProps + " bytes</p>");
            }
            if (form.dsConsistency && rootNode != null) {
                pw.println("Performing data store consistency check...");
                s = new Stats();
                this.dataStoreConsistency(pw, rootNode, s);
                pw.println(MessageFormat.format("<p>Traversed {0} nodes, {1} errors found</p>", String.valueOf(s.numNodes), String.valueOf(s.numErrors)));
            }
            pw.println("<p>Done</p>");
        }
        catch (RepositoryException e) {
            pw.println("<p>Error occur: " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
        }
        finally {
            if (session != null) {
                session.logout();
            }
        }
        pw.println("</div>");
    }

    private void traverse(PrintWriter out, Node n, Stats s, boolean logEachNode) throws IOException {
        s.numNodes++;
        try {
            long now = System.currentTimeMillis();
            if (logEachNode || s.nextLog == 0 || now > s.nextLog) {
                out.println("<p>" + this.xssApi.encodeForHTML(n.getPath()) + "</p>");
                out.flush();
                s.nextLog = 5000 + now;
            }
            PropertyIterator piter = n.getProperties();
            while (piter.hasNext()) {
                javax.jcr.Property p = piter.nextProperty();
                s.numProps++;
                if (!s.calcSize) continue;
                if (p.isMultiple()) {
                    for (long l : p.getLengths()) {
                        Stats.access$414(s, l);
                    }
                    continue;
                }
                Stats.access$414(s, p.getLength());
            }
            NodeIterator iter = n.getNodes();
            while (iter.hasNext()) {
                this.traverse(out, iter.nextNode(), s, logEachNode);
            }
        }
        catch (RepositoryException e) {
            try {
                out.println("<p>Error while traversing " + this.xssApi.encodeForHTML(n.getPath()) + ": " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
            }
            catch (RepositoryException e1) {
                out.println("<p>Error while traversing " + this.xssApi.encodeForHTML(n.toString()) + ": " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
            }
        }
    }

    private void dataStoreConsistency(PrintWriter out, Node n, Stats s) throws IOException {
        s.numNodes++;
        try {
            PropertyIterator piter = n.getProperties();
            while (piter.hasNext()) {
                javax.jcr.Property p = piter.nextProperty();
                try {
                    if (p.getType() == 2) {
                        if (p.getDefinition().isMultiple()) {
                            Value[] values = p.getValues();
                            for (int i = 0; i < values.length; ++i) {
                                values[i].getBinary().getStream().close();
                            }
                        } else {
                            p.getBinary().getStream().close();
                        }
                    }
                }
                catch (Exception e) {
                    String es = e.toString();
                    int idx = es.indexOf("datastore");
                    if (idx >= 0) {
                        es = es.substring(idx + "datastore".length());
                        idx = es.indexOf(58);
                        if (idx >= 0) {
                            es = es.substring(0, idx);
                        }
                        out.println("<p>missing file: " + this.xssApi.encodeForHTML(es) + "</p>");
                    } else {
                        out.println("<p>error: " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
                    }
                    out.println("<p>in property: " + this.xssApi.encodeForHTML(p.toString()) + "</p>");
                    s.numErrors++;
                    out.flush();
                }
                s.numProps++;
            }
            NodeIterator iter = n.getNodes();
            while (iter.hasNext()) {
                this.dataStoreConsistency(out, iter.nextNode(), s);
            }
        }
        catch (RepositoryException e) {
            try {
                out.println("<p>Error while traversing " + this.xssApi.encodeForHTML(n.getPath()) + ": " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
            }
            catch (RepositoryException e1) {
                out.println("<p>Error while traversing " + this.xssApi.encodeForHTML(n.toString()) + ": " + this.xssApi.encodeForHTML(e.toString()) + "</p>");
            }
        }
    }

    protected String[] getCssReferences() {
        return new String[]{"/repositorycheck/res/repositorycheck.css"};
    }

    private URL getResource(String path) {
        return path != null && path.startsWith("/repositorycheck/") ? this.getClass().getResource(path.substring("/repositorycheck/".length() - 1)) : null;
    }

    protected void bindRepository(SlingRepository slingRepository) {
        this.repository = slingRepository;
    }

    protected void unbindRepository(SlingRepository slingRepository) {
        if (this.repository == slingRepository) {
            this.repository = null;
        }
    }

    protected void bindXssApi(XSSAPI xSSAPI) {
        this.xssApi = xSSAPI;
    }

    protected void unbindXssApi(XSSAPI xSSAPI) {
        if (this.xssApi == xSSAPI) {
            this.xssApi = null;
        }
    }

    private static class Stats {
        private long numNodes;
        private long numProps;
        private long numErrors;
        private long sizeProps;
        private long nextLog;
        private boolean calcSize;

        private Stats() {
        }

        static /* synthetic */ long access$414(Stats x0, long x1) {
            return x0.sizeProps += x1;
        }
    }

    private class Form {
        String workspace;
        boolean traversal;
        boolean fixInconsistencies;
        boolean log;
        boolean dsConsistency;
        String path;

        public Form(HttpServletRequest req) {
            this.workspace = req.getParameter("workspace");
            if (this.workspace == null || this.workspace.length() == 0) {
                this.workspace = RepositoryCheckPlugin.this.repository.getDefaultWorkspace();
            }
            this.traversal = "on".equals(req.getParameter("traversal"));
            this.fixInconsistencies = "on".equals(req.getParameter("fixinconsistencies"));
            this.log = "on".equals(req.getParameter("log"));
            this.dsConsistency = "on".equals(req.getParameter("datastoreconsistency"));
            this.path = req.getParameter("path");
            if (this.path == null || this.path.length() == 0) {
                this.path = "/";
            }
        }
    }

}