0

I have six Java Scheduler classes, each with a different purpose but all coded in the same way. Only three of these are triggering on my WebSphere Application Server installation.

Interface:

import javax.ejb.Local;

@Local
public interface IScheduledProcessorBean 
{
    public void doProcessing();
}

Implementations (an example of one that isn't working, but all six are identical except for naming):

@Stateless
@HousekeepingProcessor
public class HousekeepingTimer implements IScheduledProcessorBean
{

    public static final String className = "HousekeepingTimer";
    @PersistenceContext(unitName = "WOTISEJB")
    private EntityManager em;
    
    /**
     * Default constructor. 
     */
    public HousekeepingTimer() 
    {
        // Default Constructor
    }
    
    // Try not to clash with the other schedule timer flows.

    @Schedule(minute="20", hour="8-20", dayOfWeek="Mon-Fri",
            dayOfMonth="*", month="*", year="*", info="HousekeepingTimer", persistent=true)
    public void doProcessing()
    {
        Logger.getGlobal().fine(()->className + " called at: " + new java.util.Date());
        try
        {
            // Specific logic goes here
        }
        catch (Exception e)
        {
            Logger.getGlobal().log(Level.SEVERE, "Scheduler failed for Housekeeping", e);
        }
    }
}

Processor Annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface HousekeepingProcessor {

}

Each of the six timers follow the exact pattern above, however only three of them trigger.

In the WebSphere Application Server 9 Console, under Enterprise Applications -> Application -> EJB JNDI names, In only see three of the Beans (the three that run successfully), and not all six. Likewise under Enterprise Applications -> Application -> Binding enterprise Bean with business interface to JNDI names I only see the three working schedulers.

And, likewise, when installing the application, the "Provide JNDI names for beans" and "Bind EJB Business" steps of the detailed installation path only show those same three beans.

When I look in ejb-jar_merged.xml in the deployed files, again, only the three working timers are there.

I have tried creating ejb-jar.xml and deploying it explicitly, and that works - so there's something in Websphere's automatic bean processing that isn't picking it up without a prompt.

Can anyone suggest what might be going on here?

simonalexander2005
  • 4,338
  • 4
  • 48
  • 92

2 Answers2

1

It looks like the three out of six Scheduler classes are not triggering in WebSphere Application Server. This is likely due to a problem with the EJB JNDI names not being bound correctly to the Scheduler classes.

Here are a few steps to troubleshoot this issue:

  1. Confirm that all six Scheduler classes are included in the deployment unit (e.g. .ear file).
  2. Check that the @Stateless annotation is present on all six Scheduler classes.
  3. Verify that there are no classpath or package level issues that prevent the Scheduler classes from being detected during deployment.
  4. Make sure that the Maven dependencies, if applicable, are properly configured in the project's pom.xml file.
  5. Ensure that all Scheduler classes have a default constructor.
  • All classes are in the ear file, all have `@Stateless`, the pom is fine, all classes have a public default constructor. For point 3, I've not seen anything. – simonalexander2005 Feb 06 '23 at 09:55
1

The fact that the EJB is not bound in JNDI indicates WebSphere does not recognize the class as an EJB. Since things work when using an ejb-jar.xml file, that suggests the EJB class is at least on the classpath for the application.

Here are some additional troubleshooting steps:

1 - Confirm the EJB class is packaged in one of the following locations: a) in a .jar file at the root of the .ear file, b) in a .jar file in the WEB-INF/lib directory of a .war file, c) in the WEB-INF/classes directory in a .war file. Only these locations will be scanned for EJB component defining annotations (as required by the EJB specification).

2 - If an application.xml file is present, ensure the version is >= 5.0. If the EJB is packaged in a .war file, ensure the web.xml file version is >= 2.5. (and ejb-jar.xml >= 3.0)

3 - Confirm the import for the @Stateless annotation is javax.ejb.Stateless (and not jakarta.ejb.Stateless).

4 - Confirm the javax.ejb.Stateless annotation class is not packaged in the application or included on the application classpath. WebSphere provides the EJB API classes and there could be a conflict if the application also includes a copy.

5 - Look for any warnings in the log that indicate there was a problem accessing annotations for the application. Possibly a message starting with CWMDF. For example, CWMDF0022W: An attempt to scan class file "{0}" in JAR file "{1}" failed with exception: "{2}".

6 - Confirm the ejb-jar.xml file does not include metadata-complete="true". Granted, it sounds like you started without an ejb-jar.xml file, but WebSphere does support an option during application install to generate an ejb-jar.xml file and mark it metadata-complete. Ensure you do not use this option at least for troubleshooting purposes.

Tracy
  • 933
  • 4
  • 7
  • It's packaged in an ear file, with a war and a jar at the root level. The jar contains the schedules. I'm not using application.xml. I have checked the import and it's correct across all 6 classes. I have found that javax.ejb-api-3.2.jar is included in the jar file's pom, but removing it doesn't appear to solve the issue. Anyway, if that was an issue I would have thought it would be an issue for all six? I can't see any of those exceptions related to my code; and I metadata-complete is false (I don't tick that box on deployment) – simonalexander2005 Feb 06 '23 at 16:29
  • That said, for 5 I do see the following in the systemout log: `com.ibm.ws.ecs.internal.scan.context.impl.ScannerContextImpl scanJA R unable to open input stream for resource module-info.class in archive WEB-INF/lib/jackson-annotations-2.13.4.jar` - and the same for a series of other jackson jar files; but those are in the WAR and not the JAR, so I don't think that's related – simonalexander2005 Feb 06 '23 at 16:31
  • WebSphere uses a bytecode scanner to process the `@Stateless` annotation. Since it appears the class is packaged properly, then the most likely cause is that the `@Stateless` annotation is just not present in the bytecode. Using a tool to decompile or scan the class could confirm that. Is it possible that 1) the build isn't re-compiling that class, but including an older .class file? 2) the build is compiling the class with an older target level, which doesn't support annotations? 3) the build is compiling the class with annotation processing disabled (-proc:none)? – Tracy Feb 07 '23 at 16:26
  • I have run the class through a decompiler and it has the @Stateless annotation – simonalexander2005 Feb 07 '23 at 16:30
  • Hmm, very strange. I'd recommend turning on trace with `*=info:EJBContainer=all:MetaData=all` and checking the trace output to see if your classes are being scanned. You should see trace ouput like this: ``` > getAnnotationData( module = xxxx 3 ASM processing class :xxxxx ``` Where the module should be your EJB moudule and the class should be your EJB class. This will identify if the class just isn't being scanned, or the annotation just isn't being found. – Tracy Feb 07 '23 at 17:11