All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.ejb.EjbInvocation Maven / Gradle / Ivy

There is a newer version: 4.1.2.181
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 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 com.sun.ejb;

//XXX: import javax.xml.rpc.handler.MessageContext;
/* HARRY : JACC Changes */

import com.sun.ejb.containers.*;
import com.sun.enterprise.deployment.MethodDescriptor;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.ResourceHandler;
import com.sun.enterprise.transaction.spi.TransactionOperationsManager;

import javax.ejb.EJBContext;
import javax.ejb.Timer;
import javax.interceptor.InvocationContext;
import com.sun.ejb.containers.interceptors.InterceptorUtil;
import javax.naming.NameNotFoundException;
import javax.transaction.Transaction;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.WebServiceContext;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.rmi.UnmarshalException;
import java.util.HashMap;
import java.util.Map;

import com.sun.ejb.containers.interceptors.InterceptorManager;
import com.sun.enterprise.deployment.EjbBundleDescriptor;

/**
 * The EjbInvocation object contains state associated with an invocation
 * on an EJB or EJBHome (local/remote). It is usually created by generated code
 * in *ObjectImpl and *HomeImpl classes. It is passed as a parameter to
 * Container.preInvoke() * and postInvoke(), which are called by the
 * EJB(Local)Object/EJB(Local)Home before and after an invocation.
 */

public class EjbInvocation
    extends ComponentInvocation
    implements InvocationContext, TransactionOperationsManager, 
         org.glassfish.ejb.api.EJBInvocation, InterceptorManager.AroundInvokeContext
{
  

    public ComponentContext context;

    private TransactionOperationsManager transactionOperationsManager;
    
    EjbInvocation(String compEnvId, Container container) {
        super.componentId = compEnvId;
        super.container = container;
        super.setComponentInvocationType(ComponentInvocation.ComponentInvocationType.EJB_INVOCATION);
        
        EjbBundleDescriptor ejbBundleDesc = container.getEjbDescriptor().getEjbBundleDescriptor();
        moduleName = ejbBundleDesc.getModuleName();
        appName = ejbBundleDesc.getApplication().getAppName();

        //By default we enable TransactionOperationsManager checks. But EjbInvocation.clone()
        //  clears transactionOperationsManager so that, be default, cloned invocations
        //  doesn't enforce Transaction Operations checks.
        transactionOperationsManager = this;
    }

    /**
     * The EJBObject/EJBLocalObject which created this EjbInvocation object.
     * This identifies the target bean.
     */
    public EJBLocalRemoteObject ejbObject;
    
    /**
     * Local flag: true if this invocation was through the 2.x (or earlier)
     * Local client view, the 3.x local client view or a no-interface client view.
     */
    public boolean isLocal=false;

    /**
     * True if this invocation was made through the 2.x (or earlier) Remote
     * client view or the 3.x remote client view. 
     */
    public boolean isRemote=false;
    
    /**
     * InvocationInfo object caches information about the current method
     */
    public InvocationInfo invocationInfo;
    
    /**
     * True if this invocation was made through a local business interface or
     * bean local view or a remote business interface.
     */
    public boolean isBusinessInterface;

    /**
     * true if this is a web service invocation
     */
    public boolean isWebService=false;

    /**
     * true if this is an ejb timeout method invocation
     */
    public boolean isTimerCallback=false;
    
    /**
     * true if this is a message-driven bean invocation
     */
    public boolean isMessageDriven=false;
    
    /**
     * true if this is an invocation on the home object
     * this is required for jacc.
     */
    public boolean isHome=false;

    /** 
     * Home, Remote, LocalHome, Local, WebService, or business interface
     * through which a synchronous ejb invocation was made.
     */
    public Class clientInterface;
    
    /**
     * Method to be invoked. This is a method of the EJB's local/remote
     * component interface for invocations on EJB(Local)Objects,
     * or of the local/remote Home interface
     * for invocations on the EJBHome.
     * Set by the EJB(Local)Object/EJB(Local)Home before calling
     * Container.preInvoke().
     */
    public java.lang.reflect.Method method;
    
    /**
     * The EJB instance to be invoked.
     * Set by Container and used by EJBObject/EJBHome.
     */
    public Object ejb;

    /**
     * This reflects any exception that has occurred during this invocation,
     * including preInvoke, bean method execution, and postInvoke.
     */
    public Throwable exception;

    /**
     * Set to any exception directly thrown from bean method invocation,
     * which could be either an application exception or a runtime exception.
     * This is set *in addition to* the this.exception field.  Some container
     * processing logic, e.g. @Remove, depends specifically on whether a
     * bean method threw an exception.  
     */
    public Throwable exceptionFromBeanMethod;
    
    
    /**
     * The client's transaction if any.
     * Set by the Container during preInvoke() and used by the Container
     * during postInvoke().
     */
    public Transaction clientTx;
    
    /**
     * The EJBContext object of the bean instance being invoked.
     * Set by the Container during preInvoke() and used by the Container
     * during postInvoke().
     */
    // Moved to com/sun/enterprise/ComponentInvocation
    // public ComponentContext context;
    
    /**
     * The transaction attribute of the bean method. Set in generated
     * EJBObject/Home/LocalObject/LocalHome class.
     */
    public int transactionAttribute;
    
    /**
     * Used by MessageBeanContainer.  true if container started
     * a transaction for this invocation.
     */
    private boolean containerStartsTx;
    
    /**
     * Used by MessageBeanContainer to keep track of the context class
     * loader that was active before message delivery began.
     */
    private ClassLoader originalContextClassLoader;
    
    /**
     * Used for web service invocations to hold SOAP message context.
     * EJBs can access message context through SessionContext.
     */
	/* HARRY: JACC Related Changes */
     public MessageContext messageContext;
    
    /**
     * Used for JACC PolicyContextHandlers. The handler can query the container
     * back for parameters on the ejb. This is set during the method invocation
     * and is not available for preInvoke calls.
     */
    public Object[] methodParams;

    public Timer timer;

    /**
     * Result of txManager.getStatus() performed at the beginning of
     * BaseContainer.preInvoke() and valid up until preinvokeTx().
     * txManager.getStatus() accesses a thread-local which is an 
     * expensive operation.  Storing status in the invocation makes it
     * easier for some of the other early pre-invoke operations to
     * re-use it.  
     */
    private Integer preInvokeTxStatus;

    /**
     * Tells if a CMP2.x bean was found in the Tx cache. Applicable
     * only for CMP2.x beans
     */
    public boolean foundInTxCache = false;

    /**
     * Tells if a fast path can be taken for a business method
     * invocation.
     */
    public boolean useFastPath = false;
  
    private java.util.concurrent.locks.Lock cmcLock;

    private boolean doTxProcessingInPostInvoke;

    private long invId;

    private boolean yetToSubmitStatus = true;

    private EjbFutureTask asyncFuture;

    private boolean wasCancelCalled = false;

    /**
     * Used by container within JAXRPC handler processing code.
     */
    private Object webServiceTie;
    private Method webServiceMethod;

    // True if lock is currently held for this invocation
    private boolean holdingSFSBSerializedLock = false;

    public ClassLoader getOriginalContextClassLoader() {
        return originalContextClassLoader;
    }

    public void setOriginalContextClassLoader(ClassLoader originalContextClassLoader) {
        this.originalContextClassLoader = originalContextClassLoader;
    }

    public EjbFutureTask getEjbFutureTask() {
        return asyncFuture;
    }

    public void setEjbFutureTask(EjbFutureTask future) {
        asyncFuture = future;
    }

    public void setWasCancelCalled(boolean flag) {
        wasCancelCalled = flag;
    }

    public boolean getWasCancelCalled() {
        return wasCancelCalled;
    }

    public long getInvId() {
        return invId;
    }

    public void setInvId(long invId) {
        this.invId = invId;
    }

    public boolean mustInvokeAsynchronously() {
        return (invocationInfo != null) && invocationInfo.isAsynchronous() && yetToSubmitStatus;
    }

    public void clearYetToSubmitStatus() {
        yetToSubmitStatus = false;
    }

    public boolean getDoTxProcessingInPostInvoke() {
        return doTxProcessingInPostInvoke;
    }

    public void setDoTxProcessingInPostInvoke(boolean doTxProcessingInPostInvoke) {
        this.doTxProcessingInPostInvoke = doTxProcessingInPostInvoke;
    }

    public EjbInvocation clone() {
        EjbInvocation newInv = (EjbInvocation) super.clone();

        newInv.ejb = null;
        newInv.exception = null;
        newInv.exceptionFromBeanMethod = null;
        newInv.clientTx = null;
        newInv.preInvokeTxStatus = null;
        newInv.originalContextClassLoader = null;

        //The cloned invocation contains a ResourceHandler that points to the same
        //  resource list as the original invocation. If any one of these resource lists
        //  are modified, then we may get a ConcurrentModification exception.
        //
        //To avoid this, we will create a new ResourceHandler for the cloned invocation. I
        //  have simply reused SimpleEjbResourceHandlerImpl that was used in async Ejb invocation.
        newInv.setResourceHandler(SimpleEjbResourceHandlerImpl.createResourceHandler(EjbContainerUtilImpl.getInstance().getTransactionManager()));

        //The cloned invocation is most likely to be used for running a batch task.
        //  In this case, we don't want TransactionOperationsManager restricting the Batch runtime
        //  from performing a java:comp/UserTransaction lookup. So, we explicitly set a null
        //  TransactionOperationsManager in this case.
        newInv.setTransactionOperationsManager(null);

        //We also don't want any JPA EMs registry entries from being shared.
        newInv.clearRegistry();

        return newInv;
    }

    /**
     * Used by JACC implementation to get an enterprise bean
     * instance for the EnterpriseBean policy handler.  The jacc
     * implementation should use this method rather than directly
     * accessing the ejb field.
     */
    public Object getJaccEjb() {
        Object bean = null;
        if( container != null ) {
            bean = ((Container) container).getJaccEjb(this);
        }
        return bean;
    }
    
    /**
     * This method returns the method interface constant for this EjbInvocation.
     */
    public String getMethodInterface() {
        if (isWebService) {
            return MethodDescriptor.EJB_WEB_SERVICE;
        } else if (isMessageDriven) {
            return MethodDescriptor.EJB_BEAN;
        } else if (isLocal) {
            return (isHome) ? MethodDescriptor.EJB_LOCALHOME :
                    MethodDescriptor.EJB_LOCAL;
        } else {
            return (isHome) ? MethodDescriptor.EJB_HOME :
                    MethodDescriptor.EJB_REMOTE;
        }
    }

    /**
     * Returns CachedPermission associated with this invocation, or
     * null if not available.
     */
    public Object getCachedPermission() {
        return (invocationInfo != null) ? invocationInfo.cachedPermission :
            null;
    }

    /**
     * @return Returns the ejbCtx.
     */
    public EJBContext getEJBContext() {
        return (EJBContext) this.context;
    }

    public Integer getPreInvokeTxStatus() {
        return preInvokeTxStatus;
    }
    
    public void setPreInvokeTxStatus(Integer txStatus) {
        // Can be null, which means preInvokeTxStatus is no longer applicable.
        preInvokeTxStatus = txStatus;
    }

    public java.util.concurrent.locks.Lock getCMCLock() {
        return cmcLock;
    }

    public void setCMCLock(java.util.concurrent.locks.Lock l) {
        cmcLock = l;
    }

    public boolean holdingSFSBSerializedLock() {
        return this.holdingSFSBSerializedLock;
    }

    public void setHoldingSFSBSerializedLock(boolean flag) {
        holdingSFSBSerializedLock = flag;
    }

    @Override
    public Object getTransactionOperationsManager() {
        return transactionOperationsManager;
    }

    public void setTransactionOperationsManager(TransactionOperationsManager transactionOperationsManager) {
        //Note: clone() clears transactionOperationsManager so that, be default, cloned invocations
        //  doesn't enforce Transaction Operations checks.
        this.transactionOperationsManager = transactionOperationsManager;
    }

    //Implementation of TransactionOperationsManager methods
    
    /**
     * Called by the UserTransaction implementation to verify 
     * access to the UserTransaction methods.
     */
    public boolean userTransactionMethodsAllowed() {
        return ((Container) container).userTransactionMethodsAllowed(this);
    }

    /**
     * Called by the UserTransaction lookup to verify 
     * access to the UserTransaction itself.
     */
    public void userTransactionLookupAllowed() throws NameNotFoundException {
        ((BaseContainer) container).checkUserTransactionLookup(this);
    }

    /**
     * Called by the UserTransaction when transaction is started.
     */
    public void doAfterUtxBegin() {
        ((Container) container).doAfterBegin(this);
    }

    //Implementation of InvocationContext methods
    
    private int interceptorIndex;

    public Method   beanMethod;

    // Only set for web service invocations.
    private WebServiceContext webServiceContext;

    // Only set for EJB JAXWS
    //FIXME: private Message message = null;
    private Object message;

    private SOAPMessage soapMessage = null;

    private Map      contextData;

    public InterceptorManager.InterceptorChain getInterceptorChain() {
        return (invocationInfo == null)
            ? null : invocationInfo.interceptorChain;
    }

    /**
     * @return Returns the bean instance.
     */
    public Object getTarget() {
        return this.ejb;
    }
 
    /**
     * @return Returns the timer instance.
     */
    public Object getTimer() {
        return timer;
    }
 
    
    /**
     * @return For AroundInvoke/AroundTimeout methods, returns the bean class 
     *         method being invoked.  For lifecycle callback methods, 
     *         returns null.
     */
    public Method getMethod() {
        return getBeanMethod();
    }
    public Method getBeanMethod() {
        return this.beanMethod;
    }

    public Constructor getConstructor() {
        return null;
    }

    /**
     * @return Returns the parameters that will be used to invoke
     * the business method.  If setParameters has been called, 
     * getParameters() returns the values to which the parameters 
     * have been set.
     */
    public Object[] getParameters() {
        return this.methodParams;
    }
    
    /**
     * Set the parameters that will be used to invoke the business method.
     *
     */
    public void setParameters(Object[] params) {
        InterceptorUtil.checkSetParameters(params, getMethod());
        this.methodParams = params;
    }

    /*
     * Method takes Object to decouple EJBInvocation interface
     * from jaxws (which isn't available in all profiles).
     */
    public void setWebServiceContext(Object webServiceContext) {
        // shouldn't be necessary, but to be safe
        if (webServiceContext instanceof WebServiceContext) {
            this.webServiceContext = (WebServiceContext) webServiceContext;
        }
    }
    
    /**
     * @return Returns the contextMetaData.
     */
    public Map getContextData() {
        if (this.contextData == null) {
            if (webServiceContext != null)
                this.contextData = webServiceContext.getMessageContext();
            else
                this.contextData = new HashMap();
        }
        return contextData;
    }

    /**
     * This is for EJB JAXWS only.
     * @param message  an unconsumed message
     */
    public  void setMessage(T message) {
        this.message = message;
    }

    /**
     * This is for EJB JAXWS only.
     * @return the JAXWS message
     */
    public Object getMessage() {
        return this.message;
    }
    
    /**
     * This is for EJB JAXWS only.
     */
    public SOAPMessage getSOAPMessage() {
        if (message != null && soapMessage == null) {
            try {
                //FIXME: soapMessage = message.readAsSOAPMessage();
                soapMessage = (SOAPMessage) message;
            } catch(Exception e) {
                throw new RuntimeException(e);
            }
            //message consumed, set it to null
            message = null;
        }
        return soapMessage;
    }

    /* (non-Javadoc)
     * @see javax.interceptor.InvocationContext#proceed()
     */
    public Object proceed()
        throws Exception
    {
        try {
            //TODO: Internal error if getInterceptorChain() is null
            interceptorIndex++;
            return getInterceptorChain().invokeNext(interceptorIndex, this);
        } catch (Exception ex) {
            throw ex;
        } catch (Error error) {
            throw error;
        } catch (Throwable t) {
            // This shouldn't be possible since we specifically catch
            // Exception and Error before this, but ...
            throw new RuntimeException(t);
        } finally {
            interceptorIndex--;
        }
    }

    /**
     * Print most useful fields.  Don't do all of them (yet) since there
     * are a large number. 
     * @return
     */
    public String toString() {

        StringBuffer sbuf = new StringBuffer();
        sbuf.append("EjbInvocation  ");
        sbuf.append("componentId="+getComponentId());
        sbuf.append(",isLocal="+isLocal);
        sbuf.append(",isRemote="+isRemote);
        sbuf.append(",isBusinessInterface="+isBusinessInterface);
        sbuf.append(",isWebService="+isWebService);
        sbuf.append(",isMessageDriven="+isMessageDriven);
        sbuf.append(",isHome="+isHome);
        sbuf.append(",clientInterface="+clientInterface);
        sbuf.append(",method="+method);
        sbuf.append(",ejb="+ejb);
        sbuf.append(",exception="+exception);
        sbuf.append(",exceptionFromBeanMethod="+exceptionFromBeanMethod);
        sbuf.append(",invId="+invId);
        sbuf.append(",wasCancelCalled="+wasCancelCalled);
        sbuf.append(",yetToSubmitStatus="+yetToSubmitStatus);

        return sbuf.toString();
    }

    // Implementation of AroundInvokeContext
    public Object[] getInterceptorInstances() {
        return  ((EJBContextImpl)context).getInterceptorInstances();
    }

    public  Object invokeBeanMethod() throws Throwable {
        return ((BaseContainer) container).invokeBeanMethod(this);
    }

    /*********************************************************/


    
    public com.sun.enterprise.security.SecurityManager getEjbSecurityManager() {
        return ((BaseContainer)container).getSecurityManager();
    }

    public boolean isAWebService() {
        return this.isWebService;
    }

    public Object[] getMethodParams() {
        return this.methodParams;
    }

    public boolean authorizeWebService(Method m) throws Exception {
        Exception ie = null;
        if (isAWebService()) {
            try {
                this.method = m;
                if (!((com.sun.ejb.Container)container).authorize(this)) {
                    ie = new Exception
                    ("Client not authorized for invocation of method {" + method + "}");
                } else {
                    // Record the method on which the successful
                    // authorization check was performed.
                    setWebServiceMethod(m);
                }
            } catch(Exception e) {
                String errorMsg = "Error unmarshalling method {" + method + "} for ejb ";
                ie = new UnmarshalException(errorMsg);
                ie.initCause(e);
            }
            if ( ie != null ) {
                exception = ie;
                throw ie;
            }
	    } else {
		    setWebServiceMethod(null);
	    }
        return true;
	} 
    
/**
    * Implements the  method in org.glassfish.ejb.api.EJBInvocation
    * @return true if the SecurityManager reports that the caller is in role
    */
   public boolean isCallerInRole(String role) {
       return getEjbSecurityManager().isCallerInRole(role);
   } 

    public void setWebServiceTie(Object tie) {
        webServiceTie = tie;
    }

    public Object getWebServiceTie() {
        return webServiceTie;
    }

    public void setWebServiceMethod(Method method) {
        webServiceMethod = method;
    }

    public Method getWebServiceMethod() {
        return webServiceMethod;
    }

    public void setMessageContext(MessageContext msgContext) {
       messageContext = msgContext;
    }

   public ResourceHandler getResourceHandler() {
       ResourceHandler rh = super.getResourceHandler();
       if (rh == null) {
           rh = context;
       }

       return rh;
   }

    public boolean isContainerStartsTx() {
        return containerStartsTx;
    }

    public void setContainerStartsTx(boolean containerStartsTx) {
        this.containerStartsTx = containerStartsTx;
    }
}
    





© 2015 - 2024 Weber Informatics LLC | Privacy Policy