/**
* 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.samples.goat.bundlecontextmodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.apache.aries.samples.goat.info.ComponentInfoImpl;
import org.apache.aries.samples.goat.info.RelationshipInfoImpl;
import org.apache.aries.samples.goat.api.ComponentInfo;
import org.apache.aries.samples.goat.api.ComponentInfoProvider;
import org.apache.aries.samples.goat.api.ModelInfoService;
import org.apache.aries.samples.goat.api.RelationshipAspect;
import org.apache.aries.samples.goat.api.RelationshipInfo;
import org.apache.aries.samples.goat.api.RelationshipInfoProvider;
public class BundleContextInfoProvider implements ModelInfoService, RelationshipInfoProvider, ComponentInfoProvider, BundleListener, ServiceListener {
private Map<String, ComponentInfo>biCache = new HashMap<String,ComponentInfo>();
private Map<String, RelationshipInfo>riCache = new HashMap<String,RelationshipInfo>();
private List<ComponentInfoListener> clisteners=null;
private List<RelationshipInfoListener> rlisteners=null;
private BundleContext ctx=null;
public BundleContextInfoProvider(BundleContext ctx){
System.err.println("BCIP built!");
this.ctx = ctx;
this.clisteners = Collections.synchronizedList(new ArrayList<ComponentInfoListener>());
this.rlisteners = Collections.synchronizedList(new ArrayList<RelationshipInfoListener>());
this.ctx.addBundleListener(this);
this.ctx.addServiceListener(this);
}
public List<ComponentInfo> getComponents() {
System.err.println("BCIP getBundles called");
Bundle[] bundles = this.ctx.getBundles();
List<ComponentInfo> result = new ArrayList<ComponentInfo>();
for(int i=0; i<bundles.length; i++){
System.err.println("BCIP converting "+i);
result.add( getComponentForId( getKeyForBundle(bundles[i])) );
}
System.err.println("BCIP returning data");
return result;
}
public void registerComponentInfoListener(ComponentInfoListener listener) {
clisteners.add(listener);
}
public void registerRelationshipInfoListener(RelationshipInfoListener listener) {
rlisteners.add(listener);
}
private Bundle getBundleForIDKey(BundleContext ctx, String id){
String s =id.substring("/root/".length());
Long l = Long.parseLong(s);
return ctx.getBundle(l.longValue());
}
private String bundleStateToString(int bundleState){
switch(bundleState){
case Bundle.UNINSTALLED : return "UNINSTALLED";
case Bundle.INSTALLED : return "INSTALLED";
case Bundle.RESOLVED : return "RESOLVED";
case Bundle.STARTING : return "STARTING";
case Bundle.STOPPING : return "STOPPING";
case Bundle.ACTIVE : return "ACTIVE";
default : return "UNKNOWN["+bundleState+"]";
}
}
public ComponentInfo getComponentForId(String id) {
if(biCache.containsKey(id)){
return biCache.get(id);
}
Bundle b = getBundleForIDKey(ctx,id);
ComponentInfoImpl bii = new ComponentInfoImpl();
bii.setId(getKeyForBundle(b));
HashSet<Long> allDepSet = new HashSet<Long>();
bii.setComponentProperties(new HashMap<String,String>());
bii.getComponentProperties().put("BundleID", ""+b.getBundleId());
bii.getComponentProperties().put("State", bundleStateToString(b.getState()));
bii.getComponentProperties().put("SymbolicName", b.getSymbolicName());
bii.getComponentProperties().put("Version", ""+b.getVersion());
Enumeration<String> e = b.getHeaders().keys();
while(e.hasMoreElements()){
String key = e.nextElement();
//Ideally we'd add everything here.. but until we add the filtering in the ui
//its easier to just filter here.. for now, all 'extra' properties are removed.
if(! (key.equals("Import-Package") || key.equals("Export-Package")) ){
//bii.getComponentProperties().put(key, String.valueOf(b.getHeaders().get(key)));
}
}
bii.setChildren(new ArrayList<ComponentInfo>());
biCache.put(id, bii);
return bii;
}
public void bundleChanged(BundleEvent arg0) {
String id = getKeyForBundle(arg0.getBundle());
if(biCache.containsKey(id)){
biCache.remove(id);
}
ComponentInfo bi = getComponentForId(getKeyForBundle(arg0.getBundle()));
for(ComponentInfoListener bil : clisteners){
bil.updateComponent(bi);
}
}
private String getKeyForBundle(Bundle b){
return "/root/"+b.getBundleId();
}
@Override
public List<RelationshipInfo> getRelationships() {
ArrayList<RelationshipInfo> r = new ArrayList<RelationshipInfo>();
Bundle bundles[] = ctx.getBundles();
PackageAdmin pa = (PackageAdmin)ctx.getService(ctx.getServiceReference(PackageAdmin.class.getName().toString()));
if(bundles!=null && bundles.length!=0){
for(Bundle b: bundles){
String bkey = getKeyForBundle(b);
ComponentInfo ci = getComponentForId(bkey);
//add all the packages..
//we only add exports, as imports are implied in the reverse
ExportedPackage eps[] = pa.getExportedPackages(b);
if(eps!=null && eps.length!=0){
for(ExportedPackage ep : eps){
RelationshipInfoImpl ri = new RelationshipInfoImpl();
ri.setProvidedBy( ci );
ri.setType("Package");
ri.setName(ep.getName());
ri.setRelationshipAspects(new ArrayList<RelationshipAspect>());
ri.setConsumedBy(new ArrayList<ComponentInfo>());
//TODO: add versioning aspect.
Bundle imps[] = ep.getImportingBundles();
if(imps!=null && imps.length!=0){
for(Bundle imp : imps){
ri.getConsumedBy().add(getComponentForId(getKeyForBundle(imp)));
}
}
r.add(ri);
}
}
//add all the services..
//we only add registered services, as ones in use are handled in the reverse
ServiceReference srs[] = b.getRegisteredServices();
if(srs!=null && srs.length!=0){
for(ServiceReference sr : srs){
RelationshipInfoImpl ri = getRIforSR(sr);
ri.setProvidedBy( ci );
r.add(ri);
}
}
}
}
return r;
}
private RelationshipInfoImpl getRIforSR(ServiceReference sr){
RelationshipInfoImpl ri = new RelationshipInfoImpl();
ri.setType("Service");
String serviceNames="";
String []objectClasses = (String[])sr.getProperty("objectClass");
if(objectClasses!=null){
for(String objectClass : objectClasses){
serviceNames+=","+objectClass;
}
}
if(serviceNames.length()>1){
serviceNames = serviceNames.substring(1);
}
ri.setName(serviceNames);
ri.setRelationshipAspects(new ArrayList<RelationshipAspect>());
//TODO: add service parameters
ri.setConsumedBy(new ArrayList<ComponentInfo>());
Bundle using[] = sr.getUsingBundles();
if(using!=null && using.length!=0){
for(Bundle u : using){
ri.getConsumedBy().add(getComponentForId(getKeyForBundle(u)));
}
}
return ri;
}
@Override
public String getName() {
return "Bundle Context Info Provider 1.0";
}
@Override
public ComponentInfoProvider getComponentInfoProvider() {
return this;
}
@Override
public RelationshipInfoProvider getRelationshipInfoProvider() {
return this;
}
@Override
public void serviceChanged(ServiceEvent arg0) {
if(arg0.getType() == ServiceEvent.REGISTERED || arg0.getType() == ServiceEvent.MODIFIED || arg0.getType() == ServiceEvent.MODIFIED_ENDMATCH){
ServiceReference sr = arg0.getServiceReference();
RelationshipInfoImpl ri = getRIforSR(sr);
ComponentInfo ci = getComponentForId(getKeyForBundle(sr.getBundle()));
ri.setProvidedBy(ci);
for(RelationshipInfoListener ril : rlisteners){
ril.updateRelationship(ri);
}
}else if(arg0.getType() == ServiceEvent.UNREGISTERING){
ServiceReference sr = arg0.getServiceReference();
RelationshipInfoImpl ri = getRIforSR(sr);
ComponentInfo ci = getComponentForId(getKeyForBundle(sr.getBundle()));
ri.setProvidedBy(ci);
for(RelationshipInfoListener ril : rlisteners){
ril.removeRelationship(ri);
}
}
}
}