FileDocCategorySizeDatePackage
AbstractEjbHandler.javaAPI DocGlassfish v2 API20736Fri May 04 22:31:34 BST 2007com.sun.enterprise.deployment.annotation.handlers

AbstractEjbHandler

public abstract class AbstractEjbHandler extends AbstractHandler
This is an abstract class for EJB annotation handler. Concrete subclass handlers need to implements the following methods: public Class<? extends Annotation> getAnnotationType(); protected String getAnnotatedName(Annotation annotation ); protected boolean isValidEjbDescriptor(EjbDescriptor ejbDesc); Annotation annotation); protected EjbDescriptor createEjbDescriptor(String elementName, AnnotationInfo ainfo) throws AnnotationProcessorException; protected HandlerProcessingResult setEjbDescriptorInfo( EjbDescriptor ejbDesc, AnnotationInfo ainfo) throws AnnotationProcessorException;
author
Shing Wai Chan

Fields Summary
Constructors Summary
Methods Summary
protected abstract com.sun.enterprise.deployment.EjbDescriptorcreateEjbDescriptor(java.lang.String elementName, com.sun.enterprise.deployment.annotation.AnnotationInfo ainfo)
Create a new EjbDescriptor for a given elementName and AnnotationInfo.

param
elementName
param
ainfo
return
a new EjbDescriptor

protected voiddoDescriptionProcessing(java.lang.String description, com.sun.enterprise.deployment.EjbDescriptor ejbDescriptor)

        // Since there are multiple descriptions allowed in the deployment
        // descriptor, there are no overriding issues here.  If the
        // component-defining annotation contains a description, it will
        // always be added to the list of descriptions for the bean.
        if( (description != null) && !description.equals("") ) {
            ejbDescriptor.setDescription(description);
        }

    
protected voiddoMappedNameProcessing(java.lang.String mappedName, com.sun.enterprise.deployment.EjbDescriptor ejbDesc)

        
        // Set mappedName() if a value has been given in the annotation and
        // it hasn't already been set on the descriptor via the .xml. 
        if( ejbDesc.getMappedName().equals("") ) {
            if( !mappedName.equals("") ) {
                ejbDesc.setMappedName(mappedName);
            }
        }
        
        
    
private voiddoTimedObjectProcessing(java.lang.Class ejbClass, com.sun.enterprise.deployment.EjbDescriptor ejbDesc)
Process TimedObject and @Timeout annotation. It's better to do it when processing the initial bean type since Timeout method is a business method that should be included in any tx processing defaulting that takes place.

        
        // Timeout methods can be declared on the bean class or any
        // super-class and can be public, protected, private, or 
        // package access.  There can be at most one timeout method for
        // the entire bean class hierarchy, so we start from the bean 
        // class and go up, stopping when we find the first one.

        MethodDescriptor timeoutMethodDesc = null;
        Class nextClass = ejbClass;
        while((nextClass != Object.class) && (nextClass != null) 
              && (timeoutMethodDesc == null) ) {
            Method[] methods = nextClass.getDeclaredMethods();
            for(Method m : methods) {
                if( (m.getAnnotation(Timeout.class) != null) ) {
                    timeoutMethodDesc = 
                        new MethodDescriptor(m, MethodDescriptor.EJB_BEAN);
                    break;
                }
            }
            nextClass = nextClass.getSuperclass();
        }

        if( (timeoutMethodDesc == null) && 
            javax.ejb.TimedObject.class.isAssignableFrom(ejbClass) ) {
            // If the class implements the TimedObject interface, it must
            // be ejbTimeout.
            timeoutMethodDesc = new MethodDescriptor
                ("ejbTimeout", "@Timeout method", 
                 new String[] { "javax.ejb.Timer" }, 
                 MethodDescriptor.EJB_BEAN);
        }

        if( timeoutMethodDesc != null ) {
            ejbDesc.setEjbTimeoutMethod(timeoutMethodDesc);
        }

        return;
    
protected booleanexcludedFromImplementsClause(java.lang.Class intf)

        return ( (intf == java.io.Serializable.class) ||
                 (intf == java.io.Externalizable.class) ||
                 ( (intf.getPackage() != null) &&
                   intf.getPackage().getName().equals("javax.ejb")) );
    
protected abstract java.lang.StringgetAnnotatedName(java.lang.annotation.Annotation annotation)
Return the name attribute of given annotation.

param
annotation
return
name

private java.lang.ClassgetComponentIntfFromHome(java.lang.Class homeIntf)


        Class componentIntf = null;

        Method[] methods = homeIntf.getMethods();
        for (Method m : methods) {
            if (m.getName().startsWith("create")) {
                componentIntf = m.getReturnType();
                break;
            }
        }

        return componentIntf;
    
protected abstract booleanisValidEjbDescriptor(com.sun.enterprise.deployment.EjbDescriptor ejbDesc, java.lang.annotation.Annotation annotation)

public com.sun.enterprise.deployment.annotation.HandlerProcessingResultprocessAnnotation(com.sun.enterprise.deployment.annotation.AnnotationInfo ainfo)
Process a particular annotation which type is the same as the one returned by @see getAnnotationType(). All information pertinent to the annotation and its context is encapsulated in the passed AnnotationInfo instance. This is a method in interface AnnotationHandler.

param
ainfo the annotation information


        Class ejbClass = (Class) ainfo.getAnnotatedElement();
        Annotation annotation = ainfo.getAnnotation();
        if (logger.isLoggable(Level.FINER)) {
            logger.finer("@ process ejb annotation " +
                annotation + " in " + ejbClass);
        }
        AnnotatedElementHandler aeHandler =
                ainfo.getProcessingContext().getHandler();
        if (aeHandler != null && aeHandler instanceof EjbContext) {
            EjbContext context = (EjbContext)aeHandler;
            EjbDescriptor desc = context.getDescriptor();
            if (isValidEjbDescriptor(desc, annotation)) {
                return getDefaultProcessedResult();
            } else {
                log(Level.SEVERE, ainfo,
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.notcompsuperclass",
                    "The annotation symbol defined in super-class is not compatible with {0} ejb {1}.",
                    new Object[] { desc.getType(), desc.getName() }));
                return getDefaultFailedResult();
            }
        } else if (aeHandler == null || !(aeHandler instanceof EjbBundleContext)) {
            return getInvalidAnnotatedElementHandlerResult(
                ainfo.getProcessingContext().getHandler(), ainfo);
        }

        EjbBundleContext ctx = (EjbBundleContext)aeHandler;

        if (logger.isLoggable(Level.FINE)) {
            logger.fine("My context is " + ctx);       
        }
        
        String elementName = getAnnotatedName(annotation);
        if (elementName.length() == 0) {
            elementName = ejbClass.getSimpleName();            
        }

        EjbBundleDescriptor currentBundle = ctx.getDescriptor();
        EjbDescriptor ejbDesc = null;
        try {
            ejbDesc = currentBundle.getEjbByName(elementName);
        } catch(IllegalArgumentException ex) {
            //getEjbByName throws IllegalArgumentException when no ejb is found
        }

        if (ejbDesc != null && !(ejbDesc instanceof DummyEjbDescriptor) ) {
            // element has already been defined in the standard DDs,
            // overriding rules applies
            if (logger.isLoggable(Level.FINE)) {            
                logger.fine("Overriding rules apply for " + ejbClass.getName());
            }

            // don't allow ejb-jar.xml overwrite ejb type
            if (!isValidEjbDescriptor(ejbDesc, annotation)) {
                // this is an error
                log(Level.SEVERE, ainfo,     
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.wrongejbtype",
                    "Wrong annotation symbol for ejb {1}",
                    new Object[] { ejbDesc }));
                return getDefaultFailedResult();
            }

            // <ejb-class> is optional if a component-defining
            // annotation is used.  If present, <ejb-class> element
            // must match the class on which the component defining annotation
            // appears.
            String descriptorEjbClass = ejbDesc.getEjbClassName();
            if( descriptorEjbClass == null ) {
                ejbDesc.setEjbClassName(ejbClass.getName());
                ejbDesc.applyDefaultClassToLifecycleMethods();
            } else if( !descriptorEjbClass.equals(ejbClass.getName()) ) {
                log(Level.SEVERE, ainfo,     
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.ejbclsmismatch",
                    "",
                    new Object[] { descriptorEjbClass, elementName, 
                                   ejbClass.getName() }));
                return getDefaultFailedResult();
            }


        } else {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Creating a new descriptor for "
                    + ejbClass.getName());
            }

            EjbDescriptor dummyEjbDesc = ejbDesc;

            ejbDesc = createEjbDescriptor(elementName, ainfo);

            // create the actual ejb descriptor using annotation info and 
            // the information from dummy ejb descriptor if applicable
            if (dummyEjbDesc != null && 
                dummyEjbDesc instanceof DummyEjbDescriptor ) {
                currentBundle.removeEjb(dummyEjbDesc);
                ejbDesc.addEjbDescriptor(dummyEjbDesc);
                // reset ejbClassName on ejbDesc
                ejbDesc.setEjbClassName(ejbClass.getName());
            }

            // add the actual ejb descriptor to the ejb bundle
            currentBundle.addEjb(ejbDesc);

            if (logger.isLoggable(Level.FINE)) {
                logger.fine("New " +
                    getAnnotationType().getName() + " bean " + elementName);
            }
        }

        HandlerProcessingResult procResult = setEjbDescriptorInfo(ejbDesc, ainfo);
        doTimedObjectProcessing(ejbClass, ejbDesc);

        EjbContext ejbContext = new EjbContext(ejbDesc, ejbClass);
        // we push the new context on the stack...
        ctx.getProcessingContext().pushHandler(ejbContext);
        
        return procResult;
    
protected com.sun.enterprise.deployment.annotation.HandlerProcessingResultsetBusinessAndHomeInterfaces(com.sun.enterprise.deployment.EjbDescriptor ejbDesc, com.sun.enterprise.deployment.annotation.AnnotationInfo ainfo)
MessageDriven bean does not need to invoke this API.

param
ejbDesc
param
ainfo for error handling
return
HandlerProcessingResult


        Set<String> localIntfNames = new HashSet<String>();
        Set<String> remoteIntfNames = new HashSet<String>();

        Class ejbClass = (Class)ainfo.getAnnotatedElement();

        // First check for annotations specifying remote/local business intfs.
        // We analyze them here because they are needed during the
        // implements clause processing for beans that specify 
        // @Stateless/@Stateful.  In addition, they should *not* be processed
        // if there is no @Stateful/@Stateless annotation.

        Remote remoteBusAnn = (Remote) ejbClass.getAnnotation(Remote.class); 
        boolean emptyRemoteBusAnn = false;
        if( remoteBusAnn != null ) {
            for(Class next : remoteBusAnn.value()) {
                remoteIntfNames.add(next.getName());
            }
            emptyRemoteBusAnn = remoteIntfNames.isEmpty();
        }

        Local localBusAnn = (Local) ejbClass.getAnnotation(Local.class); 
        if( localBusAnn != null ) {
            for(Class next : localBusAnn.value()) {
                localIntfNames.add(next.getName());
            }
        }

        List<Class> eligibleInterfaces = new LinkedList<Class>();
        for(Class next : ejbClass.getInterfaces()) {
            if( !excludedFromImplementsClause(next) ) {
                eligibleInterfaces.add(next);
            }
        }

        // total number of local/remote business interfaces declared
        // outside of the implements clause
        int nonImplementsClauseBusinessInterfaceCount =
            remoteIntfNames.size() + localIntfNames.size() +
            ejbDesc.getRemoteBusinessClassNames().size() +
            ejbDesc.getLocalBusinessClassNames().size();
        
        for(Class next : eligibleInterfaces) {
            String nextIntfName = next.getName();

            if( remoteIntfNames.contains(nextIntfName) 
                ||
                localIntfNames.contains(nextIntfName) 
                ||
                ejbDesc.getRemoteBusinessClassNames().contains(nextIntfName)
                ||
                ejbDesc.getLocalBusinessClassNames().contains(nextIntfName)){
                
                // Interface has already been identified as a Remote/Local
                // business interface, so ignore.

            } else if( next.getAnnotation(Local.class) != null ) {

                localIntfNames.add(nextIntfName);

            } else if( next.getAnnotation(Remote.class) != null ) {
                
                remoteIntfNames.add(nextIntfName);

            } else {

                if( nonImplementsClauseBusinessInterfaceCount == 0 ) {

                    // If there's an empty @Remote annotation on the class,
                    // it's treated as a remote business interface. Otherwise,
                    // it's treated as a local business interface.
                    if( emptyRemoteBusAnn ) {
                        remoteIntfNames.add(nextIntfName);
                    } else {
                        localIntfNames.add(nextIntfName);
                    }

                } else {
                    
                    // Since the component has at least one other business
                    // interface, each implements clause interface that cannot
                    // be identified as business interface via the deployment
                    // descriptor or a @Remote/@Local annotation is ignored.

                }
            }
        }

        if (localIntfNames.size() > 0) {
            for(String next : localIntfNames) {
                ejbDesc.addLocalBusinessClassName(next);
            }
        }
        if (remoteIntfNames.size() > 0) {
            for(String next : remoteIntfNames) {
                ejbDesc.addRemoteBusinessClassName(next);
            }
        }

        // Do Adapted @Home / Adapted @LocalHome processing here too since
        // they are logically part of the structural @Stateless/@Stateful info.
        RemoteHome remoteHomeAnn = (RemoteHome) 
            ejbClass.getAnnotation(RemoteHome.class); 

        if( remoteHomeAnn != null ) {
            Class remoteHome = remoteHomeAnn.value();
            Class remoteIntf = getComponentIntfFromHome(remoteHome);
            if( EJBHome.class.isAssignableFrom(remoteHome) &&
                (remoteIntf != null) ) {

                ejbDesc.setHomeClassName(remoteHome.getName());
                ejbDesc.setRemoteClassName(remoteIntf.getName());

            } else {
                log(Level.SEVERE, ainfo, 
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.invalidremotehome",
                    "Encountered invalid @RemoteHome interface {0}.",
                    new Object[] { remoteHome }));
                return getDefaultFailedResult();
            }
        }

        LocalHome localHomeAnn = (LocalHome)
            ejbClass.getAnnotation(LocalHome.class); 

        if( localHomeAnn != null ) {
            Class localHome = localHomeAnn.value();
            Class localIntf = getComponentIntfFromHome(localHome);
            if( EJBLocalHome.class.isAssignableFrom(localHome) &&
                (localIntf != null) ) {

                ejbDesc.setLocalHomeClassName(localHome.getName());
                ejbDesc.setLocalClassName(localIntf.getName());

            } else {
                log(Level.SEVERE, ainfo, 
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.invalidlocalhome",
                    "Encountered invalid @LocalHome interface {0}.",
                    new Object[] { localHome }));
                return getDefaultFailedResult();
            }
        }

        return getDefaultProcessedResult();       
    
protected abstract com.sun.enterprise.deployment.annotation.HandlerProcessingResultsetEjbDescriptorInfo(com.sun.enterprise.deployment.EjbDescriptor ejbDesc, com.sun.enterprise.deployment.annotation.AnnotationInfo ainfo)
Set Annotation information to Descriptor. This method will also be invoked for an existing descriptor with annotation as user may not specific a complete xml.

param
ejbDesc
param
ainfo
return
HandlerProcessingResult