JSR-352 Batchlet ejb nullPointerException - java

I have a problem with a batchlet where I want to use an EJB to populate a list.
When I start the project, glassfish flags an error:
Caught exception executing step:
com.ibm.jbatch.container.exception.BatchContainerRuntimeException:
java.lang.NullPointerException
Glassfish version is 4.1.1
The code of my batchlet is:
#Named
public class getPingStatusBatchlet extends AbstractBatchlet {
private static GetPingStatus gps = new GetPingStatus();
private List<Node> nodes = null;
#EJB
private NodeFacade nodeEJB;
#Override
public String process() throws NamingException {
nodes = nodeEJB.findAll();
for (Node item : nodes) {
gps.getPingStatus(item.getIpv4());
}
return "COMPLETED";
}
#Override
public void stop() throws Exception {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
I tried to run the application in debug and inspect the nodeEJB, it always keep the null value.
Have you an idea how I can use my EJB into my batchlet?
Thanks for your help
Ersch
EDIT:
the NodeFacade code:
#Stateless
public class NodeFacade extends AbstractFacade<Node> {
#PersistenceContext(unitName = "powwoPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public NodeFacade() {
super(Node.class);
}
}
beans.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"/>
getNetworkStatusBatch.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<job version="1.0" id="getNetworkStatusBatch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/jobXML_1_0.xsd" xmlns="http://xmlns.jcp.org/xml/ns/javaee" >
<step id="getNetworkStatusBatchlet">
<batchlet ref="com.powwo.app.batchlet.getPingStatusBatchlet"/>
</step>
</job>
myBackgroundJobManager.java:
#Singleton
#Startup
public class BackgroundJobManager {
#Schedule(minute = "*", hour = "*", second = "*/10", persistent = false)
public void myBackgroundJobManager() {
BatchRuntime.getJobOperator().start("getNetworkStatusBatch", null);
}
}

You need to reference the artifact from JSL by bean name (not class name).
So you should have:
<batchlet ref="getPingStatusBatchlet"/>
which matches the #Named (default) value on your batchlet.
You need this in order to load your batch artifact in Glassfish as a managed bean, and have the CDI engine perform injection of other beans.
More info:
Just for completeness, I'll mention something you already had taken care of, but someone else looking later may not have.
You also need to make sure the batch artifact is discovered as a managed bean, which you've taken care of by using the 1.0-level beans.xml. In later levels of CDI, you could use bean discovery mode = all, which is the same thing as the 1.0 beans.xml you have, or add a "bean-defining annotation" to your batch artifact, like #Dependent).

Related

Commit exception stack-trace to database when transaction fails

I have my transactional public method which tries to delete many stuff from database.
Also there is database table, containing information about errors during this deletion process.
However, I need it to work in a way that when there is exception thrown during the deletion process, all deletions will be rolled back and a commit new entry to database with the exception stack trace.
My code looks something like this:
class Clazz{
#Transactional
public void classMethod(){
try {
deleteStuff();
} catch (Exception e) {
logRepository.save(new ErrorLog(e.getMessage()));
}
}
}
As far as I'm concerned, this code would not work, because the exception is caught in the try-catch block, so the log will be saved to database, but the deletions would not be rolled back.
I've read about TransactionSynchronizationAdapter#afterCompletion method, but there is no way to access the stack trace of the exception thrown from that method.
So my question is, is there any way to catch the exception, save stack trace to database and rollback all the other commits?
Thanks in advance.
Yes, there is.
You can write your own Interceptor.
For that you will want to have your own Annotation:
#InterceptorBinding
#Inherited
#Target({ TYPE, METHOD })
#Retention(RUNTIME)
#Documented
public #interface LogExceptions {
}
Then you have to annotate your Method:
class Clazz{
#Transactional(value = TxType.REQUIRES_NEW)
#LogExceptions
public void classMethod(){
deleteStuff();
}
}
And write a Interceptor:
#Interceptor
#LogExceptions
#Priority(Interceptor.Priority.PLATFORM_BEFORE + 100) //intercept before the TransactionalInterceptor at 200
public class LogExceptionsInterceptor {
public LogExceptionsInterceptor() {}
#Inject
LogBean logBean; //some bean to persist the exception
#AroundInvoke
public Object aroundInvoke(InvocationContext ic) throws Exception {
Object result = null;
LogEntry logEntry = new LogEntry(); //a entity for the stacktrace
try {
result = ic.proceed();
}catch (Exception e) {
StringWriter s = new StringWriter();
e.printStackTrace(new PrintWriter(s));
logEntry.setStacktrace(s.toString());
logBean.persist(logEntry);
}
return result;
}
}
Finally you have to activate the Interceptor in your beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all" version="2.0">
<interceptors>
<class>your.package.LogExceptionsInterceptor</class>
</interceptors>
</beans>
Here's a link to a good tutorial:
https://rieckpil.de/howto-intercept-method-calls-using-cdi-interceptors/

Singleton CDI #Inject null pointer exception

I need to fire events from some ejb (Stateless and Singleton) using dependency injection. I do not use Spring, Guice etc.
The problem is that I get NPE in one of beans when calling its method through getInstance(). Here is the code snippet:
#Stateless
#LocalBean
public class ControllerStartStop {
#Inject
private Event<SomeWebMessage> webEvent;
public String startCircle(String passwordP, String passwordH) {
.........
String res = "some msg";
webEvent.fire(new SomeWebMessage(res, 0)); // this works fine
MainDay.getInstance().startDay(); // NullPointerException
Here is MainDay singleton:
#Singleton
public class MainDay {
private static final MainDay mDay = new MainDay();
public static MainDay getInstance() { return mDay ; }
#Inject
private Event<SomeWebMessage> webEvent;
public void startDay() {
String s = new String("MainDay");
webEvent.fire(new SomeWebMessage(s,0)); // NullPointerException
beans.xml is in META-INF:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
There is no NPE when I fire event from a call of static method like MainDay.initDS() or when method startDay() is invoked by a Sheduler (#Schedule(hour = "", minute = "", second = "/10")*.
I have no idea what is the reason
Note that #Singleton means that the container (EJB or CDI, depends on which annotation it is) will manage the instance, i.e. you shouldn't create it yourself.
If you create the instance via private static final MainDay mDay = new MainDay(); there won't be any injection by the container and thus webEvent will be null. Besides that the container won't know about that instance and using #Inject MainDay somewhere else is very likely to produce another instance.
Thus just use inject (or lookups if you need to) directly:
class ControllerStartStop {
#Inject
private MainDay mDay;
...
public String startCircle(String passwordP, String passwordH) {
...
String res = "some msg";
webEvent.fire(new SomeWebMessage(res, 0));
mDay.startDay();
...
}
There is no NPE when I fire event from a call of static method like MainDay.initDS() or when method startDay() is invoked by a Sheduler (#Schedule(hour = "", minute = "", second = "/10")*. I have no idea what is the reason
Without knowing your code it's only a guess but I'd assume you're injecting MainDay here or using a CDI/JNDI lookup. Hence the container will create an instance if there is none and will inject the Event objects.
NPE 1:
Shouldn't the targetted EJB MainDay "observe" the event and call its startDay() method?
public void onEvent(#Observes SomeWebMessage event) {
// if (...)
startDay();
}
So there is no need for a static getInstance() method.
NPE 2:
#Inject Event<SomeWebMessage> webEvent;
Dependency injection (DI) only works, if you do not manually call the constructor new MainDay() but inject instances of the wanted bean and let the DI container handle construction.
But with #Observes (javax.enterprise.event.Observes) you should be able to remove all the smelly static stuff anyway.

interface ServletContextListener don't save state of ServletContext

I have next websocket
#ServerEndpoint(value="/list")
public class WebSocketList implements ServletContextListener {
private ServletContextEvent sce;
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextInitialized");
this.sce = sce;
}
#OnMessage
public void receiveMessage(ByteBuffer bb, Session sn) {
if (sce == null)
System.out.println("not good");
}
File beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
</beans>
In debug, the object ServletContextEvent in method contextInitialized was not null, but when I receive a message from client (in method receiveMessage), always logs "not good" - object ServletContextEvent is null.
UPDATE: When I add System.out.println(this) in both methods, logged next -
WebSocketList#da599a0
WebSocketList#2942d8d0
I've just run into the same problem and as #Sotirios mentioned, the issue is that receivedMessage(ByteBuffer, Session) is called on a different object than contextInitialized(ServletContextEvent).
One way to fix it is by making your private ServletContextEvent sce field static but I suspect that doing so might cause problems when the context is stopped or reloaded. A better approach would be to extract all information that you need from the sce event and store it in one or more object fields.
In my case all I needed to store was the path of the current servlet context, so I just did this:
private static String path;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.path = sce.getServletContext().getContextPath();
}

Cant inject Bean class into Restfull WebService (JAX-RS) [duplicate]

This question already has answers here:
Inject an EJB into JAX-RS (RESTful service)
(7 answers)
Closed 7 years ago.
I'm trying to save data acquired by Rest web service to database using hibernate/persistence.
In one of my web modules i implemented that service. Database ejb connector is placed in EJB module. They are parts of EAR application.
Every time when i call pb.addDevice() im getting java.lang.NullPointerException when puting proper url with params in browser(worked till i wanted to save it to Database). Can't find what is wrong with it. I'm using jboss 6.1.0 Final.
tried answer of Dependency injection in restful WS
and after following it step by step im alse getting nullpointer also
PS. when i changed from
#EJB
PersistenceBean pb;
to
PersistenceBean pb = new PersistenceBean();
i got null pointer on EntityManager em = emf.createEntityManager();
code:
#Stateless
#Path("/RestService")
public class RestPush {
#EJB
PersistenceBean pb;
#GET
#Path("/RegisterDevice")
public void registerDevice(
#QueryParam("deviceId") String deviceId){
Device d = new Device(true);
d.setId = deviceId;
pb.addDevice(d);
}
}
and EJB class:
#Stateless(mappedName = "PersistenceBean")
public class PersistenceBean {
#PersistenceUnit(unitName = "PersistentUnitName")
EntityManagerFactory emf;
private void persist(Object o, EntityManager entityManager) {
try {
entityManager.persist(o);
} catch (Exception e) {
logger.severe("Error writing to DB: " + e);
logger.severe("" + e.fillInStackTrace());
}
}
public void addDevice(Device d) {
try {
EntityManager em = emf.createEntityManager();
if (persist(device, em)) {
logger.info("Device with id : " + device.getId()
+ " has been added ");
} else {
logger.info("Failed to add device with id: " + device.getId());
} catch (Exception e) {
logger.severe("PersistenceBean: Could not save device.");
e.printStackTrace();
}
}
upadate:
EAR
--EarContent
--META-INF
--application.xml
EJB
--package in ejbModule
--PersistenceBean
--Device
--META-INF
--ejb-jar.xml
--MANIFEST.MF
--persistence.xml
--beans.xml
Web
--package in webModule
--Rest (auto generated class while creating Webservice)
--RestPush
--WebContent
--META-INF
--MANIFEST.MF
--WEB-INF
--web.xml
--beans.xml
stack trace:
`10:23:28,629 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/RestWeb].[Resteasy]] Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at
Caused by: java.lang.NullPointerException
at package.RestPush.registerDevice(RestPush.java:68) [:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_27]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [:1.6.0_27]
The #EJB annotation is not supposed to work for all objects.
For this to work you need to use CDI, so substitute the #EJB with #Inject and your bean will be correctly injected.
See also: Inject an EJB into JAX-RS (RESTful service)
EDIT:
Also be sure to add beans.xml to every jar/war archive containing classes you want to inject or be injected. It goes into META-INF for jars and WEB-INF for wars.
Your REST application class packaget.Rest should extend javax.ws.rs.core.Application as in:
#ApplicationPath("/root-path")
public class Rest extends Application
{
}
And according to the documentation here on JBoss 6.1 REST and CDI should work out of the box. If you specify the org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher and the org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap you are probably messing up the RestEasy/CDI classloading.
So your web.xml should look as:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee java.sun.com/xml/ns/javaee/…">
</web-app>
Anyway, I pushed a working example on github
You should add /src/main/resources/META-INF/beans.xml. This will enable injection.
I has similar issue, for me the problem was creating my RESTful bean on my own with constructor, which was dumb while using EJBs and #EJB injection:
PROBLEM:
#ApplicationPath("/")
public class RestApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
public RestApplication() {
singletons.add(new RestService());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
SOLUTION:
#ApplicationPath("/")
public class RestApplication extends Application {
}
Hope it might save sb's time.

CXF/Spring Injecting Top-Level Service Name and Namespace into JAX-WS Interface

I'm flying a CXF-based Web service not unsimilar to the example on the CXF Web site at http://cxf.apache.org/docs/jax-ws-configuration.html . This service has an implemented endpoint based on the following sample context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint id="myServiceMembersImpl"
implementor="#myService"
endpointName="e:MyServiceMembersEndpoint"
serviceName="s:MyServiceMembersService"
address="http://localhost:8080/myservicemembers"
xmlns:e="http://localhost:8080/myservicemembers/ns"
xmlns:s="http://localhost:8080/myservicemembers/ns"/>
</beans>
Then, of course, there is the Java ...
Interface:
package com.me.service;
#WebService
public interface MyService {
String MEMBER = "MEMBER";
#WebResult(name = MEMBER)
Member getMember(#WebParam(name = "memberId") long memberId) throws Exception;
// ...
// more interface declarations
// ...
} // end interface
and, implementation:
package com.me.service.impl;
#WebService(endpointInterface = "com.me.service.MyService")
#Path("/")
public class MyServiceMembersImpl implements MyService {
#GET
#Path("/{id}")
#Consumes({ APP_JSON, APP_XML })
#Produces({ APP_JSON, APP_XML })
#Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public Member getMember(#PathParam("id") final long memberId) throws Exception {
// ...
// business logic
// ...
return theMember;
} // end method
} // end class
Which returns a WSDL that starts somewhat like this:
<?xml version="1.0" encoding="UTF-8" ?>
<wsdl:definitions name="MyServiceImplService"
targetNamespace="http://localhost:8080/myservicemembers/ns"
xmlns:ns1="**http://service.me.com/**"
xmlns:ns2="http://schemas.xmlsoap.org/soap/http"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://localhost:8080/myservicemembers/ns"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import location="http://localhost:8080/myservicemembers?wsdl=**MyService**.wsdl"
namespace="**http://service.me.com/**" />
<wsdl:binding name="MyServiceImplServiceSoapBinding" type="ns1:**MyService**">
<!-- ... -->
</wsdl:definitions>
It's fairly simple using the "jaxws:endpoint" element in the application context to change the settings for the endpoint. This fleshes out the service name, endpoint name and other fields. However, the top-level interface still has a say in the WSDL file. The STARRED items above are from the top-level interface. How can I inject values into the top-level interface for the targetNamespace and serviceName?
My good reasons for doing this include (1) not wanting to expose package names in the WSDL and (2) wanting to switch namespaces as an application moves down a deployment runway. Thus I cannot use annotations since those are compile-time values, I can't substitute them with property placeholders, and I will not recompile my code in the production tier.
You can do this by programmatically creating the services using JaxWsServerFactoryBean instead of using <jaxws:endpoint> in your Spring config. Doing the creation programmatically gives you a lot more control.
For example:
#Autowired
var myServiceImpl: MyService = _
val propMap = mutable.HashMap[String, AnyRef]("org.apache.cxf.logging.FaultListener"->faultListener.asInstanceOf[AnyRef])
val sf = new JaxWsServerFactoryBean
sf.setServiceBean(myServiceImpl)
sf.setAddress("/myservice")
sf.setServiceName(new QName(WEB_SERVICE_NAMESPACE, "myService", "MyService"))
sf.setProperties(propMap)
sf.create

Categories