ClassificationsExporter.java 13.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.cq.scheduled.exporter.ExportException
 *  com.adobe.cq.scheduled.exporter.Exporter
 *  com.adobe.cq.scheduled.exporter.TransformationException
 *  com.day.cq.wcm.webservicesupport.Configuration
 *  javax.jcr.Node
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Workspace
 *  javax.jcr.lock.Lock
 *  javax.jcr.lock.LockException
 *  javax.jcr.lock.LockManager
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.ReferenceCardinality
 *  org.apache.felix.scr.annotations.ReferencePolicy
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.osgi.framework.ServiceReference
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.analytics.sitecatalyst.impl.exporter;

import com.adobe.cq.scheduled.exporter.ExportException;
import com.adobe.cq.scheduled.exporter.Exporter;
import com.adobe.cq.scheduled.exporter.TransformationException;
import com.day.cq.analytics.sitecatalyst.ClassificationsService;
import com.day.cq.analytics.sitecatalyst.ClassificationsTransformer;
import com.day.cq.wcm.webservicesupport.Configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.lock.LockManager;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, label="Adobe AEM Classifications Exporter", description="Exports classification data to Analytics")
@Service
@Properties(value={@Property(name="exporter.type", value={"saint-exporter"}, propertyPrivate=1)})
public class ClassificationsExporter
implements Exporter {
    private static final int DEFAULT_PAGE_SIZE = 1000;
    private static final int MAX_PAGESIZE = 25000;
    private static final String[] DEFAULT_INCLUDE_PATHS = new String[]{"/var/export(/.*)?"};
    @Property(label="Allowed Source Paths", description="Allowed source paths for exporting data.", cardinality=4096, value={"/var/export(/.*)?"})
    private static final String ALLOWED_PATHS = "allowed.paths";
    @Property(label="Export Page Size", description="Page size for SAINT ImportJob population.", intValue={1000})
    private static final String PAGE_SIZE = "cq.analytics.saint.exporter.pagesize";
    private Logger log;
    @Reference
    private ClassificationsService classificationsService;
    @Reference(referenceInterface=ClassificationsTransformer.class, name="transformer", policy=ReferencePolicy.DYNAMIC, cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE)
    private Map<String, ClassificationsTransformer> transformers;
    private int pageSize;
    private String[] includePaths;
    private ComponentContext context;
    private Set<ServiceReference> delayedTransformers;

    public ClassificationsExporter() {
        this.log = LoggerFactory.getLogger(this.getClass());
        this.transformers = new HashMap<String, ClassificationsTransformer>();
        this.pageSize = 1000;
        this.delayedTransformers = new HashSet<ServiceReference>();
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public void exportData(Resource config, Resource source) throws ExportException {
        block24 : {
            if (!this.doInclude(source.getPath())) {
                this.log.warn("Source [{}] is not an included path, skipping.", (Object)source.getPath());
                return;
            }
            ResourceResolver resolver = source.getResourceResolver();
            Session session = (Session)resolver.adaptTo(Session.class);
            LockManager lockMgr = null;
            Node sourceNode = (Node)source.adaptTo(Node.class);
            try {
                this.log.debug("exportData: Locking source node for export");
                sourceNode.addMixin("mix:lockable");
                sourceNode.getSession().save();
                lockMgr = session.getWorkspace().getLockManager();
                lockMgr.lock(sourceNode.getPath(), true, true, Long.MAX_VALUE, null);
                if (source.listChildren().hasNext()) {
                    ValueMap props = (ValueMap)config.getParent().adaptTo(ValueMap.class);
                    Resource configPageResource = config.getParent().getParent().getParent();
                    Configuration configuration = (Configuration)configPageResource.adaptTo(Configuration.class);
                    String transformerClass = (String)props.get("transformer", null);
                    ClassificationsTransformer transformer = this.transformers.get(transformerClass);
                    if (transformer == null) {
                        throw new ExportException("exportData: No bound transformer {" + transformerClass + "} found");
                    }
                    this.log.debug("exportData: Using transformer {}", (Object)transformer.getClass().getName());
                    Object[] header = transformer.getHeader((Resource)source.listChildren().next());
                    String description = (String)props.get("description", (Object)"CQ SAINT Export");
                    String email = (String)props.get("email", (Object)"");
                    boolean checkDivisions = (Boolean)props.get("checkdivisons", (Object)true);
                    boolean exportResults = false;
                    boolean overwrite = (Boolean)props.get("overwrite", (Object)false);
                    String element = (String)props.get("dataset", (Object)"");
                    Object[] reportsuites = (String[])props.get("reportsuites", (Object)new String[0]);
                    boolean deleteProcessed = (Boolean)props.get("deleteprocessed", (Object)false);
                    this.log.debug("exportData: Create import job (description=" + description + ",email=" + email + ",header=" + Arrays.toString(header) + ",element=" + element + ",check-divisions=" + checkDivisions + ",export=" + false + ",overwrite=" + overwrite + ",reportsuites=" + Arrays.toString(reportsuites) + ")", (Object)Arrays.toString(header));
                    int jobId = this.classificationsService.createImport(configuration, description, email, (String[])header, element, checkDivisions, false, overwrite, (String[])reportsuites);
                    Iterator it = source.listChildren();
                    int page = 1;
                    ArrayList<String[]> rows = new ArrayList<String[]>();
                    ArrayList<Resource> processed = new ArrayList<Resource>();
                    while (it.hasNext()) {
                        Resource data = (Resource)it.next();
                        try {
                            Object[] row = (String[])transformer.transform(data);
                            this.log.debug("exportData: Adding data entry {}: {}", (Object)data.getPath(), (Object)Arrays.toString(row));
                            rows.add((String[])row);
                            processed.add(data);
                        }
                        catch (TransformationException te) {
                            this.log.error("exportData: Error occurred during transformation", (Throwable)te);
                            continue;
                        }
                        if (it.hasNext() && rows.size() < this.pageSize) continue;
                        this.log.debug("exportData: ImportPopulate(jobId={},page={})", (Object)jobId, (Object)page);
                        boolean success = this.classificationsService.populateImport(configuration, jobId, page, rows);
                        if (!success) {
                            this.log.error("exportData: ImportPopulate was not successful.");
                            throw new ExportException("exportData: ImportPopulate was not successful.");
                        }
                        rows.clear();
                        ++page;
                    }
                    if (!this.classificationsService.commitImport(configuration, jobId)) {
                        this.log.error("exportData: ImportCommit was not successful.");
                        throw new ExportException("exportData: ImportCommit was not successful.");
                    }
                    if (deleteProcessed) {
                        this.log.debug("exportData: Deleting processed nodes.");
                        this.deleteProcessedNodes(session, processed);
                        processed.clear();
                    }
                    break block24;
                }
                this.log.info("exportData: No data available for export");
            }
            catch (Exception e) {
                this.log.error("exportData: An error occurred during export", (Throwable)e);
            }
            finally {
                try {
                    if (lockMgr != null && sourceNode.isLocked()) {
                        this.log.debug("exportData: Unlocking node");
                        lockMgr.unlock(source.getPath());
                    }
                }
                catch (LockException le) {
                    this.log.warn("exportData: Unlocking node failed.");
                }
                catch (RepositoryException e) {
                    this.log.error(e.getMessage(), (Throwable)e);
                }
            }
        }
    }

    private void deleteProcessedNodes(Session session, List<Resource> processed) throws RepositoryException {
        for (Resource proc : processed) {
            Node procNode = (Node)proc.adaptTo(Node.class);
            procNode.remove();
        }
        session.save();
    }

    @Activate
    protected void activate(ComponentContext context) {
        Dictionary properties = context.getProperties();
        this.context = context;
        this.includePaths = PropertiesUtil.toStringArray(properties.get("allowed.paths"), (String[])DEFAULT_INCLUDE_PATHS);
        this.pageSize = PropertiesUtil.toInteger(properties.get("cq.analytics.saint.exporter.pagesize"), (int)1000);
        if (this.pageSize > 25000) {
            this.pageSize = 25000;
        }
        for (ServiceReference serviceReference : this.delayedTransformers) {
            this.bindClassificationsTransformer(serviceReference);
        }
        this.delayedTransformers.clear();
    }

    @Deactivate
    protected void deactivate(ComponentContext context) {
        this.context = null;
    }

    protected void bindClassificationsTransformer(ServiceReference ref) {
        ComponentContext context = this.context;
        if (context != null) {
            ClassificationsTransformer transformer = (ClassificationsTransformer)context.locateService("transformer", ref);
            if (transformer != null) {
                ClassificationsTransformer registeredTransformer = this.transformers.get(transformer.getClass().getName());
                if (registeredTransformer == null) {
                    this.log.info("bindClassificationsTransformer: Registering class {}", (Object)transformer.getClass().getName());
                    this.transformers.put(transformer.getClass().getName(), transformer);
                } else {
                    this.log.warn("bindClassificationsTransformer: Class {} already registered by exporter {}", (Object)ref.getClass().getName(), (Object)registeredTransformer);
                }
            }
        } else {
            this.delayedTransformers.add(ref);
        }
    }

    protected void unbindClassificationsTransformer(ServiceReference ref) {
        ClassificationsTransformer transformer;
        ComponentContext context = this.context;
        if (context != null && (transformer = (ClassificationsTransformer)context.locateService("transformer", ref)) != null) {
            this.log.info("unbindClassificationsTransformer: Unregistering class {}", (Object)transformer.getClass().getName());
            this.transformers.remove(transformer.getClass().getName());
        }
        this.delayedTransformers.remove((Object)ref);
    }

    private boolean doInclude(String path) {
        for (String inlcudePath : this.includePaths) {
            if (!path.matches(inlcudePath)) continue;
            this.log.debug("Include path {}", (Object)path);
            return true;
        }
        return false;
    }

    protected void bindClassificationsService(ClassificationsService classificationsService) {
        this.classificationsService = classificationsService;
    }

    protected void unbindClassificationsService(ClassificationsService classificationsService) {
        if (this.classificationsService == classificationsService) {
            this.classificationsService = null;
        }
    }
}