DeltaSpike

A Working DeltaSpike Tutorial

David Kelly Development Technologies, Java 3 Comments

Attention: The following article was published over 8 years ago, and the information provided may be aged or outdated. Please keep that in mind as you read the post.

On a recent project, I was faced with an interesting problem: take a service method that was given a single object and reuse the same code in the context of a nightly process that would run independently of the application over thousands of the same type of object.

It would have been ridiculous to try to maintain an identical process of this size and complexity in two places, so I needed to find a way to share the code. One possible solution was to use DeltaSpike, Apache’s collection of CDI extensions, to provide a simple way to access entities and classes from the primary Java/JPA/Hibernate application.

There seemed to be ample documentation for getting DeltaSpike running in similar situations across the web, but there was some skepticism about the viability of its use in this application; my team had been unable to get it working for another part of the project, and had moved on to using Spring Batch for that piece.

The biggest hurdle was the inability to create a functional EntityManager, no matter how closely they followed the documentation and examples they could find. This smaller component of the project presented another good candidate for implementing DeltaSpike, but after the all-too-familiar dance of following tutorials, finding how-to’s, and reading the official implementation instructions, I was stuck in the same place: the EntityManager simply would not work, at least not with the combination of technologies and versions I had in front of me.

Fortunately, I was able to Frankenstein parts of several tutorials and examples together to get a working implementation of DeltaSpike for my situation, so I thought I would share what I found so it might be a little easier for someone else the next time.

The Basics

For starters, I’m using Maven, so here are the dependencies you’ll need to add:

<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-api</artifactId>
    <version>1.2.1</version>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se</artifactId>
    <version>1.1.16.Final</version>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-weld</artifactId>
    <version>1.2.1</version>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.core</groupId>
    <artifactId>deltaspike-core-api</artifactId>
    <version>1.5.0</version>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-jpa-module-api</artifactId>
    <version>1.4.0</version>
</dependency>

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-jpa-module-impl</artifactId>
    <version>1.4.0</version>
</dependency>

As you can see, we’re looking at implementing DeltaSpike in a project that also needs JBoss/Weld. Other dependencies I had included javax.enterprise, Hibernate, and JPA. Depending on your final implementation, you may not need all of these DeltaSpike dependencies, so be sure to clean up your pom.xml when you’re finished.

The App

For my example, I’ll use a basic Application class that follows a pattern you may have seen in other DeltaSpike examples:

import javax.enterprise.context.ApplicationScoped;
import org.apache.deltaspike.cdise.api.CdiContainer;
import org.apache.deltaspike.cdise.api.CdiContainerLoader;
import org.apache.deltaspike.cdise.api.ContextControl;
import org.apache.deltaspike.core.api.config.ConfigResolver;

public class Application {
    
    public static void main(String[] args) {
        CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
        cdiContainer.boot();
        
        ContextControl contextControl = cdiContainer.getContextControl();
        contextControl.startContext(ApplicationScoped.class);
        
        //Your code here
        
        cdiContainer.shutdown();
    }
}

Notice this line in particular:

contextControl.startContext(ApplicationScoped.class);

This line looks for classes with the @ApplicationScoped annotation that need to be included as part of the context.

The EntityManagerProducer

Here’s where things get tricky. Following your typical DeltaSpike tutorial would give you an EntityManagerProducer that looks something like this:

@ApplicationScoped
public class EntityManagerProducer
{
    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Produces
    @Default
    @RequestScoped
    public EntityManager create()
    {
        return this.entityManagerFactory.createEntityManager();
    }

    public void dispose(@Disposes @Default EntityManager entityManager)
    {
        if (entityManager.isOpen())
        {
            entityManager.close();
        }
    }
}

The only problem I had was this didn’t work at all, given the combination of factors I was dealing with. The EntityManager was always null, no matter what I tried. I suspected the EntityManagerFactory wasn’t working correctly, so I did some digging and found this approach to getting an EntityManagerFactory:

private EntityManagerFactory entityManagerFactory = 
Persistence.createEntityManagerFactory("PERSISTENCE_UNIT", setProperties());

Using this I was able to get a working EntityManagerFactory based on the persistence unit that was defined in the persistence.xml that had the name I provided in the parameters. There I defined the entities the application would need to be a part of the EntityManagerFactory in order to be able to do the little things… like run.

Here’s what the new and improved EntityManagerProducer looks like:

@ApplicationScoped
public class EntityManagerProducer {

    private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE_UNIT", setProperties());

    private EntityManager entityManager;

    protected void closeEntityManager(@Disposes EntityManager entityManager) {
        if (entityManager.isOpen()) {
            entityManager.close();
        }
    }

    @Produces
    protected EntityManager createEntityManager() {
        if (entityManager == null) {
            entityManager = entityManagerFactory.createEntityManager();
        }
        return entityManager;
    }
    
    protected Properties setProperties() {
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
        properties.setProperty("hibernate.show_sql", "false");
        properties.setProperty("hibernate.hbm2ddl.auto", "none");
        properties.setProperty("hibernate.enable_lazy_load_no_trans", "true");
        properties.setProperty("hibernate.jdbc.batch_size", "20");
        properties.setProperty("hibernate.connection.driver_class", "oracle.jdbc.driver.OracleDriver");
        properties.setProperty("hibernate.connection.url", "JDBC_URL");
        properties.setProperty("hibernate.default_schema", System.getProperty("SCHEMA_NAME"));
        properties.setProperty("javax.persistence.jdbc.user", System.getProperty("USER"));
        properties.setProperty("javax.persistence.jdbc.password", System.getProperty("PASSWORD"));
        properties.setProperty("org.hibernate.flushMode", "ALWAYS");
        return properties;
    }
    
}

Notice the @ApplicationScoped tag; this ensures that this class is included in the context when the CDI Container is started. Also note that you can set your properties to be passed into the EntityManagerFactory you create, including getting them from System Properties that are part of the server arguments, which is useful if there are environmental variables that could change how your application functions.

Final Thoughts

Hopefully this provides a simple and effective example of how to set up and implement DeltaSpike.

Side note: I ended up not being able to use this approach to solve the problem because the number of objects to be processed was MUCH larger than anticipated (several million), but I thought it would still be useful to share what I found.

0 0 votes
Article Rating
Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments