JPA and async Servlet integration

A few base classes useful when developing asynchronous servlets performing JPA operations

License

License

GroupId

GroupId

pl.morgwai.base
ArtifactId

ArtifactId

servlet-jpa
Last Version

Last Version

1.0-alpha1
Release Date

Release Date

Type

Type

jar
Description

Description

JPA and async Servlet integration
A few base classes useful when developing asynchronous servlets performing JPA operations
Project URL

Project URL

https://github.com/morgwai/servlet-jpa
Source Code Management

Source Code Management

https://github.com/morgwai/servlet-jpa.git

Download servlet-jpa

How to add to project

<!-- https://jarcasting.com/artifacts/pl.morgwai.base/servlet-jpa/ -->
<dependency>
    <groupId>pl.morgwai.base</groupId>
    <artifactId>servlet-jpa</artifactId>
    <version>1.0-alpha1</version>
</dependency>
// https://jarcasting.com/artifacts/pl.morgwai.base/servlet-jpa/
implementation 'pl.morgwai.base:servlet-jpa:1.0-alpha1'
// https://jarcasting.com/artifacts/pl.morgwai.base/servlet-jpa/
implementation ("pl.morgwai.base:servlet-jpa:1.0-alpha1")
'pl.morgwai.base:servlet-jpa:jar:1.0-alpha1'
<dependency org="pl.morgwai.base" name="servlet-jpa" rev="1.0-alpha1">
  <artifact name="servlet-jpa" type="jar" />
</dependency>
@Grapes(
@Grab(group='pl.morgwai.base', module='servlet-jpa', version='1.0-alpha1')
)
libraryDependencies += "pl.morgwai.base" % "servlet-jpa" % "1.0-alpha1"
[pl.morgwai.base/servlet-jpa "1.0-alpha1"]

Dependencies

compile (1)

Group / Artifact Type Version
pl.morgwai.base : servlet-scopes jar 1.0-alpha1

provided (4)

Group / Artifact Type Version
com.google.inject : guice jar 5.0.1
javax.servlet : javax.servlet-api jar 4.0.1
javax.websocket : javax.websocket-api jar 1.1
javax.persistence : javax.persistence-api jar 2.2

Project Modules

There are no modules declared in this project.

JPA and async Servlet integration

A few base classes useful when developing asynchronous servlets performing JPA operations.
Built on top of Servlet and Websocket Guice Scopes library.

latest release: 1.0-alpha1

SUMMARY

SimpleAsyncJpaServlet

Base class for servlets that do not perform synchronous time consuming operations other than JPA calls.
Request handling is dispatched to the app wide ContextTrackingExecutor associated with persistence unit's JDBC connection pool. This way the total number of server's threads can remain constant and small regardless of the number of concurrent requests, while providing optimal performance.

JpaServlet

Base class for servlets that do perform other type(s) of time consuming operations apart from JPA.
Mostly just provides some helper methods.

JpaServletContextListener

Base class for app's JpaServletContextListener. Configures and creates Guice Injector and manages lifecycle of persistence unit and its associated ContextTrackingExecutor.

USAGE

public class LabelServlet extends SimpleAsyncJpaServlet {

    @Inject MyDao dao;

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // this code will be executed on the app wide executor associated with persistent unit,
        // so threads from server's main thread pool will not be waiting on JPA operations
        // nor for JDBC connections to become available.
        try (
            PrintWriter writer = response.getWriter();
        ) {
            MyEntity myEntity = dao.find(Long.valueOf(request.getParameter("objectId")));
            for (String label: myEntity.getLabels()) writer.println(label);
            String newLabel = request.getParameter("newLabel");
            if (newLabel == null) return;
            performInTx(() -> {
                myEntity.addLabel();
                writer.println(newLabel);
            });
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }
}
@WebListener
public class ServletContextListener extends JpaServletContextListener {

    @Override
    protected String getMainPersistenceUnitName() {
        return "my-persistence-unit";  // same as in persistence.xml
    }

    @Override
    protected int getMainJpaThreadPoolSize() {
        // return the same value as my-persistence-unit's connection pool size. This way threads
        // from the pool will never have to wait for a JDBC connection to become available
        return 10;
    }

    @Override
    protected LinkedList<Module> configureInjections() {
        var modules = super.configureInjections();
        modules.add((binder) -> {
            binder.bind(MyDao.class).to(MyJpaDao.class).in(Scopes.SINGLETON);
            // more bindings here...
        });
        return modules;
    }

    @Override
    protected void configureServletsFiltersEndpoints() throws ServletException {
        addServlet("label", LabelServlet.class, "/label");  // will have its fields injected
        // more servlets/filters here...
    }
}
public class MyJpaDao implements MyDao {

    @Inject Provider<EntityManager> entityManagerProvider;

    @Override
    public MyEntity find(long id) {
        return entityManagerProvider.get().find(MyEntity.class, id);
    }

    // more dao stuff here...
}

EXAMPLES

See sample app

Versions

Version
1.0-alpha1