Integrate JBoss AS Maven Plugin with NetBeans Actions

Deploying JEE Artefacts such as EAR Files to a JBoss EAP Server instance is unfortunately not working with NetBeans out-of-the-box. The NetBeans Application Server Plugin as well as the additionally available Wildfly Plugin do not help. If you are a corporate developer whose company licensed a fairly new JBoss EAP 6.2.x (at least at the time of writing this entry) – you’re out of luck.

Fortunately NetBeans excellent maven integration comes to the rescue in form of the JBoss Application Server 7 Maven Plugin. There is also Wildfly Maven Plugin available. Just add the following lines to your pom.xml’s “plugins” section (in my case a maven EAR module):

1
2
3
4
5
6
7
8
9
10
11
  <plugin>
    <groupId>org.jboss.as.plugins</groupId>
    <artifactId>jboss-as-maven-plugin</artifactId>
    <version>7.6.Final</version>
    <configuration>
      <hostname>localhost</hostname>
      <port>9999</port>
      <username>jbossadmin</username>
      <password>*******</password>
    </configuration>
  </plugin>

Hostname, port, username and password have to be changed according to your needs.
Now you have quite a few additional maven goals at hand – deploying, undeploying and redeploying as well as starting and stopping the JBoss EAP Server instance. I usually have an already running JBoss instance on my notebook, hence the deployment related goals matter to me:

  • jboss-as:undeploy — undeploys your already deployed artefact from the running JBoss instance
  • jboss-as:deploy — deploys the artefact that is generated by your maven project to the running JBoss instance
  • jboss-as:redeploy — redeploys your artefact

You could bind the redeploy goal to the packaging phase, so that every time the artefact is built, it is also redeployed to your local JBoss EAP Server instance. I prefer explicit execution of the redeployment goal. NetBeans offers two ways doing that:

Deploy through the NetBeans Navigator Window

Select the maven artefact project – in my case this is the pla-ear-2.0.0. The Navigator Window displays all maven goals that are not bound to maven life cycles. Double click the jboss-as redeploy goal and 8 seconds later, the artefact is deployed and ready to be debugged. At least when you have your debugger attached to the running JBoss EAP Server instance.

navigator-window-redeploy

Deploy with custom NetBeans Actions

I have three custom actions, that let me deploy, undeploy and redeploy the built artefact to my locally running JBoss EAP Server instance. The actions can be reached through a right click on the maven JEE artefact project node. It opens up the projects context menu. Here select the Custom entry, that again opens a sub-menu with all your custom NetBeans actions refering to maven jboss-as plugin goals.

context-menu

Set-up the goals as actions in the projects properties screen. Select the Actions category.

actions

With the Add Custom… button I created three additional actions: Deploy, Undeploy and Redeploy. For each action  fill in the relevant maven goal: jboss-as:deploy, jboss-as:undeploy and jboss-as:redeploy. These show up later under the projects context menus Custom entry.

Make sure to uncheck the Compile On Save checkbox! Otherwise NetBeans own server deployment mechanism interferes with the maven plugin:

compile-on-save

Happy deploying!

Multi-Tenancy with Java EE and JBoss

Multi-tenancy is a frequent requirement in large business applications. Besides the requirement to separate different clients or environments, multi-tenancy may also be andvantageous in terms of distributing your data client wise across multiple databases. Currently frameworks such as hibernate or other API’s are not of much help.

A large business application for market risk evaluation that needed services and a Java EE compatible Front-End is exactly designed in this way: each tenant has its own database. What makes it even more complex: each tenant has not only one database to handle its entire data needs, but one for each product class. Huge amounts of data are produced every night and now need to be analysed, eventually corrected and calculations re-triggered.

I used an entity manager delegate that looks up the needed entity manager for the current tenant/product class combination via JNDI on each call. This is almost transparent to the clients of the delegate, except that, and that should be clear, somehow an identifier for the tenant/product class tuple needs to be supplied.
JBoss JNDI lookup of entity managers works flawless as of Wildfly 8.0 or JBoss EAP 6.1.1. In earlier versions issues existed and the lookup failed: https://issues.jboss.org/browse/WFLY-299.

Here is the code for the multi-tenant entity manager:

@Stateless
@LocalBean
public class MultiTenantEntityManager {

    private static final String JNDI_ENV = "java:app/entitymanager/";

    @Resource
    private SessionContext ctx;

    public MultiTenantEntityManager() {
    }

....

    public Query createQuery(String dataSourceName, String string) {
        return entityManager(dataSourceName).createQuery(string);
    }

    public <T> TypedQuery<T> createQuery(String dataSourceName, CriteriaQuery<T> cq) {
        return entityManager(dataSourceName).createQuery(cq);
    }

    public <T> TypedQuery<T> createQuery(String dataSourceName, String string, Class<T> type) {
        return entityManager(dataSourceName).createQuery(string, type);
    }

    public void detach(String dataSourceName, Object o) {
        entityManager(dataSourceName).detach(o);
    }

    public <T> T find(String dataSourceName, Class<T> type, Object o) {
        return entityManager(dataSourceName).find(type, o);
    }

    public <T> T find(String dataSourceName, Class<T> type, Object o, Map<String, Object> map) {
        return entityManager(dataSourceName).find(type, o, map);
    }

    public <T> T find(String dataSourceName, Class<T> type, Object o, LockModeType lmt) {
        return entityManager(dataSourceName).find(type, o, lmt);
    }

    public <T> T find(String dataSourceName, Class<T> type, Object o, LockModeType lmt, Map<String, Object> map) {
        return entityManager(dataSourceName).find(type, o, lmt, map);
    }

....

    private EntityManager entityManager(String dataSourceName) {

        final EntityManager entityManager = (EntityManager) ctx.lookup(JNDI_ENV + dataSourceName);

        if (entityManager == null) {
            throw new RuntimeException("Unknown data source name '" + dataSourceName + "'.");
        }

        return entityManager;

    }

}

I left out most of the overriden delegate methods in order to clearly outline the idea. Each method call to the delegate has an additional parameter: The name of the datasource. The name is a string that follows a simple schema: “tenant_productClass” and thus identifies the database we need to access. You are free to come up with your own naming scheme that suits your needs best.
I did tests with configurations that consisted of up to 700 datasource pools. JBoss EAP managed them without any difficulty (ok, at one point during testing the database servers gave up – but that was an easy fix ). The datasource’s name is also part of the JNDI lookup string for the real JPA entity manager. The delegate looks up first the entity manager in the JNDI tree and then calls the actual entity managers method with the supplied parameters.

Here is an example persistence.xml for a persistence unit (as there are many of them, I generate them by script):

  <persistence-unit name="tenant1_eq" transaction-type="JTA">
    <jta-data-source>java:/jboss/datasources/itpdb_pdbeq</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.SybaseASE15Dialect"/>
      <property name="hibernate.cache.use_second_level_cache" value="false"/>
      <property name="hibernate.jdbc.batch_size" value="50"/>
      <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
      <property name="hibernate.order_inserts" value="true"/>
      <property name="hibernate.order_updates" value="true"/>
      <property name="hibernate.generate_statistics" value="true"/>
      <property name="jboss.entity.manager.jndi.name" value="java:app/entitymanager/tenant1_eq"/>
      <property name="jboss.entity.manager.factory.jndi.name" value="java:app/entitymanagerfactory/tenant1_eq"/>
    </properties>
  </persistence-unit>

The multi-tenant entity manager is injected into each bean that would normally have an entity manager injected. For each call, the datasource’s name, to which the entity manager references, has to be known as it is also part of the entity manager’s JNDI name. Below is a snippet of a boundary, that uses the multi-tenant entity manager.

@Stateless
@Remote(AggregationConfig.class)
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class AggregationConfigBean implements AggregationConfig {

    private static final Logger LOG = LoggerFactory.getLogger(AggregationConfigBean.class.getSimpleName());

    @EJB
    MultiTenantEntityManager entityManager;

    /**
     * Default constructor.
     */
    public AggregationConfigBean() {
    }

    @Override
    public List<AggConfigMeta> findConfigMeta(String dataSourceName) {

        List<AggConfigMeta> res = Lists.newArrayList();

        Query q = entityManager.createNativeQuery(dataSourceName, "SELECT meta FROM ConfigMeta WHERE type='config'");
        List<String> result = q.getResultList();

        LOG.info("Found " + result.size() + " meta entries.");

        ObjectMapper mapper = new ObjectMapper();

        LOG.info("Instantiated ObjectMapper...");

        for (String meta : result) {
            try {
                res.add(mapper.readValue(meta, AggConfigMeta.class));
            } catch (IOException ex) {
                LOG.error("Failed reading AggConfig meta data.", ex);
            }
        }

        return res;

    }

.....

}

The usage is actually straight forward. This approach may also be used to handle database-sharding in a similiar way, see database-sharding.
It opens a window to a whole lot of new ideas on how to handle large amounts of data with Java EE.