LaunchesEventHandler.java 16.4 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.cq.launches.api.Launch
 *  com.adobe.cq.launches.api.LaunchManager
 *  com.day.cq.wcm.api.PageEvent
 *  com.day.cq.wcm.api.PageModification
 *  com.day.cq.wcm.api.PageModification$ModificationType
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  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.PropertyOption
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.commons.osgi.OsgiUtil
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.apache.sling.event.jobs.JobBuilder
 *  org.apache.sling.event.jobs.JobBuilder$ScheduleBuilder
 *  org.apache.sling.event.jobs.JobManager
 *  org.apache.sling.event.jobs.ScheduledJobInfo
 *  org.osgi.service.component.ComponentContext
 *  org.osgi.service.event.Event
 *  org.osgi.service.event.EventHandler
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.wcm.launches.impl;

import com.adobe.cq.launches.api.Launch;
import com.adobe.cq.launches.api.LaunchManager;
import com.adobe.cq.wcm.launches.utils.LaunchUtils;
import com.day.cq.wcm.api.PageEvent;
import com.day.cq.wcm.api.PageModification;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
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.PropertyOption;
import org.apache.felix.scr.annotations.Reference;
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.ResourceResolverFactory;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.event.jobs.JobBuilder;
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.ScheduledJobInfo;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, immediate=1, label="%launches.eventhandler.name", description="%launches.eventhandler.description")
@Service(value={EventHandler.class})
@Properties(value={@org.apache.felix.scr.annotations.Property(name="event.topics", propertyPrivate=1, value={"com/day/cq/wcm/core/page"}), @org.apache.felix.scr.annotations.Property(name="event.filter", value={"(!(event.application=*))"})})
public class LaunchesEventHandler
implements EventHandler {
    @Reference
    private ResourceResolverFactory resolverFactory;
    @Reference
    private JobManager jobManager;
    private static final Logger log = LoggerFactory.getLogger(LaunchesEventHandler.class);
    @org.apache.felix.scr.annotations.Property(intValue={5})
    private static final String DEFAULT_THREADPOOL_MAX_SIZE = "launches.eventhandler.threadpool.maxsize";
    @org.apache.felix.scr.annotations.Property(value={"MIN"}, options={@PropertyOption(name="NORM", value="%launches.eventhandler.threadpool.priority.normal"), @PropertyOption(name="MAX", value="%launches.eventhandler.threadpool.priority.maximal"), @PropertyOption(name="MIN", value="%launches.eventhandler.threadpool.priority.minimal")})
    private static final String DEFAULT_THREADPOOL_PRIORITY = "launches.eventhandler.threadpool.priority";
    private static final boolean DEFAULT_UPDATE_LAST_MODIFICATION = false;
    @org.apache.felix.scr.annotations.Property(boolValue={0})
    private static final String UPDATE_LAST_MODIFICATION = "launches.eventhandler.updatelastmodification";
    private boolean updateLastModification;
    private static final String LAUNCH_EVENT_SERVICE_USER = "launch-event-service";
    private final BlockingDeque<Event> events = new LinkedBlockingDeque<Event>();
    private EventProcessor processor;
    private static final Event POISON_PILL = new Event("poison", null);
    private ExecutorService serviceExecutor;

    public void handleEvent(Event event) {
        try {
            this.events.put(event);
        }
        catch (InterruptedException e) {
            log.error(e.getMessage(), (Throwable)e);
        }
    }

    private void start() {
        this.processor = new EventProcessor();
        Thread thread = new Thread(this.processor);
        thread.setDaemon(true);
        thread.start();
    }

    private void stop() {
        this.processor.stop();
        this.events.addFirst(POISON_PILL);
    }

    @Activate
    protected void activate(ComponentContext context) throws Exception {
        Dictionary props = context.getProperties();
        Integer maxPoolSize = PropertiesUtil.toInteger(props.get("launches.eventhandler.threadpool.maxsize"), (int)5);
        final THREAD_PRIORITY threadPriority = THREAD_PRIORITY.valueOf(OsgiUtil.toString(props.get("launches.eventhandler.threadpool.priority"), (String)THREAD_PRIORITY.MIN.name()));
        ThreadFactory threadFactory = new ThreadFactory(){

            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setPriority(threadPriority.getPriority());
                return thread;
            }
        };
        this.serviceExecutor = Executors.newFixedThreadPool(maxPoolSize, threadFactory);
        this.updateLastModification = PropertiesUtil.toBoolean(props.get("launches.eventhandler.updatelastmodification"), (boolean)false);
        this.start();
    }

    @Deactivate
    protected void deactivate(ComponentContext context) {
        if (this.serviceExecutor != null) {
            this.serviceExecutor.shutdownNow();
            this.serviceExecutor = null;
        }
        this.stop();
    }

    static /* synthetic */ BlockingDeque access$100(LaunchesEventHandler x0) {
        return x0.events;
    }

    static /* synthetic */ Event access$200() {
        return POISON_PILL;
    }

    static /* synthetic */ ExecutorService access$400(LaunchesEventHandler x0) {
        return x0.serviceExecutor;
    }

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

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

    protected void bindJobManager(JobManager jobManager) {
        this.jobManager = jobManager;
    }

    protected void unbindJobManager(JobManager jobManager) {
        if (this.jobManager == jobManager) {
            this.jobManager = null;
        }
    }

    private static enum THREAD_PRIORITY {
        NORM(5),
        MIN(1),
        Max(10);
        
        private final int priority;

        private THREAD_PRIORITY(int priority) {
            this.priority = priority;
        }

        public int getPriority() {
            return this.priority;
        }
    }

    private class PageEventProcessor
    implements Callable<Boolean> {
        final PageEvent pageEvent;

        PageEventProcessor(PageEvent pageEvent) {
            this.pageEvent = pageEvent;
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        @Override
        public Boolean call() {
            ResourceResolver resolver = null;
            try {
                Map<String, String> info = Collections.singletonMap("sling.service.subservice", "launch-event-service");
                resolver = LaunchesEventHandler.this.resolverFactory.getServiceResourceResolver(info);
                Iterator iter = this.pageEvent.getModifications();
                block10 : while (iter.hasNext()) {
                    PageModification pm = (PageModification)iter.next();
                    String masterPath = pm.getPath();
                    if (masterPath.equals(pm.getDestination())) continue;
                    switch (pm.getType()) {
                        case MODIFIED: 
                        case CREATED: 
                        case DELETED: {
                            Resource launchRes;
                            Node launchNode;
                            Resource pageResource = resolver.getResource(masterPath);
                            if (pm.getType() == PageModification.ModificationType.DELETED) {
                                pageResource = resolver.getResource(masterPath.substring(0, masterPath.lastIndexOf(47)));
                            }
                            if (pageResource == null || (launchRes = LaunchUtils.getLaunchResource(pageResource)) == null) continue block10;
                            if (masterPath.equals(launchRes.getPath())) {
                                Object prop;
                                Object changes = pm.getEventProperties().get("changes");
                                if (changes == null || !(changes instanceof Set)) continue block10;
                                Set changesSet = (Set)changes;
                                Iterator i$ = changesSet.iterator();
                                do {
                                    if (!i$.hasNext()) continue block10;
                                } while (!(prop = i$.next()).toString().endsWith("isProductionReady") && !prop.toString().endsWith("liveDate"));
                                Launch launch = (Launch)launchRes.adaptTo(Launch.class);
                                Calendar liveDate = launch.getLiveDate();
                                boolean isProductionReady = launch.isProductionReady();
                                this.setAutoPromoteJob(resolver, launchRes.getPath(), liveDate, pm.getUserId(), isProductionReady);
                                break;
                            }
                            if (!LaunchesEventHandler.this.updateLastModification || !(launchNode = (Node)launchRes.adaptTo(Node.class)).hasNode("jcr:content")) continue block10;
                            try {
                                Node launchContentNode = launchNode.getNode("jcr:content");
                                Calendar when = Calendar.getInstance();
                                when.setTime(pm.getModificationDate());
                                launchContentNode.setProperty("cq:lastModified", when);
                                launchContentNode.setProperty("cq:lastModifiedBy", pm.getUserId());
                                log.debug("Touching launch's modification date [{}] due to page modification [{}]", (Object)launchRes.getPath(), (Object)masterPath);
                                launchNode.getSession().save();
                            }
                            catch (RepositoryException e) {
                                log.error("Unable to update last modification date for launch {}", (Object)launchRes.getPath(), (Object)e);
                            }
                            break;
                        }
                        default: {
                            log.debug("Received PageEvent of type {}: nothing to do", (Object)pm.getType());
                        }
                    }
                }
            }
            catch (Exception e) {
                log.error("Exception during process of event {}", (Throwable)e);
            }
            finally {
                if (resolver != null) {
                    resolver.close();
                }
            }
            return Boolean.TRUE;
        }

        private void setAutoPromoteJob(ResourceResolver resolver, String launchPath, Calendar liveDate, String userId, boolean isProductionReady) {
            HashMap<String, Object> autoPromoteJobCfg = new HashMap<String, Object>();
            autoPromoteJobCfg.put("launchPath", launchPath);
            try {
                Collection jobInfos = LaunchesEventHandler.this.jobManager.getScheduledJobs("com/adobe/cq/wcm/launches/autopromote", 1, new Map[]{autoPromoteJobCfg});
                if (!jobInfos.isEmpty()) {
                    ScheduledJobInfo jobInfo = (ScheduledJobInfo)jobInfos.iterator().next();
                    log.info("Unscheduling previously planned auto-promotion of launch [{}]", (Object)launchPath);
                    jobInfo.unschedule();
                }
            }
            catch (NoSuchElementException e) {
                log.warn("Unable to remove auto-promotion job for launch [{}]", (Object)launchPath);
            }
            if (isProductionReady && liveDate != null && liveDate.getTime().after(new Date())) {
                try {
                    log.info("Scheduling auto-promotion of launch [{}] at date: {}", (Object)launchPath, (Object)liveDate.getTime());
                    autoPromoteJobCfg.put("liveDate", liveDate);
                    autoPromoteJobCfg.put("userId", userId);
                    Launch launch = ((LaunchManager)resolver.adaptTo(LaunchManager.class)).getLaunch(launchPath);
                    LaunchesEventHandler.this.jobManager.createJob("com/adobe/cq/wcm/launches/autopromote").properties(autoPromoteJobCfg).schedule().at(liveDate.getTime()).add();
                }
                catch (Exception e) {
                    log.error("Unable to run auto-promotion of launch [{}] at date: {}", (Object)new Object[]{launchPath, liveDate.getTime()}, (Object)e);
                }
            }
        }
    }

    private class EventProcessor
    implements Runnable {
        private volatile boolean stop;

        private EventProcessor() {
            this.stop = false;
        }

        public void stop() {
            this.stop = true;
        }

        /*
         * Exception decompiling
         */
        @Override
        public void run() {
            // This method has failed to decompile.  When submitting a bug report, please provide this stack trace, and (if you hold appropriate legal rights) the relevant class file.
            // org.benf.cfr.reader.util.ConfusedCFRException: Tried to end blocks [6[DOLOOP]], but top level block is 10[UNCONDITIONALDOLOOP]
            // org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement.processEndingBlocks(Op04StructuredStatement.java:397)
            // org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement.buildNestedBlocks(Op04StructuredStatement.java:449)
            // org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement.createInitialStructuredBlock(Op03SimpleStatement.java:2877)
            // org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisInner(CodeAnalyser.java:825)
            // org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisOrWrapFail(CodeAnalyser.java:217)
            // org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysis(CodeAnalyser.java:162)
            // org.benf.cfr.reader.entities.attributes.AttributeCode.analyse(AttributeCode.java:95)
            // org.benf.cfr.reader.entities.Method.analyse(Method.java:355)
            // org.benf.cfr.reader.entities.ClassFile.analyseMid(ClassFile.java:768)
            // org.benf.cfr.reader.entities.ClassFile.analyseInnerClassesPass1(ClassFile.java:681)
            // org.benf.cfr.reader.entities.ClassFile.analyseMid(ClassFile.java:764)
            // org.benf.cfr.reader.entities.ClassFile.analyseTop(ClassFile.java:700)
            // org.benf.cfr.reader.Main.doJar(Main.java:134)
            // org.benf.cfr.reader.Main.main(Main.java:189)
            throw new IllegalStateException("Decompilation failed");
        }
    }

}