1 22 package org.jboss.proxy.ejb; 23 24 import java.lang.reflect.Proxy ; 25 import java.lang.reflect.Constructor ; 26 import java.lang.reflect.InvocationHandler ; 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.rmi.ServerException ; 32 33 import javax.ejb.EJBHome ; 34 import javax.ejb.EJBObject ; 35 import javax.ejb.EJBMetaData ; 36 import javax.management.ObjectName ; 37 import javax.naming.InitialContext ; 38 import javax.naming.NamingException ; 39 40 import org.jboss.deployment.DeploymentException; 41 import org.jboss.ejb.Container; 42 import org.jboss.ejb.EJBProxyFactory; 43 import org.jboss.ejb.EJBProxyFactoryContainer; 44 import org.jboss.invocation.Invocation; 45 import org.jboss.invocation.Invoker; 46 import org.jboss.invocation.InvocationContext; 47 import org.jboss.invocation.InvocationKey; 48 import org.jboss.logging.Logger; 49 import org.jboss.metadata.InvokerProxyBindingMetaData; 50 import org.jboss.metadata.MetaData; 51 import org.jboss.metadata.EntityMetaData; 52 import org.jboss.metadata.SessionMetaData; 53 import org.jboss.metadata.BeanMetaData; 54 import org.jboss.naming.Util; 55 import org.jboss.proxy.Interceptor; 56 import org.jboss.proxy.ClientContainer; 57 import org.jboss.proxy.ClientContainerEx; 58 import org.jboss.proxy.IClientContainer; 59 import org.jboss.proxy.ejb.handle.HomeHandleImpl; 60 import org.jboss.system.Registry; 61 import org.jboss.util.NestedRuntimeException; 62 import org.w3c.dom.Element ; 63 import org.w3c.dom.Node ; 64 import org.w3c.dom.NodeList ; 65 66 67 88 public class ProxyFactory 89 implements EJBProxyFactory 90 { 91 protected static final String HOME_INTERCEPTOR = "home"; 92 protected static final String BEAN_INTERCEPTOR = "bean"; 93 protected static final String LIST_ENTITY_INTERCEPTOR = "list-entity"; 94 95 protected static Logger log = Logger.getLogger(ProxyFactory.class); 96 97 public EJBMetaData ejbMetaData; 99 100 protected boolean isServiceEndpointOnly; 103 104 protected EJBHome home; 105 protected EJBObject statelessObject; 106 107 protected String jndiBinding; 109 protected ObjectName jmxName; 110 protected int jmxNameHash; 111 private Integer jmxNameHashInteger; 112 113 protected Invoker beanInvoker; 118 protected Invoker homeInvoker; 119 protected InvokerProxyBindingMetaData invokerMetaData; 120 121 124 protected ArrayList homeInterceptorClasses = new ArrayList (); 125 128 protected ArrayList beanInterceptorClasses = new ArrayList (); 129 132 protected ArrayList listEntityInterceptorClasses = new ArrayList (); 133 134 protected boolean includeIClientIface; 135 protected Container container; 137 138 protected Constructor proxyClassConstructor; 139 140 141 143 public void setContainer(Container con) 144 { 145 this.container = con; 146 } 147 148 public void setInvokerMetaData(InvokerProxyBindingMetaData metadata) 149 { 150 this.invokerMetaData = metadata; 151 } 152 153 public void setInvokerBinding(String binding) 154 { 155 this.jndiBinding = binding; 156 } 157 158 public void create() throws Exception 159 { 160 jmxName = container.getJmxName(); 161 jmxNameHash = jmxName.hashCode(); 162 jmxNameHashInteger = new Integer (jmxNameHash); 163 165 BeanMetaData bmd = container.getBeanMetaData(); 166 boolean isSession = !(bmd instanceof EntityMetaData); 167 boolean isStatelessSession = false; 168 if(isSession) 169 { 170 SessionMetaData smd = (SessionMetaData) bmd; 171 if(bmd.getRemote() == null) 172 { 173 isServiceEndpointOnly = true; 174 return; 176 } 177 isStatelessSession = smd.isStateless(); 178 } 179 Class pkClass = null; 180 if(!isSession) 181 { 182 EntityMetaData metaData = (EntityMetaData) bmd; 183 String pkClassName = metaData.getPrimaryKeyClass(); 184 try 185 { 186 if(pkClassName != null) 187 { 188 pkClass = container.getClassLoader().loadClass(pkClassName); 189 } 190 else 191 { 192 pkClass 193 = container.getClassLoader() 194 .loadClass(metaData.getEjbClass()) 195 .getField(metaData.getPrimKeyField()) 196 .getClass(); 197 } 198 } 199 catch(NoSuchFieldException e) 200 { 201 log.error( 202 "Unable to identify Bean's Primary Key class!" 203 + " Did you specify a primary key class and/or field? Does that field exist?" 204 ); 205 throw new RuntimeException ("Primary Key Problem"); 206 } 207 catch(NullPointerException e) 208 { 209 log.error( 210 "Unable to identify Bean's Primary Key class!" 211 + " Did you specify a primary key class and/or field? Does that field exist?" 212 ); 213 throw new RuntimeException ("Primary Key Problem"); 214 } 215 } 216 217 ejbMetaData = new EJBMetaDataImpl( 218 ((EJBProxyFactoryContainer) container).getRemoteClass(), 219 ((EJBProxyFactoryContainer) container).getHomeClass(), 220 pkClass, isSession, isStatelessSession, new HomeHandleImpl(jndiBinding) 224 ); 225 log.debug("Proxy Factory for " + jndiBinding + " initialized"); 226 227 initInterceptorClasses(); 228 } 229 230 234 public void start() throws Exception 235 { 236 if(!isServiceEndpointOnly) 237 { 238 setupInvokers(); 239 bindProxy(); 240 } 241 } 242 243 248 protected void setupInvokers() throws Exception 249 { 250 ObjectName oname = new ObjectName (invokerMetaData.getInvokerMBean()); 251 Invoker invoker = (Invoker) Registry.lookup(oname); 252 if(invoker == null) 253 { 254 throw new RuntimeException ("invoker is null: " + oname); 255 } 256 257 homeInvoker = beanInvoker = invoker; 258 } 259 260 261 264 protected void initInterceptorClasses() throws Exception 265 { 266 HashMap interceptors = new HashMap (); 267 268 Element proxyConfig = invokerMetaData.getProxyFactoryConfig(); 269 Element clientInterceptors = MetaData.getOptionalChild( 270 proxyConfig, 271 "client-interceptors", null 272 ); 273 if(clientInterceptors != null) 274 { 275 String value = MetaData.getElementAttribute(clientInterceptors, "exposeContainer"); 276 this.includeIClientIface = Boolean.valueOf(value).booleanValue(); 277 NodeList children = clientInterceptors.getChildNodes(); 278 for(int i = 0; i < children.getLength(); i++) 279 { 280 Node currentChild = children.item(i); 281 if(currentChild.getNodeType() == Node.ELEMENT_NODE) 282 { 283 Element interceptor = (Element ) children.item(i); 284 interceptors.put(interceptor.getTagName(), interceptor); 285 } 286 } 287 } 288 else 289 { 290 log.debug("client interceptors element is null"); 291 } 292 Element homeInterceptorConf = (Element ) interceptors.get(HOME_INTERCEPTOR); 293 loadInterceptorClasses(homeInterceptorClasses, homeInterceptorConf); 294 if(homeInterceptorClasses.size() == 0) 295 { 296 throw new DeploymentException("There are no home interface interceptors configured"); 297 } 298 299 Element beanInterceptorConf = (Element ) interceptors.get(BEAN_INTERCEPTOR); 300 loadInterceptorClasses(beanInterceptorClasses, beanInterceptorConf); 301 if(beanInterceptorClasses.size() == 0) 302 { 303 throw new DeploymentException("There are no bean interface interceptors configured"); 304 } 305 306 Element listEntityInterceptorConf = (Element ) interceptors.get(LIST_ENTITY_INTERCEPTOR); 307 loadInterceptorClasses(listEntityInterceptorClasses, listEntityInterceptorConf); 308 } 309 310 316 protected void loadInterceptorClasses(ArrayList classes, Element interceptors) 317 throws Exception 318 { 319 Iterator interceptorElements = MetaData.getChildrenByTagName(interceptors, "interceptor"); 320 ClassLoader loader = container.getClassLoader(); 321 while(interceptorElements != null && interceptorElements.hasNext()) 322 { 323 Element ielement = (Element ) interceptorElements.next(); 324 String className = null; 325 className = MetaData.getElementContent(ielement); 326 327 String byValueAttr = MetaData.getElementAttribute(ielement, "call-by-value"); 329 if(byValueAttr != null) 330 { 331 if (container.isCallByValue() == new Boolean (byValueAttr).booleanValue()) 332 { 333 Class clazz = loader.loadClass(className); 334 classes.add(clazz); 335 } 336 } 337 else 338 { 339 Class clazz = loader.loadClass(className); 340 classes.add(clazz); 341 } 342 } 343 } 344 345 351 protected void loadInterceptorChain(ArrayList chain, ClientContainer client) 352 throws Exception 353 { 354 Interceptor last = null; 355 for(int i = 0; i < chain.size(); i++) 356 { 357 Class clazz = (Class ) chain.get(i); 358 Interceptor interceptor = (Interceptor) clazz.newInstance(); 359 if(last == null) 360 { 361 last = interceptor; 362 client.setNext(interceptor); 363 } 364 else 365 { 366 last.setNext(interceptor); 367 last = interceptor; 368 } 369 } 370 } 371 372 379 protected void bindProxy() throws Exception 380 { 381 try 382 { 383 InvocationContext context = new InvocationContext(); 385 386 context.setObjectName(jmxNameHashInteger); 387 context.setValue(InvocationKey.JNDI_NAME, jndiBinding); 388 context.setInvoker(homeInvoker); 390 context.setValue(InvocationKey.EJB_METADATA, ejbMetaData); 391 context.setInvokerProxyBinding(invokerMetaData.getName()); 392 393 ClientContainer client = null; 394 EJBProxyFactoryContainer pfc = (EJBProxyFactoryContainer) container; 395 Class [] ifaces = {pfc.getHomeClass(), Class.forName("javax.ejb.Handle")}; 396 if( includeIClientIface ) 397 { 398 ifaces = new Class [] {IClientContainer.class, pfc.getHomeClass(), 399 Class.forName("javax.ejb.Handle")}; 400 client = new ClientContainerEx(context); 401 } 402 else 403 { 404 client = new ClientContainer(context); 405 } 406 loadInterceptorChain(homeInterceptorClasses, client); 407 408 this.home = (EJBHome ) Proxy.newProxyInstance( 410 pfc.getHomeClass().getClassLoader(), 412 ifaces, 414 client); 416 417 if(ejbMetaData.isStatelessSession() == true) 420 { 421 context = new InvocationContext(); 423 424 context.setObjectName(jmxNameHashInteger); 425 context.setValue(InvocationKey.JNDI_NAME, jndiBinding); 426 context.setInvoker(beanInvoker); 428 context.setInvokerProxyBinding(invokerMetaData.getName()); 429 context.setValue(InvocationKey.EJB_HOME, home); 430 431 Class [] ssifaces = {pfc.getRemoteClass()}; 432 if( includeIClientIface ) 433 { 434 ssifaces = new Class [] {IClientContainer.class, pfc.getRemoteClass()}; 435 client = new ClientContainerEx(context); 436 } 437 else 438 { 439 client = new ClientContainer(context); 440 } 441 loadInterceptorChain(beanInterceptorClasses, client); 442 443 this.statelessObject = 444 (EJBObject )Proxy.newProxyInstance( 445 pfc.getRemoteClass().getClassLoader(), 447 ssifaces, 449 client 451 ); 452 } 453 else 454 { 455 Class [] intfs = {pfc.getRemoteClass()}; 457 if( this.includeIClientIface ) 458 { 459 intfs = new Class []{IClientContainer.class, pfc.getRemoteClass()}; 460 } 461 Class proxyClass = Proxy.getProxyClass(pfc.getRemoteClass().getClassLoader(), intfs); 462 final Class [] constructorParams = {InvocationHandler .class}; 463 proxyClassConstructor = proxyClass.getConstructor(constructorParams); 464 } 465 466 467 rebindHomeProxy(); 469 } 470 catch(Exception e) 471 { 472 throw new ServerException ("Could not bind home", e); 473 } 474 } 475 476 protected void rebindHomeProxy() throws NamingException 477 { 478 log.debug("(re-)Binding Home " + jndiBinding); 480 Util.rebind( 481 new InitialContext (), 483 jndiBinding, 485 getEJBHome() 487 ); 488 489 log.info("Bound EJB Home '" + container.getBeanMetaData().getEjbName() + "' to jndi '" + jndiBinding + "'"); 490 } 491 492 public void stop() 493 { 494 } 495 496 public void destroy() 497 { 498 if(!isServiceEndpointOnly) 499 { 500 log.info("Unbind EJB Home '" + container.getBeanMetaData().getEjbName() + "' from jndi '" + jndiBinding + "'"); 501 502 try 503 { 504 InitialContext ctx = new InitialContext (); 505 ctx.unbind(jndiBinding); 506 } 507 catch(Exception e) 508 { 509 } 511 homeInterceptorClasses.clear(); 512 beanInterceptorClasses.clear(); 513 listEntityInterceptorClasses.clear(); 514 } 515 516 container = null; 517 ejbMetaData = null; 518 home = null; 519 statelessObject = null; 520 beanInvoker = null; 521 homeInvoker = null; 522 invokerMetaData = null; 523 } 524 525 527 public boolean isIdentical(Container container, Invocation mi) 528 { 529 throw new UnsupportedOperationException ("TODO provide a default implementation"); 530 } 531 532 public EJBMetaData getEJBMetaData() 533 { 534 return ejbMetaData; 535 } 536 537 public Object getEJBHome() 538 { 539 return home; 540 } 541 542 545 public Object getStatelessSessionEJBObject() 546 { 547 548 return statelessObject; 549 } 550 551 554 public Object getStatefulSessionEJBObject(Object id) 555 { 556 InvocationContext context = new InvocationContext(); 558 559 context.setObjectName(jmxNameHashInteger); 560 context.setCacheId(id); 561 context.setValue(InvocationKey.JNDI_NAME, jndiBinding); 562 context.setInvoker(beanInvoker); 563 log.debug("seting invoker proxy binding for stateful session: " + invokerMetaData.getName()); 564 context.setInvokerProxyBinding(invokerMetaData.getName()); 565 context.setValue(InvocationKey.EJB_HOME, home); 566 context.setValue("InvokerID", Invoker.ID); 567 568 ClientContainer client; 569 if( includeIClientIface ) 570 { 571 client = new ClientContainerEx(context); 572 } 573 else 574 { 575 client = new ClientContainer(context); 576 } 577 578 try 579 { 580 loadInterceptorChain(beanInterceptorClasses, client); 581 } 582 catch(Exception e) 583 { 584 throw new NestedRuntimeException("Failed to load interceptor chain", e); 585 } 586 587 try 588 { 589 return (EJBObject ) proxyClassConstructor.newInstance(new Object []{client}); 590 } 591 catch(Exception ex) 592 { 593 throw new NestedRuntimeException(ex); 594 } 595 596 } 597 598 601 public Object getEntityEJBObject(Object id) 602 { 603 Object result; 604 if(id == null) 605 { 606 result = null; 607 } 608 else 609 { 610 InvocationContext context = new InvocationContext(); 612 613 context.setObjectName(jmxNameHashInteger); 614 context.setCacheId(id); 615 context.setValue(InvocationKey.JNDI_NAME, jndiBinding); 616 context.setInvoker(beanInvoker); 617 context.setInvokerProxyBinding(invokerMetaData.getName()); 618 context.setValue(InvocationKey.EJB_HOME, home); 619 620 ClientContainer client; 621 if( includeIClientIface ) 622 { 623 client = new ClientContainerEx(context); 624 } 625 else 626 { 627 client = new ClientContainer(context); 628 } 629 630 try 631 { 632 loadInterceptorChain(beanInterceptorClasses, client); 633 } 634 catch(Exception e) 635 { 636 throw new NestedRuntimeException("Failed to load interceptor chain", e); 637 } 638 639 try 640 { 641 result = proxyClassConstructor.newInstance(new Object []{client}); 642 } 643 catch(Exception ex) 644 { 645 throw new NestedRuntimeException(ex); 646 } 647 } 648 return result; 649 } 650 651 654 public Collection getEntityCollection(Collection ids) 655 { 656 ArrayList list = new ArrayList (ids.size()); 657 Iterator idEnum = ids.iterator(); 658 659 while(idEnum.hasNext()) 660 { 661 Object nextId = idEnum.next(); 662 list.add(getEntityEJBObject(nextId)); 663 } 664 return list; 665 } 666 } 667 | Popular Tags |