DeploymentScanner timeouts on OpenShift JBoss AS7

I haven’t seen this error often on the hosted OpenShift service (only occasionally when there’d been a system update and your app doesn’t redeploy correctly once restarted), but running OpenShift Origin locally I was seeing this consistently trying to deploy a new application:

2012/07/25 15:00:24,158 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) JBAS015052: Did not receive a response to the deployment operation within the allowed timeout period [60 seconds]. Check the server configuration file and the server logs to find more about the status of the deployment.
2012/07/25 15:00:24,160 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 2) JBAS015870: Deploy of deployment "ROOT.war" was rolled back with failure message Operation cancelled

To increase the deployment scanner’s timeout setting, edit your project’s .openshift/config/standalone.xml, and find the deployment-scanner element:

<subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1">
            <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" />
        </subsystem>

…and then add this attribute to <deployment-scanner> :

deployment-timeout="1200"

The XSD schema for this element says the default value is 600 second, but the error above says it’s timing out after 60 seconds. Assuming the default value is 600, I doubled it, and this fixed my timeout issues.

Adding a Mysql datasource to JBoss AS 7

I haven’t used JBoss since 4.x days. Seems adding a datasource is a few steps more complicated than it used to be. To summarize this post, the steps you need are:

  1. create a com/mysql/main dir under /jobss-as-7.1.final-install-dir/modules
  2. drop your mysql connector in this dir
  3. create a module.xml file in the same dir with the following content:
  4. <?xml version="1.0" encoding="UTF-8"?>
    <module xmlns="urn:jboss:module:1.0" name="com.mysql">
      <resources>
        <resource-root path="mysql-connector-java-5.1.18-bin.jar"/>
      </resources>
      <dependencies>
        <module name="javax.api"/>
      </dependencies>
    </module>
  5. modify your jboss-install-dir/standalone/configuration/standalone.xml file and define your datasource by adding a section like this to the subsystem datasources section:
    <datasource jndi-name="java:jboss/datasources/MysqlDS" pool-name="MysqlDS" enabled="true" use-java-context="true">
                        <connection-url>jdbc:mysql://localhost:3306/your_db_name</connection-url>
                        <driver>mysql</driver>
                        <security>
                            <user-name>your_userid</user-name>
                            <password>your_password</password>
                        </security>
                    </datasource>
                    <drivers>
                        <driver name="mysql" module="com.mysql">
                            <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
                        </driver>
                    </drivers>

Configuring a Spring web app using JPA2 to use a JBoss datasource on OpenShift

By default, when creating a web app with Spring Roo, your JPA configuration is set up to use a Commons DBCP BasicDataSource. This works great for testing locally on Tomcat, but doesn’t work when deployed to the OpenShift environment, you’ll get errors like this as Hibernate tries to get connections and set up your schema based on your Entity mappings :

2012/03/08 18:17:03,423 ERROR [org.hibernate.tool.hbm2ddl.SchemaExport]
(MSC service thread 1-3) HHH000231: Schema export unsuccessful:
java.lang.UnsupportedOperationException: The application must supply JDBC connections

At the current time there isn’t a great deal of documentation on the Open Shift site that explains how to config your app to use a datasource, but this post on the community forum has some good clues (this one is Flex specific, but it mentions the standalone.xml JBoss config file).

When you add a database cartridge to your app in OpenShift, your JBoss in your environment is also configured with a DataSource using connection properties set up to access your MySQL (or other) db, and it’s ready to go.

To get your Spring Roo app configured to use the datasource requires a bit more effort. There’s various posts online about how to configure JPA2 to use a DataSource provided by a container, but getting all the right parts changed or removed in your existing config is a bit tricky. This post here lists all the steps needed, and most of the text below is taken from this post (thanks to the poster of this entry on the Spring forum as before I got to this stage I had already spent a few hours trying to piece this together) – here we go:

Edit src/main/resources/META-INF/spring/applicationContext.xml:

  • remove the BasicDataSource bean (the DataSource is now specified in persistence.xml)
  • remove the JpaTransactionManager bean
  • add <tx:jta-transaction-manager /> to look up JBoss’ JtaTransactionManager from JNDI instead. The default name of the bean using this tag is ‘transactionManager’
  • If you had previously used the <tx:annotation-driven> tag, make sure it’s transaction-manger attribute now uses ‘transactionManager’ (from the previous step):
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

 

  • remove the LocalContainerEntityManagerFactoryBean
  • add this bean:
<jee:jndi-lookup id="entityManagerFactory"
        jndi-name="your/app/MyEntityManagerFactory"
        expected-type="javax.persistence.EntityManagerFactory" />

Your EntityManagerFactory gets exposed by JBoss from the following changes to your persistence.xml files:

Edit src/main/resources/META-INF/persistence.xml:

  • change the persistence-unit’s “transaction-type” attribute from RESOURCE_LOCAL to JTA
  • add a child element to “persistence-unit” as follows:
<jta-data-source>java:/MyDSName</jta-data-source>

Add the following property to expose your EntityManagerFactory:

<property name="jboss.entity.manager.factory.jndi.name"
        value="your/app/MyEntityManagerFactory"/>