While integrating no-interface metadata support in AS i see that there's one more
stumbling block - the jndi policy decorator(s). From what i see of those decorators, they
are meant to provide (decorated) jndi names on the metadata:
| * Decorate a JBossSessionBeanMetaData with the ability to resolve JNDI Names
| * based on a specified JNDI Binding Policy, so any getter of a JNDI
| * name will never return null.
|
The JBossSessionPolicyDecorator looks like this:
| public class JBossSessionPolicyDecorator<T extends JBossSessionBeanMetaData>
extends JBossServiceBeanMetaData implements ResolveableJndiNameJbossSessionBeanMetadata
| {
| ...
| private T delegate;
|
| private DefaultJndiBindingPolicy jndiPolicy;
|
| @SuppressWarnings("unchecked")
| public JBossSessionPolicyDecorator(T delegate, DefaultJndiBindingPolicy
jndiPolicy)
| {
| assert delegate != null : "delegate is null";
| assert jndiPolicy != null : this.getClass().getSimpleName() + " requires a
specified "
| + DefaultJndiBindingPolicy.class.getSimpleName();
|
| // Disallow double-wrapping
| if(delegate instanceof JBossSessionPolicyDecorator)
| {
| JBossSessionPolicyDecorator<T> d
=(JBossSessionPolicyDecorator<T>)delegate;
| delegate = d.getDelegate();
| }
|
| this.delegate = delegate;
| this.jndiPolicy = jndiPolicy;
| }
| ...
| // overrides everything from the JBossSessionBeanMetaData to pass control to the
delegate
| // just some example overriden methods
| @Override
| public BusinessLocalsMetaData getBusinessLocals()
| {
| return delegate.getBusinessLocals();
| }
|
| @Override
| public BusinessRemotesMetaData getBusinessRemotes()
| {
| return delegate.getBusinessRemotes();
| }
|
| @Override
| public CacheConfigMetaData getCacheConfig()
| {
| return delegate.getCacheConfig();
| }
|
|
And then when we want to decorate the merged metadata, we create a new instance of this
decorator (notice that the decorator itself is a metadata instance):
| // Create a Session JNDI Policy Decorated Bean
| JBossSessionBeanMetaData decoratedBean = new
JBossSessionPolicyDecorator<JBossSessionBeanMetaData>(sessionBean, policy);
| // then add as attachment to deployment unit
| du.addAttachment(...,decoratedBean);
|
|
The real problem here is that the decorator itself extends from the metadata (i.e.
it's an metadata itself) and we instantiate this decorated metadata and pass it along.
Most of the methods in this decorated metadata have been overriden to pass the control to
the delegate metadata from which this is constructed. However, if any new methods gets
added (like we just added for the EJB3.1 support), then unless someone goes and updates
this class to override such methods, this decorated metadata is going to return incorrect
information. For example (pseudo code):
| JBossSessionBean31MetaData original = new JBossSessionBean31MetaData();
| original.setNoInterfaceBean(true);
| assertTrue(original.isNoInterfaceBean()); // succeeds
| // now decorate (remember pseudo code, but you get the idea)
| JBossSessionBean31MetaData decorated = new
JBossSessionPolicyDecorator(original,jndiPolicy);
| // now check whether the no-interface information was kept intact
| assertTrue(decorated.isNoInterfaceBean()); // FAILS
|
So unless i go and update the decorator to override this method, things are not going to
work:
| public class JBossSession31PolicyDecorator<T extends JBossSession31BeanMetaData>
extends JBossSessionPolicyDecorator
| {
|
| @Overriden
| public boolean isNoInterfaceBean()
| {
| delegate.isNoInterfaceBean;
| }
| ...
|
This is going to be an issue with the introduction of more and more 3.1 metadata support
(for ex: async-methods).
So here's what i was thinking:
The decorator really just needs to update/decorate the metadata with appropriate JNDI
names. It shouldn't really mess with anything else. So why not have something like:
| public interface EnterpriseBeanJNDINameDecorator<T extends
JBossEnterpriseBeanMetaData>
| {
|
| /**
| * Updates the <code>metaData</code> with the ability to resolve JNDI
names.
| * It's upto the implementations of this interface to either:
| * <ul>
| * <li>Create a new instance of metadata and add the ability to resolve
JNDI names and return it
| * </li>
| * <li>Or update the passed <code>metaData</code> with the
ability to resolve JNDI names
| * and return it back</li>
| * </ul>
| * @param metaData The metaData which will be decorated with JNDI names
| * @return Returns the updated metadata
| */
| T decorate(T metaData);
| }
|
Then an implementation of the decorator for the session beans would look like:
| /**
| * JBossSessionBeanMetaDataJNDINameDecorator
| *
| * Decorates a JBossSessionBeanMetaData with the ability to resolve JNDI Names
| * based on a specified JNDI Binding Policy.
| *
| * @author Jaikiran Pai
| * @version $Revision: $
| */
| public class JBossSessionBeanMetaDataJNDINameDecorator<T extends
JBossSessionBeanMetaData>
| implements
| EnterpriseBeanJNDINameDecorator<T>
| {
|
| private DefaultJndiBindingPolicy jndiPolicy;
|
| public JBossSessionBeanMetaDataJNDINameDecorator(DefaultJndiBindingPolicy
jndiPolicy)
| {
| this.jndiPolicy = jndiPolicy;
| }
|
| /**
| * @see
org.jboss.metadata.ejb.jboss.jndipolicy.plugins.EnterpriseBeanJNDINameDecorator#decorate(org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData)
| */
| @Override
| public T decorate(T sessionBeanMetaData)
| {
| // create a resolveable metadata
| ResolveableJndiNameJbossSessionBeanMetadata resolveableJndiNameMetaData = new
JNDIPolicyBasedResolveableJndiNameJBossSessionBeanMetaDataImpl<T>(
| sessionBeanMetaData, this.jndiPolicy);
|
| // Now decorate the metadata (i.e. Update all the relevant JNDI names in the
metadata)
|
| // local jndi name
| String localJndiName =
resolveableJndiNameMetaData.determineResolvedLocalBusinessDefaultJndiName();
| if (localJndiName != null)
| {
| sessionBeanMetaData.setLocalJndiName(localJndiName);
| }
| // remote jndi name
| String jndiName =
resolveableJndiNameMetaData.determineResolvedRemoteBusinessDefaultJndiName();
| if (jndiName != null)
| {
| sessionBeanMetaData.setJndiName(jndiName);
| }
| // home jndi name
| String homeJndiName =
resolveableJndiNameMetaData.determineResolvedRemoteHomeJndiName();
| if (homeJndiName != null)
| {
| sessionBeanMetaData.setHomeJndiName(homeJndiName);
| }
| // local home jndi name
| String localHomeJndiName =
resolveableJndiNameMetaData.determineResolvedLocalHomeJndiName();
| if (localHomeJndiName != null)
| {
| sessionBeanMetaData.setLocalHomeJndiName(localHomeJndiName);
| }
| // mapped name
| String mappedName = this.getMappedName(sessionBeanMetaData,
resolveableJndiNameMetaData);
| if (mappedName != null)
| {
| sessionBeanMetaData.setMappedName(mappedName);
| }
|
| // return the decorated metadata
| return sessionBeanMetaData;
| }
|
This decorator uses the jndipolicy and an implementation of
ResolveableJndiNameJbossSessionBeanMetadata to decorate the bean with the JNDI names. The
implementation of ResolveableJndiNameJbossSessionBeanMetadata looks like this (i just
moved it out of the existing JBossSessionPolicyDecorator):
| public class JNDIPolicyBasedResolveableJndiNameJBossSessionBeanMetaDataImpl<T
extends JBossSessionBeanMetaData>
| implements
| ResolveableJndiNameJbossSessionBeanMetadata
| {
|
| ...
| /**
| * Constructor
| *
| * @param bean The enterprise bean metadata whose jndi name has to be transiently
resolvable
| * @param jndiPolicy The JNDI policy which will be used to resolve the jndi name(s)
of the <code>bean</code>
| */
| public JNDIPolicyBasedResolveableJndiNameJBossSessionBeanMetaDataImpl(T bean,
DefaultJndiBindingPolicy jndiPolicy)
| {
| this.sessionBean = bean;
| this.jndiPolicy = jndiPolicy;
| }
|
| // ... THIS implementation has just been moved out of the current
JBossSessionPolicyDecorator, so
| // there's nothing new here. No point posting all the code in the forum, so just
one method has been
| // posted as an example
| /**
| * Returns the resolved JNDI target to which the
| * default EJB3.x Local Business interfaces are to be bound
| *
| * @return
| */
| @Override
| public String determineResolvedLocalBusinessDefaultJndiName()
| {
| String s = this.sessionBean.getLocalJndiName();
| if (s != null && s.length() > 0)
| return s;
|
| return getJNDIPolicy().getJndiName(getEjbDeploymentSummary(),
KnownInterfaces.LOCAL,
| KnownInterfaceType.BUSINESS_LOCAL);
| }
|
So now that we have a decorator (which is *not* an metadata in itself), we can use it to
decorate the existing/original metadata as follows:
| JBossSessionBean31MetaData original = new JBossSessionBean31MetaData();
| original.setNoInterfaceBean(true);
| assertTrue(original.isNoInterfaceBean()); // succeeds
| // now decorate
| // 1. create a decorator
| EnterpriseBeanJNDINameDecorator<JBossSessionBean31MetaData> decorator = new
JBossSessionBeanMetaDataJNDINameDecorator<JBossSessionBean31MetaData>(new
BasicJndiBindingPolicy());
| // decorate with this decorator
| JBossSessionBean31MetaData decorated = decorator.decorate(original);
| // now check whether the no-interface information was kept intact
| assertTrue(decorated.isNoInterfaceBean()); // Now passes
|
Overall, the difference here is that we have now moved away from the decorator being a
metadata in itself.
My local testcases (around no-interface) are now passing with these changes. There are
some more things that i'll have to work on (for example: a decorator for service beans
etc...), but before i do anything around this, i wanted to have other's opinion on
this change. Any thoughts on how we should proceed? Does this look OK?
View the original post :
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4270186#...
Reply to the post :
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&a...