/*
* Copyright 2012 Jörg Hoh, Alexander Saar, Markus Haack
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.joerghoh.cq5.jmx.bundles;
import java.util.Dictionary;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* This class makes some OSGI bundle statistics available tbe Mbean "de.joerghoh.cq5.jmx:id=bundles".
*
* Currently these are:
* * the number of bundles in active state
* * the number of bundles in installed state
* * the number of bundles in resolved state
* * the number of fragment bundles
*
* Usually you would observe the number of bundles in installed and resolved state and make
* sure that these numbers are always 0.
*
* Also a blacklist feature is available. Bundles on this blacklist are ignored when
* counting the numbers listed above. If you need to have bundles not in an active state
* (best example: org.apache.sling.jcr.webdav due to the CQ5 security checklist), you can put
* the symbolic name of it to the blacklist. Then you still can check the number of bundles in
* installed state for being 0.
*
*
* @author joerg@joerghoh.de
*
*/
@Component(immediate = true, metatype = true, description = "Exports some bundle status to JMX", label = "JMX bundle status provider")
@Service(value = BundleStatusMBean.class)
@Properties({
@Property(name = "jmx.objectname", value = "de.joerghoh.cq5.jmx:id=bundles", propertyPrivate=true)
})
public class BundleStatusImpl implements BundleStatusMBean {
Logger log = LoggerFactory.getLogger(this.getClass());
@Property(cardinality=Integer.MAX_VALUE, description="The symbolic name of bundles which should be ignored", label="Ignored bundles")
private final static String PROP_IGNORED_BUNDLES="ignoredBundles";
String[] ignored_bundles;
private BundleContext bctx;
// TODO implement event listening??
public int getActiveBundles() {
Bundle[] bundles = bctx.getBundles();
int activeBundleCount = 0;
for (Bundle b : bundles) {
if (isIgnored(b)) {
continue;
}
@SuppressWarnings("unchecked")
Dictionary<String, String> headers = b.getHeaders();
boolean isFragment = (headers.get("Fragment-Host") != null);
boolean isActive = (b.getState() == Bundle.ACTIVE);
if (!isFragment && isActive) {
activeBundleCount++;
}
}
return activeBundleCount;
}
@Activate
protected void activate(ComponentContext ctx) {
bctx = ctx.getBundleContext();
ignored_bundles = PropertiesUtil.toStringArray(ctx.getProperties().get(PROP_IGNORED_BUNDLES));
if (ignored_bundles != null ) {
log.info ("Ignoring bundles {}", ignored_bundles.toString());
}
}
public int getFragmentBundles() {
Bundle[] bundles = bctx.getBundles();
int fragmentBundleCount = 0;
for (Bundle b : bundles) {
if (isIgnored(b)) {
continue;
}
@SuppressWarnings("unchecked")
Dictionary<String, String> headers = b.getHeaders();
boolean isFragment = (headers.get("Fragment-Host") != null);
if (isFragment) {
fragmentBundleCount++;
}
}
return fragmentBundleCount;
}
public int getInstalledBundles() {
Bundle[] bundles = bctx.getBundles();
int installedBundleCount = 0;
for (Bundle b : bundles) {
if (isIgnored(b)) {
continue;
}
boolean isInstalled = (b.getState() == Bundle.INSTALLED);
if (isInstalled) {
installedBundleCount++;
}
}
return installedBundleCount;
}
public int getResolvedBundles() {
Bundle[] bundles = bctx.getBundles();
int resolvedBundleCount = 0;
for (Bundle b : bundles) {
if (isIgnored(b)) {
continue;
}
@SuppressWarnings("unchecked")
Dictionary<String, String> headers = b.getHeaders();
boolean isResolved = (b.getState() == Bundle.RESOLVED);
boolean isFragment = (headers.get("Fragment-Host") != null);
if (isResolved && !isFragment) {
resolvedBundleCount++;
}
}
return resolvedBundleCount;
}
/**
* helper method to determine if a certain bundel is
* on the ignored_bundles list.
* @param b the bundle to check
* @return true if the bundle should be ignored
*/
private boolean isIgnored(Bundle b) {
if (ignored_bundles == null) {
return false;
}
String name = b.getSymbolicName();
for (int i=0; i< ignored_bundles.length;i++) {
String ignored = ignored_bundles[i];
if (ignored.equals(name)) {
return true;
}
}
return false;
}
}