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

org.glassfish.ejb.deployment.util.EjbBundleValidator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.ejb.deployment.util;

import com.sun.ejb.containers.EJBTimerSchedule;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbInterceptor;
import com.sun.enterprise.deployment.InjectionCapable;
import com.sun.enterprise.deployment.LifecycleCallbackDescriptor;
import com.sun.enterprise.deployment.MethodDescriptor;
import com.sun.enterprise.deployment.ResourceEnvReferenceDescriptor;
import com.sun.enterprise.deployment.ResourceReferenceDescriptor;
import com.sun.enterprise.deployment.RoleReference;
import com.sun.enterprise.deployment.ScheduledTimerDescriptor;
import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.WebService;
import com.sun.enterprise.deployment.types.EjbReference;
import com.sun.enterprise.deployment.types.MessageDestinationReferencer;
import com.sun.enterprise.deployment.util.ComponentValidator;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.deployment.util.EjbBundleVisitor;
import com.sun.enterprise.util.LocalStringManagerImpl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.api.naming.SimpleJndiName;
import org.glassfish.ejb.LogFacade;
import org.glassfish.ejb.deployment.descriptor.DummyEjbDescriptor;
import org.glassfish.ejb.deployment.descriptor.EjbBundleDescriptorImpl;
import org.glassfish.ejb.deployment.descriptor.EjbCMPEntityDescriptor;
import org.glassfish.ejb.deployment.descriptor.EjbDescriptor;
import org.glassfish.ejb.deployment.descriptor.EjbEntityDescriptor;
import org.glassfish.ejb.deployment.descriptor.EjbMessageBeanDescriptor;
import org.glassfish.ejb.deployment.descriptor.EjbSessionDescriptor;
import org.glassfish.ejb.deployment.descriptor.FieldDescriptor;
import org.glassfish.ejb.deployment.descriptor.InterceptorBindingDescriptor;
import org.glassfish.ejb.deployment.descriptor.PersistenceDescriptor;
import org.glassfish.ejb.deployment.descriptor.RelationshipDescriptor;
import org.glassfish.internal.api.Globals;
import org.glassfish.internal.deployment.AnnotationTypesProvider;
import org.glassfish.logging.annotation.LogMessageInfo;
import org.glassfish.security.common.Role;

import static com.sun.enterprise.deployment.MethodDescriptor.EJB_BEAN;
import static com.sun.enterprise.deployment.MethodDescriptor.EJB_LOCAL;

/**
 * This class validates a EJB Bundle descriptor once loaded from an .jar file
 *
 * @author Jerome Dochez
 */
public class EjbBundleValidator extends ComponentValidator implements EjbBundleVisitor, EjbVisitor {
    private static final LocalStringManagerImpl I18N = new LocalStringManagerImpl(EjbBundleValidator.class);
    private static final Logger LOG  = LogFacade.getLogger();

    @LogMessageInfo(
        message = "Passivation-capable value of stateful session bean [{0}] is false, " +
                "it should not have any PrePassivate nor PostActivate configuration, " +
                "but you have configuration at [{1}].",
        level = "WARNING")
    private static final String REDUNDANT_PASSIVATION_CALLBACK_METADATA = "AS-EJB-00048";

    protected EjbBundleDescriptorImpl ejbBundleDescriptor;
    protected EjbDescriptor ejb;


    @Override
    public void accept(BundleDescriptor descriptor) {
        this.bundleDescriptor = descriptor;
        this.application = descriptor.getApplication();
        if (descriptor instanceof EjbBundleDescriptorImpl) {
            EjbBundleDescriptorImpl ejbBundle = (EjbBundleDescriptorImpl) descriptor;
            accept(ejbBundle);

            for (EjbDescriptor anEjb : ejbBundle.getEjbs()) {
                anEjb.visit(getSubDescriptorVisitor(anEjb));
            }
            if (ejbBundle.hasRelationships()) {
                for (Object element : ejbBundle.getRelationships()) {
                    RelationshipDescriptor rd = (RelationshipDescriptor) element;
                    accept(rd);
                }
            }
            for (WebService aWebService : ejbBundle.getWebServices().getWebServices()) {
                accept(aWebService);
            }

            // Ejb-jar level dependencies

            // Visit all injectables first.  In some cases, basic type
            // information has to be derived from target inject method or
            // inject field.
            for (InjectionCapable injectable : ejbBundle.getInjectableResources(ejbBundle)) {
                accept(injectable);
            }
        }
        super.accept(descriptor);
    }

    @Override
    public void accept(EjbBundleDescriptor bundleDesc) {
        this.application = bundleDesc.getApplication();
        EjbBundleDescriptorImpl bundle = (EjbBundleDescriptorImpl) bundleDesc;
        if (bundle.getEjbs().isEmpty()) {
            throw new IllegalArgumentException(I18N.getLocalString(
                "enterprise.deployment.util.no_ejb_in_ejb_jar",
                "Invalid ejb jar {0}: it contains zero ejb. A valid ejb jar requires at least one session/entity/message driven bean.",
                new Object[] {bundle.getModuleDescriptor().getArchiveUri()}));
        }

        if (!areResourceReferencesValid(bundle)) {
            throw new RuntimeException("Incorrectly resolved role references");
        }

        this.ejbBundleDescriptor = bundle;

        // Now that we have a classloader, we have to check for any
        // interceptor bindings that were specified in .xml to use
        // the syntax that refers to all overloaded methods with a
        // given name.
        handleOverloadedInterceptorMethodBindings(bundle);

        InterceptorBindingTranslator bindingTranslator = new InterceptorBindingTranslator(bundle);

        for (EjbDescriptor ejb0 : bundle.getEjbs()) {
            if (ejb0.isRemoteInterfacesSupported()
                && (ejb0.getRemoteClassName() == null || ejb0.getRemoteClassName().isBlank())) {
                throw new IllegalArgumentException(
                    I18N.getLocalString("enterprise.deployment.util.componentInterfaceMissing",
                        "{0} Component interface is missing in EJB [{1}]", "Remote", ejb0.getName()));
            }
            if (ejb0.isLocalInterfacesSupported()
                && (ejb0.getLocalClassName() == null || ejb0.getLocalClassName().isBlank())) {
                throw new IllegalArgumentException(
                    I18N.getLocalString("enterprise.deployment.util.componentInterfaceMissing",
                        "{0} Component interface is missing in EJB [{1}]", EJB_LOCAL, ejb0.getName()));
            }

            if (!EjbEntityDescriptor.TYPE.equals(ejb0.getType())) {
                ejb0.applyInterceptors(bindingTranslator);
            }
        }
    }


    /**
     * @return true if all ejb role references link to roles specified here.
     */
    private boolean areResourceReferencesValid(EjbBundleDescriptorImpl bundle) {
        // run through each of the ejb's role references, checking that the roles exist in bundle
        for (EjbDescriptor ejbDescriptor : bundle.getEjbs()) {
            for (RoleReference reference : ejbDescriptor.getRoleReferences()) {
                Role referredRole = reference.getRole();
                Set roles = bundle.getRoles();
                if (!referredRole.getName().isEmpty() && !roles.contains(referredRole)) {
                    LOG.log(Level.WARNING, "Bad role reference to {0}, roles: {1}", new Object[] {referredRole, roles});
                    return false;
                }
            }
        }
        return true;
    }


    private void handleOverloadedInterceptorMethodBindings(EjbBundleDescriptorImpl bundleDesc) {
        List origBindings = bundleDesc.getInterceptorBindings();
        if (origBindings.isEmpty()) {
            return;
        }

        ClassLoader cl = bundleDesc.getClassLoader();
        List newBindings = new ArrayList<>();
        for (InterceptorBindingDescriptor next : origBindings) {
            if (!next.getNeedsOverloadResolution()) {
                newBindings.add(next);
                continue;
            }
            MethodDescriptor overloadedMethodDesc = next.getBusinessMethod();
            String methodName = overloadedMethodDesc.getName();
            // For method-specific interceptors, there must be an ejb-name.
            String ejbName = next.getEjbName();
            EjbDescriptor ejbDesc = bundleDesc.getEjbByName(ejbName);
            Class ejbClass = null;
            try {
                ejbClass = cl.loadClass(ejbDesc.getEjbClassName());
            } catch (Exception e) {
                throw new RuntimeException("Error loading ejb class " + ejbDesc.getEjbClassName(), e);
            }

            boolean isMethod = false;
            for (Method ejbClassMethod : ejbClass.getDeclaredMethods()) {
                if (ejbClassMethod.getName().equals(methodName)) {
                    isMethod = true;
                    InterceptorBindingDescriptor newInterceptorBinding = new InterceptorBindingDescriptor();
                    MethodDescriptor newMethodDesc = new MethodDescriptor(ejbClassMethod, EJB_BEAN);
                    newInterceptorBinding.setEjbName(ejbName);
                    newInterceptorBinding.setBusinessMethod(newMethodDesc);
                    for (String interceptorClass : next.getInterceptorClasses()) {
                        newInterceptorBinding.appendInterceptorClass(interceptorClass);
                    }
                    newInterceptorBinding.setIsTotalOrdering(next.getIsTotalOrdering());
                    newInterceptorBinding.setExcludeDefaultInterceptors(next.getExcludeDefaultInterceptors());
                    newInterceptorBinding.setExcludeClassInterceptors(next.getExcludeClassInterceptors());
                    newBindings.add(newInterceptorBinding);
                }

            }

            // We didn't find a method with this name in class methods,
            // check if it's a constructor
            if (!isMethod && methodName.equals(ejbClass.getSimpleName())) {
                // Constructor - will resolve via implicit comparison
                newBindings.add(next);
            }
        }
        bundleDesc.setInterceptorBindings(newBindings);
    }


    /**
     * Visits an ejb descriptor
     *
     * @param ejb descriptor
     */
    @Override
    public void accept(EjbDescriptor ejb) {
        // all the DummyEjbDescriptor which stored partial information from
        // xml should already be resolved to actual ejb descriptors.
        // if not, this means there is a referencing error in the user
        // application
        if (ejb instanceof DummyEjbDescriptor) {
            throw new IllegalArgumentException("Referencing error: this bundle has no bean of name: " + ejb.getName());
        }

        this.ejb =ejb;
        setDOLDefault(ejb);
        computeRuntimeDefault(ejb);
        checkDependsOn(ejb);

        validateConcurrencyMetadata(ejb);
        validateStatefulTimeout(ejb);
        validatePassivationConfiguration(ejb);

        try {

            ClassLoader cl = ejb.getEjbBundleDescriptor().getClassLoader();
            Class ejbClass = cl.loadClass(ejb.getEjbClassName());

            if (Globals.getDefaultHabitat() == null) {
                return;
            }

            // Perform 2.x style TimedObject processing if the class
            // hasn't already been identified as a timed object.
            AnnotationTypesProvider provider = Globals.getDefaultHabitat().getService(AnnotationTypesProvider.class, "EJB");
            if (provider == null) {
                throw new IllegalStateException("Cannot find AnnotationTypesProvider named 'EJB'");
            }

            if (ejb.getEjbTimeoutMethod() == null
                && provider.getType("jakarta.ejb.TimedObject").isAssignableFrom(ejbClass)) {
                MethodDescriptor timedObjectMethod = new MethodDescriptor("ejbTimeout", "TimedObject timeout method",
                    new String[] {"jakarta.ejb.Timer"}, MethodDescriptor.TIMER_METHOD);
                ejb.setEjbTimeoutMethod(timedObjectMethod);

            } else if (ejb.getEjbTimeoutMethod() != null) {
                // If timeout-method was only processed from the descriptor,
                // we need to create a MethodDescriptor using the actual
                // Method object corresponding to the timeout method. The
                // timeout method can have any access type and be anywhere
                // in the bean class hierarchy.
                MethodDescriptor timeoutMethodDescOrig = ejb.getEjbTimeoutMethod();
                MethodDescriptor timeoutMethodDesc = processTimeoutMethod(ejb, timeoutMethodDescOrig, provider, ejbClass);
                ejb.setEjbTimeoutMethod(timeoutMethodDesc);
            }

            for (ScheduledTimerDescriptor sd : ejb.getScheduledTimerDescriptors()) {
                try {
                    // This method creates new schedule and attempts to calculate next timeout.
                    // The second part ensures that all values that are not verified up-front
                    // are also validated.
                    // It does not check that such timeout date is a valid date.
                    EJBTimerSchedule.isValid(sd);
                } catch (Exception e) {
                    throw new RuntimeException(ejb.getName() + ": Invalid schedule " + "defined on method "
                        + sd.getTimeoutMethod().getFormattedString() + ": " + e.getMessage());
                }

                MethodDescriptor timeoutMethodDescOrig = sd.getTimeoutMethod();
                MethodDescriptor timeoutMethodDesc = processTimeoutMethod(ejb, timeoutMethodDescOrig, provider, ejbClass);
                sd.setTimeoutMethod(timeoutMethodDesc);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error processing EjbDescriptor", e);
        }

        // Visit all injectables first.  In some cases, basic type information
        // has to be derived from target inject method or inject field.
        for (InjectionCapable injectable : ejb.getEjbBundleDescriptor().getInjectableResources(ejb)) {
            accept(injectable);
        }

        for (EjbReference aRef : ejb.getEjbReferenceDescriptors()) {
            accept(aRef);
        }

        for (ResourceReferenceDescriptor element : ejb.getResourceReferenceDescriptors()) {
            accept(element);
        }

        for (ResourceEnvReferenceDescriptor element : ejb.getResourceEnvReferenceDescriptors()) {
            accept(element);
        }

        for (MessageDestinationReferencer element : ejb.getMessageDestinationReferenceDescriptors()) {
            accept(element);
        }

        // If this is a message bean, it can be a message destination referencer as well.
        if (ejb.getType().equals(com.sun.enterprise.deployment.EjbMessageBeanDescriptor.TYPE)) {
            if (ejb instanceof MessageDestinationReferencer) {
                MessageDestinationReferencer msgDestReferencer = (MessageDestinationReferencer) ejb;
                if (msgDestReferencer.getMessageDestinationLinkName() != null) {
                    accept(msgDestReferencer);
                }
            }
        }

        Set serviceRefs = ejb.getServiceReferenceDescriptors();
        for (ServiceReferenceDescriptor serviceRef : serviceRefs) {
            accept(serviceRef);
        }

        if (ejb instanceof EjbCMPEntityDescriptor) {
            EjbCMPEntityDescriptor cmp = (EjbCMPEntityDescriptor)ejb;
            PersistenceDescriptor persistenceDesc = cmp.getPersistenceDescriptor();
            for (FieldDescriptor element : persistenceDesc.getCMPFields()) {
                accept(element);
            }
        }
    }

    public void accept(WebService webService) {
    }


    private void validateConcurrencyMetadata(EjbDescriptor ejb) {

        if (ejb instanceof EjbSessionDescriptor) {
            EjbSessionDescriptor sessionDesc = (EjbSessionDescriptor) ejb;
            List accessTimeoutInfo = sessionDesc.getAccessTimeoutInfo();
            for (EjbSessionDescriptor.AccessTimeoutHolder accessTimeoutHolder : accessTimeoutInfo) {
                MethodDescriptor accessTimeoutMethodDesc = accessTimeoutHolder.method;
                Method accessTimeoutMethod = accessTimeoutMethodDesc.getMethod(ejb);
                if (accessTimeoutMethod == null) {
                    throw new RuntimeException("Invalid AccessTimeout method signature " + accessTimeoutMethodDesc
                        + " . Method could not be resolved to a bean class method for bean " + ejb.getName());
                }
            }

            for (MethodDescriptor lockMethodDesc : sessionDesc.getReadAndWriteLockMethods()) {
                Method readLockMethod = lockMethodDesc.getMethod(sessionDesc);
                if (readLockMethod == null) {
                    throw new RuntimeException("Invalid Lock method signature " + lockMethodDesc
                        + " . Method could not be resolved to a bean class method for bean " + ejb.getName());
                }
            }
        }
    }


    /**
     * Validates @StatefulTimeout or  values.
     * Any value less than -1 is invalid.
     */
    private void validateStatefulTimeout(EjbDescriptor ejb) {
        if (ejb instanceof EjbSessionDescriptor) {
            EjbSessionDescriptor sessionDesc = (EjbSessionDescriptor) ejb;
            Long statefulTimeoutValue = sessionDesc.getStatefulTimeoutValue();
            if (statefulTimeoutValue != null && statefulTimeoutValue < -1) {
                throw new IllegalArgumentException(I18N.getLocalString(
                    "enterprise.deployment.invalid_stateful_timeout_value",
                    "Invalid value [{0}] for @StatefulTimeout or  element in EJB [{1}]."
                    + " Values less than -1 are not valid.",
                    new Object[] {statefulTimeoutValue, sessionDesc.getName()}));
            }
        }
    }


    /**
     * Check when passivation-capable of sfsb is false,
     * PrePassivate and PostActivate configurations are not recommended.
     */
    private void validatePassivationConfiguration(EjbDescriptor ejb) {
        if (ejb instanceof EjbSessionDescriptor) {
            EjbSessionDescriptor sessionDesc = (EjbSessionDescriptor) ejb;
            if (!sessionDesc.isStateful() || sessionDesc.isPassivationCapable()) {
                return;
            }

            String callbackInfo = getAllPrePassivatePostActivateCallbackInfo(sessionDesc);
            if (callbackInfo.length() > 0) {
                LOG.log(Level.WARNING, REDUNDANT_PASSIVATION_CALLBACK_METADATA,
                    new Object[] {ejb.getName(), callbackInfo});
            }
        }
    }


    private String getAllPrePassivatePostActivateCallbackInfo(EjbSessionDescriptor sessionDesc) {
        List descriptors = new ArrayList<>();
        descriptors.addAll(sessionDesc.getPrePassivateDescriptors());
        descriptors.addAll(sessionDesc.getPostActivateDescriptors());
        for (EjbInterceptor interceptor : sessionDesc.getInterceptorClasses()) {
            descriptors.addAll(interceptor.getCallbackDescriptors(LifecycleCallbackDescriptor.CallbackType.PRE_PASSIVATE));
            descriptors.addAll(interceptor.getCallbackDescriptors(LifecycleCallbackDescriptor.CallbackType.POST_ACTIVATE));
        }

        StringBuilder result = new StringBuilder();
        for (LifecycleCallbackDescriptor each : descriptors) {
            result.append(each.getLifecycleCallbackClass());
            result.append(".");
            result.append(each.getLifecycleCallbackMethod());
            result.append(", ");
        }

        if (result.length() > 2) {
            return result.substring(0, result.length() - 2);
        }
        return result.toString();
    }


    private void checkDependsOn(EjbDescriptor ejb) {
        if (ejb instanceof EjbSessionDescriptor) {
            EjbSessionDescriptor sessionDesc = (EjbSessionDescriptor) ejb;
            if (sessionDesc.hasDependsOn()) {
                if (!sessionDesc.isSingleton()) {
                    throw new RuntimeException("Illegal usage of DependsOn for EJB " + ejb.getName()
                        + ". DependsOn is only supported for Singleton beans");
                }
                String[] dependsOn = sessionDesc.getDependsOn();
                for (String next : dependsOn) {

                    // TODO support new EJB 3.1 syntax

                    boolean fullyQualified = next.contains("#");

                    EjbBundleDescriptor sessionEjbBundleDescriptor = sessionDesc.getEjbBundleDescriptor();
                    Application app = sessionEjbBundleDescriptor.getApplication();

                    if (fullyQualified) {

                        int indexOfHash = next.indexOf("#");
                        String ejbName = next.substring(indexOfHash + 1);
                        String relativeJarPath = next.substring(0, indexOfHash);

                        BundleDescriptor bundle = app.getRelativeBundle(sessionEjbBundleDescriptor, relativeJarPath);

                        if (bundle == null) {
                            throw new IllegalStateException(
                                "Invalid @DependOn value = " + next + " for Singleton " + sessionDesc.getName());
                        }

                        EjbBundleDescriptorImpl ejbBundle = bundle.getModuleType() == null
                            || !bundle.getModuleType().equals(DOLUtils.warType())
                            ? (EjbBundleDescriptorImpl) bundle
                            : bundle.getExtensionsDescriptors(EjbBundleDescriptorImpl.class).iterator().next();

                        if (!ejbBundle.hasEjbByName(ejbName)) {
                            throw new RuntimeException(
                                "Invalid DependsOn dependency '" + next + "' for EJB " + ejb.getName());
                        }

                    } else {

                        EjbBundleDescriptor bundle = ejb.getEjbBundleDescriptor();
                        if (!bundle.hasEjbByName(next) ) {
                            throw new RuntimeException("Invalid DependsOn dependency '" +
                               next + "' for EJB " + ejb.getName());
                        }
                    }
                }
            }
        }

    }


    @Override
    protected EjbBundleDescriptorImpl getEjbBundleDescriptor() {
        return ejbBundleDescriptor;
    }


    @Override
    protected EjbDescriptor getEjbDescriptor() {
        return this.ejb;
    }


    /**
     * @return the Application object if any
     */
    @Override
    protected Application getApplication() {
        return application;
    }


    /**
     * @return the bundleDescriptor we are validating
     */
    @Override
    protected BundleDescriptor getBundleDescriptor() {
        return ejbBundleDescriptor;
    }


    /**
     * Set default value for EjbDescriptor.
     */
    private void setDOLDefault(EjbDescriptor ejb) {
        if (ejb.getUsesCallerIdentity() == null) {
            if (ejb instanceof EjbMessageBeanDescriptor) {
                ejb.setUsesCallerIdentity(false);
            } else {
                ejb.setUsesCallerIdentity(true);
            }
        }
        // for ejb 3.0
        if (ejb.getTransactionType() == null) {
            ejb.setTransactionType(com.sun.enterprise.deployment.EjbDescriptor.CONTAINER_TRANSACTION_TYPE);
        }
        ejb.setUsesDefaultTransaction();
    }


    /**
     * Set runtime default value for EjbDescriptor.
     */
    private void computeRuntimeDefault(EjbDescriptor ejb) {

        String intfName = null;
        if (ejb.getJndiName() == null || ejb.getJndiName().isEmpty()) {
            if (ejb.isRemoteInterfacesSupported() && ejb.isRemoteBusinessInterfacesSupported()) {
                // can't use a default.
            } else if (ejb.isRemoteInterfacesSupported()) {
                // For 2.x view, use the Home as the basis for the default
                intfName = ejb.getHomeClassName();
            } else if (ejb.isRemoteBusinessInterfacesSupported()) {
                Set classNames = ejb.getRemoteBusinessClassNames();
                if (classNames.size() == 1) {
                    intfName = classNames.iterator().next();
                }
            }
        }

        if (intfName != null) {
            ejb.setJndiName(SimpleJndiName.of(intfName));
        }

        if (!ejb.getUsesCallerIdentity()) {
            computeRunAsPrincipalDefault(ejb.getRunAsIdentity(), ejb.getApplication());
        }
    }


    private MethodDescriptor processTimeoutMethod(EjbDescriptor ejb, MethodDescriptor timeoutMethodDescOrig,
        AnnotationTypesProvider provider, Class ejbClass) throws ClassNotFoundException {
        Method m = timeoutMethodDescOrig.getDeclaredMethod(ejb);
        if (m == null) {
            // In case deployment descriptor didn't specify "jakarta.ejb.Timer"
            // as the method-params, and we were not relying on it before,
            // check explicitly for a method with "jakarta.ejb.Timer" param type.
            Class[] params = new Class[1];
            params[0] = provider.getType("jakarta.ejb.Timer");

            m = timeoutMethodDescOrig.getDeclaredMethod(ejb, params);
        }

        if (m == null) {
            throw new RuntimeException("Class " + ejbClass.getName() + " does not define timeout method "
                + timeoutMethodDescOrig.getFormattedString());
        }
        return new MethodDescriptor(m, MethodDescriptor.TIMER_METHOD);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy