/*=============================================================================*
* Copyright 2006 The Apache Software Foundation
*
* 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 org.apache.muse.core.platform.osgi.routing;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.muse.core.Environment;
import org.apache.muse.core.Resource;
import org.apache.muse.core.ResourceManager;
import org.apache.muse.core.descriptor.PersistenceDefinition;
import org.apache.muse.core.descriptor.ResourceDefinition;
import org.apache.muse.core.descriptor.RouterDefinition;
import org.apache.muse.core.descriptor.SerializerDefinition;
import org.apache.muse.core.descriptor.WsdlConfig;
import org.apache.muse.core.platform.osgi.internal.OSGiResourceManager;
import org.apache.muse.core.platform.osgi.OSGiEnvironment;
import org.apache.muse.core.platform.osgi.OSGiEnvironmentImpl;
import org.apache.muse.core.platform.osgi.OSGiPlatformConstants;
import org.apache.muse.core.platform.osgi.ResourceManagementProvider;
import org.apache.muse.core.platform.osgi.descriptor.OSGiDeploymentDescriptor;
import org.apache.muse.core.platform.osgi.util.BundleRootHelper;
import org.apache.muse.core.platform.osgi.util.OSGiReflectUtilHelper;
import org.apache.muse.core.routing.ResourceRouter;
import org.apache.muse.core.routing.RouterPersistence;
import org.apache.muse.core.routing.SimpleResourceRouter;
import org.apache.muse.core.serializer.ArraySerializer;
import org.apache.muse.core.serializer.Serializer;
import org.apache.muse.core.serializer.SerializerRegistry;
import org.apache.muse.util.ReflectUtils;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.EndpointReference;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
*
* OSGiResourceRouter is an extension of the SimpleResourceRouter that supports
* a delegation model for additional Muse-enabled Bundles. This class is intended
* for use by <code>ResourceManagementProvider</code> implementations. It is not
* intended for use by normal Muse-enabled bundles.
*
* @see ResourceManagementProvider
* @author Joel Hawkins (joelh)
*
*/
public class OSGiResourceRouter extends SimpleResourceRouter implements BundleListener{
private static HashMap bundleToDefinitionMap = new HashMap();
private static HashMap delegateMap = new HashMap();
private static HashMap deferredResources = new HashMap();
private static HashMap bundleToContextMap = new HashMap();
private static HashMap contextToBundleMap = new HashMap();
private static ResourceManagementProvider provider;
private static OSGiResourceRouter _router = new OSGiResourceRouter();
public static OSGiResourceRouter getDefault(){ return _router;}
protected ResourceManager createResourceManager() {
OSGiResourceManager manager = new OSGiResourceManager();
return manager;
}
public Bundle getDelegateBundle(){
Environment env = getEnvironment();
EndpointReference epr = env.getAddressingContext().getToAddress();
String address = epr.getAddress().toString();
Iterator keys = contextToBundleMap.keySet().iterator();
while(keys.hasNext()){
String currentKey = (String)keys.next();
if(address.endsWith(currentKey)){
return (Bundle)contextToBundleMap.get(currentKey);
}
}
return null;
}
public Element invoke(Element soapBody){
Resource resource = null;
try {
Bundle bundle = getDelegateBundle();
ResourceRouter delegateRouter = null;
if(bundle != null){
delegateRouter = (ResourceRouter)delegateMap.get(bundle);
}
((OSGiEnvironment)getEnvironment()).setThreadLocalBundle(bundle);
return delegateRouter.invoke(soapBody);
} finally {
((OSGiEnvironment)getEnvironment()).setThreadLocalBundle(null);
}
}
public void setEnvironment(Environment environment) {
super.setEnvironment(environment);
//set the environment of all the delegates
if (!deferredResources.isEmpty()) {
synchronized (deferredResources) {
Iterator iter = deferredResources.keySet().iterator();
while (iter.hasNext()) {
Bundle bundle = (Bundle) iter.next();
try {
String target = (String) bundle.getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_MANIFEST_HEADER);
URL resourceURL = bundle.getResource(target);
((OSGiEnvironment) this.getEnvironment())
.setThreadLocalBundle(bundle);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(bundle);
addResourceDefinitions(bundle, resourceURL);
} catch (Throwable t) {
t.printStackTrace();
} finally {
((OSGiEnvironment) this.getEnvironment())
.setThreadLocalBundle(null);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(null);
}
}
//TODO I think we just set these to FALSE
deferredResources.clear();
}
}
}
public void initialize(BundleContext context) {
context.addBundleListener(this);
Bundle bundles[] = context.getBundles();
OSGiEnvironment env = new OSGiEnvironmentImpl(false);
for (int i = 0; i < bundles.length; i++) {
switch (bundles[i].getState()) {
case Bundle.ACTIVE:
case Bundle.RESOLVED:
case Bundle.STARTING:
String target = (String) bundles[i].getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_MANIFEST_HEADER);
String contextPath = (String) bundles[i].getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
if (target != null) {
registerBundleResources(bundles[i], contextPath, target);
}
break;
default:
break;
}
}
}
private class ContextInfo {
public ContextInfo(String contextPath, String wsdlPath){
this.contextPath = contextPath;
this.wsdlPath = wsdlPath;
}
public String getContextPath(){
return contextPath;
}
private String getWsdlPath(){
return wsdlPath;
}
private String contextPath;
private String wsdlPath;
}
private Collection getContextPathsForBundle(Bundle bundle, String target) {
ArrayList list = new ArrayList();
OSGiEnvironment env = new OSGiEnvironmentImpl(false);
env.setThreadLocalBundle(bundle);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(bundle);
try {
Document ddXML = env.getDocument(target);
OSGiDeploymentDescriptor dd = new OSGiDeploymentDescriptor();
Collection resourceDefs = dd.loadContextPaths(ddXML, env);
Iterator paths = resourceDefs.iterator();
String contextPath = (String) bundle.getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
while (paths.hasNext()) {
String context = (String) paths.next();
String wsdlPath = dd.getWsdlPathForContext(ddXML, context);
//FIXME - this will work for Axis - not sure about others
contextToBundleMap.put(contextPath + "/services/" + context, bundle);
list.add(new ContextInfo(context, wsdlPath));
}
this.bundleToContextMap.put(bundle, new ArrayList(list));
} catch (Throwable t) {
t.printStackTrace();
}
return list;
}
private void deployManagementServices(Bundle bundle, String contextName, String target){
Collection contextPaths = getContextPathsForBundle(bundle, target);
Iterator i = contextPaths.iterator();
while (i.hasNext()) {
ContextInfo info = (ContextInfo)i.next();
String path = info.getContextPath();
String wsdl = info.getWsdlPath();
String trimmedPath = path;
if (trimmedPath.startsWith("/"))
trimmedPath = trimmedPath.substring(1);
try {
provider.deployManagementService(bundle, contextName, trimmedPath, wsdl);
BundleRootHelper.registerContext(bundle,contextName);
} catch (Exception e) {
// TODO requeue?
e.printStackTrace();
}
}
}
public void attachManagementProvider(ResourceManagementProvider provider) {
this.provider = provider;
synchronized(deferredResources){
Iterator i = deferredResources.keySet().iterator();
while(i.hasNext()){
Bundle bundle = (Bundle)i.next();
Boolean resource = (Boolean)deferredResources.get(bundle);
if(resource != null && resource.booleanValue()){
String target = (String) bundle.getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_MANIFEST_HEADER);
String contextPath = (String) bundle.getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
deployManagementServices(bundle, contextPath, target);
deferredResources.put(bundle, Boolean.FALSE);
}
}
}
}
public void releaseManagementProvider() {
provider = null;
}
protected void addResourceDefinitions(Bundle bundle, Collection definitions) {
if (definitions.isEmpty())
return;
synchronized (bundleToDefinitionMap) {
bundleToDefinitionMap.put(bundle, definitions);
}
}
public Document getDocument(Bundle bundle, URL resourceConfig) {
try {
return XmlUtils.createDocument(resourceConfig.openStream());
}
catch (Exception error) {
error.printStackTrace();
return null;
}
}
protected void deferBundleResources(Bundle bundle, String contextName,
String target) {
// Register the resource contexts with the soap provider
synchronized(deferredResources){
if (provider != null) {
if(Boolean.TRUE.equals(deferredResources.get(bundle))){
deployManagementServices(bundle, contextName, target);
deferredResources.put(bundle, Boolean.FALSE);
}
} else {
deferredResources.put(bundle, Boolean.TRUE);
}
}
}
protected void addResourceDefinitions(Bundle bundle, URL resourceConfig) {
OSGiDeploymentDescriptor dd = new OSGiDeploymentDescriptor();
Document ddXML = getDocument(bundle, resourceConfig);
if (ddXML == null)
return;
try {
dd.setBundle(bundle);
dd.load(ddXML, this.getEnvironment());
//
// put all custom serializers in the serializer registry
//
Collection serializerDefinitions = dd.getSerializerDefinitions();
Iterator i = serializerDefinitions.iterator();
SerializerRegistry registry = SerializerRegistry.getInstance();
while (i.hasNext()) {
SerializerDefinition next = (SerializerDefinition) i.next();
Serializer ser = next.create();
Class type = ser.getSerializableType();
Class arrayType = ReflectUtils.getArrayClassFromClass(type);
Serializer arraySer = new ArraySerializer(arrayType, ser);
registry.registerSerializer(type, ser);
registry.registerSerializer(arrayType, arraySer);
}
//
// check for any specified router - this may be used
// as a delegate when trying to resolve a reference
// to a resource
//
RouterDefinition rd = dd.getRouterDefinition();
Class delegateRouter = rd.getRouterClass();
ResourceRouter delegate = null;
//initialize persistence for router
PersistenceDefinition persistenceDef = rd.getPersistenceDefinition();
if(delegateRouter != null){
delegate = rd.newInstance();
if(persistenceDef != null){
RouterPersistence persistence = (RouterPersistence)persistenceDef.newInstance();
delegate.setPersistence(persistence);
}
delegate.initialize();
}
Collection resourceDefs = dd.getResourceDefinitions();
this.addResourceDefinitions(bundle, resourceDefs);
if(delegate != null){
delegateMap.put(bundle, delegate);
Iterator iter = resourceDefs.iterator();
while(iter.hasNext()){
ResourceDefinition def = (ResourceDefinition)iter.next();
String contextPath = (String) bundle.getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
def.getContextPath();
contextToBundleMap.put(contextPath + "/services/" + def.getContextPath(), bundle);
}
}
} catch (Throwable t) {
// Log the error somewhere
t.printStackTrace();
}
}
protected synchronized void registerBundleResources(Bundle bundle, String contextPath,
String target) {
OSGiEnvironment env = (OSGiEnvironment) this.getEnvironment();
if (env != null) {
URL resourceURL = bundle.getResource(target);
try {
env.setThreadLocalBundle(bundle);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(bundle);
addResourceDefinitions(bundle, resourceURL);
} catch (Throwable t) {
// TODO JOEL log this somewhere.
t.printStackTrace();
} finally {
((OSGiEnvironment) this.getEnvironment())
.setThreadLocalBundle(null);
OSGiReflectUtilHelper.getDefault().setThreadLocalBundle(null);
}
} else {
deferBundleResources(bundle, contextPath, target);
}
}
protected void removeBundleResources(Bundle bundle){
//FIXME cleanup
}
public void bundleChanged(BundleEvent event) {
String target;
Bundle bundle;
switch (event.getType()) {
case BundleEvent.INSTALLED:
break;
case BundleEvent.RESOLVED:
// Check for SOA deployment information
target = (String) event.getBundle().getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_MANIFEST_HEADER);
String contextPath = (String) event.getBundle().getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
bundle = event.getBundle();
if (target != null) {
if (this.getEnvironment() != null) {
URL resourceURL = bundle.getResource(target);
addResourceDefinitions(bundle, resourceURL);
} else {
registerBundleResources(bundle, contextPath, target);
}
}
break;
case BundleEvent.STARTING:
break;
case BundleEvent.STARTED:
// Check for SOA deployment information
target = (String) event.getBundle().getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_MANIFEST_HEADER);
contextPath = (String) event.getBundle().getHeaders().get(
OSGiPlatformConstants.MANAGEMENT_CONTEXT_HEADER);
bundle = event.getBundle();
if (target != null) {
// process SOA artifacts - expecting a set of comma-delimited
// names.
// The lookup process is as follows - look in configuration
// repository,
// then look in bundle classpath
if (getEnvironment() != null) {
((OSGiEnvironment)getEnvironment()).setThreadLocalBundle(event.getBundle());
URL resourceURL = bundle.getResource(target);
addResourceDefinitions(bundle, resourceURL);
((OSGiEnvironment)getEnvironment()).setThreadLocalBundle(null);
} else {
registerBundleResources(bundle, contextPath, target);
}
}
break;
case BundleEvent.STOPPING:
break;
case BundleEvent.STOPPED:
removeBundleResources(event.getBundle());
break;
case BundleEvent.UNINSTALLED:
break;
case BundleEvent.UNRESOLVED:
break;
case BundleEvent.UPDATED:
break;
default:
break;
}
}
}