001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.openejb;
018    
019    import java.io.IOException;
020    import java.util.Collection;
021    import java.util.Map;
022    import java.util.Properties;
023    import java.util.Set;
024    import java.util.TreeSet;
025    import java.util.concurrent.ConcurrentHashMap;
026    import java.util.concurrent.ConcurrentMap;
027    
028    import javax.ejb.spi.HandleDelegate;
029    import javax.management.ObjectName;
030    import javax.naming.NamingException;
031    import javax.naming.Context;
032    import javax.resource.spi.ResourceAdapter;
033    import javax.transaction.TransactionManager;
034    
035    import org.apache.commons.logging.Log;
036    import org.apache.commons.logging.LogFactory;
037    import org.apache.geronimo.connector.ResourceAdapterWrapper;
038    import org.apache.geronimo.gbean.AbstractName;
039    import org.apache.geronimo.gbean.AbstractNameQuery;
040    import org.apache.geronimo.gbean.GBeanInfo;
041    import org.apache.geronimo.gbean.GBeanInfoBuilder;
042    import org.apache.geronimo.gbean.ReferenceCollection;
043    import org.apache.geronimo.gbean.ReferenceCollectionEvent;
044    import org.apache.geronimo.gbean.ReferenceCollectionListener;
045    import org.apache.geronimo.kernel.GBeanNotFoundException;
046    import org.apache.geronimo.kernel.Kernel;
047    import org.apache.geronimo.persistence.PersistenceUnitGBean;
048    import org.apache.openejb.Container;
049    import org.apache.openejb.DeploymentInfo;
050    import org.apache.openejb.NoSuchApplicationException;
051    import org.apache.openejb.OpenEJBException;
052    import org.apache.openejb.UndeployException;
053    import org.apache.openejb.assembler.classic.AppInfo;
054    import org.apache.openejb.assembler.classic.Assembler;
055    import org.apache.openejb.assembler.classic.ClientInfo;
056    import org.apache.openejb.assembler.classic.ContainerInfo;
057    import org.apache.openejb.assembler.classic.EjbJarInfo;
058    import org.apache.openejb.assembler.classic.MdbContainerInfo;
059    import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
060    import org.apache.openejb.assembler.classic.SecurityServiceInfo;
061    import org.apache.openejb.assembler.classic.TransactionServiceInfo;
062    import org.apache.openejb.assembler.dynamic.PassthroughFactory;
063    import org.apache.openejb.config.AppModule;
064    import org.apache.openejb.config.ClientModule;
065    import org.apache.openejb.config.ConfigurationFactory;
066    import org.apache.openejb.config.EjbModule;
067    import org.apache.openejb.core.ServerFederation;
068    import org.apache.openejb.loader.SystemInstance;
069    import org.apache.openejb.spi.ApplicationServer;
070    import org.apache.openejb.spi.ContainerSystem;
071    import org.apache.openejb.spi.SecurityService;
072    import org.apache.openejb.util.proxy.Jdk13ProxyFactory;
073    import org.omg.CORBA.ORB;
074    
075    /**
076     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
077     */
078    public class OpenEjbSystemGBean implements OpenEjbSystem {
079        private static final Log log = LogFactory.getLog(OpenEjbSystemGBean.class);
080        private final ConfigurationFactory configurationFactory;
081        private final Assembler assembler;
082        private final Set<String> registeredResouceAdapters = new TreeSet<String>();
083        private final ConcurrentMap<String,ResourceAdapterWrapper> processedResourceAdapterWrappers =  new ConcurrentHashMap<String,ResourceAdapterWrapper>() ;
084        private final Kernel kernel;
085        private final ClassLoader classLoader;
086        // These are provided by the corba subsystem when it first initializes.  
087        // Once we have a set, we ignore any additional notifications. 
088        private ORB orb;
089    
090        public OpenEjbSystemGBean(TransactionManager transactionManager) throws Exception {
091            this(transactionManager, null, null, null, OpenEjbSystemGBean.class.getClassLoader());
092        }
093        public OpenEjbSystemGBean(TransactionManager transactionManager, Collection<ResourceAdapterWrapper> resourceAdapters, Collection<PersistenceUnitGBean> persistenceUnitGBeans, Kernel kernel, ClassLoader classLoader) throws Exception {
094            this.kernel = kernel;
095            this.classLoader = classLoader;
096    
097            System.setProperty("duct tape","");
098            System.setProperty("admin.disabled", "true");
099            System.setProperty("openejb.logger.external", "true");
100    
101            setDefaultProperty("openejb.deploymentId.format", "{moduleId}/{ejbName}");
102            setDefaultProperty("openejb.jndiname.strategy.class", "org.apache.openejb.assembler.classic.JndiBuilder$TemplatedStrategy");
103            setDefaultProperty("openejb.jndiname.format", "{ejbName}{interfaceType.annotationName}");
104            setDefaultProperty("openejb.jndiname.failoncollision", "false");
105    
106            System.setProperty("openejb.naming", "xbean");
107            if (transactionManager == null) {
108                throw new NullPointerException("transactionManager is null");
109            }
110    
111            boolean offline = true;
112            configurationFactory = new ConfigurationFactory(offline);
113            assembler = new Assembler();
114    
115            // install application server
116            ApplicationServer applicationServer = new ServerFederation();
117            SystemInstance.get().setComponent(ApplicationServer.class, applicationServer);
118    
119            // install transaction manager
120            transactionManager = getRawService(kernel, transactionManager);
121            TransactionServiceInfo transactionServiceInfo = new TransactionServiceInfo();
122            PassthroughFactory.add(transactionServiceInfo, transactionManager);
123            transactionServiceInfo.id = "Default Transaction Manager";
124            transactionServiceInfo.service = "TransactionManager";
125            assembler.createTransactionManager(transactionServiceInfo);
126    
127            // install security service
128            SecurityService securityService = new GeronimoSecurityService();
129            SecurityServiceInfo securityServiceInfo = new SecurityServiceInfo();
130            PassthroughFactory.add(securityServiceInfo, securityService);
131            securityServiceInfo.id = "Default Security Service";
132            securityServiceInfo.service = "SecurityService";
133            assembler.createSecurityService(securityServiceInfo);
134    
135            // install proxy factory
136            ProxyFactoryInfo proxyFactoryInfo = new ProxyFactoryInfo();
137            proxyFactoryInfo.id = "Default JDK 1.3 ProxyFactory";
138            proxyFactoryInfo.service = "ProxyFactory";
139            proxyFactoryInfo.className = Jdk13ProxyFactory.class.getName();
140            proxyFactoryInfo.properties = new Properties();
141            assembler.createProxyFactory(proxyFactoryInfo);
142            
143            // add our thread context listener
144            GeronimoThreadContextListener.init();
145    
146            // process all resource adapters
147            processResourceAdapterWrappers(resourceAdapters);
148            processPersistenceUnitGBeans(persistenceUnitGBeans);
149        }
150    
151        private void setDefaultProperty(String key, String value) {
152            SystemInstance systemInstance = SystemInstance.get();
153    
154    
155            String format = systemInstance.getProperty(key);
156            if (format == null){
157                systemInstance.setProperty(key, value);
158            }
159        }
160    
161        @SuppressWarnings({"unchecked"})
162        private static <T> T getRawService(Kernel kernel, T proxy) {
163            if (kernel == null) return proxy;
164    
165            AbstractName abstractName = kernel.getAbstractNameFor(proxy);
166            if (abstractName == null) return proxy;
167    
168            try {
169                Object service = kernel.getGBean(abstractName);
170                return (T) service;
171            } catch (GBeanNotFoundException e) {
172            }
173    
174            return proxy;
175        }
176    
177        private void processPersistenceUnitGBeans(Collection<PersistenceUnitGBean> persistenceUnitGBeans) {
178            if (persistenceUnitGBeans == null) {
179                return;
180            }
181    
182            if (persistenceUnitGBeans instanceof ReferenceCollection) {
183                ReferenceCollection referenceCollection = (ReferenceCollection) persistenceUnitGBeans;
184                referenceCollection.addReferenceCollectionListener(new ReferenceCollectionListener() {
185                    public void memberAdded(ReferenceCollectionEvent event) {
186                        addPersistenceUnitGBean((PersistenceUnitGBean) event.getMember());
187                    }
188    
189                    public void memberRemoved(ReferenceCollectionEvent event) {
190                        removePersistenceUnitGBean((PersistenceUnitGBean) event.getMember());
191                    }
192    
193                });
194            }
195            for (PersistenceUnitGBean persistenceUnitGBean : persistenceUnitGBeans) {
196                addPersistenceUnitGBean(persistenceUnitGBean);
197            }
198        }
199    
200        private void addPersistenceUnitGBean(PersistenceUnitGBean persistenceUnitGBean) {
201            String unit = persistenceUnitGBean.getPersistenceUnitName();
202            String rootUrl = persistenceUnitGBean.getPersistenceUnitRoot();
203            String id = unit + " " + rootUrl.hashCode();
204            Context context = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext();
205            try {
206                context.bind("java:openejb/PersistenceUnit/" + id, persistenceUnitGBean.getEntityManagerFactory());
207            } catch (Exception e) {
208                throw new IllegalStateException(e);
209            }
210        }
211    
212        private void removePersistenceUnitGBean(PersistenceUnitGBean persistenceUnitGBean) {
213            String unit = persistenceUnitGBean.getPersistenceUnitName();
214            String rootUrl = persistenceUnitGBean.getPersistenceUnitRoot();
215            String id = unit + " " + rootUrl.hashCode();
216            Context context = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext();
217            try {
218                context.unbind("java:openejb/PersistenceUnit/" + id);
219            } catch (Exception e) {
220                throw new IllegalStateException(e);
221            }
222        }
223    
224    
225        private void processResourceAdapterWrappers(Collection<ResourceAdapterWrapper> resourceAdapterWrappers) {
226            if (resourceAdapterWrappers == null) {
227                return;
228            }
229    
230            if (resourceAdapterWrappers instanceof ReferenceCollection) {
231                ReferenceCollection referenceCollection = (ReferenceCollection) resourceAdapterWrappers;
232                referenceCollection.addReferenceCollectionListener(new ReferenceCollectionListener() {
233                    public void memberAdded(ReferenceCollectionEvent event) {
234                        addResourceAdapter((ResourceAdapterWrapper) event.getMember());
235                    }
236    
237                    public void memberRemoved(ReferenceCollectionEvent event) {
238                        removeResourceAdapter((ResourceAdapterWrapper) event.getMember());
239                    }
240                });
241            }
242            for (ResourceAdapterWrapper resourceAdapterWrapper : resourceAdapterWrappers) {
243                addResourceAdapter(resourceAdapterWrapper);
244            }
245    
246        }
247    
248        private void addResourceAdapter(ResourceAdapterWrapper resourceAdapterWrapper) {
249            ResourceAdapter resourceAdapter = resourceAdapterWrapper.getResourceAdapter();
250            if (resourceAdapter == null) {
251                return;
252            }
253            if (registeredResouceAdapters.contains(resourceAdapterWrapper.getName())) {
254                // already registered
255                return;
256            }
257            registeredResouceAdapters.add(resourceAdapterWrapper.getName());
258            
259            Map<String, String> listenerToActivationSpecMap = resourceAdapterWrapper.getMessageListenerToActivationSpecMap();
260            if (listenerToActivationSpecMap == null) {
261                return;
262            }
263    
264            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
265            Thread.currentThread().setContextClassLoader(classLoader);
266            try {
267                for (Map.Entry<String, String> entry : listenerToActivationSpecMap.entrySet()) {
268                    String messageListenerInterface = entry.getKey();
269                    String activationSpecClass = entry.getValue();
270    
271                    // only process RA if not previously processed
272                    String containerName = getResourceAdapterId(resourceAdapterWrapper) + "-" + messageListenerInterface;
273                    if (processedResourceAdapterWrappers.putIfAbsent(containerName,  resourceAdapterWrapper) == null) {
274                        try {
275                            // get default mdb config
276                            ContainerInfo containerInfo = configurationFactory.configureService(MdbContainerInfo.class, containerName, null, null, "Container");
277                            containerInfo.id = containerName;
278                            containerInfo.displayName = containerName;
279    
280                            // set ra specific properties
281                            containerInfo.properties.put("MessageListenerInterface",
282                                    resourceAdapter.getClass().getClassLoader().loadClass(messageListenerInterface));
283                            containerInfo.properties.put("ActivationSpecClass",
284                                    resourceAdapter.getClass().getClassLoader().loadClass(activationSpecClass));
285                            containerInfo.properties.put("ResourceAdapter", resourceAdapter);
286                            containerInfo.properties.put("TxRecovery", true);
287     
288                            // create the container
289                            assembler.createContainer(containerInfo);
290                        } catch (Exception e) {
291                            log.error("Unable to deploy mdb container " + containerName, e);
292                        }
293                    }
294                }
295            } finally {
296                Thread.currentThread().setContextClassLoader(oldClassLoader);
297            }
298        }
299    
300        private void removeResourceAdapter(ResourceAdapterWrapper resourceAdapterWrapper) {
301            Map<String, String> listenerToActivationSpecMap = resourceAdapterWrapper.getMessageListenerToActivationSpecMap();
302            if (listenerToActivationSpecMap != null) {
303                for (String messageListenerInterface : listenerToActivationSpecMap.keySet()) {
304                    String containerName = getResourceAdapterId(resourceAdapterWrapper) + "-" + messageListenerInterface;
305                    processedResourceAdapterWrappers.remove(containerName);
306                    assembler.removeContainer(containerName);
307                }
308                registeredResouceAdapters.remove(resourceAdapterWrapper.getName());
309            }
310        }
311    
312        private String getResourceAdapterId(ResourceAdapterWrapper resourceAdapterWrapper) {
313            String name = resourceAdapterWrapper.getName();
314            try {
315                ObjectName objectName = new ObjectName(name);
316                Map properties = objectName.getKeyPropertyList();
317                String shortName = (String) properties.get("name");
318                String moduleName = (String) properties.get("ResourceAdapterModule");
319                if (shortName != null && moduleName != null) {
320                    return moduleName + "." + shortName;
321                }
322            } catch (Exception ignored) {
323            }
324            return name;
325        }
326    
327        public ContainerSystem getContainerSystem() {
328            return assembler.getContainerSystem();
329        }
330    
331        public Container createContainer(Class<? extends ContainerInfo> type, String serviceId, Properties declaredProperties, String providerId) throws OpenEJBException {
332            ContainerInfo containerInfo = configurationFactory.configureService(type, serviceId, declaredProperties, providerId, "Container");
333            assembler.createContainer(containerInfo);
334            Container container = assembler.getContainerSystem().getContainer(serviceId);
335            return container;
336        }
337    
338        public ClientInfo configureApplication(ClientModule clientModule) throws OpenEJBException {
339            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
340            Thread.currentThread().setContextClassLoader(clientModule.getClassLoader());
341            try {
342                return configurationFactory.configureApplication(clientModule);
343            } finally {
344                Thread.currentThread().setContextClassLoader(oldClassLoader);
345            }
346        }
347    
348        public AppInfo configureApplication(AppModule appModule) throws OpenEJBException {
349            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
350            Thread.currentThread().setContextClassLoader(appModule.getClassLoader());
351            try {
352                return configurationFactory.configureApplication(appModule);
353            } finally {
354                Thread.currentThread().setContextClassLoader(oldClassLoader);
355            }
356        }
357    
358        public EjbJarInfo configureApplication(EjbModule ejbModule) throws OpenEJBException {
359            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
360            Thread.currentThread().setContextClassLoader(ejbModule.getClassLoader());
361            try {
362                return configurationFactory.configureApplication(ejbModule);
363            } finally {
364                Thread.currentThread().setContextClassLoader(oldClassLoader);
365            }
366        }
367    
368        public void createClient(ClientInfo clientInfo, ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
369            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
370            Thread.currentThread().setContextClassLoader(classLoader);
371            try {
372                assembler.createClient(clientInfo, classLoader);
373            } finally {
374                Thread.currentThread().setContextClassLoader(oldClassLoader);
375            }
376        }
377    
378        public void createEjbJar(EjbJarInfo ejbJarInfo, ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
379            Set<AbstractName> names = kernel.listGBeans(new AbstractNameQuery(ResourceAdapterWrapper.class.getName()));
380            for (AbstractName name : names) {
381                try {
382                    ResourceAdapterWrapper resourceAdapterWrapper = (ResourceAdapterWrapper) kernel.getGBean(name);
383                    addResourceAdapter(resourceAdapterWrapper);
384                } catch (GBeanNotFoundException ignored) {
385                }
386            }
387    
388            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
389            Thread.currentThread().setContextClassLoader(classLoader);
390            try {
391                assembler.createEjbJar(ejbJarInfo, classLoader);
392            } finally {
393                Thread.currentThread().setContextClassLoader(oldClassLoader);
394            }
395        }
396    
397        public void removeEjbJar(EjbJarInfo ejbJarInfo, ClassLoader classLoader) throws UndeployException, NoSuchApplicationException {
398            assembler.destroyApplication(ejbJarInfo.jarPath);
399        }
400    
401        public DeploymentInfo getDeploymentInfo(String deploymentId) {
402            return getContainerSystem().getDeploymentInfo(deploymentId);
403        }
404    
405        public void setORBContext(ORB orb, HandleDelegate handleDelegate) {
406            // this is only processed once, since these are global values. 
407            if (this.orb == null) {
408                this.orb = orb; 
409                SystemInstance.get().setComponent(ORB.class, orb);
410                SystemInstance.get().setComponent(HandleDelegate.class, handleDelegate);
411            }
412        }
413    
414        public static final GBeanInfo GBEAN_INFO;
415    
416        static {
417            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(OpenEjbSystemGBean.class);
418            infoBuilder.addReference("TransactionManager", TransactionManager.class);
419            infoBuilder.addReference("ResourceAdapterWrappers", ResourceAdapterWrapper.class);
420            infoBuilder.addReference("PersistenceUnitGBeans", PersistenceUnitGBean.class);
421            infoBuilder.addAttribute("kernel", Kernel.class, false);
422            infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
423            infoBuilder.setConstructor(new String[] {
424                    "TransactionManager",
425                    "ResourceAdapterWrappers",
426                    "PersistenceUnitGBeans",
427                    "kernel",
428                    "classLoader",
429            });
430            GBEAN_INFO = infoBuilder.getBeanInfo();
431        }
432    
433        public static GBeanInfo getGBeanInfo() {
434            return GBEAN_INFO;
435        }
436    }