|
Size: 7399
Comment:
|
← Revision 8 as of 2011-12-17 23:11:40 ⇥
Size: 1585
Comment:
|
| Deletions are marked like this. | Additions are marked like this. |
| Line 6: | Line 6: |
| Keep in mind this only works for Stateless session beans, for stateful beans, see the usage example below. |
Code excerpts are from [[http://code.google.com/p/flowlogix/wiki/TapestryLibrary|Flow Logix Tapestry Library]] |
| Line 26: | Line 25: |
| {{{ | [[http://code.google.com/p/flowlogix/source/browse/tapestry-services/src/main/java/com/flowlogix/web/services/internal/EJBAnnotationWorker.java|EJBAnnotationWorker.java]] |
| Line 28: | Line 27: |
| /** * Inject an EJB into tapestry sources * * @author Magnus * Enhancements by Lenny Primak */ public class EJBAnnotationWorker implements ComponentClassTransformWorker2 { @Override @SneakyThrows(NamingException.class) public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) { for (PlasticField field : plasticClass.getFieldsWithAnnotation(EJB.class)) { final EJB annotation = field.getAnnotation(EJB.class); String fieldType = field.getTypeName(); String lookupname = null; //try lookup if (!isBlankOrNull(annotation.lookup())) { lookupname = annotation.lookup(); } //try name else if(!isBlankOrNull(annotation.name())) { lookupname = annotation.name(); } else if(!isBlankOrNull(annotation.beanName())) { lookupname = annotation.beanName(); } //use type if (lookupname == null) { lookupname = guessByType(fieldType); } lookupname = prependPortableName(lookupname); Object injectionValue = locator.getJNDIObject(lookupname); if (injectionValue != null) { field.inject(injectionValue); field.claim(annotation); } } } public static String guessByType(String type) { String lookupname = type.substring(type.lastIndexOf(".") + 1); // support naming convention that strips Local/Remote from the // end of an interface class to try to determine the actual bean name, // to avoid @EJB(beanName="myBeanName"), and just use plain old @EJB String uc = lookupname.toUpperCase(); if (uc.endsWith(LOCAL) || uc.endsWith(REMOTE)) { lookupname = StripLocalPattern.matcher(lookupname).replaceFirst(""); } return lookupname; } public static String prependPortableName(String lookupname) { //convert to jndi name if (!lookupname.startsWith("java:")) { lookupname = "java:module/" + lookupname; } return lookupname; } private boolean isBlankOrNull(String s) { return s == null || s.trim().equals(""); } private final JNDIObjectLocator locator = new JNDIObjectLocator(); private static final String REMOTE = "REMOTE"; private static final String LOCAL = "LOCAL"; public static final Pattern StripLocalPattern = Pattern.compile(LOCAL + "|" + REMOTE, Pattern.CASE_INSENSITIVE); } }}} == Using @EJB in your client code == |
== Using Stateless @EJB in your client code == |
| Line 137: | Line 44: |
| @SetupRender private void init() { if(statefulBeanExists == false) { statefulBean = new JNDIObjectLocator().getObject(MyStatefulBeanLocal.class); } if(statefulBean2 == null) { // A new instance of JNDIObjectLocator has to be used for each lookup, // because it caches lookups, and for stateful session beans this is a no-no statefulBean2 = new JNDIObjectLocator().getObject(MyStatefulBeanLocal.class); } } @SessionState(create = false) private MyStatefulBeanLocal statefulBean; private boolean statefulBeanExists; // another example private @Persist MyStatefulBeanLocal statefulBean2; |
private @EJB @Stateful MyStatefulBeanLocal statefulBean; // stored as SessionState object private @EJB @Stateful(isSessionAttribute = true) MyStatefulBeanLocal statefulBean2; // stored as SessionAttribute object |
| Line 163: | Line 50: |
| There is an even simpler way to use Stateful beans, if you are using the [[http://code.google.com/p/flowlogix/wiki/TapestryLibrary|Flow Logix Tapestry Library]]: {{{ private @EJB @Stateful MyStatefulBeanLocal statefulBean; // its that simple! }}} |
|
| Line 171: | Line 52: |
| {{{ import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import lombok.Getter; import lombok.SneakyThrows; /** * JNDIObjectLocator is used to centralize all JNDI lookups. It minimises the overhead of JNDI lookups by caching the * objects it looks up. * * @author Geoff Callendar * Enhancements by Lenny Primak */ public class JNDIObjectLocator { @SneakyThrows(NamingException.class) public JNDIObjectLocator() { initialContext = new InitialContext(); } @SneakyThrows(NamingException.class) public<T> T getObject(Class<T> beanClass) { String name = EJBAnnotationWorker.guessByType(beanClass.getName()); return getObject(EJBAnnotationWorker.prependPortableName(name)); } @SuppressWarnings("unchecked") public<T> T getObject(String jndiName) throws NamingException { return (T)getJNDIObject(jndiName); } public synchronized void clear() { jndiObjectCache.clear(); } public Object getJNDIObject(String jndiName) throws NamingException { Object jndiObject = jndiObjectCache.get(jndiName); if (jndiObject == null && !jndiObjectCache.containsKey(jndiName)) { try { jndiObject = lookup(jndiName); jndiObjectCache.put(jndiName, jndiObject); } catch (NamingException e) { clear(); throw e; } } return jndiObject; } private synchronized Object lookup(String name) throws NamingException { // Recheck the cache because the name we're looking for may have been added while we were waiting for sync. if (!jndiObjectCache.containsKey(name)) { try { return getInitialContext().lookup(name); } catch (NameNotFoundException e) { clear(); throw e; } } else { return jndiObjectCache.get(name); } } @Getter private final InitialContext initialContext; private final Map<String, Object> jndiObjectCache = Collections.synchronizedMap(new HashMap<String, Object>()); } }}} |
[[http://code.google.com/p/flowlogix/source/browse/tapestry-services/src/main/java/com/flowlogix/ejb/JNDIObjectLocator.java|JNDIObjectLocator.java]] |
How to make @EJB Annotation work in Tapestry pages and components
This works on Tapestry 5.3 or higher. Has been tested with Glassfish 3.1.
Code excerpts are from Flow Logix Tapestry Library
In your AppModule.java file, add the following method
@Contribute(ComponentClassTransformWorker2.class)
@Primary
public static void provideClassTransformWorkers(OrderedConfiguration<ComponentClassTransformWorker2> configuration)
{
configuration.addInstance("EJB", EJBAnnotationWorker.class, "before:Property");
}
EJBAnnotationWorker.java
(add this to one of your non-tapestry packages)
Using Stateless @EJB in your client code
class SomeTapestryPage
{
private @EJB MyStatelessBeanLocal localBean;
}
Using Stateful Session Beans in your client code
class SomeTapestryPage
{
private @EJB @Stateful MyStatefulBeanLocal statefulBean; // stored as SessionState object
private @EJB @Stateful(isSessionAttribute = true) MyStatefulBeanLocal statefulBean2; // stored as SessionAttribute object
}