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?
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:
Confirm that all six Scheduler classes are included in the
deployment unit (e.g. .ear file).
Check that the #Stateless annotation is present on all six Scheduler
classes.
Verify that there are no classpath or package level issues that
prevent the Scheduler classes from being detected during deployment.
Make sure that the Maven dependencies, if applicable, are properly
configured in the project's pom.xml file.
Ensure that all Scheduler classes have a default constructor.
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.
Related
We got Java EE 7 project with the following structure:
app.ear
META-INF
application.xml
lib
framework.jar
webapp.war
core.jar
Framework.jar is our framework that uses some kind of command pattern.
This is how it works. Each command has it's own ejb attached to it that does all the business logic. This command ejb extends CommandEJB class that have an execute method.
For example, this is an example of a command ejb:
public class cmdCreateBookEJB<T extends cmdCreateBook> extends CommandEJB<T> {
#Override
public void execute() {
//do something
}
}
And in our framework, we also have CommandExecutorEJB that sets the appropriate ejb for the command and execute it.
Example:
CmdCreateBook cmdCreateBook = new cmdCreateBook();
cmdCreateBook.setEjb(cmdCreateBookEJB.class.getSimpleName());
commandExecutorEJB.execute(cmdCreateBook);
The problem is our framework, specifically CommandExecutorEJB(that is packed in framework.jar inside lib folder) needs to know about ejb's from core.jar, so it can handle the command. What actually happens in the framework is that the the specific command ejb(cmdCreateBookEJB) in my example is cast to CommandEJB and then it's execute method is called.
The question is how to make the framework know about command ejbs.
I know that one option is to specify am env-entry in ejb-jar.xml with the core jar module name, and then use #Resource in commandExecutorEJB to find the entry, and then use the JNDI lookup to find the resource that would be cast to CommandBean.
But, I would like not to use ejb-jar.xml as we're using ejb 3.2 and ejb-jar.xml isn't necessary anymore.
EDIT:
To better explain here is how the jndi lookup string would look like for my example: java:app/core.jar/cmdCreateBookEJB
Because framework isn't and shouldn't be aware of the core.jar(The name core.jar name is just an example, someone could name it BookStoreCore.jar), I somehow need to pass module name(in my example core.jar), so that the framework know where to look for classes to find a specific command EJB, in my example cmdCreateBookEJB.
I know that I can use an env-var in ejb-jar.xml to pass module name to the framework. Here's an example:
<session>
<ejb-name>CommandExecutorEJB</ejb-name>
<ejb-class>com.mypackage.CommandExecutorEJB</ejb-class>
<session-type>Stateless</session-type>
<env-entry>
<env-entry-name>com.mypackage.CommandExecutorEJB/moduleName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>core</env-entry-value>
</env-entry>
</session>
But, I would love to eliminate ejb-jar.xml from our project setup
You're using Java EE 7.
You can completely avoid class visibility problems by putting everything in your WAR file. core.jar and framework.jar can both be added to your WEB-INF/lib directory.
You can then directly inject EJBs where ever they're needed.
I have some problem with injecting dependencies to the project. In my case I have WAR file with some specialized GWT handlers, and jar with dispatcher classes (dispatcher + common: actions, handlers, results). In this jar I try scan all Handlers and automatically register them:
#Inject
private void init(#Any Instance<ActionHandler<?, ?>> handlers) {
...
InstanceActionHandlerRegistry registry = new DefaultActionHandlerRegistry();
for (ActionHandler<?, ?> handler : handlers) {
registry.addHandler(handler);
}
...
}
The problem is that all handlers from jar are registered but Handlers from WAR are not. Both jar and war file have beans.xml files. Does anyone know what I should do to force find all instances of handlers - not only listed in library jar file?
The reason was that WAR file do not have deployed some library required by handlers. Project compiled successfully and deployed successfully without any error/warning. This was very simple reason but in case when Weld do not report problem - it was very hard to find the source of troubles. (I suppose that better level of problem reporting can be set somewhere for Weld)
I am using Glassfish 4. And I have an EAR which has a WAR and a JAR (with the EJBs).
I want to call the EJBs from my WAR but am not really sure if I need to use Local or Remote interfaces.
Inside my JAR, my Bean looks like this :
#Stateless
public class Test implements TestLocal {
#Override
public void testing() {
}
}
And my local :
#Local
public interface TestLocal {
void testing();
}
Inside my WAR I have a web service and it looks like this :
#WebService(serviceName = "TestWS")
public class TestWS {
private #EJB TestLocal testBean;
#WebMethod(operationName = "test")
public String test() {
testBean.test();
}
}
Both of these are packaged into an EAR.
When I call my WebService method I get an AccessLocalException :
Warnung: javax.ejb.AccessLocalException: Client not authorized for
this invocation at
com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1895)
at
com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:210)
Firstly :
Is this the correct way to call the EJB. Can a WAR inside an EAR use Local interfaces from an included JAR?
If so then does anyone know what I am doing wrong? Do I need to setup some kind of security configuration?
To look up a remote EJB, it must have a remote interface exposed. Include that remote interface into your war.
The GlassFish documentation has an entry for this error:
javax.ejb.AccessLocalException: Client Not Authorized Error
Description
Role-mapping information is available in Sun-specific XML (for example, sun-ejb-jar.xml), and authentication is okay, but the following error message is displayed:
[...INFO|sun-appserver-pe8.0|javax.enterprise.system.container.ejb|...|
javax.ejb.AccessLocalException: Client not authorized for this invocation.
at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:...
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(...)
Solution
Check whether the EJB module (.jar) or web module (.war) is packaged in an application (.ear) and does not have role-mapping information in application level, Sun-specific, sun-application.xml. For any application (.ear), security role-mapping information must be specified in sun-application.xml. It is acceptable to have both module-level XML and application-level XML.
#Remote is usefull if you deploy separately your jar which contain your EJBs on a different server, for example.
There, war and jar are in the same ear so you just have to use the Local annotation.
Tips : since EJB 3.1 interfaces are not required, you can use #LocalBean directly on your "Test" class and remove the TestLocal interface.
To call a ejb method into a class which is your war, you firstly have to create a link between war and jar. Being in the same ear is not enough.
If you use Maven, you can simply add the jar reference into your dependencies in the pom of your war.
The issue I am currently experiencing is that my entityManager fails to be injected during the execution of a web application deployed within an ear.
The ear is setup as follows:
/META-INF -application.xml (EJBJar +
WAR)
-MANIFEST.MF
-weblogic-application.xml (currently just the default one that eclipse
generates)
/APP-INF
-lib
-EJBClientJar (interfaces + pojos)
-other jars
-classes
EJBJar
/META-INF
-persistence.xml
/src
-Annotated classes
WAR
-Service classes
Classes are as follows:
DAO inside EJBJar
#Stateless(mappedName="AwesomeBean")
public class Awesome implements AwesomeRemote //AwesomeRemote in EJBClientJar
{
#PersistenceContext
EntityManager em;
}
public class AwesomeService //Inside WAR
{
AwesomeRemote = context.lookup (Awesome.path.to.AwesomeRemote) //Is found
}
The call stack is like this:
War -> EJBClientJar -> EJBJar
On the EJB jar the entity manager is null. Question being how do I ensure that the PersistenceContext gets injected? The JNDI lookup succeeds on the AwesomeRemote Interface. The Interface has no annotations on it.
It's probably due to the fact that you try to inject on POJO class, not on managed component. Could you try to mark it as #Stateless and public and check whether it works?
For simple testing you can also add #WebService annotation and invoke your bean with SoapUI for example.
You should read about "packaging" part of ejb specifications.
This structure should be sufficient and work:
/
/lib
EJBClientJar (interfaces + pojos)
/META-INF
persistence.xml
application.xml
EJBJar.jar
WAR.war
As some formatting was lost, I'm not sure about what wasn't right in yours.
If this still doesn't work, try removing the only tricky part from above: put all classes from EJBClientJar in root. You the just have the most simple EAR packaging possible, it just will work.
Also, if you don't use your session bean outside a web application, you could use #Local instead of #Remote .
I'm working on a project which includes persistence library (JPA 1.2), EJB 3 and Web presentation layer (JSF). I develop application using Eclipse and application is published on Websphere Application Server Community Edition (Geronimo 2.1.4) through eclipse plugin (but the same thing happens if I publish manually). When publishing to server I get the following error:
java.lang.NoClassDefFoundError: Could not fully load class: manager.administration.vehicles.VehicleTypeAdminBean
due to:manager/vehicles/VehicleType
in classLoader:
org.apache.geronimo.kernel.classloader.TemporaryClassLoader#18878c7
at org.apache.xbean.finder.ClassFinder.(ClassFinder.java:177)
at org.apache.xbean.finder.ClassFinder.(ClassFinder.java:146)...
In web.xml I have reference to EJB:
<ejb-local-ref>
<ejb-ref-name>ejb/VehicleTypeAdmin</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>manager.administration.vehicles.VehicleTypeAdmin</local>
<ejb-link>VehicleTypeAdminBean</ejb-link>
</ejb-local-ref>
EJB project has a reference to persistence project, and Web project has references to both projects. I don't get any compilation errors, so I suppose classes and references are correct.
I don't know if it is app server problem, but I ran previously application on the same server using same configuration parameters.
Does anybody have a clue what might be the problem?
Looks almost like it couldn't find the class manager.vehicles.VehicleType when it was attempting to create/load the class manager.administration.vehicles.VehicleTypeAdminBean.
I've encountered similar problems before. When the class loader attempts to load the class it looks at the import statements (and other class usage declarations) and then attempts to load those classes and so on until it reaches the bottom of the chain (ie java.lang.Object). If it cannot find one class along the chain (in your case it looks like it cannot load VehicleType) then it will state that it cannot load the class at the top of the chain (in your case VehicleTypeAdminBean).
Is the VehicleType class in a different jar? If you have a web module and and EJB module do you have the jar containing the VehicleType class in the appropriate place(s). Sometimes with web projects you have to put the jars in the WebContent/WEB-INF/lib folder or it won't find them.
Are both of these projects deployed separately (ie. two ears? or one ear and one war?) or are they together (ie, one ear with jars and a war inside?). I'm assuming the second given you declared your EJB local?
The jars that you are dependent on also have to be declared in your MANIFEST.MF files in the projects that use it.
I'm kind of running on guesses since I do not know your project structure. Showing that would help quite a bit. But I'd still check on where VehicleType is located with regards to your EJB class. You might find it isn't where you think it is come packaging or runtime.
Thanks #Chris for WebContent/WEB-INF/lib idea ! it works for me by following these steps :
1- Export my EJBs to a JAR (MyEJBs.jar)
2- I created another jar with your_installation_path/IBM/SDP/runtimes/your_version/binCreateEJBStrub.bat via CMD.exe, by executing this command :
createEJBStubs.bat <my_path>/MyEJBs.jar -newfile –quiet
3- A new jar will be automatically created in the same directory as MyEJBs.jar named MyEJBs_withStubs.jar
4- Put your new jar in WebContent/WEB-INF/lib
5- Call your EJBs by :
MyEJBRemote eJBRemote;
InitialContext ic = new InitialContext();
obj = ic.lookup("your_ejb_name_jndi");
eJBRemote = (MyEJBRemote ) PortableRemoteObject.narrow(obj,
MyEJBRemote.class);
eJBRemote = (MyEJBRemote ) obj;
Now you can call your EJBs from another EAR