All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.cq.upgradesexecutor.Activator Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2012 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.cq.upgradesexecutor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.jcr.Item;
import javax.jcr.Session;

import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.launchpad.api.StartupHandler;
import org.apache.sling.launchpad.api.StartupMode;
import org.apache.sling.startupfilter.StartupInfoProvider;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.compat.codeupgrade.CodeUpgradeTask;

/** Run CodeUpgradeTasks, synchronously in the Activator.start() method */ 
public class Activator implements BundleActivator {
    private final Logger log = LoggerFactory.getLogger(getClass());
    
    /** If this property is true, upgrades execute whatever the StartupMode is.
     *  Useful for troubleshooting the upgrade code. */
    public static final String FORCE_UPGRADES_PATH = "/var/upgrade/status/upgradesExecutor.forceUpgrades";

    /** Provides informational status messages in the 503 responses that CQ
     *  returns during startup.
     */
    class InfoProvider implements StartupInfoProvider {

        private String progressInfo = "Initializing";
        private volatile CodeUpgradeTask task;
        
        public String getProgressInfo() {
            if(task != null) {
                String info = task.getProgressInfo();
                if(info == null) {
                    info = "No info yet";
                }
                return "Running " + task + ": " + info; 
            }
            return progressInfo;
        }
        
        void say(String info) {
            log.info(info);
            progressInfo = info;
        }
        
        void setTask(CodeUpgradeTask t) {
            task = t;
        }
    };
    
    /** When this bundle starts, execute all available CodeUpgradeTasks
     *  if StartupMode is UPDATE.
     */
    public void start(BundleContext context) throws Exception {
        // Nothing to do unless startup mode is UPDATE
        final ServiceReference ref = context.getServiceReference(StartupHandler.class.getName());
        if(ref == null) {
            throw new IllegalStateException(
                    "StartupHandler not found, cannot decide whether to run upgrade code or not");
        }
        final StartupHandler sh = (StartupHandler)context.getService(ref);
        final StartupMode sm = sh.getMode();
        if(sm != StartupMode.UPDATE) {
            // If we have a repository service and the FORCE_UPGRADES_PATH property is
            // true, force upgrade code to run
            boolean force = false;
            final ServiceReference repoRef = context.getServiceReference(SlingRepository.class.getName());
            if(repoRef != null) {
                final SlingRepository repo = (SlingRepository)context.getService(repoRef);
                final Session s = repo.loginAdministrative(repo.getDefaultWorkspace());
                try {
                    if(s.itemExists(FORCE_UPGRADES_PATH)) {
                        final Item it = s.getItem(FORCE_UPGRADES_PATH);
                        if(!it.isNode()) {
                            force = s.getProperty(FORCE_UPGRADES_PATH).getBoolean();
                            log.warn("{}=true will force upgrade code to run every time this bundle is started - "
                                    + " if this is not desired, remove that property",
                                    FORCE_UPGRADES_PATH);
                        }
                    }
                } finally {
                    s.logout();
                }
            }
            
            if(force) {
                log.info("StartupMode is {} but {} is true, executing upgrade tasks", sm, FORCE_UPGRADES_PATH);
            } else {
                log.info("UPGRADE NOT NEEDED - StartupMode is {}", sm);
                return;
            }
        }
        
        log.info("UPGRADE STARTS - StartupMode is {}", sm);
        
        // StartupInfoProvider progress info is included in the 503
        // response that CQ provides during startup
        final InfoProvider ip = new InfoProvider();
        ServiceRegistration reg = null;
        try {
            reg = context.registerService(StartupInfoProvider.class.getName(), ip, null);
            runUpgradeTasks(context, ip);
        } finally {
            reg.unregister();
        }
    }

    public void stop(BundleContext context) throws Exception {
        // nothing to do
    }
    
    private void runUpgradeTasks(BundleContext context, InfoProvider ip) throws InvalidSyntaxException {
        ip.say("Collecting CodeUpgradeTasks");
        
        // Get tasks and sort by service ranking
        final ServiceReference [] refs = context.getServiceReferences(CodeUpgradeTask.class.getName(), null);
        if(refs == null || refs.length < 1) {
            log.info("NO UPGRADE TASKS - no {} services found, nothing to do", CodeUpgradeTask.class.getName());
            return;
        }
        Arrays.sort(refs);
        
        // Collect tasks
        final List tasks = new ArrayList();
        for(ServiceReference ref : refs) {
            tasks.add((CodeUpgradeTask)context.getService(ref));
        }
        
        // Execute tasks
        final long startTime = System.currentTimeMillis();
        ip.say("Checking " + refs.length + " candidate CodeUpgradeTasks: " + tasks);
        int executed = 0;
        for(CodeUpgradeTask t : tasks) {
            if(t.upgradeNeeded()) {
                try {
                    ip.say("UPGRADE TASK STARTING: " + t);
                    ip.setTask(t);
                    t.run();
                    ip.setTask(null);
                    ip.say("UPGRADE TASK DONE: " + t);
                    executed++;
                } finally {
                    ip.setTask(null);
                }
            } else {
                ip.say("UPGRADE TASK SKIPPED: " + t);
            }
        }
        
        final long elapsed = System.currentTimeMillis() - startTime;
        log.info("UPGRADE FINISHED: {} CodeUpgradeTasks executed (out of {}), total time about {} seconds", 
                new Object[] { executed, refs.length, elapsed / 1000 });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy