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.Collections;
022    import java.util.Map;
023    import java.util.Properties;
024    import java.util.Set;
025    import java.util.TreeSet;
026    import java.util.concurrent.ConcurrentHashMap;
027    import java.util.concurrent.ConcurrentMap;
028    
029    import javax.ejb.spi.HandleDelegate;
030    import javax.management.ObjectName;
031    import javax.naming.NamingException;
032    import javax.persistence.EntityManagerFactory;
033    import javax.resource.spi.ResourceAdapter;
034    import javax.transaction.TransactionManager;
035    
036    import org.apache.commons.logging.Log;
037    import org.apache.commons.logging.LogFactory;
038    import org.apache.geronimo.connector.ResourceAdapterWrapper;
039    import org.apache.geronimo.gbean.AbstractName;
040    import org.apache.geronimo.gbean.AbstractNameQuery;
041    import org.apache.geronimo.gbean.GBeanInfo;
042    import org.apache.geronimo.gbean.GBeanInfoBuilder;
043    import org.apache.geronimo.gbean.ReferenceCollection;
044    import org.apache.geronimo.gbean.ReferenceCollectionEvent;
045    import org.apache.geronimo.gbean.ReferenceCollectionListener;
046    import org.apache.geronimo.kernel.GBeanNotFoundException;
047    import org.apache.geronimo.kernel.Kernel;
048    import org.apache.geronimo.persistence.PersistenceUnitGBean;
049    import org.apache.openejb.Container;
050    import org.apache.openejb.DeploymentInfo;
051    import org.apache.openejb.NoSuchApplicationException;
052    import org.apache.openejb.OpenEJBException;
053    import org.apache.openejb.UndeployException;
054    import org.apache.openejb.assembler.classic.AppInfo;
055    import org.apache.openejb.assembler.classic.Assembler;
056    import org.apache.openejb.assembler.classic.ClientInfo;
057    import org.apache.openejb.assembler.classic.ContainerInfo;
058    import org.apache.openejb.assembler.classic.EjbJarInfo;
059    import org.apache.openejb.assembler.classic.LinkResolver;
060    import org.apache.openejb.assembler.classic.MdbContainerInfo;
061    import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
062    import org.apache.openejb.assembler.classic.SecurityServiceInfo;
063    import org.apache.openejb.assembler.classic.TransactionServiceInfo;
064    import org.apache.openejb.assembler.classic.UniqueDefaultLinkResolver;
065    import org.apache.openejb.assembler.dynamic.PassthroughFactory;
066    import org.apache.openejb.config.AppModule;
067    import org.apache.openejb.config.ClientModule;
068    import org.apache.openejb.config.ConfigurationFactory;
069    import org.apache.openejb.config.EjbModule;
070    import org.apache.openejb.core.ServerFederation;
071    import org.apache.openejb.loader.SystemInstance;
072    import org.apache.openejb.spi.ApplicationServer;
073    import org.apache.openejb.spi.ContainerSystem;
074    import org.apache.openejb.spi.SecurityService;
075    import org.apache.openejb.util.proxy.Jdk13ProxyFactory;
076    import org.omg.CORBA.ORB;
077    
078    /**
079     * @version $Rev$ $Date$
080     */
081    public class OpenEjbSystemGBean implements OpenEjbSystem {
082        private static final Log log = LogFactory.getLog(OpenEjbSystemGBean.class);
083        private final ConfigurationFactory configurationFactory;
084        private final Assembler assembler;
085        private final Set<String> registeredResouceAdapters = new TreeSet<String>();
086        private final ConcurrentMap<String,ResourceAdapterWrapper> processedResourceAdapterWrappers =  new ConcurrentHashMap<String,ResourceAdapterWrapper>() ;
087        private final Collection<PersistenceUnitGBean> persistenceUnitGBeans;
088        private final Kernel kernel;
089        private final ClassLoader classLoader;
090        // These are provided by the corba subsystem when it first initializes.  
091        // Once we have a set, we ignore any additional notifications. 
092        private ORB orb;
093    
094        public OpenEjbSystemGBean(TransactionManager transactionManager) throws Exception {
095            this(transactionManager, null, null, null, OpenEjbSystemGBean.class.getClassLoader());
096        }
097        public OpenEjbSystemGBean(TransactionManager transactionManager, Collection<ResourceAdapterWrapper> resourceAdapters, Collection<PersistenceUnitGBean> persistenceUnitGBeans, Kernel kernel, ClassLoader classLoader) throws Exception {
098            this.kernel = kernel;
099            this.classLoader = classLoader;
100            if (persistenceUnitGBeans == null) {
101                this.persistenceUnitGBeans = Collections.emptySet();
102            } else {
103                this.persistenceUnitGBeans = persistenceUnitGBeans;
104            }
105            System.setProperty("duct tape","");
106            System.setProperty("admin.disabled", "true");
107            SystemInstance systemInstance = SystemInstance.get();
108    
109            String format = systemInstance.getProperty("openejb.deploymentId.format");
110            if (format == null){
111                systemInstance.setProperty("openejb.deploymentId.format", "{moduleId}/{ejbName}");
112            }
113    
114            systemInstance.setProperty("openejb.jndiname.strategy.class", "org.apache.openejb.assembler.classic.JndiBuilder$TemplatedStrategy");
115            systemInstance.setProperty("openejb.jndiname.format", "{deploymentId}/{interfaceClass}");
116    
117            System.setProperty("openejb.naming", "xbean");
118            if (transactionManager == null) {
119                throw new NullPointerException("transactionManager is null");
120            }
121    
122            boolean offline = true;
123            configurationFactory = new ConfigurationFactory(offline);
124            assembler = new Assembler();
125    
126            // install application server
127            ApplicationServer applicationServer = new ServerFederation();
128            SystemInstance.get().setComponent(ApplicationServer.class, applicationServer);
129    
130            // install transaction manager
131            transactionManager = getRawService(kernel, transactionManager);
132            TransactionServiceInfo transactionServiceInfo = new TransactionServiceInfo();
133            PassthroughFactory.add(transactionServiceInfo, transactionManager);
134            transactionServiceInfo.id = "Default Transaction Manager";
135            transactionServiceInfo.serviceType = "TransactionManager";
136            assembler.createTransactionManager(transactionServiceInfo);
137    
138            // install security service
139            SecurityService securityService = new GeronimoSecurityService();
140            SecurityServiceInfo securityServiceInfo = new SecurityServiceInfo();
141            PassthroughFactory.add(securityServiceInfo, securityService);
142            securityServiceInfo.id = "Default Security Service";
143            securityServiceInfo.serviceType = "SecurityService";
144            assembler.createSecurityService(securityServiceInfo);
145    
146            // install proxy factory
147            ProxyFactoryInfo proxyFactoryInfo = new ProxyFactoryInfo();
148            proxyFactoryInfo.id = "Default JDK 1.3 ProxyFactory";
149            proxyFactoryInfo.serviceType = "ProxyFactory";
150            proxyFactoryInfo.className = Jdk13ProxyFactory.class.getName();
151            proxyFactoryInfo.properties = new Properties();
152            assembler.createProxyFactory(proxyFactoryInfo);
153            
154            // add our thread context listener
155            GeronimoThreadContextListener.init();
156    
157            // process all resource adapters
158            processResourceAdapterWrappers(resourceAdapters);
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 processResourceAdapterWrappers(Collection<ResourceAdapterWrapper> resourceAdapterWrappers) {
178            if (resourceAdapterWrappers == null) {
179                return;
180            }
181    
182            if (resourceAdapterWrappers instanceof ReferenceCollection) {
183                ReferenceCollection referenceCollection = (ReferenceCollection) resourceAdapterWrappers;
184                referenceCollection.addReferenceCollectionListener(new ReferenceCollectionListener() {
185                    public void memberAdded(ReferenceCollectionEvent event) {
186                        addResourceAdapter((ResourceAdapterWrapper) event.getMember());
187                    }
188    
189                    public void memberRemoved(ReferenceCollectionEvent event) {
190                        removeResourceAdapter((ResourceAdapterWrapper) event.getMember());
191                    }
192                });
193            }
194            for (ResourceAdapterWrapper resourceAdapterWrapper : resourceAdapterWrappers) {
195                addResourceAdapter(resourceAdapterWrapper);
196            }
197    
198        }
199    
200        private void addResourceAdapter(ResourceAdapterWrapper resourceAdapterWrapper) {
201            ResourceAdapter resourceAdapter = resourceAdapterWrapper.getResourceAdapter();
202            if (resourceAdapter == null) {
203                return;
204            }
205            if (registeredResouceAdapters.contains(resourceAdapterWrapper.getName())) {
206                // already registered
207                return;
208            }
209            registeredResouceAdapters.add(resourceAdapterWrapper.getName());
210            
211            Map<String, String> listenerToActivationSpecMap = resourceAdapterWrapper.getMessageListenerToActivationSpecMap();
212            if (listenerToActivationSpecMap == null) {
213                return;
214            }
215    
216            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
217            Thread.currentThread().setContextClassLoader(classLoader);
218            try {
219                for (Map.Entry<String, String> entry : listenerToActivationSpecMap.entrySet()) {
220                    String messageListenerInterface = entry.getKey();
221                    String activationSpecClass = entry.getValue();
222    
223                    // only process RA if not previously processed
224                    String containerName = getResourceAdapterId(resourceAdapterWrapper) + "-" + messageListenerInterface;
225                    if (processedResourceAdapterWrappers.putIfAbsent(containerName,  resourceAdapterWrapper) == null) {
226                        try {
227                            // get default mdb config
228                            ContainerInfo containerInfo = configurationFactory.configureService(MdbContainerInfo.class);
229                            containerInfo.id = containerName;
230                            containerInfo.displayName = containerName;
231    
232                            // set ra specific properties
233                            containerInfo.properties.put("MessageListenerInterface",
234                                    resourceAdapter.getClass().getClassLoader().loadClass(messageListenerInterface));
235                            containerInfo.properties.put("ActivationSpecClass",
236                                    resourceAdapter.getClass().getClassLoader().loadClass(activationSpecClass));
237                            containerInfo.properties.put("ResourceAdapter", resourceAdapter);
238    
239                            // create the container
240                            assembler.createContainer(containerInfo);
241                        } catch (Exception e) {
242                            log.error("Unable to deploy mdb container " + containerName, e);
243                        }
244                    }
245                }
246            } finally {
247                Thread.currentThread().setContextClassLoader(oldClassLoader);
248            }
249        }
250    
251        private void removeResourceAdapter(ResourceAdapterWrapper resourceAdapterWrapper) {
252            Map<String, String> listenerToActivationSpecMap = resourceAdapterWrapper.getMessageListenerToActivationSpecMap();
253            if (listenerToActivationSpecMap != null) {
254                for (String messageListenerInterface : listenerToActivationSpecMap.keySet()) {
255                    String containerName = getResourceAdapterId(resourceAdapterWrapper) + "-" + messageListenerInterface;
256                    processedResourceAdapterWrappers.remove(containerName);
257                    assembler.removeContainer(containerName);
258                }
259                registeredResouceAdapters.remove(resourceAdapterWrapper.getName());
260            }
261        }
262    
263        private String getResourceAdapterId(ResourceAdapterWrapper resourceAdapterWrapper) {
264            String name = resourceAdapterWrapper.getName();
265            try {
266                ObjectName objectName = new ObjectName(name);
267                Map properties = objectName.getKeyPropertyList();
268                String shortName = (String) properties.get("name");
269                String moduleName = (String) properties.get("ResourceAdapterModule");
270                if (shortName != null && moduleName != null) {
271                    return moduleName + "." + shortName;
272                }
273            } catch (Exception ignored) {
274            }
275            return name;
276        }
277    
278        public ContainerSystem getContainerSystem() {
279            return assembler.getContainerSystem();
280        }
281    
282        public Container createContainer(Class<? extends ContainerInfo> type, String serviceId, Properties declaredProperties, String providerId) throws OpenEJBException {
283            ContainerInfo containerInfo = configurationFactory.configureService(type, serviceId, declaredProperties, providerId, "Container");
284            assembler.createContainer(containerInfo);
285            Container container = assembler.getContainerSystem().getContainer(serviceId);
286            return container;
287        }
288    
289        public ClientInfo configureApplication(ClientModule clientModule) throws OpenEJBException {
290            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
291            Thread.currentThread().setContextClassLoader(clientModule.getClassLoader());
292            try {
293                return configurationFactory.configureApplication(clientModule);
294            } finally {
295                Thread.currentThread().setContextClassLoader(oldClassLoader);
296            }
297        }
298    
299        public AppInfo configureApplication(AppModule appModule) throws OpenEJBException {
300            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
301            Thread.currentThread().setContextClassLoader(appModule.getClassLoader());
302            try {
303                return configurationFactory.configureApplication(appModule);
304            } finally {
305                Thread.currentThread().setContextClassLoader(oldClassLoader);
306            }
307        }
308    
309        public EjbJarInfo configureApplication(EjbModule ejbModule) throws OpenEJBException {
310            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
311            Thread.currentThread().setContextClassLoader(ejbModule.getClassLoader());
312            try {
313                return configurationFactory.configureApplication(ejbModule);
314            } finally {
315                Thread.currentThread().setContextClassLoader(oldClassLoader);
316            }
317        }
318    
319        public void createClient(ClientInfo clientInfo, ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
320            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
321            Thread.currentThread().setContextClassLoader(classLoader);
322            try {
323                assembler.createClient(clientInfo, classLoader);
324            } finally {
325                Thread.currentThread().setContextClassLoader(oldClassLoader);
326            }
327        }
328    
329        public void createEjbJar(EjbJarInfo ejbJarInfo, ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
330            Set<AbstractName> names = kernel.listGBeans(new AbstractNameQuery(ResourceAdapterWrapper.class.getName()));
331            for (AbstractName name : names) {
332                try {
333                    ResourceAdapterWrapper resourceAdapterWrapper = (ResourceAdapterWrapper) kernel.getGBean(name);
334                    addResourceAdapter(resourceAdapterWrapper);
335                } catch (GBeanNotFoundException ignored) {
336                }
337            }
338    
339            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
340            Thread.currentThread().setContextClassLoader(classLoader);
341            LinkResolver<EntityManagerFactory> emfLinkResolver = new UniqueDefaultLinkResolver<EntityManagerFactory>();
342            for (PersistenceUnitGBean persistenceUnitGBean: persistenceUnitGBeans) {
343                EntityManagerFactory factory = persistenceUnitGBean.getEntityManagerFactory();
344                String persistenceUnitRoot = persistenceUnitGBean.getPersistenceUnitRoot();
345                String persistenceUnitName = persistenceUnitGBean.getPersistenceUnitName();
346                if (!"cmp".equals(persistenceUnitName)) {
347                    emfLinkResolver.add(persistenceUnitRoot, persistenceUnitName, factory);
348                }
349            }
350            try {
351                assembler.createEjbJar(ejbJarInfo, emfLinkResolver, classLoader);
352            } finally {
353                Thread.currentThread().setContextClassLoader(oldClassLoader);
354            }
355        }
356    
357        public void removeEjbJar(EjbJarInfo ejbJarInfo, ClassLoader classLoader) throws UndeployException, NoSuchApplicationException {
358            assembler.destroyApplication(ejbJarInfo.jarPath);
359        }
360    
361        public DeploymentInfo getDeploymentInfo(String deploymentId) {
362            return getContainerSystem().getDeploymentInfo(deploymentId);
363        }
364    
365        public void setORBContext(ORB orb, HandleDelegate handleDelegate) {
366            // this is only processed once, since these are global values. 
367            if (this.orb == null) {
368                this.orb = orb; 
369                SystemInstance.get().setComponent(ORB.class, orb);
370                SystemInstance.get().setComponent(HandleDelegate.class, handleDelegate);
371            }
372        }
373    
374        public static final GBeanInfo GBEAN_INFO;
375    
376        static {
377            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(OpenEjbSystemGBean.class);
378            infoBuilder.addReference("TransactionManager", TransactionManager.class);
379            infoBuilder.addReference("ResourceAdapterWrappers", ResourceAdapterWrapper.class);
380            infoBuilder.addReference("PersistenceUnitGBeans", PersistenceUnitGBean.class);
381            infoBuilder.addAttribute("kernel", Kernel.class, false);
382            infoBuilder.addAttribute("classLoader", ClassLoader.class, false);
383            infoBuilder.setConstructor(new String[] {
384                    "TransactionManager",
385                    "ResourceAdapterWrappers",
386                    "PersistenceUnitGBeans",
387                    "kernel",
388                    "classLoader",
389            });
390            GBEAN_INFO = infoBuilder.getBeanInfo();
391        }
392    
393        public static GBeanInfo getGBeanInfo() {
394            return GBEAN_INFO;
395        }
396    }