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.corba.deployment;
018    
019    import java.util.Collection;
020    import java.util.Map;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.jar.JarFile;
024    import java.io.File;
025    import java.net.URI;
026    import java.net.URL;
027    
028    import org.apache.geronimo.common.DeploymentException;
029    import org.apache.geronimo.corba.TSSLinkGBean;
030    import org.apache.geronimo.deployment.ModuleIDBuilder;
031    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
032    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
033    import org.apache.geronimo.gbean.AbstractName;
034    import org.apache.geronimo.gbean.AbstractNameQuery;
035    import org.apache.geronimo.gbean.GBeanData;
036    import org.apache.geronimo.gbean.GBeanInfo;
037    import org.apache.geronimo.gbean.GBeanInfoBuilder;
038    import org.apache.geronimo.gbean.GBeanLifecycle;
039    import org.apache.geronimo.j2ee.deployment.EARContext;
040    import org.apache.geronimo.j2ee.deployment.Module;
041    import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
042    import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
043    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
044    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
045    import org.apache.geronimo.kernel.GBeanNotFoundException;
046    import org.apache.geronimo.kernel.Kernel;
047    import org.apache.geronimo.kernel.Naming;
048    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
049    import org.apache.geronimo.kernel.config.ConfigurationStore;
050    import org.apache.geronimo.kernel.repository.Environment;
051    import org.apache.geronimo.naming.deployment.ENCConfigBuilder;
052    import org.apache.geronimo.openejb.deployment.EjbModule;
053    import org.apache.openejb.assembler.classic.EnterpriseBeanInfo;
054    
055    import org.apache.openejb.jee.oejb2.GeronimoEjbJarType; 
056    import org.apache.openejb.jee.oejb2.TssLinkType; 
057    
058    import org.apache.geronimo.openejb.xbeans.ejbjar.OpenejbGeronimoEjbJarType;
059    import org.apache.geronimo.openejb.xbeans.ejbjar.OpenejbTssLinkType;
060    
061    /**
062     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
063     */
064    public class CorbaModuleBuilderExtension implements ModuleBuilderExtension, GBeanLifecycle {
065    
066        private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
067        static {
068            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-css-config_1_0", "http://openejb.apache.org/xml/ns/corba-css-config-2.1");
069            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-css-config-2.0", "http://openejb.apache.org/xml/ns/corba-css-config-2.1");
070            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-tss-config_1_0", "http://openejb.apache.org/xml/ns/corba-tss-config-2.1");
071            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-tss-config-2.0", "http://openejb.apache.org/xml/ns/corba-tss-config-2.1");
072            NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/corba-tss-config-2.1", "http://openejb.apache.org/xml/ns/corba-tss-config-2.1");
073        }
074        // our default environment
075        protected Environment defaultEnvironment;
076    
077        public CorbaModuleBuilderExtension() throws Exception {
078            this(null);
079        }
080    
081        public CorbaModuleBuilderExtension(Environment defaultEnvironment) {
082            this.defaultEnvironment = defaultEnvironment;
083        }
084    
085        public void doStart() throws Exception {
086            XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
087        }
088    
089        public void doStop() {
090            XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
091        }
092    
093        public void doFail() {
094            doStop();
095        }
096    
097        /**
098         * Early module creation.  If this module contains
099         * and CORBA enablement links, the corba default 
100         * environment is merged in.
101         * 
102         * @param module     The module being deployed.
103         * @param plan       The module plan
104         * @param moduleFile The jar file containing the module.
105         * @param targetPath The module path.
106         * @param specDDUrl  The schema information.
107         * @param environment
108         *                   The current environment (used for the merge).
109         * @param moduleContextInfo
110         *                   The module context.
111         * @param earName    The name of the ear file.
112         * @param naming     The naming context.
113         * @param idBuilder
114         * 
115         * @exception DeploymentException
116         */
117        public void createModule(Module module, Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
118            if (module.getType() != ConfigurationModuleType.EJB) {
119                return;
120            }
121            
122            // if we have a default environment specified, we merge it in, but only if 
123            // this module has tss links.  The vendorDD isn't available yet, so we'll have to look at the  
124            // jaxb version of this information now. 
125            if (this.defaultEnvironment != null) {
126                EjbModule ejbModule = (EjbModule)module;
127                GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getEjbModule().getAltDDs().get("geronimo-openejb.xml");
128                
129                if (geronimoEjbJarType != null) {
130                    List<TssLinkType> links = geronimoEjbJarType.getTssLink(); 
131                    if (links != null && links.size() > 0) {
132                        EnvironmentBuilder.mergeEnvironments(environment, this.defaultEnvironment);
133                    }
134                }
135            }        
136        }
137    
138        public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
139        }
140    
141        public void initContext(EARContext earContext, Module module, ClassLoader cl) throws DeploymentException {
142        }
143    
144        /**
145         * Add any GBeans to the deployment that might be 
146         * required by the presence of tss-link definitions
147         * in the ejb plans.
148         * 
149         * @param earContext The earContext of the module deployment.
150         * @param module     The module being deployed.
151         * @param cl         The module class loader instance.
152         * @param repository The repository.
153         * 
154         * @exception DeploymentException
155         *                   Thrown if any of the tss-link information cannot
156         *                   be resolved (missing ejb or TSSBean).
157         */
158        public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repository) throws DeploymentException {
159    
160            if (module.getType() != ConfigurationModuleType.EJB) {
161                return;
162            }
163            EjbModule ejbModule = (EjbModule) module;
164            OpenejbGeronimoEjbJarType jarInfo = ejbModule.getVendorDD(); 
165    
166            OpenejbTssLinkType[] links = jarInfo.getTssLinkArray(); 
167            // if there are no links, then there's nothing to do. 
168            if (links == null || links.length == 0) {
169                return; 
170            }
171            
172            URI moduleURI = module.getModuleURI();
173            String moduleString = moduleURI == null ? null : moduleURI.toString();
174            
175            for (OpenejbTssLinkType link : links) {
176                AbstractName tssBeanName = resolveTssBean(earContext, link.getTssName(), moduleString); 
177                AbstractName ejbName = resolveEjb(earContext, ejbModule, link.getEjbName());
178                
179                AbstractName tssLinkName = earContext.getNaming().createChildName(ejbName, link.getTssName(), NameFactory.CORBA_TSS_LINK);
180                GBeanData tssLinkData = new GBeanData(tssLinkName, TSSLinkGBean.GBEAN_INFO);
181                tssLinkData.setAttribute("jndiNames", link.getJndiNameArray());
182                tssLinkData.setReferencePattern("EJB", ejbName);
183                tssLinkData.setReferencePattern("TSSBean", tssBeanName);
184                try {
185                    earContext.addGBean(tssLinkData);
186                } catch (GBeanAlreadyExistsException e) {
187                    throw new DeploymentException("tss link gbean already present", e);
188                }
189            }
190        }
191        
192        /**
193         * Resolve a TSSBean name specified in a tss-link 
194         * item to the bean's abstract name.  
195         * 
196         * @param context The ear context for the module were processing
197         * @param name    The target name of the TSSBean.
198         * @param module  The module name used to qualifiy the look ups.
199         * 
200         * @return An AbstractName for the target TSSBean. 
201         * @exception DeploymentException
202         *                   Thrown if the target TSSBean could not be located.
203         */
204        private AbstractName resolveTssBean(EARContext context, String name, String module) throws DeploymentException {
205            AbstractNameQuery tssBeanName = ENCConfigBuilder.buildAbstractNameQuery(null, module, name, NameFactory.CORBA_TSS, NameFactory.EJB_MODULE);
206            try {
207                return context.findGBean(tssBeanName);
208            } catch (GBeanNotFoundException e) {
209                tssBeanName = ENCConfigBuilder.buildAbstractNameQuery(null, null, name, NameFactory.CORBA_TSS, null);
210                try {
211                    return context.findGBean(tssBeanName);
212                } catch (GBeanNotFoundException e1) {
213                    throw new DeploymentException("No tss bean " + name + " not found for module " + module, e);
214                }
215            }
216        }
217        
218        /**
219         * Resolve an EJB name used in a tss-link element to
220         * the abstract name for that EJB.  The EJB must be part
221         * of the current module bean set to be resolveable.
222         * 
223         * @param context   The ear context used for resolution.
224         * @param ejbModule The EJBModule we're currently processing.
225         * @param name      The name of the target EJB.
226         * 
227         * @return An AbstractName for the referenced EJB.
228         * @exception DeploymentException
229         *                   Thrown if the ejb does not exist in the current
230         *                   module.
231         */
232        private AbstractName resolveEjb(EARContext earContext, EjbModule ejbModule, String name) throws DeploymentException {
233            for (EnterpriseBeanInfo bean : ejbModule.getEjbJarInfo().enterpriseBeans) {
234                // search for the target ejb 
235                if (name.equals(bean.ejbName)) {
236                    switch (bean.type) {
237                        case EnterpriseBeanInfo.STATELESS: {
238                            return earContext.getNaming().createChildName(ejbModule.getModuleName(), name, NameFactory.STATELESS_SESSION_BEAN);
239                        }
240                        case EnterpriseBeanInfo.STATEFUL: {
241                            return earContext.getNaming().createChildName(ejbModule.getModuleName(), name, NameFactory.STATEFUL_SESSION_BEAN);
242                        }
243                        case EnterpriseBeanInfo.ENTITY: {
244                            return earContext.getNaming().createChildName(ejbModule.getModuleName(), name, NameFactory.ENTITY_BEAN);
245                        }
246                        case EnterpriseBeanInfo.MESSAGE: {
247                            return earContext.getNaming().createChildName(ejbModule.getModuleName(), name, NameFactory.MESSAGE_DRIVEN_BEAN);
248                        }
249                    }
250                }
251            }
252            throw new DeploymentException("EJB " + name + " not found for module " + ejbModule.getModuleName());
253        }
254    
255    
256        public static final GBeanInfo GBEAN_INFO;
257    
258        static {
259            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(CorbaModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
260            infoBuilder.addInterface(ModuleBuilderExtension.class);
261            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
262    
263            infoBuilder.setConstructor(new String[]{"defaultEnvironment"});
264    
265            GBEAN_INFO = infoBuilder.getBeanInfo();
266        }
267    
268        public static GBeanInfo getGBeanInfo() {
269            return GBEAN_INFO;
270        }
271    }
272