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 018 package org.apache.geronimo.openejb.deployment; 019 020 import java.net.URI; 021 import java.net.URISyntaxException; 022 import java.util.Collection; 023 import java.util.Collections; 024 import java.util.List; 025 import java.util.Map; 026 import java.util.HashMap; 027 import java.util.Set; 028 import java.util.TreeSet; 029 import java.util.Arrays; 030 import java.util.ArrayList; 031 032 import org.apache.commons.logging.Log; 033 import org.apache.commons.logging.LogFactory; 034 import org.apache.geronimo.common.DeploymentException; 035 import org.apache.geronimo.gbean.GBeanInfo; 036 import org.apache.geronimo.gbean.GBeanInfoBuilder; 037 import org.apache.geronimo.j2ee.deployment.Module; 038 import org.apache.geronimo.j2ee.deployment.annotation.EJBAnnotationHelper; 039 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 040 import org.apache.geronimo.kernel.config.ConfigurationModuleType; 041 import org.apache.geronimo.kernel.repository.Environment; 042 import org.apache.geronimo.naming.deployment.AbstractNamingBuilder; 043 import org.apache.geronimo.openejb.ClientEjbReference; 044 import org.apache.geronimo.xbeans.javaee.EjbLocalRefType; 045 import org.apache.geronimo.xbeans.javaee.EjbRefType; 046 import org.apache.geronimo.xbeans.javaee.InjectionTargetType; 047 import org.apache.geronimo.xbeans.geronimo.naming.GerEjbRefType; 048 import org.apache.geronimo.xbeans.geronimo.naming.GerEjbRefDocument; 049 import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType; 050 import org.apache.geronimo.xbeans.geronimo.naming.GerEjbLocalRefDocument; 051 import org.apache.geronimo.xbeans.geronimo.naming.GerEjbLocalRefType; 052 import org.apache.openejb.OpenEJBException; 053 import org.apache.openejb.assembler.classic.EjbJarInfo; 054 import org.apache.openejb.assembler.classic.JndiEncBuilder; 055 import org.apache.openejb.assembler.classic.JndiEncInfo; 056 import org.apache.openejb.assembler.classic.AppInfo; 057 import org.apache.openejb.config.JndiEncInfoBuilder; 058 import org.apache.openejb.config.AppModule; 059 import org.apache.openejb.core.ivm.naming.IntraVmJndiReference; 060 import org.apache.openejb.jee.EjbLocalRef; 061 import org.apache.openejb.jee.EjbRef; 062 import org.apache.openejb.jee.InjectionTarget; 063 import org.apache.openejb.jee.JndiConsumer; 064 import org.apache.openejb.jee.SessionBean; 065 import org.apache.xmlbeans.QNameSet; 066 import org.apache.xmlbeans.XmlObject; 067 068 /** 069 * @version $Revision: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 070 */ 071 public class EjbRefBuilder extends AbstractNamingBuilder { 072 private static final Log log = LogFactory.getLog(EjbRefBuilder.class); 073 074 private final QNameSet ejbRefQNameSet; 075 private final QNameSet ejbLocalRefQNameSet; 076 private final URI uri; 077 078 public EjbRefBuilder(Environment defaultEnvironment, String[] eeNamespaces, String host, int port) throws URISyntaxException { 079 super(defaultEnvironment); 080 if (host != null) { 081 uri = new URI("ejb", null, host, port, null, null, null); 082 } else { 083 uri = null; 084 } 085 086 ejbRefQNameSet = buildQNameSet(eeNamespaces, "ejb-ref"); 087 ejbLocalRefQNameSet = buildQNameSet(eeNamespaces, "ejb-local-ref"); 088 ejbRefQNameSet.union(ejbLocalRefQNameSet); 089 } 090 091 public QNameSet getSpecQNameSet() { 092 return ejbRefQNameSet; 093 } 094 095 public QNameSet getPlanQNameSet() { 096 return QNameSet.EMPTY; 097 } 098 099 protected boolean willMergeEnvironment(XmlObject specDD, XmlObject plan) { 100 return specDD.selectChildren(ejbRefQNameSet).length > 0 || specDD.selectChildren(ejbLocalRefQNameSet).length > 0; 101 } 102 103 public void buildNaming(XmlObject specDD, XmlObject plan, Module module, Map componentContext) throws DeploymentException { 104 // skip ejb modules... they have alreayd been processed 105 if (module.getType() == ConfigurationModuleType.EJB) { 106 return; 107 } 108 109 // map the refs declared in the vendor plan, so we can match them to the spec references 110 Map<String, GerEjbRefType> refMap = mapEjbRefs(plan); 111 Map<String, GerEjbLocalRefType> localRefMap = mapEjbLocalRefs(plan); 112 113 // JndiConsumer holds the ref objects that OpenEJB needs 114 JndiConsumer consumer = new SessionBean(); 115 116 // Add the refs declaraed the the spec deployment descriptor (e.g., ejb-jar.xml or web.xml) 117 List<EjbRefType> ejbRefs = convert(specDD.selectChildren(ejbRefQNameSet), JEE_CONVERTER, EjbRefType.class, EjbRefType.type); 118 List<EjbLocalRefType> ejbLocalRefs = convert(specDD.selectChildren(ejbLocalRefQNameSet), JEE_CONVERTER, EjbLocalRefType.class, EjbLocalRefType.type); 119 addRefs(consumer, ejbRefs, refMap, ejbLocalRefs, localRefMap, componentContext); 120 121 // Discover and process any @EJB annotations (if !metadata-complete) 122 if ((module != null) && (module.getClassFinder() != null)) { 123 processAnnotations(module); 124 125 // @EJB remote refs 126 ejbRefs = asList(module.getAnnotatedApp().getEjbRefArray()); 127 128 // @EJB local refs 129 ejbLocalRefs = asList(module.getAnnotatedApp().getEjbLocalRefArray()); 130 131 // @EJB ambiguous refs 132 ejbRefs.addAll(module.getAnnotatedApp().getAmbiguousEjbRefs()); 133 134 // add the refs 135 addRefs(consumer, ejbRefs, refMap, ejbLocalRefs, localRefMap, componentContext); 136 } 137 138 Map<String, Object> map = null; 139 try { 140 EjbModuleBuilder.EarData earData = (EjbModuleBuilder.EarData) module.getRootEarContext().getGeneralData().get(EjbModuleBuilder.EarData.class); 141 Collection<EjbJarInfo> ejbJars = Collections.emptySet(); 142 if (earData != null) { 143 ejbJars = earData.getEjbJars(); 144 } 145 146 147 AppInfo appInfo = new AppInfo(); 148 appInfo.ejbJars.addAll(ejbJars); 149 150 JndiEncInfoBuilder jndiEncInfoBuilder = new JndiEncInfoBuilder(appInfo); 151 JndiEncInfo jndiEncInfo; 152 if (module.isStandAlone()) { 153 jndiEncInfo = jndiEncInfoBuilder.build(consumer, "GeronimoEnc", null); 154 } else { 155 jndiEncInfo = jndiEncInfoBuilder.build(consumer, "GeronimoEnc", module.getTargetPath()); 156 } 157 JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(jndiEncInfo, null, module.getName(), getClass().getClassLoader()); 158 159 map = jndiEncBuilder.buildMap(); 160 } catch (OpenEJBException e) { 161 throw new DeploymentException(e); 162 } 163 164 for (Map.Entry<String, Object> entry : map.entrySet()) { 165 String name = entry.getKey(); 166 Object value = entry.getValue(); 167 168 // work with names prefixed with java:comp/ 169 if (name.startsWith("java:comp/")) { 170 name = name.substring("java:comp/".length()); 171 } 172 173 // if this is a ref it will be prefixed with env/ 174 if (name.startsWith("env/")) { 175 if (uri != null) { 176 value = createClientRef(value); 177 } 178 getJndiContextMap(componentContext).put(name, value); 179 } 180 } 181 } 182 183 private Object createClientRef(Object value) { 184 if (value instanceof IntraVmJndiReference) { 185 IntraVmJndiReference intraVmJndiReference = (IntraVmJndiReference) value; 186 String deploymentId = intraVmJndiReference.getJndiName(); 187 if (deploymentId.startsWith("java:openejb/ejb/")) { 188 deploymentId = deploymentId.substring("java:openejb/ejb/".length()); 189 } 190 if (deploymentId.startsWith("java:openejb/Deployment/")) { 191 deploymentId = deploymentId.substring("java:openejb/Deployment/".length()); 192 } 193 ClientEjbReference clientRef = new ClientEjbReference(uri.toString(), deploymentId); 194 return clientRef; 195 } 196 return value; 197 } 198 199 private void addRefs(JndiConsumer jndiConsumer, List<EjbRefType> ejbRefs, Map<String, GerEjbRefType> refMap, List<EjbLocalRefType> ejbLocalRefs, Map<String, GerEjbLocalRefType> localRefMap, Map componentContext) { 200 Set<String> declaredEjbRefs = new TreeSet<String>(); 201 for (EjbRef ejbRef : jndiConsumer.getEjbRef()) { 202 declaredEjbRefs.add(ejbRef.getName()); 203 } 204 for (EjbRefType xmlbeansRef : ejbRefs) { 205 // skip refs that have already been declared 206 String refName = getStringValue(xmlbeansRef.getEjbRefName()); 207 if (declaredEjbRefs.contains(refName)) { 208 continue; 209 } 210 211 // skip corba refs 212 GerEjbRefType ejbRefType = refMap.get(refName); 213 if (ejbRefType != null) { 214 if (ejbRefType.getNsCorbaloc() != null) { 215 continue; 216 } 217 } 218 // create the ejb-ref 219 EjbRef ref = new EjbRef(); 220 // ejb-ref-name 221 ref.setEjbRefName(refName); 222 223 jndiConsumer.getEjbRef().add(ref); 224 225 // ejb-ref-type 226 String refType = getStringValue(xmlbeansRef.getEjbRefType()); 227 if ("SESSION".equalsIgnoreCase(refType)) { 228 ref.setEjbRefType(org.apache.openejb.jee.EjbRefType.SESSION); 229 } else if ("ENTITY".equalsIgnoreCase(refType)) { 230 ref.setEjbRefType(org.apache.openejb.jee.EjbRefType.ENTITY); 231 } else { 232 ref.setRefType(EjbRef.Type.UNKNOWN); 233 } 234 235 // home 236 ref.setHome(getStringValue(xmlbeansRef.getHome())); 237 238 // remote 239 ref.setRemote(getStringValue(xmlbeansRef.getRemote())); 240 241 // ejb-link 242 ref.setEjbLink(getStringValue(xmlbeansRef.getEjbLink())); 243 244 // mapped-name 245 ref.setMappedName(getStringValue(xmlbeansRef.getMappedName())); 246 247 // handle external refs 248 if (ejbRefType != null) { 249 if (ejbRefType.getNsCorbaloc() != null) { 250 // corba refs are simple delegated back to Geronimo 251 ref.setMappedName("jndi:java:comp/geronimo/env/" + ref.getEjbRefName()); 252 } else if (ejbRefType.getPattern() != null) { 253 // external ear ref 254 // set mapped name to the deploymentId of the external ref 255 GerPatternType pattern = ejbRefType.getPattern(); 256 String module = pattern.getModule(); 257 if (module == null) { 258 module = pattern.getArtifactId(); 259 } 260 String ejbName = pattern.getName(); 261 String deploymentId = module.trim() + "/" + ejbName; 262 ref.setMappedName(deploymentId.trim()); 263 } 264 } 265 266 // openejb handling of injection-targets 267 if (xmlbeansRef.getInjectionTargetArray() != null) { 268 for (InjectionTargetType injectionTargetType : xmlbeansRef.getInjectionTargetArray()) { 269 InjectionTarget injectionTarget = new InjectionTarget(); 270 injectionTarget.setInjectionTargetClass(getStringValue(injectionTargetType.getInjectionTargetClass())); 271 injectionTarget.setInjectionTargetName(getStringValue(injectionTargetType.getInjectionTargetName())); 272 ref.getInjectionTarget().add(injectionTarget); 273 } 274 } 275 //geronimo's handling of injection-target 276 addInjections(refName, xmlbeansRef.getInjectionTargetArray(), componentContext); 277 278 } 279 280 Set<String> declaredEjbLocalRefs = new TreeSet<String>(); 281 for (EjbLocalRef ejbLocalRef : jndiConsumer.getEjbLocalRef()) { 282 declaredEjbLocalRefs.add(ejbLocalRef.getName()); 283 } 284 285 for (EjbLocalRefType xmlbeansRef : ejbLocalRefs) { 286 // skip refs that have already been declared 287 String refName = getStringValue(xmlbeansRef.getEjbRefName()); 288 if (declaredEjbLocalRefs.contains(refName)) { 289 continue; 290 } 291 292 // create the ejb-ref 293 EjbLocalRef ref = new EjbLocalRef(); 294 // ejb-ref-name 295 ref.setEjbRefName(refName); 296 297 jndiConsumer.getEjbLocalRef().add(ref); 298 299 // ejb-ref-type 300 String refType = getStringValue(xmlbeansRef.getEjbRefType()); 301 if ("SESSION".equalsIgnoreCase(refType)) { 302 ref.setEjbRefType(org.apache.openejb.jee.EjbRefType.SESSION); 303 } else if ("ENTITY".equalsIgnoreCase(refType)) { 304 ref.setEjbRefType(org.apache.openejb.jee.EjbRefType.ENTITY); 305 } 306 307 // home 308 ref.setLocalHome(getStringValue(xmlbeansRef.getLocalHome())); 309 310 // remote 311 ref.setLocal(getStringValue(xmlbeansRef.getLocal())); 312 313 // ejb-link 314 ref.setEjbLink(getStringValue(xmlbeansRef.getEjbLink())); 315 316 // mapped-name 317 ref.setMappedName(getStringValue(xmlbeansRef.getMappedName())); 318 319 // handle external refs 320 GerEjbLocalRefType ejbLocalRefType = localRefMap.get(ref.getEjbRefName()); 321 if (ejbLocalRefType != null && ejbLocalRefType.getPattern() != null) { 322 // external ear ref 323 // set mapped name to the deploymentId of the external ref 324 GerPatternType pattern = ejbLocalRefType.getPattern(); 325 String module = pattern.getModule(); 326 if (module == null) { 327 module = pattern.getArtifactId(); 328 } 329 String ejbName = pattern.getName(); 330 String deploymentId = module.trim() + "/" + ejbName; 331 ref.setMappedName(deploymentId.trim()); 332 } 333 334 // openejb handling of injection-targets 335 if (xmlbeansRef.getInjectionTargetArray() != null) { 336 for (InjectionTargetType injectionTargetType : xmlbeansRef.getInjectionTargetArray()) { 337 InjectionTarget injectionTarget = new InjectionTarget(); 338 injectionTarget.setInjectionTargetClass(getStringValue(injectionTargetType.getInjectionTargetClass())); 339 injectionTarget.setInjectionTargetName(getStringValue(injectionTargetType.getInjectionTargetName())); 340 ref.getInjectionTarget().add(injectionTarget); 341 } 342 } 343 //geronimo's handling of injection-target 344 addInjections(refName, xmlbeansRef.getInjectionTargetArray(), componentContext); 345 } 346 } 347 348 private Map<String, GerEjbRefType> mapEjbRefs(XmlObject plan) { 349 Map<String, GerEjbRefType> refMap = new HashMap<String, GerEjbRefType>(); 350 351 if (plan == null) { 352 return refMap; 353 } 354 355 QNameSet qnameSet = QNameSet.singleton(GerEjbRefDocument.type.getDocumentElementName()); 356 XmlObject[] xmlObjects = plan.selectChildren(qnameSet); 357 if (xmlObjects != null) { 358 for (XmlObject xmlObject : xmlObjects) { 359 GerEjbRefType ref = (GerEjbRefType) xmlObject.copy().changeType(GerEjbRefType.type); 360 refMap.put(ref.getRefName().trim(), ref); 361 } 362 } 363 return refMap; 364 } 365 366 private Map<String, GerEjbLocalRefType> mapEjbLocalRefs(XmlObject plan) { 367 Map<String, GerEjbLocalRefType> refMap = new HashMap<String, GerEjbLocalRefType>(); 368 369 if (plan == null) { 370 return refMap; 371 } 372 373 QNameSet qnameSet = QNameSet.singleton(GerEjbLocalRefDocument.type.getDocumentElementName()); 374 XmlObject[] xmlObjects = plan.selectChildren(qnameSet); 375 if (xmlObjects != null) { 376 for (XmlObject xmlObject : xmlObjects) { 377 GerEjbLocalRefType ref = (GerEjbLocalRefType) xmlObject.copy().changeType(GerEjbLocalRefType.type); 378 refMap.put(ref.getRefName().trim(), ref); 379 } 380 } 381 return refMap; 382 } 383 384 385 // XMLBean uses lame arrays that can be null, so we need an asList that handles nulls 386 // Beware Arrays.asList(), it returns an ArrayList lookalike, that is not fully mutable... 387 public static <E> List<E> asList(E[] array) { 388 if (array == null) { 389 return new ArrayList<E>(); 390 } else { 391 return new ArrayList<E>(Arrays.asList(array)); 392 } 393 } 394 395 private void processAnnotations(Module module) { 396 // Process all the annotations for this naming builder type 397 if (EJBAnnotationHelper.annotationsPresent(module.getClassFinder())) { 398 try { 399 EJBAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder()); 400 } catch (Exception e) { 401 log.warn("Unable to process @EJB annotations for module" + module.getName(), e); 402 } 403 } 404 } 405 406 public static final GBeanInfo GBEAN_INFO; 407 408 static { 409 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(EjbRefBuilder.class, NameFactory.MODULE_BUILDER); 410 411 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true); 412 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true); 413 infoBuilder.addAttribute("host", String.class, true); 414 infoBuilder.addAttribute("port", int.class, true); 415 416 infoBuilder.setConstructor(new String[]{"defaultEnvironment", "eeNamespaces", "host", "port"}); 417 418 GBEAN_INFO = infoBuilder.getBeanInfo(); 419 } 420 421 public static GBeanInfo getGBeanInfo() { 422 return GBEAN_INFO; 423 } 424 425 }