InactiveBundlesHealthCheck.java 6.12 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  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.PropertyUnbounded
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.apache.sling.hc.api.HealthCheck
 *  org.apache.sling.hc.api.Result
 *  org.apache.sling.hc.api.ResultLog
 *  org.apache.sling.hc.util.FormattingResultLog
 *  org.osgi.framework.Bundle
 *  org.osgi.framework.BundleContext
 *  org.osgi.framework.Version
 *  org.osgi.service.component.ComponentContext
 */
package com.adobe.granite.bundles.hc.impl;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
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.PropertyUnbounded;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.hc.api.HealthCheck;
import org.apache.sling.hc.api.Result;
import org.apache.sling.hc.api.ResultLog;
import org.apache.sling.hc.util.FormattingResultLog;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Version;
import org.osgi.service.component.ComponentContext;

@Component(metatype=1, label="Adobe Granite Active Bundles Health Check", description="This health check scan the current set of OSGi bundles for inactive bundles.")
@Properties(value={@Property(name="hc.name", value={"Active Bundles"}, propertyPrivate=1), @Property(name="hc.tags", unbounded=PropertyUnbounded.ARRAY, label="Tags", description="Tags for this check to be used by composite health checks."), @Property(name="hc.mbean.name", value={"inactiveBundles"}, propertyPrivate=1)})
@Service(value={HealthCheck.class})
public class InactiveBundlesHealthCheck
implements HealthCheck {
    @Property(label="Ignored Bundles", description="One or more Bundle Symbolic Names to be ignored.", unbounded=PropertyUnbounded.ARRAY, value={"com.day.crx.crxde-support", "com.adobe.granite.crx-explorer", "com.adobe.granite.crxde-lite"})
    private static final String PROP_IGNORED_BUNDLES = "ignored.bundles";
    private Set<String> ignoredBundles;
    private BundleContext bundleContext;
    private Dictionary<Integer, String> bundleState;

    private void populateBundleStateDictionary() {
        this.bundleState = new Hashtable<Integer, String>();
        this.bundleState.put(32, "Active");
        this.bundleState.put(2, "Installed");
        this.bundleState.put(4, "Resolved");
        this.bundleState.put(8, "Starting");
        this.bundleState.put(16, "Stopping");
        this.bundleState.put(1, "Uninstalled");
    }

    @Activate
    protected void activate(ComponentContext cc) {
        this.bundleContext = cc.getBundleContext();
        String[] ignored = PropertiesUtil.toStringArray(cc.getProperties().get("ignored.bundles"), (String[])null);
        this.ignoredBundles = ignored == null ? Collections.emptySet() : Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(ignored)));
        this.populateBundleStateDictionary();
    }

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

    public Result execute() {
        Bundle[] bundles;
        FormattingResultLog resultLog = new FormattingResultLog();
        int inactiveBundles = 0;
        for (Bundle b : bundles = this.bundleContext.getBundles()) {
            if (InactiveBundlesHealthCheck.isBundleActive(b) || this.isIgnored(b)) continue;
            ++inactiveBundles;
            resultLog.warn("Bundle {}:{} is in the following state: {}", new Object[]{b.getSymbolicName(), b.getVersion(), this.bundleState.get(b.getState())});
        }
        if (this.ignoredBundles != null && this.ignoredBundles.size() > 0) {
            StringBuilder builder = new StringBuilder();
            for (String bundle : this.ignoredBundles) {
                builder.append(bundle).append(", ");
            }
            builder.delete(builder.length() - 2, builder.length());
            resultLog.info("[The following bundles are added to the ignore list and do not count towards the health check output: {}.]( )", new Object[]{builder.toString()});
            resultLog.info("[You can add or remove bundles to the ignore list by changing the InactiveBundlesHealthCheck configuration in the administration console.]( )", new Object[0]);
        }
        if (inactiveBundles > 0) {
            String msg = inactiveBundles == 1 ? "[There is one inactive bundle. You can view it or change its status in the administration console.]" : MessageFormat.format("[There are {0} inactive bundles. You can view them or change their status in the administration console.]", inactiveBundles);
            resultLog.info(msg + "(/system/console/bundles)", new Object[0]);
        } else {
            resultLog.debug("No inactive or unresolved bundles were found.", new Object[0]);
        }
        return new Result((ResultLog)resultLog);
    }

    private boolean isIgnored(Bundle b) {
        return this.ignoredBundles.contains(b.getSymbolicName());
    }

    private static boolean isBundleActive(Bundle b) {
        if (b.getState() == 32) {
            return true;
        }
        if (b.getState() == 8 && InactiveBundlesHealthCheck.isLazyActivatian(b)) {
            return true;
        }
        return InactiveBundlesHealthCheck.getFragmentHostHeader(b) != null;
    }

    private static String getFragmentHostHeader(Bundle b) {
        return (String)b.getHeaders().get("Fragment-Host");
    }

    private static boolean isLazyActivatian(Bundle b) {
        return "lazy".equals(b.getHeaders().get("Bundle-ActivationPolicy"));
    }
}