OutboxImpl.java 10 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.durbo.DurboOutput
 *  javax.annotation.Nonnull
 *  javax.annotation.Nullable
 *  javax.jcr.Binary
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.ValueFactory
 *  org.apache.commons.io.input.ClosedInputStream
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.replication.impl;

import com.day.cq.replication.Outbox;
import com.day.cq.replication.ReplicationAction;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationException;
import com.day.durbo.DurboOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import org.apache.commons.io.input.ClosedInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OutboxImpl
implements Outbox {
    private static final Logger log = LoggerFactory.getLogger(OutboxImpl.class);
    private static final int OUTBOX_FOLDER_SIZE = 1000;
    private final Node outbox;
    private final String path;

    public OutboxImpl(@Nonnull Node outbox) throws RepositoryException {
        this.outbox = outbox;
        this.path = outbox.getPath();
    }

    @Override
    public String getPath() {
        return this.path;
    }

    private Node getOutboxFolder() throws RepositoryException {
        NodeIterator nIter = this.outbox.getNodes();
        Node folder = null;
        while (nIter.hasNext()) {
            folder = nIter.nextNode();
        }
        if (folder != null && !folder.isNodeType("{http://www.jcp.org/jcr/nt/1.0}folder")) {
            folder = null;
        }
        if (folder != null) {
            nIter = folder.getNodes();
            int count = 0;
            while (nIter.hasNext()) {
                nIter.nextNode();
                ++count;
            }
            if (count >= 1000) {
                folder = null;
            }
        }
        if (folder == null) {
            folder = this.outbox.addNode(String.valueOf(System.currentTimeMillis()), "sling:OrderedFolder");
        }
        return folder;
    }

    @Override
    public synchronized void put(ReplicationAction action) throws ReplicationException {
        this.put(action, null);
    }

    @Override
    public synchronized void put(ReplicationAction action, InputStream in) throws ReplicationException {
        if (in == null) {
            if (action.getType() == ReplicationActionType.ACTIVATE) {
                throw new ReplicationException("ACTIVATE requires replication content.");
            }
            in = ClosedInputStream.CLOSED_INPUT_STREAM;
        }
        this.internalPut(in, action);
    }

    private void internalPut(InputStream in, ReplicationAction action) throws ReplicationException {
        if (action != null && action.getType() != null && ReplicationActionType.TEST.equals((Object)action.getType())) {
            return;
        }
        String nodeName = String.valueOf(System.currentTimeMillis());
        Session systemSession = null;
        try {
            Node outboxFolder = this.getOutboxFolder();
            systemSession = outboxFolder.getSession();
            Node fileToAdd = outboxFolder.addNode(nodeName, "{http://www.jcp.org/jcr/nt/1.0}unstructured");
            Node content = fileToAdd.addNode("{http://www.jcp.org/jcr/1.0}content", "{http://www.jcp.org/jcr/nt/1.0}unstructured");
            Binary bin = systemSession.getValueFactory().createBinary(in);
            content.setProperty("{http://www.jcp.org/jcr/1.0}data", bin);
            content.setProperty("{http://www.jcp.org/jcr/1.0}lastModified", Calendar.getInstance());
            content.setProperty("{http://www.jcp.org/jcr/1.0}mimeType", "application/octet-stream");
            if (action != null && action.getType() != null) {
                content.setProperty("cq:repActionType", action.getType().name());
                content.setProperty("cq:repPath", action.getPath());
            }
            systemSession.save();
            log.info("Added new outbox item {} for {}", (Object)fileToAdd, (Object)action);
        }
        catch (RepositoryException e) {
            try {
                if (systemSession != null) {
                    systemSession.refresh(false);
                }
            }
            catch (RepositoryException fileToAdd) {
                // empty catch block
            }
            String msg = "Unable to store content.";
            throw new ReplicationException(msg, (Exception)e);
        }
    }

    @Override
    public synchronized void fetch(Calendar time, OutputStream out) throws ReplicationException {
        try {
            if (time != null) {
                this.purge(this.outbox, time);
            }
        }
        catch (RepositoryException e) {
            try {
                this.outbox.getSession().refresh(false);
            }
            catch (RepositoryException var4_4) {
                // empty catch block
            }
            String msg = "Unable to purge old items.";
            throw new ReplicationException(msg, (Exception)e);
        }
        OutboxImpl.writeOutbox(this.outbox, out);
    }

    public static void writeOutbox(@Nullable Node outboxNode, OutputStream out) throws ReplicationException {
        try {
            DurboOutput durboOut = new DurboOutput(out);
            durboOut.openNode("outbox");
            if (outboxNode != null) {
                OutboxIterator files = new OutboxIterator(outboxNode);
                while (files.hasNext()) {
                    OutboxImpl.writeNode(files.next(), durboOut);
                }
            }
            durboOut.closeNode();
            durboOut.close();
        }
        catch (IOException e) {
            String msg = "Unable to write items.";
            throw new ReplicationException(msg, e);
        }
        catch (RepositoryException e) {
            String msg = "Unable to iterate over outbox.";
            throw new ReplicationException(msg, (Exception)e);
        }
    }

    private void purge(Node outbox, Calendar time) throws RepositoryException {
        ArrayList<String> outdated = new ArrayList<String>();
        OutboxIterator files = new OutboxIterator(outbox);
        while (files.hasNext()) {
            Node file = files.next();
            if (!file.hasNode("{http://www.jcp.org/jcr/1.0}content")) continue;
            Node content = file.getNode("{http://www.jcp.org/jcr/1.0}content");
            Calendar cal = content.getProperty("{http://www.jcp.org/jcr/1.0}lastModified").getDate();
            if (!cal.before(time)) break;
            outdated.add(file.getPath());
        }
        if (outdated.size() > 0) {
            for (String s : outdated) {
                outbox.getSession().getNode(s).remove();
            }
            outdated.clear();
            NodeIterator folders = outbox.getNodes();
            while (folders.hasNext()) {
                Node folder = folders.nextNode();
                if (!folder.isNodeType("{http://www.jcp.org/jcr/nt/1.0}folder") || folder.getNodes().hasNext()) continue;
                outdated.add(folder.getPath());
            }
            for (String s2 : outdated) {
                outbox.getSession().getNode(s2).remove();
            }
            outbox.getSession().save();
        }
    }

    private static void writeNode(Node file, DurboOutput out) throws IOException, RepositoryException {
        if (!file.hasNode("{http://www.jcp.org/jcr/1.0}content")) {
            return;
        }
        Node content = file.getNode("{http://www.jcp.org/jcr/1.0}content");
        out.openNode(file.getName());
        out.writeProperty(content.getProperty("{http://www.jcp.org/jcr/1.0}lastModified"));
        OutboxImpl.writeOptionalProperty(content, "cq:repActionType", out);
        OutboxImpl.writeOptionalProperty(content, "cq:repPath", out);
        out.writeProperty("outbox.item.path", file.getPath());
        out.writeProperty(content.getProperty("{http://www.jcp.org/jcr/1.0}data"));
        out.closeNode();
    }

    private static void writeOptionalProperty(Node parent, String propertyName, DurboOutput out) throws IOException, RepositoryException {
        if (parent.hasProperty(propertyName)) {
            out.writeProperty(parent.getProperty(propertyName));
        }
    }

    private static final class OutboxIterator
    implements Iterator<Node> {
        private NodeIterator outer = null;
        private NodeIterator inner = null;
        private Node nextNode;

        private OutboxIterator(Node outbox) throws RepositoryException {
            this.outer = outbox.getNodes();
            this.nextNode = this.seek();
        }

        @Override
        public boolean hasNext() {
            return this.nextNode != null;
        }

        @Override
        public Node next() {
            Node ret = this.nextNode;
            this.nextNode = this.seek();
            return ret;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        private Node seek() {
            try {
                if (this.inner != null && this.inner.hasNext()) {
                    return this.inner.nextNode();
                }
                this.inner = null;
                if (!this.outer.hasNext()) {
                    return null;
                }
                Node folder = this.outer.nextNode();
                if (folder.isNodeType("{http://www.jcp.org/jcr/nt/1.0}folder")) {
                    this.inner = folder.getNodes();
                    return this.seek();
                }
                return folder;
            }
            catch (RepositoryException e) {
                return null;
            }
        }
    }

}