SigmondsMart
eTorg on Bluemix

This article (only in English) describes experiences deploying eTorg on Bluemix Cloud Foundry. eTorg was originally developed to be deployed on local PC and also on a VPS (Virtual Private Server) on Linux (outside of Bluemix) to be accessed from Internet. It is configuration in there (CSS) that allows the application to be used and displayed properly on any device (PC, tablet, mobile) using any web browser. I will in this article discuss the process of enabling the app to be stored and served by Bluemix,and not so much the other technical issues. The ability to set up Hibernate to create tables and relations automatically when it does not exist in database is used. This is very convenient for a demo project, but is not recommendable for a real commercial project. The development platform is Eclipse Mars on local PC and not directly any editing in Bluemix. I used the IBM® Eclipse Tools for Bluemix plugin and WebSphere® Application Server Developer Tools for Eclipse. The .war file was then deployed to Bluemix.

Technology
  • Java 8
  • Spring 4.2.3 -> ... + Spring cloud service connector
  • Hibernate 4,3.11, c3P0 connection pool
  • MySQL 5.1.9 or PostGreSQL 9.4 -> ClearDB MySQL or SQL Database (IBM limited version DB2 10.5)
  • Maven
  • Web application deployed as .war file
  • Log4J
  • JSF: Java server faces (Oracle Mojarra 2.2.8 -> Apache MyFaces 2.2.9)
  • Tomcat 7/8 -> IBM WebSphere Liberty Profile
  • Servlet 2.5 -> 3.1 (Dynamic Web Module in Eclipse project facets)
  • Eclipse Mars with WTP and eGit -> ...+ Eclipse tools for Bluemix + IBM WAS dev tools.
  • Oxxus VPS -> Bluemix Cloud Foundry.
Bluemix buid packs
It is build packs for Tomcat on Bluemix, but I chose to switch web server to IBM WebSphere Liberty Profile. Since Tomcat 8 was not released yet on my original Java hosting vendor Oxxus, I have to revert to 2.5 Servlet version when deploying there (and web.xml is changed). This is the only problem with this that I detected. I have prioritized to use as much Java annotation configuration as possible. ApplicationContext.xml that included some DB-configuration in dbConfig.xml were replaced by SpringConfig.java. This I did initially before any porting to Bluemix. I started to look for possibilities to remove web.xml and faces-confi.xml (needed for JSF), but did not have time to do that. I think it is possible, at least if I can get rid of using Servlet 2.5 in any of my deployments.
Activities done to be able to deploy on Bluemix
    This cookbook is brief and simple, so a lot of details are omitted here
  1. I removed Spring XML configuration and replaced with Java annotation based configuration. This is not required for Bluemix, but makes conditional deployment much easier using Spring Profiles.
  2. I installed additional Eclipse plugins (Bluemix tools and WAS tools).
  3. I installed IBM WebSphere application server (WAS) liberty profile 8.5
  4. I Adapted the web demo app so it can run on local WAS liberty server: I added WAS liberty server (file, new, other server, select WAS liberty and point to installation) defined as server in Eclipse on localhost (in addition to Tomcat 7 and 8 that was already there).I do not remember I did much more than this to get it up and running inside Eclipse.
  5. It can be advisable to deploy a very simple project with a JSP page and no Java first on Bluemix. I did that initially.
  6. Some configuration and application changes were necessary to get the demo app up and running on Bluemix using one of the two database services. I describe what changes that were required in section on next page: "Changes required to get the web demo app running on Bluemix".
  7. I added Bluemix as a server (file, new, other server, Bluemix).
  8. Log into Bluemix dashboard on your account, eventually create account. I will not tell you how here.
  9. The web demo app, already added to the local WAS liberty server, was added to Bluemix as a server in Eclipse. This was the moment where the fun started, I could now start to publish to Bluemix. It is possible to deploy the entire WAS liberty server, I did not do that.You can select services to bind to web demo app. I have tried two different databases ClearDB MySQL database and SQL Database. After the push (deployment) is completed, the app will show up as one of your apps in Bluemix.
  10. You will now be able to inspect in Bluemix that the ClearDB MySQL Database or SQL Database were added as a service. If the database service was not already added when deploying, you can add it later. Do only bind one of them to demo app at the same time.
  11. Click on the route. The demo app will appear in the browserjust as it did locally in Eclipse.
Of cause I had to apply some changes and try many deployments to get the deployed code to work on Bluemix. I think I used between one week and two weeks something like that to adapt the application. This includes some changes in Java code and some configuration changes. In total I used some more time, but not all of these changes was directly related to Bluemix. Some were related to JSF implementation and others to improved configuration of the demo software. I used some time on improving Spring configuration, because I think this is very important in general for Java web applications.
Changes required to get the web demo app running on Bluemix
  1. Selecting the JSF implementation
    There are two implementations of the JSF implementation. Oracle Mojarra and Apache MyFaces. My demo application was originally based on Oracle Mojarra. By default the Apache MyFaces libraries is included in WAS liberty server. It is possible to get the app to work with Oracle Mojarra by including the right libraries when deploying, and being very careful with configuration when deploying to Bluemix. But I discovered that it was easier to change implementation to Apache MyFaces. Changes was done in the POM. Remember to set the scope correctly, either provided or compile. Since Apache MyFaces is included, the correct scope should be provided. But since I also test app on Tomcat where Oracle Mojarra were included I have set the scope to compile, although not required for WAS liberty server. A different listener had to be set up in the web.xml file for Apache MyFaces. At some point I got the idea of trying to remove both the web.xml and faces-config.xml (JSF configuration), but I did not have time to look at that.

  2. WAS liberty server configuration (server.xml)
    It is very important in Eclipse to check that this is correctly done, either directly in the server.xml file or in the feature manager in Eclipse. Enabled configuration locally on Eclipse was: jsf-2.2, jsp-2.3, localConnector-1.0 and servlet 3.1. This is the minimum that is required for app to run. Alternatively webProfile-7.0 could be used that includes a lot more features. If Oracle Mojarra is to be used, the jsf 2.2 feature must be removed, so the libraries included in the .war file is used instead.

    Note: add/change idLength in server.xml to 28: httpSession idLength="28", or else you will risk multiple warnings and problems when rendering HTML in WebSphere Liberty Profile locally on PC. You can google for reasons for this.

    If you are pushing a WAR or EAR to Bluemix, then a server.xml will be generated for you with the correct parameters for use with Cloud Foundry. Server.xml is stored in Files.wlp.servers.defaultServer on Bluemix, so you can inspect the contents. I did no additional configuration on Bluemix to get this to work.

  3. Verifying bean scopes for JSF / Spring
    Request scope is used for all beans in the demo application, except for that uses session scope. Send a request to the web server and retrieve a result from the database is the typical simple scenario for request scoped beans. No state is required in cache on server because state is stored in the database. OrderBacking (that refers to the Order entity) was different: Before logging into the shopping cart, nothing is stored in the database and session scope is used to keep shopping basket in memory. An order with status CART is a shopping cart, transient in memory. An order defined with other status values is persistent (in database). Currently the possible status values are: CART, DEFINED, PAID.

    According to Bluemix guidelines, storing state in session beans are not recommended. So I should really rewrite application to store temporary orders (shopping basket) in database and change scope to request scope. This rewrite was not done for the demo. The demo still works as it is with session scope used for order.

  4. Removing binding from session scoped bean
    This had to be done because of different implementation in Oracle Mojarra and Apache MyFaces. The existing web GUI simply crashed when replacing Oracle Mojarra with Apache MyFaces. Googling confirmed that the method I had used really was not recommended for JSF 2 and newer versions of JSF anyhow. Binding was used to recalculate the total price of selected products when changing the number of a product selected in a table (onChange event in JSF); by assessing the internals of the view in the MVC. I changed the code so that this recalculation was done later when pressing button (e.g. recalculate) and onChange event was removed. In a real application I guess a more advanced GUI component could be used to avoid pressing recalculate. This was the only problem I found with my code when changing to Apache MyFaces!

  5. Removing file based logging
    This is also recommended in Bluemix, because actually you do not know how long the log files is kept there. Best solution is probably to implement a log table in the database. But this weakness did not prevent my demo app to work, so I did not do this either.

  6. Profile based Spring configuration
    When deploying on Bluemix, the cloud profile is automatically selected. As stated earlier, I removed XML based configuration to be replaced by SpringConfig.java and annotation based configuration. This is perhaps the most important improvement I did in the demo application, to enable it to be deployed on different platforms for test and development by just selecting the appropriate profile.
    @Profile("mysql"): To be able to run using Mysql on private PC.
    @Profile("postgres"): To be able to run PostGreSQL locally on IBM PC.
    Could not use Mysql on job PC because of license issues.
    @Profile("default", uses MySQL, need not define active profile for this one. Also used when application is deployed on Oxxus VPS (Linux Virutal Private Server). This was the original “production” platform before porting to Cloud Foundry on Bluemix.
    @Profile("cloud"): Used on Bluemix.

    Conclusion: The Spring @Profile mechanism is very powerful and enables customizable configuration in Java. I chose to keep all configuration in on Java configuration file. @Profile is a server property and must be set there in some way. How this is done is different for different type of servers. Bluemix automatically uses the Cloud profile. When deployed locally on WAS liberty profile SPRINT.PROFILE.ACTIVE=postgres is set in the server.env file. You can also set WLP_SKIP_MAXPERMSIZE=true to avoid some warnings. When deployed locally on Tomcat this is set in command line arguments: -Dspring.profiles.active="postgres". For further detail, please study the enclosed SpringConfig.java file.

  7. Demo app picks up the cloud based config automatically
    Originally user name and password and database connection parameters for database was stored in a .properties file on server (jdbc.driver.class, jdbc.hibernate.dialect, jdbc.url, jdbc.username and jdpc.password). This is just not the way to do it on Bluemix, where the credentials, port, host, jdbcurl is generated when defining the service. You need to read those values by letting the Java configuration pick it up. The values are stored in individual environment variables, and the complete configuration is kept in VCAP_SERVICES. I tried different methods to get this information, e.g. by reading the environment variables directly. But not all of these variables had values assigned to them when SpringConfig.java was called. I used some time before I realized that JSON parsing from VCAP_SERVICES was the safe way to do this. This method is described in Bluemix documentation.

  8. Bluemix automatic reconfiguration or manual configuration
    The problem with Bluemix auto reconfiguration is that you have very little control of what actually is happening and how things are configured. I e.g. discovered that hibernate.hbm2ddl.auto was turned off. This is the feature that enables tables and relations to be automatically created in database if they did not exist. A very useful option for a demo, but not advisable for real production systems. In addition I have a customizable naming strategy between hibernate domain objects and database tables, originally because “user” was a reserved word in PostGreSQL and could not be a table name. I wanted to use C3P0 connection pooling to make this consistent on all deployment platforms. (I started to use C3P0 then I got into problems with default connection pooling settings locally for PostGreSQL on my PC). I use Hibernate LocalSessionFactoryBean. I discovered that if "DataSource" was included as a Spring bean, then reconfiguration would automatically happen and I got into trouble: My code in "Datasource" was not run. So I did not do that. Study the code!

  9. Selection of database service in Bluemix
    First I got the demo app working for ClearDB MySQL, because I am used to that database and how to interface with it using Hibernate. But the free version of this implementation is very limited, e.g. regarding the number of connections (study connection pooling parameters in the Java configuration file). By googling I found that SQL DB (IBM DB2) was a better choice, and also included a database tool for looking into the database itself using Bluemix. I used some time getting the DB2 driver as dependency into the POM (must be done manually). But I got this working quite quickly. Automatic creation of tables and relations worked at once using SQL DB. The configuration is written in such a way that it interprets VCAP_SERVICES and finds what database service that is included. Since the demo app can run without a database before you log in as a user, I made a specific Java configuration when no database service was added. This was a bit tricky and involved a dummy data source. (I tried some different methods that crashed initial Spring configuration). If I had not done this, a restart on Bluemix will halt due to expectingC3P0 connection pool initialization. This actually proves that the same piece of software on Bluemix with effort can be configured to work with variable bindingof services (at startup time). Any kind of advanced configuration based on interpretation of VCAP_SERVICES is of cause possible.
Deploying on Bluemix in Eclipse is smooth by just treating Bluemix as any server (start, stop, push, add and remove app). If a new application, you can add required services now or later. The deployment process on Bluemix is not very fast, but not that slow either (a minute for demo application typically). The ability to first test and debug the application locally on PC onWAS Liberty Profile (or using other server) is a big advantage. You should always deploy and test application locally on WAS Liberty Profile, before deploying to Bluemix.

Remote debugging on Bluemix from Eclipse is possible, but it was never needed for the demo project. It was good enough to study error messages that was logged in the Eclipse console. I did not use the Liberty for Java starter pack. The code needed to be stored locally on my PC using Eclipse and the Web IDE on Bluemix was not used. I used Git on PC and eGit in Eclipse.
Conclusion
Overall I am very satisfied and impressed with Bluemix. It took a couple of weeks to deploy a working version of the demo web software on Bluemix Cloud Foundry. Remark that I had never used Bluemix before this attempt. But I had been reading about the concepts and done a conceptual Bluemix online course not involving coding. The environment seems to be very stable, in fact even more stable that the VPS solution I got on Oxxus (I have sometimes to reboot the virtual server there, but rare).

Look at the configuration java file on GitHub