Saturday, August 20, 2011

Deploy a Java EE application on OpenShift Express (with AS7 support)

During the past few years, I've been hearing about "cloud" services more and more. Initially I wasn't really curious to try them out. But a few months (a year?) back, I decided to see what it was all about. I have been involved with Java EE development for more than 7 years now, so I decided to see what it takes to deploy my Java EE application to the cloud. I set out looking for documentation and other usual blog articles and such. At that point, whichever cloud services I thought of trying out, would require me to provide my credit card details even to try out a trial application. I wasn't too keen to provide my credit card details just to try out a few applications of mine. So I kind of gave up on trying out my applications on cloud, although I kept reading about what other developers were doing to deploy their applications on cloud.

At about the same time, I came across this elaborate writeup on how one of the developers had setup his application involving Weld and JSF, on Google App Engine - Part1, Part2. The blog was well written and explained what was required to get your Java EE application up and running on a cloud service. But the important piece of information in those articles was that, users who had an application which was implemented as per Java EE standards (to be portable) had to change many of the application parts just to get them running on cloud. This was because many of the Java EE technologies weren't supported by the cloud service provider. This didn't look appealing to me. After all, what would I gain by doing that. So at that point, I as a Java EE developer, wasn't too interested in experimenting with deploying my application on cloud.

Enter OpenShift!

But this month, the OpenShift announcement about being able to deploy your JBoss AS7 Java EE applications to cloud, caught my eye. By the way, I do work for RedHat and am part of the JBoss AS7 team, but I wasn't keeping a watch on what the OpenShift team was upto, so this announcement came as a pleasant surprise! So I decided to give it a try. After reading some of the documentation on the project site, I found out that OpenShift offers two different services. One was "OpenShift Express" and the other "OpenShift Flex". OpenShift Express is free to use (that was one more good news for me) while OpenShift Flex requires your Amazon EC2 credentials and you'll be charged for the EC2 usage (there's however a free trial going on currently). I decided to give OpenShift Express a try since it was free and suits my current needs of just trying out a quick and simple Java EE application deployment and access to that application.

So here's what I did to be able to deploy my Java EE application which uses the technologies available in Java EE6 webprofile and which deploys fine on my local AS7 instance, to OpenShift Express. You might have already guessed that I'm no expert about OpenShift (or cloud services in general), so in this article doesn't have any advanced technical details, but contains more of a how-to on deploying Java EE applications to OpenShift Express.

So let's start then.

Sign up

The first step is to sign up here to create an account for yourself. The sign up just requires a valid email address to which your account details will be dispatched. On signing up, you'll receive a mail which contains a link to activate your account and will take you to the login screen. Login using the email id and password that you used to register.

Get Access to OpenShift Express

So let's got the OpenShift Express page. On that page you will notice a "Get Access to Express" button on left hand side. Click on it to get access to "Express". You'll be notified (immediately) through a mail to the email id which you registered. Check the mail which will contain a link to a quick start guide, to help you get started with OpenShift Express.

Install client tools

The quick start contains the instructions to get you started with the installation procedure. The first step includes installing a few client tools on your system to help you interact with OpenShift. Follow those instructions to install the client tools (I won't repeat them here, since it's well explained in that guide).

Create a domain

Now once we have the client tools, we are now ready to setup our "domain" on the OpenShift cloud. Setting up a domain will create a unique domain name that you can use for your applications. The domain name will be part of the URL which you will use to access the application and which you'll publish to your users for access. The command to create the domain is easy:
 rhc-create-domain -l <email-id-you-registered-with> -n <domain-name-of-your-choice>  
Running that command will ask you for the password that you used to register. Enter that password and let the command complete (a few seconds).

The "rhc-create-domain" is part of the client tool that you installed earlier. If you haven't yet installed those tools, then you won't be able to use these commands, so don't miss that step! The "rhc-create-domain" accepts a few more optional parameters. To see the list of accepted parameters, you can run the following command:
 rhc-create-domain --help  

Create a jbossas-7.0 application

Once you have successfully create a domain, your next step is to create an "application". Currently OpenShift Express supports different "types" of applications, each of them backed by Git (which is a version control system). At the point of writing this post, the supported application types are jbossas-7.0, perl-5.10, rack-1.1, wsgi-3.2 and php-5.3. I'm interested in deploying a Java EE application, so I'll be creating a "jbossas-7.0" application. This type of application provides you a JBoss AS 7.0.0 instance in the OpenShift cloud to which you can deploy your applications. So let's now create an application of type jbossas-7.0.

Note that the term "application" can be a bit confusing (atleast I found it a bit confusing) because all you are doing at this point is setting up JBoss AS7 server.

The command to create an application is rhc-create-app. The rhc-create-app accepts multiple options. For a complete list of options run:
 rhc-create-app --help  
To create a jbossas-7.0 application, we'll run the following command:
 rhc-create-app -a <application-name> -l <email-id-you-used-to-register> -t jbossas-7.0 -r <path-on-local-filesystem-for-the-repository>  
Running that command will ask you for the password that you used to register. Enter that password and let the command complete (a few seconds).

The -a option lets you specify the name for your application. This name will be part of the URL that you use to access your application. If your application name is "foo" and (the previously created) domain name is "bar", then the URL to access your application will be http://foo-bar.rhcloud.com/.

The -t option in that command, specifies the application type. In our case, we are interested in jbossas-7.0

The other option of importance is the -r option which you'll use to point to a folder on your local filesystem where OpenShift will store all the data related to your application. Part of that data will be a local copy of the git repo (version control system). We'll see this in more detail later on in this blog.

Access your server URL

So once you run the command and it successfully completes, it will print out the URL where the application is available. You can (immediately) use that URL to access the application. On accessing that URL you'll notice a welcome page, which is an indication that the application has been installed successfully and available for access. For me, the URL to the newly created application was http://jaikiran-jbossas.rhcloud.com/.

So at this point, we have created a domain and then an application and have made sure that it's accessible to the world. In short, your cloud server is up and running and you can now deploy your Java EE applications to that server.

Create and deploy a Java EE application

So let's now move to the step of creating and deploying a Java EE application. I didn't have any specific application in mind, but wanted to deploy an application which would involve accessing a database. Instead of creating a brand new application, I decide to use one of the quick start applications that come with JBoss AS7. The quick start applications for JBoss AS7 are available for download here. Once you have downloaded the quick start archive, unzip it to a location of your choice. Building the quick start examples will require Maven build tool be installed on your system. The details about the quick start applications and how to build them can be found here. Those interested in trying it out themselves, might want to look at that guide.

I chose the "kitchensink" application from those quick starts. The kitchensink application uses Java Persistence API (JPA) for persistence and by default uses the java:jboss/datasources/ExampleDS which is shipped by default by JBoss AS7. The ExampleDS uses H2 as its database.This is how the persistence.xml looks like:
 <?xml version="1.0" encoding="UTF-8"?>  
 <persistence version="2.0"  
   xmlns="http://java.sun.com/xml/ns/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">  
   <persistence-unit name="primary">  
    <!-- If you are running in a production environment, add a managed   
      data source, the example data source is just for proofs of concept! -->  
    <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>  
    <properties>  
      <!-- Properties for Hibernate -->  
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />  
      <property name="hibernate.show_sql" value="false" />  
    </properties>  
   </persistence-unit>  
 </persistence>  
That's enough for me now, to show how to deploy the application and also show the DB support available in OpenShift Express.

After building the application, the deployable war is named jboss-as-kitchensink.war and is available on my local file system. My next step would be to deploy it my JBoss AS7 server which we have setup on the OpenShift Express cloud. Let's see how that's done.

Deploy the application to OpenShift Express

Remember, while creating the "application" using the rhc-create-app command, we used the -r option to point to a folder on our local file system to create a local copy of the application repository. That's the place which will be used now for deploying our applications. In my case, I used /home/jpai/OpenShift/myapps/demo as the repo location. This is how that folder looks like:
 demo  
 |  
 |--- deployments  
 |  
 |--- pom.xml  
 |  
 |--- README  
 |  
 |--- src  
There's more than one way to deploy your application to OpenShift Express. One way is to write your code and commit the source code within the src folder of your local repository and then push your changes to the remote git repository. This will then trigger a Maven build for your project on the remote repository. More details about this approach is available in this blog.

In our case, we'll focus on how to deploy an already built Java EE application to your OpenShift Express cloud server. In the previous step, we built the jboss-as-kitchensink.war. Now, copy that war file to the "deployments" subfolder of your local git repository. In this case, it's /home/jpai/OpenShift/myapps/demo/deployments:
 cp /home/jpai/jboss-as-quickstarts-7.0.0.Final/kitchensink/target/jboss-as-kitchensink.war /home/jpai/OpenShift/myapps/demo/deployments  
Once you have copied it here, your next step is to "commit" this change using the git commit command:
 jpai@jpai-laptop:demo$ git add deployments/jboss-as-kitchensink.war  
 jpai@jpai-laptop:demo$ git commit -m "Deploy kitchensink application" deployments/jboss-as-kitchensink.war  
 [master 1637c21] Deploy kitchensink application  
  1 files changed, 0 insertions(+), 0 deletions(-)  
  create mode 100644 deployments/jboss-as-kitchensink.war  
So at this point your kitchensink application has been commited to your local git repo. Next we should "push" this commit to the remote git repo:
 jpai@jpai-laptop:openshift$ git push origin master  
 Counting objects: 6, done.  
 Delta compression using up to 2 threads.  
 Compressing objects: 100% (4/4), done.  
 Writing objects: 100% (4/4), 393.71 KiB, done.  
 Total 4 (delta 1), reused 0 (delta 0)  
 remote: Stopping application...  
 remote: done  
 remote: Found .openshift/config/standalone.xml... copying to ...  
 ....  
 ....  
 ....  
 remote: Starting application...done  
 To ssh://6a7ff43a6c2246999de28219a5aaa4ae@jaikiran-jbossas.rhcloud.com/~/git/jaikiran.git/  
   6e57976..1637c21 master -> master  
(trimmed some logs from the above output).

So with this "push" we have now deployed our application to the remote OpenShift Express JBoss AS7 server. The jboss-as-kitchensink.war will be deployed at the "jboss-as-kitchensink" web application context. So the URL to access the application will be http://jaikiran-jbossas.rhcloud.com/jboss-as-kitchensink. Go ahead and access that URL. The application does nothing fancy - it allows you to add a user name, email and phone number which will then be stored in the database.


Like I mentioned earlier, the kitchensink application uses ExampleDS datasource which is backed by H2 database. So all the data will be stored remotely in the H2 database.

Using the MySQL database available in OpenShift Express

OpenShift Express sets up a MySQL datasource template for you when you create a jbossas-7.0 application type. The details of the database can be found in the <path-to-local-repo>/.openshift/config/standalone.xml:
 <subsystem xmlns="urn:jboss:domain:datasources:1.0">  
      <datasources>  
           <datasource jndi-name="java:jboss/datasources/ExampleDS" enabled="true" use-java-context="true" pool-name="H2DS">  
                <connection-url>jdbc:h2:${jboss.server.data.dir}/test;DB_CLOSE_DELAY=-1</connection-url>  
                <driver>h2</driver>  
                <pool></pool>  
                <security>  
                     <user-name>sa</user-name>  
                     <password>sa</password>  
                </security>  
                <validation></validation>  
                <timeout></timeout>  
                <statement></statement>  
           </datasource>  
           <datasource jndi-name="java:jboss/datasources/MysqlDS" enabled="false" use-java-context="true" pool-name="MysqlDS">  
                <connection-url>jdbc:mysql://127.1.1.1:3306/mysql</connection-url>  
                <driver>mysql</driver>  
                <security>  
                 <user-name>admin</user-name>  
                 <password>changeme</password>  
                </security>  
           </datasource>  
           <drivers>  
                <driver name="h2" module="com.h2database.h2">  
                     <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>  
                </driver>  
                <driver name="mysql" module="com.mysql.jdbc">  
                     <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>  
                </driver>  
           </drivers>  
      </datasources>  
 </subsystem>  
You'll notice that apart from the ExampleDS that comes by default in AS7, OpenShift Express has setup a MySQL datasource which will be available at java:jboss/datasources/MysqlDS. The important piece to note here is that it is disabled (i.e. enabled=false) by default. Also notice that the password is "changeme". Basically, this datasource configuration for MysqlDS in the standalone.xml is there as a template. In order to enable that datasource, we first have to create a MySQL database for our application. That can be done by using the following command:
 jpai@jpai-laptop:openshift$ rhc-ctl-app -a <application-name> -l <email-id-we-used-to-register> -e add-mysql-5.1   
The rhc-ctl-app is passed the application name (which is the one that we used during rhc-create-app) and also our account id. Additionally, we use the -e option to specify what we want to do. In this case, we issue a "add-mysql-5.1" command. Running that command will ask you for your account password and on successful completion will show the output similar to:
 RESULT:  
 Mysql 5.1 database added. Please make note of these credentials:  
 Root User: admin  
 Root Password: as43n34023n  
 Connection URL: mysql://127.1.1.1:3306/  
Note down the user name, password and the connection url. Now open the <repo-home>/.openshift/config/standalone.xml in a text editor and update the MysqlDS configuration to use the connection URL, the user name and the new password. Also set the enabled flag to "true" so that the datasource is enabled. Ultimately the datasource configuration will look like:
 <datasource jndi-name="java:jboss/datasources/MysqlDS" enabled="true" use-java-context="true" pool-name="MysqlDS">  
      <connection-url>jdbc:mysql://127.1.1.1:3306/mysql</connection-url>  
      <driver>mysql</driver>  
      <security>  
       <user-name>admin</user-name>  
       <password>as43n34023n</password>  
      </security>  
 </datasource>  
Pay attention to the connection-url. It has to be of the format jdbc:mysql://<ip:port>/dbname. Typically, you don't have to touch that connection-url at all, since the rhc-ctl-app add-mysql-5.1 and the datasource template are in sync with the IP/port. The important pieces to change are the password and the enabled flag.

Once this file is updated, save the changes and commit it to your local git repo:
 jpai@jpai-laptop:demo$ git commit -m "Enable the MysqlDS and fix the password" ./  
 [master dd7b58a] Fix the datasource password  
 1 files changed, 1 insertions(+), 1 deletions(-)  
 Push these changes to remote repo:  
 jpai@jpai-laptop:openshift$ git push origin master  
 Counting objects: 9, done.  
 Delta compression using up to 2 threads.  
 Compressing objects: 100% (4/4), done.  
 Writing objects: 100% (5/5), 494 bytes, done.  
 Total 5 (delta 2), reused 0 (delta 0)  
 remote: Stopping application...  
 remote: done  
 ....  
 .....  
 remote: Starting application...done  
 To ssh://6a7ff43a6c2246999de28219a5aaa4ae@jaikiran-jbossas.rhcloud.com/~/git/jaikiran.git/  
 2d38fa8..dd7b58a master -&gt; master  
So we now have added MySQL DB and enabled the MysqlDS datasource which is available at java:jboss/datasources/MysqlDS jndi name on the server. So if the kitchensink application has to use MySQL as its database, instead of H2, then all it has to do is use the java:jboss/datasources/MysqlDS. Let's now edit the persistence.xml file that we saw earlier and use the MysqlDS instead:
 <?xml version="1.0" encoding="UTF-8"?>  
 <persistence version="2.0"  
   xmlns="http://java.sun.com/xml/ns/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">  
   <persistence-unit name="primary">  
    <!-- Changed to use MysqlDS -->  
    <jta-data-source>java:jboss/datasources/MysqlDS</jta-data-source>  
    <properties>  
      <!-- Properties for Hibernate -->  
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />  
      <property name="hibernate.show_sql" value="false" />  
    </properties>  
   </persistence-unit>  
 </persistence>   
Additionally, just to "show" that this new application has been updated to use MySQL database, I also edited the index.xhtml page of the kitchensink application, to add a message on that page about MySQL database being used:
 <h3>  
       <span style="color: red;">  
            This application uses MySQL database as its persistence store  
        </span>  
 </h3>  
Next, I'll build the kitchensink application locally using Maven, to reflect these changes and generate the new jboss-as-kitchensink.war. Once built, let's now again copy it to our local git repo and then commit the change and push it to the remote git repo:
 jpai@jpai-laptop:kitchensink$ cp target/jboss-as-kitchensink.war /home/jpai/OpenShift/myapps/demo/deployments  

 jpai@jpai-laptop:demo$ git commit -m "Use MySQL database for kitchensink application" ./  
 [master ded2445] Use MySQL database for kitchensink application  
 1 files changed, 0 insertions(+), 0 deletions(-)  

 jpai@jpai-laptop:openshift$ git push origin master  
 Counting objects: 7, done.  
 Delta compression using up to 2 threads.  
 Compressing objects: 100% (4/4), done.  
 Writing objects: 100% (4/4), 1.35 KiB, done.  
 Total 4 (delta 2), reused 0 (delta 0)  
 remote: Stopping application...  
 remote: done  
 remote: Found .openshift/config/standalone.xml... copying to...  
 ...  
 ...  
 ...  
 remote: Starting application...done  
 To ssh://6a7ff43a6c2246999de28219a5aaa4ae@jaikiran-jbossas.rhcloud.com/~/git/jaikiran.git/  
 1637c21..ded2445 master -&gt; master  
 jpai@jpai-laptop:demo$   
(trimmed some logs from the output)

So at this point we have now changed our kitchensink application to use MySQL database and have deployed it to our OpenShift Express AS7 server. So let's access the application URL again http://jaikiran-jbossas.rhcloud.com/jboss-as-kitchensink. As you see, that page now prominently displays our message about MySQL DB being used. Go ahead and try out that app by adding some dummy user information.


That's it! We have successfully deployed our application to OpenShift Express server and the application is available for use.

Summary

It's been a pleasant experience so far with OpenShift. I plan to try out a few more things with OpenShift, in the coming days and blog about any interesting details.

Useful resources

While working on deploying this application, I had to use some documents and help from the OpenShift community to understand how this is all setup,. Here's a list of useful resources related to OpenShift in general:

OpenShift Express User guide
OpenShift forums
OpenShift IRC #openshift on irc.freenode.net. The folks here are very helpful!
Scott Stark's blog. Scott's blogs contain a lot of useful information about AS7 on OpenShift and OpenShift in general. Scott's blog is definitely a must read!

Where to look for help

OpenShift questions in general are answered in the OpenShift forums. For questions around AS7 on OpenShift, the best place to ask questions is the JBoss Cloud Group.


10 comments:

Erik said...

Great post, very helpful!

However, I cannot figure out which standalone.xml to edit on openshift... there are a few of them! Posted about this on the flex forum:

https://www.redhat.com/openshift/forums/flex/which-standalonexml-to-modify-for-changing-as7-database

Anil said...

really a great post


i am new to openshift and to command line as well. but this post helped me in understanding many things. i thank you very much for this one.

Turbo said...

Do you know in how far the solution is tailored towards JBoss?

Say I use a Standard java EAR file, made in Netbeans (and verified to work on glassfish, without glassfish extentions). Would that work?

Jaikiran said...

If you don't have any GlassFish specific configurations/resources and your application is based on Java EE APIs, then you should be able to deploy it fine on Openshift.

Yoursever said...

5* for this brilliant post.

I'm also using Openshift for hosting my application.

Actually I'm facing some problem while deploying it.

PROJECT: Dynamic Web Project(Using jsps,servlets and javascript) SERVER: sofar using Tomcat 6.0.35

Now when I deploying application in great PaaS like OpenShift,...what you have told @SS2000(just following step by step)

Then at the time of Deployment,though I'm getting this error:

remote: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project simsys: Compilation failure: Co mpilation failure: remote: [ERROR] /var/lib/stickshift/04c05124d4f14b28870a39a84b70721c/app-root/ru ntime/repo/src/main/java/com/simsystech/Export.java:[3,23] error: package org.ap ache.log4j does not exist remote: [ERROR] /var/lib/stickshift/04c05124d4f14b28870a39a84b70721c/app-root/ru ntime/repo/src/main/java/com/simsystech/Export.java:[25,9] error: cannot find sy mbol remote: [ERROR] class Export remote: [ERROR] /var/lib/stickshift/04c05124d4f14b28870a39a84b70721c/app-root/ru ntime/repo/src/main/java/com/simsystech/Groupdelete.java:[3,23] error: package o rg.apache.log4j does not exist remote: [ERROR] /var/lib/stickshift/04c05124d4f14b28870a39a84b70721c/app-root/ru ntime/repo/src/main/java/com/simsystech/Groupdelete.java:[20,9] error: cannot fi nd symbol remote: [ERROR] class Groupdelete remote: [ERROR] /var/lib/stickshift/04c05124d4f14b28870a39a84b70721c/app-root/ru ntime/repo/src/main/java/com/simsystech/Import.java:[12,30] error: package au.co m.bytecode.opencsv does not exist

In spite of these error but first couple of times it's showing pages of my application,but right now it's showing nothing :( :(

even when I click on your link http://jaikiran-jbossas.rhcloud.com/jboss-as-kitchensink(showing the blank page just like my application after being deployed)

but still when I'm trying to run my application(let say a page of my application ): "http://security-simsyssecurex.rhcloud.com/simsystech/jsp/login.jsp" as a result -> in fire it's showing just a blank page,in internet explorer it's showing Internet Explorer cannot display the webpage.

Any kind of inputs will be appreciated.
With Regards
Tirtha

Phong Nguyen said...

I followed your instructions, but it didn't work. Here's my kitchen-sink-quickstart-ds.xml for my Java EE app:





jdbc:h2:mem:kitchensink-quickstart;DB_CLOSE_DELAY=-1
h2

sa
sa



mysql://$OPENSHIFT_MYSQL_DB_HOST:$OPENSHIFT_MYSQL_DB_PORT/
mysql

adminIRDtwlS
n1n9x7nY3KEc




And here is my persistence.xml:






java:jboss/datasources/MysqlDS







Unknown said...

Where is the persistence.xml stored? Is it similar to standalone.xml so I have to get a copy from .openshift/config and then commit?

Jaikiran said...

>> Where is the persistence.xml stored?

Tom, In my example here, I used the approach of publishing the pre-built binary application to OpenShift. So the persistence.xml is already part of the .war binary. The EE spec mandates the persistence.xml to be at a specific location within the .war (.war/WEB-INF/classes/META-INF folder).

Anonymous said...

>> tom thaler said...
>> Where is the persistence.xml stored?

Inside the WAR.
Which we cannot alter (as it's a signed archive)
And should not contain container specific code...
Such as:

java:jboss/datasources/ExampleDS






This snippet of config ties your code both to JBoss and to Hibernate.... Kinda makes you wonder what the whole point of EE and JPA was again????

Can anyone, please, show a complete working example using code/config inside the WAR that is actually *portable*? I don't want to make 15 different WARs to be able to support 5 EE server types and 3 persistence providers.... :(

Jaikiran said...

@stijndewitt You can use a portable JNDI name to point to the datasource. Take a look at one such example here https://github.com/javaee-samples/javaee7-samples/blob/master/jpa/datasourcedefinition-webxml-pu/src/main/resources/META-INF/persistence.xml#L7.

There are more such examples in that github repo:

https://github.com/javaee-samples/javaee7-samples/tree/master/jpa (JPA specific)