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