Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/AriesProxyService.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/AriesProxyService.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/AriesProxyService.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/AriesProxyService.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,238 @@ +/** + * 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.ejb.openejb.extender; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + +import javax.resource.spi.IllegalStateException; + +import org.apache.aries.proxy.InvocationListener; +import org.apache.aries.proxy.ProxyManager; +import org.apache.aries.proxy.UnableToProxyException; +import org.apache.aries.util.tracker.SingleServiceTracker; +import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener; +import org.apache.openejb.OpenEJBException; +import org.apache.openejb.util.proxy.InvocationHandler; +import org.apache.openejb.util.proxy.ProxyFactory; +import org.osgi.framework.BundleContext; + +public class AriesProxyService implements ProxyFactory, SingleServiceListener { + + private static class NoProxySupportException extends RuntimeException { + public NoProxySupportException() { + super("No Proxy support is available"); + } + } + + private static final class InvocationHandlerProxy implements Callable<Object>, InvocationListener { + + private final InvocationHandler handler; + + private final Map<Thread, Class<?>> invocations = new ConcurrentHashMap<Thread, Class<?>>(); + private final ConcurrentMap<Class<?>, Object> proxys = new ConcurrentHashMap<Class<?>, Object>(); + + public InvocationHandlerProxy(InvocationHandler handler) { + this.handler = handler; + } + + public InvocationHandler getHandler() { + return handler; + } + + public void postInvoke(Object arg0, Object arg1, Method arg2, Object arg3) + throws Throwable { + // No op + } + + public void postInvokeExceptionalReturn(Object arg0, Object arg1, + Method arg2, Throwable arg3) throws Throwable { + //No op + } + + public Object preInvoke(Object arg0, Method arg1, Object[] arg2) + throws Throwable { + invocations.put(Thread.currentThread(), arg1.getDeclaringClass()); + return null; + } + + public Object call() throws Exception { + Class<?> c = invocations.remove(Thread.currentThread()); + if(c == null) + throw new IllegalStateException("Unable to establish any context"); + else if (c.equals(Object.class)) { + c = Serializable.class; + } + + Object proxy = proxys.get(c); + + if(proxy == null) { + Object tmp = Proxy.newProxyInstance(c.getClassLoader(), new Class[] {c}, handler); + proxy = proxys.putIfAbsent(c, tmp); + if(proxy == null) + proxy = tmp; + } + return proxy; + } + + } + + private static class InnerProxyDelegator implements Callable<Object> { + + private final Object delegate; + + public InnerProxyDelegator(Object delegate) { + this.delegate = delegate; + } + + public Object call() { + return delegate; + } + } + + private final Map<Class<?>, Object> proxies = Collections.synchronizedMap( + new WeakHashMap<Class<?>, Object>()); + + private final SingleServiceTracker<ProxyManager> proxyTracker; + + private AriesProxyService(BundleContext ctx) { + proxyTracker = new SingleServiceTracker<ProxyManager>(ctx, ProxyManager.class, this); + proxyTracker.open(); + } + + private final AtomicReference<ProxyManager> manager = + new AtomicReference<ProxyManager>(); + + private static final AtomicReference<AriesProxyService> INSTANCE = + new AtomicReference<AriesProxyService>(); + + private final ProxyManager getManager() { + ProxyManager pManager = manager.get(); + + if(pManager == null) { + throw new NoProxySupportException(); + } + return pManager; + } + + public static AriesProxyService get() { + return INSTANCE.get(); + } + + public static void init(BundleContext ctx) { + AriesProxyService oTM = new AriesProxyService(ctx); + if(!!!INSTANCE.compareAndSet(null, oTM)) + oTM.destroy(); + } + + public void destroy() { + proxyTracker.close(); + } + + public void serviceFound() { + update(); + } + + public void serviceLost() { + update(); + } + + public void serviceReplaced() { + update(); + } + + private void update() { + manager.set(proxyTracker.getService()); + } + + + + public InvocationHandler getInvocationHandler(Object arg0) + throws IllegalArgumentException { + Callable<Object> unwrapped = getManager().unwrap(arg0); + + if(unwrapped instanceof InnerProxyDelegator) { + unwrapped = getManager().unwrap(((InnerProxyDelegator)unwrapped).call()); + } + + if(unwrapped instanceof InvocationHandlerProxy) { + return ((InvocationHandlerProxy) unwrapped).getHandler(); + } + return null; + } + + public Class getProxyClass(Class iface) throws IllegalArgumentException { + if(iface == null || !!!iface.isInterface()) + throw new IllegalArgumentException("Not an interface " + iface); + return newProxyInstance(iface, null).getClass(); + } + + public Class getProxyClass(Class[] ifaces) throws IllegalArgumentException { + if(ifaces == null || ifaces.length == 0) + throw new IllegalArgumentException("No interfaces."); + + for(Class iface : ifaces) { + if (!!!iface.isInterface()) + throw new IllegalArgumentException("Not an interface " + iface + " in " + Arrays.toString(ifaces)); + } + + return newProxyInstance(ifaces, null).getClass(); + } + + public void init(Properties arg0) throws OpenEJBException { + //No op + } + + public boolean isProxyClass(Class arg0) { + return proxies.containsKey(arg0); + } + + public Object newProxyInstance(Class iface, InvocationHandler arg1) + throws IllegalArgumentException { + return newProxyInstance(new Class[] {iface}, arg1); + } + + public Object newProxyInstance(Class[] ifaces, InvocationHandler arg1) + throws IllegalArgumentException { + InvocationHandlerProxy ihProxy = new InvocationHandlerProxy(arg1); + List<Class<?>> classes = new ArrayList<Class<?>>(); + for(Class<?> iface : ifaces) + classes.add(iface); + try { + Object inner = getManager().createDelegatingProxy(null, classes, ihProxy, null); + + Object proxy = getManager().createDelegatingInterceptingProxy(null, classes, + new InnerProxyDelegator(inner), null, ihProxy); + proxies.put(proxy.getClass(), null); + return proxy; + } catch (UnableToProxyException e) { + throw new IllegalArgumentException(e); + } + } +}
Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBExtender.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBExtender.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBExtender.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBExtender.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,405 @@ +/** + * 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.ejb.openejb.extender; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.naming.NamingException; + +import org.apache.aries.util.AriesFrameworkUtil; +import org.apache.aries.util.manifest.ManifestHeaderProcessor; +import org.apache.aries.util.manifest.ManifestHeaderProcessor.NameValuePair; +import org.apache.aries.util.tracker.RecursiveBundleTracker; +import org.apache.openejb.AppContext; +import org.apache.openejb.BeanContext; +import org.apache.openejb.ContainerType; +import org.apache.openejb.OpenEJBException; +import org.apache.openejb.assembler.classic.Assembler; +import org.apache.openejb.assembler.classic.EjbJarInfo; +import org.apache.openejb.assembler.classic.ProxyFactoryInfo; +import org.apache.openejb.assembler.classic.ProxyInterfaceResolver; +import org.apache.openejb.assembler.classic.SecurityServiceInfo; +import org.apache.openejb.assembler.classic.TransactionServiceInfo; +import org.apache.openejb.assembler.dynamic.PassthroughFactory; +import org.apache.openejb.config.ConfigurationFactory; +import org.apache.openejb.config.EjbModule; +import org.apache.openejb.loader.SystemInstance; +import org.apache.openejb.ri.sp.PseudoSecurityService; +import org.apache.openejb.util.OpenEjbVersion; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.BundleTrackerCustomizer; + +public class EJBExtender implements BundleActivator, BundleTrackerCustomizer { + + private static final int STARTABLE = Bundle.STARTING | Bundle.ACTIVE; + + private static final Object PROCESSING_OBJECT = new Object(); + private static final Object REMOVING_OBJECT = new Object(); + private static final String NONE = "NONE"; + private static final String ALL = "ALL"; + + private RecursiveBundleTracker tracker; + + private final ConcurrentMap<Bundle, RunningApplication> runningApps = + new ConcurrentHashMap<Bundle, RunningApplication>(); + + private final ConcurrentMap<Bundle, Object> processingMap = + new ConcurrentHashMap<Bundle, Object>(); + + public void start(BundleContext context) throws Exception { + + //Internal setup + OSGiTransactionManager.init(context); + AriesProxyService.init(context); + + + //Setup OpenEJB with our own extensions + setupOpenEJB(); + + tracker = new RecursiveBundleTracker(context, Bundle.INSTALLED | Bundle.RESOLVED | + Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING, this); + + tracker.open(); + } + + private void setupOpenEJB() throws OpenEJBException { + //Avoid a ClassLoader problem + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(OpenEjbVersion.class.getClassLoader()); + OpenEjbVersion.get(); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + + Assembler a = new Assembler(); + TransactionServiceInfo tsi = new TransactionServiceInfo(); + tsi.service = "TransactionManager"; + tsi.id = "OSGi Transaction Manager"; + PassthroughFactory.add(tsi, OSGiTransactionManager.get()); + //Avoid another ClassLoader problem + try { + Thread.currentThread().setContextClassLoader(PassthroughFactory.class.getClassLoader()); + a.createTransactionManager(tsi); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + + SecurityServiceInfo ssi = new SecurityServiceInfo(); + ssi.service = "SecurityService"; + ssi.id = "Pseudo Security Service"; + PassthroughFactory.add(ssi, new PseudoSecurityService()); + //Avoid another ClassLoader problem + try { + Thread.currentThread().setContextClassLoader(PassthroughFactory.class.getClassLoader()); + a.createSecurityService(ssi); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + + + ProxyFactoryInfo proxyFactoryInfo = new ProxyFactoryInfo(); + proxyFactoryInfo.id = "Aries ProxyFactory"; + proxyFactoryInfo.service = "ProxyFactory"; + proxyFactoryInfo.properties = new Properties(); + PassthroughFactory.add(proxyFactoryInfo, AriesProxyService.get()); + try { + Thread.currentThread().setContextClassLoader(PassthroughFactory.class.getClassLoader()); + a.createProxyFactory(proxyFactoryInfo); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + } + + public void stop(BundleContext context) throws Exception { + tracker.close(); + AriesProxyService.get().destroy(); + OSGiTransactionManager.get().destroy(); + } + + public Object addingBundle(Bundle bundle, BundleEvent event) { + + if(mightContainEJBs(bundle)) { + if((bundle.getState() & STARTABLE) != 0) { + startEJBs(bundle); + } + return bundle; + } + return null; + } + + + private boolean mightContainEJBs(Bundle bundle) { + Dictionary<String, String> headers = bundle.getHeaders(); + return (headers.get("Export-EJB") != null) || (headers.get("Web-ContextPath") != null); + } + + public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) { + if((bundle.getState() & STARTABLE) != 0) { + startEJBs(bundle); + } else if (bundle.getState() == Bundle.STOPPING) { + stopEJBs(bundle); + } + } + + private void startEJBs(final Bundle bundle) { + + try { + //If there is another thread adding or removing then stop here + Object o = processingMap.put(bundle, PROCESSING_OBJECT); + if(o == REMOVING_OBJECT || o == PROCESSING_OBJECT) { + return; + } + //If already running then avoid + if(runningApps.get(bundle) != null) + return; + + EjbModule ejbModule = new EjbModule(AriesFrameworkUtil.getClassLoaderForced(bundle), + null, null, null); + + addAltDDs(ejbModule, bundle); + //We build our own because we can't trust anyone to get the classpath right otherwise! + ejbModule.setFinder(new OSGiFinder(bundle)); + + ConfigurationFactory configurationFactory = new ConfigurationFactory(); + + EjbJarInfo ejbInfo = null; + //Avoid yet another ClassLoading problem + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(new ClassLoader(OpenEjbVersion.class.getClassLoader()) { + protected Class<?> findClass(String name) throws ClassNotFoundException { + for(Bundle b : bundle.getBundleContext().getBundles()) { + if(b.getSymbolicName().contains("jaxb-impl")) + return b.loadClass(name); + + } + throw new ClassNotFoundException(name); + } + }); + + ejbInfo = configurationFactory.configureApplication(ejbModule); + //Another oddity here + ejbInfo.validationInfo = null; + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + + + Assembler assembler = (Assembler) SystemInstance.get().getComponent(Assembler.class); + RunningApplication app = null; + try { + SystemInstance.get().setProperty("openejb.geronimo", "true"); + cl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(OpenEjbVersion.class.getClassLoader()); + app = new RunningApplication(assembler.createApplication(ejbInfo, + new AppClassLoader(ejbModule.getClassLoader()))); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + } finally { + SystemInstance.get().getProperties().remove("openejb.geronimo"); + } + runningApps.put(bundle, app); + + app.addRegs(registerEJBs(app.getCtx(), bundle)); + + } catch (OpenEJBException oee) { + // TODO Auto-generated catch block + oee.printStackTrace(); + } catch (NamingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if(processingMap.remove(bundle) == REMOVING_OBJECT) { + stopEJBs(bundle); + } + } + } + + private void addAltDDs(EjbModule ejbModule, Bundle bundle) { + + Map<String, Object> altDDs = ejbModule.getAltDDs(); + + String folder = (bundle.getHeaders().get("Web-ContextPath") == null) ? + "META-INF" : "WEB-INF"; + + Enumeration<URL> e = bundle.findEntries(folder, "*.xml", false); + if(e == null) + return; + + for(URL u : Collections.list(e)) { + + String urlString = u.toExternalForm(); + urlString = urlString.substring(urlString.lastIndexOf('/') + 1); + + altDDs.put(urlString, u); + } + //Persistence descriptors are handled by Aries JPA + altDDs.remove("persistence.xml"); + } + + private Collection<ServiceRegistration<?>> registerEJBs(AppContext appCtx, Bundle bundle) { + + Collection<ServiceRegistration<?>> regs = new ArrayList<ServiceRegistration<?>>(); + + Collection<String> names = new HashSet<String>(); + + Dictionary<String, String> d = bundle.getHeaders(); + String valueOfExportEJBHeader = d.get("Export-EJB"); + + if((valueOfExportEJBHeader == null)||(valueOfExportEJBHeader.equals(""))){ + return Collections.emptyList(); + } + + List<NameValuePair> contentsOfExportEJBHeader = ManifestHeaderProcessor.parseExportString(valueOfExportEJBHeader); + for(NameValuePair nvp:contentsOfExportEJBHeader){ + names.add(nvp.getName()); + } + + if(names.contains(NONE)){ + return Collections.emptyList(); + } + + if(names.contains(ALL)){ + names = new AllCollection<String>(); + } + + //Register our session beans + for (BeanContext beanContext : appCtx.getDeployments()) { + String ejbName = beanContext.getEjbName(); + //Skip if not a Singleton or stateless bean + ContainerType type = beanContext.getContainer().getContainerType(); + boolean register = type == ContainerType.SINGLETON || type == ContainerType.STATELESS; + + //Skip if not allowed name + register &= names.contains(ejbName); + + if(!register) { + continue; + } + + if (beanContext.isLocalbean()) { + + BeanContext.BusinessLocalBeanHome home = beanContext.getBusinessLocalBeanHome(); + + Dictionary<String, Object> props = new Hashtable<String, Object>(); + + props.put("ejb.name", ejbName); + props.put("ejb.type", getCasedType(type)); + regs.add(bundle.getBundleContext().registerService(beanContext.getBeanClass().getName(), + new EJBServiceFactory(home), props)); + } + + + for (Class<?> interfce : beanContext.getBusinessLocalInterfaces()) { + + BeanContext.BusinessLocalHome home = beanContext.getBusinessLocalHome(interfce); + + Dictionary<String, Object> props = new Hashtable<String, Object>(); + + props.put("ejb.name", ejbName); + props.put("ejb.type", getCasedType(type)); + regs.add(bundle.getBundleContext().registerService(interfce.getName(), + new EJBServiceFactory(home), props)); + } + + for (Class<?> interfce : beanContext.getBusinessRemoteInterfaces()) { + + List<Class> interfaces = ProxyInterfaceResolver.getInterfaces(beanContext.getBeanClass(), + interfce, beanContext.getBusinessRemoteInterfaces()); + BeanContext.BusinessRemoteHome home = beanContext.getBusinessRemoteHome(interfaces, interfce); + + Dictionary<String, Object> props = new Hashtable<String, Object>(); + + props.put("sevice.exported.interfaces", interfce.getName()); + props.put("ejb.name", ejbName); + props.put("ejb.type", getCasedType(type)); + regs.add(bundle.getBundleContext().registerService(interfce.getName(), + new EJBServiceFactory(home), props)); + } + } + return regs; + } + + private String getCasedType(ContainerType type) { + String s = type.toString().substring(0,1).toUpperCase(); + s += type.toString().substring(1).toLowerCase(); + return s; + } + + private void stopEJBs(Bundle bundle) { + if(processingMap.put(bundle, REMOVING_OBJECT) == PROCESSING_OBJECT) + return; + else { + try { + RunningApplication app = runningApps.remove(bundle); + if(app != null) { + for(ServiceRegistration<?> reg : app.getRegs()) { + AriesFrameworkUtil.safeUnregisterService(reg); + } + Assembler assembler = (Assembler) SystemInstance.get().getComponent(Assembler.class); + assembler.destroyApplication(app.getCtx()); + } + } catch (OpenEJBException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + if(processingMap.remove(bundle) == PROCESSING_OBJECT) + startEJBs(bundle); + } + } + } + + public void removedBundle(Bundle bundle, BundleEvent event, Object object) { + if (bundle.getState() == Bundle.STOPPING) { + stopEJBs(bundle); + } + } + + private static final class AppClassLoader extends ClassLoader { + private AppClassLoader(ClassLoader parentLoader) { + super(parentLoader); + } + + @Override + protected Class<?> findClass(String className) + throws ClassNotFoundException { + return Class.forName(className, false, OpenEjbVersion.class.getClassLoader()); + } + } +} Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBServiceFactory.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBServiceFactory.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBServiceFactory.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/EJBServiceFactory.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,84 @@ +/** + * 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.ejb.openejb.extender; + +import java.lang.reflect.Method; + +import org.apache.openejb.BeanContext.BusinessLocalBeanHome; +import org.apache.openejb.BeanContext.BusinessLocalHome; +import org.apache.openejb.BeanContext.BusinessRemoteHome; +import org.apache.openejb.core.ivm.BaseEjbProxyHandler; +import org.apache.openejb.util.proxy.InvocationHandler; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceFactory; +import org.osgi.framework.ServiceRegistration; + +public class EJBServiceFactory implements ServiceFactory<Object>{ + + private static enum Type {LOCAL, LOCAL_NO_IFACE, REMOTE;} + + private final BusinessLocalBeanHome localBeanHome; + private final BusinessLocalHome localHome; + private final BusinessRemoteHome remoteHome; + + private final Type type; + + public EJBServiceFactory(BusinessLocalBeanHome home) { + this.localBeanHome = home; + type = Type.LOCAL_NO_IFACE; + this.remoteHome = null; + this.localHome = null; + } + + public EJBServiceFactory(BusinessLocalHome home) { + this.localHome = home; + type = Type.LOCAL; + this.remoteHome = null; + this.localBeanHome = null; + } + + public EJBServiceFactory(BusinessRemoteHome home) { + this.remoteHome = home; + type = Type.REMOTE; + this.localHome = null; + this.localBeanHome = null; + } + + public Object getService(Bundle bundle, + ServiceRegistration<Object> registration) { + switch(type) { + case LOCAL : + return localHome.create(); + case LOCAL_NO_IFACE : + return localBeanHome.create(); + case REMOTE : { + InvocationHandler ih = AriesProxyService.get().getInvocationHandler(remoteHome); + + if(ih instanceof BaseEjbProxyHandler) { + ((BaseEjbProxyHandler)ih).setIntraVmCopyMode(false); + } + return remoteHome.create(); + } + default : + throw new IllegalArgumentException("Unknown EJB type " + type); + } + } + + public void ungetService(Bundle bundle, + ServiceRegistration<Object> registration, Object service) { + } +} Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiFinder.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiFinder.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiFinder.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiFinder.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,57 @@ +/** + * 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.ejb.openejb.extender; + +import java.io.IOException; +import java.net.URL; + +import org.apache.xbean.finder.AbstractFinder; +import org.osgi.framework.Bundle; +import org.osgi.framework.wiring.BundleWiring; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OSGiFinder extends AbstractFinder { + + private final Bundle b; + + private static final Logger logger = LoggerFactory.getLogger(OSGiFinder.class); + + public OSGiFinder(Bundle bundle) { + b = bundle; + + for(String resource : bundle.adapt(BundleWiring.class). + listResources("/", "*.class", BundleWiring.LISTRESOURCES_RECURSE)) { + + try { + readClassDef(getResource(resource).openStream()); + } catch (IOException e) { + logger.warn("Error processing class file " + resource); + } + } + } + + @Override + protected URL getResource(String name) { + return b.getResource(name); + } + + @Override + protected Class<?> loadClass(String className) throws ClassNotFoundException { + return b.loadClass(className); + } +} Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiTransactionManager.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiTransactionManager.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiTransactionManager.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/OSGiTransactionManager.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,187 @@ +/** + * 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.ejb.openejb.extender; + +import java.util.concurrent.atomic.AtomicReference; + +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.InvalidTransactionException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; + +import org.apache.aries.util.tracker.SingleServiceTracker; +import org.apache.aries.util.tracker.SingleServiceTracker.SingleServiceListener; +import org.osgi.framework.BundleContext; + +public class OSGiTransactionManager implements TransactionManager, + TransactionSynchronizationRegistry, SingleServiceListener { + + private static class NoTransactionManagerException extends SystemException { + public NoTransactionManagerException() { + super("No Transaction Manager is available"); + } + } + + private static class NoTransactionSynchronizationRegistryException extends RuntimeException { + public NoTransactionSynchronizationRegistryException() { + super("No Transaction Synchronization Registry is available"); + } + } + + private final SingleServiceTracker<TransactionManager> tmTracker; + private final SingleServiceTracker<TransactionSynchronizationRegistry> tsrTracker; + + private final AtomicReference<TransactionManager> tm = + new AtomicReference<TransactionManager>(); + + private final AtomicReference<TransactionSynchronizationRegistry> tsr = + new AtomicReference<TransactionSynchronizationRegistry>(); + + private static final AtomicReference<OSGiTransactionManager> INSTANCE = + new AtomicReference<OSGiTransactionManager>(); + + private OSGiTransactionManager(BundleContext ctx) { + tmTracker = new SingleServiceTracker<TransactionManager>(ctx, TransactionManager.class, this); + tsrTracker = new SingleServiceTracker<TransactionSynchronizationRegistry>(ctx, + TransactionSynchronizationRegistry.class, this); + + tmTracker.open(); + tsrTracker.open(); + } + + private final TransactionManager getTM() throws SystemException { + TransactionManager tManager = tm.get(); + + if(tManager == null) { + throw new NoTransactionManagerException(); + } + return tManager; + } + + private final TransactionSynchronizationRegistry getTSR() { + TransactionSynchronizationRegistry tSReg = tsr.get(); + + if(tSReg == null) { + throw new NoTransactionSynchronizationRegistryException(); + } + return tSReg; + } + + public static OSGiTransactionManager get() { + return INSTANCE.get(); + } + + public static void init(BundleContext ctx) { + OSGiTransactionManager oTM = new OSGiTransactionManager(ctx); + if(!!!INSTANCE.compareAndSet(null, oTM)) + oTM.destroy(); + } + + public void destroy() { + tmTracker.close(); + tsrTracker.close(); + } + + public void serviceFound() { + update(); + } + + public void serviceLost() { + update(); + } + + public void serviceReplaced() { + update(); + } + + private void update() { + tm.set(tmTracker.getService()); + tsr.set(tsrTracker.getService()); + } + + public void begin() throws NotSupportedException, SystemException { + getTM().begin(); + } + + public void commit() throws HeuristicMixedException, + HeuristicRollbackException, IllegalStateException, RollbackException, + SecurityException, SystemException { + getTM().commit(); + } + + public int getStatus() throws SystemException { + return getTM().getStatus(); + } + + public Transaction getTransaction() throws SystemException { + return getTM().getTransaction(); + } + + public void resume(Transaction arg0) throws IllegalStateException, + InvalidTransactionException, SystemException { + getTM().resume(arg0); + } + + public void rollback() throws IllegalStateException, SecurityException, + SystemException { + getTM().rollback(); + } + + public void setRollbackOnly() throws IllegalStateException { + getTSR().setRollbackOnly(); + } + + public void setTransactionTimeout(int arg0) throws SystemException { + getTM().setTransactionTimeout(arg0); + } + + public Transaction suspend() throws SystemException { + return getTM().suspend(); + } + + public Object getResource(Object arg0) { + return getTSR().getResource(arg0); + } + + public boolean getRollbackOnly() { + return getTSR().getRollbackOnly(); + } + + public Object getTransactionKey() { + return getTSR().getTransactionKey(); + } + + public int getTransactionStatus() { + return getTSR().getTransactionStatus(); + } + + public void putResource(Object arg0, Object arg1) { + getTSR().putResource(arg0, arg1); + } + + public void registerInterposedSynchronization(Synchronization arg0) { + getTSR().registerInterposedSynchronization(arg0); + } +} + + Added: aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/RunningApplication.java URL: http://svn.apache.org/viewvc/aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/RunningApplication.java?rev=1161653&view=auto ============================================================================== --- aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/RunningApplication.java (added) +++ aries/trunk/ejb/openejb-extender/src/main/java/org/apache/aries/ejb/openejb/extender/RunningApplication.java Thu Aug 25 17:26:19 2011 @@ -0,0 +1,47 @@ +/** + * 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.ejb.openejb.extender; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.apache.openejb.AppContext; +import org.osgi.framework.ServiceRegistration; + +public class RunningApplication { + + private final AppContext ctx; + private final Collection<ServiceRegistration<?>> regs = + Collections.synchronizedCollection(new ArrayList<ServiceRegistration<?>>()); + + public RunningApplication(AppContext context) { + this.ctx = context; + } + + public AppContext getCtx() { + return ctx; + } + + public Collection<ServiceRegistration<?>> getRegs() { + return regs; + } + + public void addRegs(Collection<ServiceRegistration<?>> toAdd) { + regs.addAll(toAdd); + } +} Modified: aries/trunk/ejb/pom.xml URL: http://svn.apache.org/viewvc/aries/trunk/ejb/pom.xml?rev=1161653&r1=1161652&r2=1161653&view=diff ============================================================================== --- aries/trunk/ejb/pom.xml (original) +++ aries/trunk/ejb/pom.xml Thu Aug 25 17:26:19 2011 @@ -33,6 +33,8 @@ <modules> <module>ejb-modeller</module> <module>ejb-modeller-itest</module> + <module>openejb-extender</module> + <module>openejb-extender-itest</module> </modules> </project>
