alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (AbstractEjbHandler.java)

This example Glassfish source code file (AbstractEjbHandler.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

annotationinfo, annotationprocessorexception, class, class, ejb, ejbcontext, ejbdescriptor, ejbdescriptor, handlerprocessingresult, log, methoddescriptor, object, object, reflection, servlet, set, string, string, util, web

The Glassfish AbstractEjbHandler.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.ejb.deployment.annotation.handlers;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

import java.util.Set;
import java.util.List;
import java.util.LinkedList;
import java.util.HashSet;
import java.util.logging.Level;
import javax.ejb.Timeout;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.Remote;
import javax.ejb.Local;
import javax.ejb.LocalBean;
import javax.ejb.RemoteHome;
import javax.ejb.LocalHome;
import javax.ejb.Stateless;


import org.jvnet.hk2.component.Habitat;

import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.util.TypeUtil;

import org.glassfish.apf.AnnotatedElementHandler;
import org.glassfish.apf.AnnotationInfo;
import org.glassfish.apf.AnnotationProcessorException;
import org.glassfish.apf.HandlerProcessingResult;
import org.glassfish.internal.api.Globals;
import com.sun.enterprise.deployment.annotation.context.EjbBundleContext;
import com.sun.enterprise.deployment.annotation.context.EjbContext;
import com.sun.enterprise.deployment.annotation.context.EjbsContext;
import com.sun.enterprise.deployment.annotation.handlers.AbstractHandler;

import org.glassfish.apf.context.AnnotationContext;



/**
 * 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
 */
public abstract class AbstractEjbHandler extends AbstractHandler {

    private AnnotationTypesProvider provider = null;
            
    public AbstractEjbHandler() {
        Habitat h = Globals.getDefaultHabitat();
        if( h != null ) {
            provider = h.getComponent(AnnotationTypesProvider.class, "EJB");
        }
    }
    /**
     * Return the name attribute of given annotation.
     * @param annotation
     * @return name
     */
    protected abstract String getAnnotatedName(Annotation annotation);

    /*
     * check if the given EjbDescriptor matches the given Annotation.
     * @param ejbDesc
     * @param annotation
     * @return boolean check for validity of EjbDescriptor
     */
    protected abstract boolean isValidEjbDescriptor(EjbDescriptor ejbDesc,
            Annotation annotation);

    /**
     * Create a new EjbDescriptor for a given elementName and AnnotationInfo.
     * @param elementName
     * @param ainfo
     * @return a new EjbDescriptor
     */
    protected abstract EjbDescriptor createEjbDescriptor(String elementName,
            AnnotationInfo ainfo) throws AnnotationProcessorException;

    /**
     * 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
     */
    protected abstract HandlerProcessingResult setEjbDescriptorInfo(
            EjbDescriptor ejbDesc, AnnotationInfo ainfo)
            throws AnnotationProcessorException;

    /**
     * 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
     */
    public HandlerProcessingResult processAnnotation(AnnotationInfo ainfo) 
            throws AnnotationProcessorException {



        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 {0}",
                    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);
            }
        }

        // We need to include all ejbs of the same name in the annotation processing context
        // in order to handle the case that a bean class has both a component-defining
        // annotation and there are other ejb-jar.xml-defined beans with the same bean class.

        
        EjbDescriptor[] ejbDescs = currentBundle.getEjbByClassName(ejbClass.getName());
        HandlerProcessingResult procResult = null;
        for(EjbDescriptor next : ejbDescs) {
            procResult = setEjbDescriptorInfo(next, ainfo);
            doTimedObjectProcessing(ejbClass, next);               
        }

        AnnotationContext annContext = null;
        if( ejbDescs.length == 1 ) {
            annContext = new EjbContext(ejbDesc, ejbClass);
        } else {

            annContext = new EjbsContext(ejbDescs, ejbClass);
        }


        // we push the new context on the stack...
        ctx.getProcessingContext().pushHandler(annContext);
        
        return procResult;
    }   

    /**
     * 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. 
     */
    private void doTimedObjectProcessing(Class ejbClass, 
                                         EjbDescriptor ejbDesc) {
        
        // 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;
    }

    /**
     * MessageDriven bean does not need to invoke this API.
     * @param ejbDesc
     * @param ainfo  for error handling
     * @return HandlerProcessingResult
     */
    protected HandlerProcessingResult setBusinessAndHomeInterfaces(
            EjbDescriptor ejbDesc, AnnotationInfo ainfo)
            throws AnnotationProcessorException {

        Set<Class>  localBusIntfs  = new HashSet();
        Set<Class>  remoteBusIntfs  = new HashSet();
        
        Set<Class> clientInterfaces = new HashSet();

        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()) {
                clientInterfaces.add(next);
                remoteBusIntfs.add(next);
            }
            emptyRemoteBusAnn = remoteBusIntfs.isEmpty();
        }

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

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

        LocalBean localBeanAnn = (LocalBean) ejbClass.getAnnotation(LocalBean.class);
        if( localBeanAnn != null ) {
            ejbDesc.setLocalBean(true);
        }

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

            if( remoteBusIntfs.contains(next)
                ||
                localBusIntfs.contains(next)
                ||
                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 ) {

                clientInterfaces.add(next);
                localBusIntfs.add(next);

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

                clientInterfaces.add(next);
                remoteBusIntfs.add(next);

            } else {

                if( (nonImplementsClauseBusinessInterfaceCount == 0) &&
                    (!ejbDesc.isLocalBean()) ) {

                    // 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 ) {
                        remoteBusIntfs.add(next);
                    } else {
                        localBusIntfs.add(next);
                    }
                    clientInterfaces.add(next);

                } 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 (localBusIntfs.size() > 0) {
            for(Class next : localBusIntfs) {
                ejbDesc.addLocalBusinessClassName(next.getName());
            }
        }

        if (remoteBusIntfs.size() > 0) {
            for(Class next : remoteBusIntfs) {
                ejbDesc.addRemoteBusinessClassName(next.getName());
            }
        }


        // 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) ) {

                clientInterfaces.add(remoteHome);
                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) ) {

                clientInterfaces.add(localHome);
                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();
            }
        }

        // Web Service API might not be available so do a check before looking
        // for @WebService on bean class
        boolean canDoWebServiceAnnCheck = false;
        try {
            canDoWebServiceAnnCheck = (provider.getType("javax.jws.WebService") != null);

        } catch(Exception e) {
            log(Level.FINE, ainfo, e.getMessage());
        }

        if( (!ejbDesc.isLocalBean()) &&
            (clientInterfaces.size() == 0) &&
            !ejbDesc.hasWebServiceEndpointInterface() &&
            ( !canDoWebServiceAnnCheck ||
                (canDoWebServiceAnnCheck &&
                (ejbClass.getAnnotation(javax.jws.WebService.class) == null)) ) ) {
            ejbDesc.setLocalBean(true);
        }
        
        //If this is a no-Interface local EJB, set all classes for this bean
        if (ejbDesc.isLocalBean()) {
            addNoInterfaceLocalBeanClasses(ejbDesc, ejbClass);
        }


        return getDefaultProcessedResult();       
    }

    private void addNoInterfaceLocalBeanClasses(EjbDescriptor ejbDesc, Class ejbClass) {
        Class nextClass = ejbClass;
        //The session bean's no-interface view can be accessed via the bean class
        //and all its super classes
        while ((nextClass != Object.class) && (nextClass != null)) {
            ejbDesc.addNoInterfaceLocalBeanClass(nextClass.getName());
            nextClass = nextClass.getSuperclass();
        }
    }
    private Class getComponentIntfFromHome(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 boolean excludedFromImplementsClause(Class intf) {
        return ( (intf == java.io.Serializable.class) ||
                 (intf == java.io.Externalizable.class) ||
                 ( (intf.getPackage() != null) &&
                   intf.getPackage().getName().equals("javax.ejb")) );
    }

    protected void doDescriptionProcessing(String description,
                                           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 void doMappedNameProcessing(String mappedName,
                                          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);
            }
        }
        
        
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish AbstractEjbHandler.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.