I'm tinkering a Jersey Webservice that access the default JavaDB integrated into the Glassfish4 Application Server. The idea is to create new objects during the runtime of the application on the server and use the Java Persistence API (JPA) to access them even if the server is shut down or the application is being removed from the server.
The first question would be if this is a viable option?
The second question is regarding some a problem I have with injecting the EntityManagerFactory so I can access it while handling the HTTP requests.
My simple test case looks like this:
@Path("jpaResource/")
public class JpaResource {
@PersistenceUnit
private EntityManagerFactory emf;
@GET
@Path("html")
@Produces(MediaType.TEXT_HTML)
public String getHtml() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("WebApp"); System.out.println(aThing); }
Thing thing = (Thing) factory.createEntityManager().createQuery("select u from Thing u").getResultList().get(1);
return "<h1>Hey HTML! I'm: " + thing.getDescription() + "</h1>";
}
@GET
@Path("text")
@Produces(MediaType.TEXT_PLAIN)
public String getText() {
Thing thing = (Thing) emf.createEntityManager().createQuery("select u from Thing u").getResultList().get(0);
return "Hey text! I'm: " + thing.getDescription();
}
}
The first GET method works fine. However the second one doesn't because the EntityManagerFactory emf is NULL.
The Thing object is a simple POJO and looks like:
@Entity
@NamedQuery(name="Thing.findAll", query="SELECT t FROM Thing t")
public class Thing {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String description;
private String summary;
public Thing() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getSummary() {
return this.summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
}
The persistence.xml file is stored in the .../src/main/resources/META-INF folder of my eclipse project and looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="WebApp" transaction-type="RESOURCE_LOCAL">
<!--provider>org.eclipse.persistence.jpa.PersistenceProvider</provider-->
<!--provider>org.hibernate.ejb.HibernatePersistence</provider-->
<jta-data-source>jdbc/__default</jta-data-source>
<class>com.test.webapp.objects.Thing</class>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
The stacktrace looks like this:
StandardWrapperValve[Jersey Web Application]: Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
at com.test.webapp.resources.JpaResource.getText(JpaResource.java:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:125)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:91)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:346)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:341)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:101)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:224)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:198)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:946)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:323)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:744)
If someone has any idea what I'm doing wrong please let me know.
Greetings
[edit: ] Ok I did some more testing and I have an implementation of the ServletContextListener interface in my project that handles initialization when the application is started for the first time.
public class ServletContextClass implements ServletContextListener {
@PersistenceUnit(unitName="WebApp")
private EntityManagerFactory emf;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("##############################");
System.out.println("ServletContextListener started");
System.out.println("##############################");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("###############################");
System.out.println("SevletContextListener destroyed");
System.out.println("###############################");
}
}
In this class the injection works without any problems and I'm able to access the JavaDB to retrieve the objects.
The tutorial I watched used a Glassfish3 server. Is it possible that this feature was removed from Java EE7 and thus is not working on a Glassfish4 Server? I found a similar question that suggests that my approach should work with Java EE 6 (PersistenceContext EntityManager injection NullPointerException). Now I'm really confused.
I will add my web.xml so if someone is interested in answering my question and needs the deployment descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" 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/web-app_2_5.xsd">
<listener>
<listener-class>com.test.webapp.startup.ServletContextClass</listener-class>
</listener>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.test.webapp.resources</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>