/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.aries.jmx.framework.wiring;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import org.apache.aries.jmx.Logger;
import org.apache.aries.jmx.codec.BundleWiringData;
import org.apache.aries.jmx.util.FrameworkUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRequirement;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleRevisions;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.jmx.framework.wiring.BundleWiringStateMBean;
public class BundleWiringState implements BundleWiringStateMBean {
private final BundleContext bundleContext;
private final Logger logger;
public BundleWiringState(BundleContext bundleContext, Logger logger) {
this.bundleContext = bundleContext;
this.logger = logger;
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getCurrentRevisionDeclaredRequirements(long, java.lang.String)
*/
public CompositeData[] getCurrentRevisionDeclaredRequirements(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevision revision = bundle.adapt(BundleRevision.class);
return BundleWiringData.getRequirementsCompositeData(revision.getDeclaredRequirements(namespace));
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getCurrentRevisionDeclaredCapabilities(long, java.lang.String)
*/
public CompositeData[] getCurrentRevisionDeclaredCapabilities(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevision revision = bundle.adapt(BundleRevision.class);
return BundleWiringData.getCapabilitiesCompositeData(revision.getDeclaredCapabilities(namespace));
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getCurrentWiring(long, java.lang.String)
*/
public CompositeData getCurrentWiring(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevision currentRevision = bundle.adapt(BundleRevision.class);
Map<BundleRevision, Integer> revisionIDMap = getCurrentRevisionTransitiveRevisionsClosure(bundleId, namespace);
return getRevisionWiring(currentRevision, 0, namespace, revisionIDMap);
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getCurrentWiringClosure(long)
*/
public TabularData getCurrentWiringClosure(long rootBundleId, String namespace) throws IOException {
Map<BundleRevision, Integer> revisionIDMap = getCurrentRevisionTransitiveRevisionsClosure(rootBundleId, namespace);
TabularData td = new TabularDataSupport(BundleWiringStateMBean.BUNDLES_WIRING_TYPE);
for (Map.Entry<BundleRevision, Integer> entry : revisionIDMap.entrySet()) {
td.put(getRevisionWiring(entry.getKey(), entry.getValue(), namespace, revisionIDMap));
}
return td;
}
// The current revision being passed in always gets assigned revision ID 0
// All the other revision IDs unique, but don't increase monotonous.
private Map<BundleRevision, Integer> getCurrentRevisionTransitiveRevisionsClosure(long rootBundleId, String namespace) throws IOException {
Bundle rootBundle = FrameworkUtils.resolveBundle(bundleContext, rootBundleId);
BundleRevision rootRevision = rootBundle.adapt(BundleRevision.class);
return getRevisionTransitiveClosure(rootRevision, namespace);
}
private Map<BundleRevision, Integer> getRevisionTransitiveClosure(BundleRevision rootRevision, String namespace) {
Map<BundleRevision, Integer> revisionIDMap = new HashMap<BundleRevision, Integer>();
populateTransitiveRevisions(namespace, rootRevision, revisionIDMap);
// Set the root revision ID to 0,
// TODO check if there is already a revision with ID 0 and if so swap them. Quite a small chance that this will be needed
revisionIDMap.put(rootRevision, 0);
return revisionIDMap;
}
private void populateTransitiveRevisions(String namespace, BundleRevision rootRevision, Map<BundleRevision, Integer> allRevisions) {
allRevisions.put(rootRevision, System.identityHashCode(rootRevision));
BundleWiring wiring = rootRevision.getWiring();
if (wiring == null)
return;
List<BundleWire> requiredWires = wiring.getRequiredWires(namespace);
for (BundleWire wire : requiredWires) {
BundleRevision revision = wire.getCapability().getRevision();
if (!allRevisions.containsKey(revision)) {
populateTransitiveRevisions(namespace, revision, allRevisions);
}
}
List<BundleWire> providedWires = wiring.getProvidedWires(namespace);
for (BundleWire wire : providedWires) {
BundleRevision revision = wire.getRequirement().getRevision();
if (!allRevisions.containsKey(revision)) {
populateTransitiveRevisions(namespace, revision, allRevisions);
}
}
}
private CompositeData getRevisionWiring(BundleRevision revision, int revisionID, String namespace, Map<BundleRevision, Integer> revisionIDMap) {
BundleWiring wiring = revision.getWiring();
List<BundleCapability> capabilities = wiring.getCapabilities(namespace);
List<BundleRequirement> requirements = wiring.getRequirements(namespace);
List<BundleWire> providedWires = wiring.getProvidedWires(namespace);
List<BundleWire> requiredWires = wiring.getRequiredWires(namespace);
BundleWiringData data = new BundleWiringData(wiring.getBundle().getBundleId(), revisionID, capabilities, requirements, providedWires, requiredWires, revisionIDMap);
return data.toCompositeData();
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getRevisionsDeclaredRequirements(long, java.lang.String, boolean)
*/
public TabularData getRevisionsDeclaredRequirements(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
TabularData td = new TabularDataSupport(BundleWiringStateMBean.REVISIONS_REQUIREMENTS_TYPE);
for (BundleRevision revision : revisions.getRevisions()) {
td.put(BundleWiringData.getRevisionRequirements(
System.identityHashCode(revision),
revision.getDeclaredRequirements(namespace)));
}
return td;
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getRevisionsDeclaredCapabilities(long, java.lang.String, boolean)
*/
public TabularData getRevisionsDeclaredCapabilities(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
TabularData td = new TabularDataSupport(BundleWiringStateMBean.REVISIONS_CAPABILITIES_TYPE);
for (BundleRevision revision : revisions.getRevisions()) {
td.put(BundleWiringData.getRevisionCapabilities(
System.identityHashCode(revision),
revision.getDeclaredCapabilities(namespace)));
}
return td;
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getRevisionsWiring(long, java.lang.String)
*/
public TabularData getRevisionsWiring(long bundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, bundleId);
BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
TabularData td = new TabularDataSupport(BundleWiringStateMBean.BUNDLES_WIRING_TYPE);
for (BundleRevision revision : revisions.getRevisions()) {
Map<BundleRevision, Integer> revisionIDMap = getRevisionTransitiveClosure(revision, namespace);
td.put(getRevisionWiring(revision, System.identityHashCode(revision), namespace, revisionIDMap));
}
return td;
}
/* (non-Javadoc)
* @see org.osgi.jmx.framework.BundleRevisionsStateMBean#getWiringClosure(long, java.lang.String)
*/
public TabularData getRevisionsWiringClosure(long rootBundleId, String namespace) throws IOException {
Bundle bundle = FrameworkUtils.resolveBundle(bundleContext, rootBundleId);
BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
Map<BundleRevision, Integer> revisionIDMap = new HashMap<BundleRevision, Integer>();
for (BundleRevision revision : revisions.getRevisions()) {
populateTransitiveRevisions(namespace, revision, revisionIDMap);
}
// Set the root current revision ID to 0,
// TODO check if there is already a revision with ID 0 and if so swap them. Quite a small chance that this will be needed
BundleRevision revision = bundle.adapt(BundleRevision.class);
revisionIDMap.put(revision, 0);
TabularData td = new TabularDataSupport(BundleWiringStateMBean.BUNDLES_WIRING_TYPE);
for (Map.Entry<BundleRevision, Integer> entry : revisionIDMap.entrySet()) {
td.put(getRevisionWiring(entry.getKey(), entry.getValue(), namespace, revisionIDMap));
}
return td;
}
}