Contents


Move your Java application into a hybrid cloud using Bluemix, Part 3

Migrate a stand-alone Java program to Bluemix

Comments

This tutorial was written using a previous version of the IBM Bluemix® interface. Given the rapid evolution of technology, some steps and illustrations may have changed.

In Part 1 and Part 2 of this series, we covered the typical Java EE use case of migrating a web application to Bluemix™. Now we ask, what if you have a stand-alone Java application? How do you make a Java program with a main() method run in Bluemix?

This is a common scenario. There are lots of reasons why you'd want to do this. Your application might be a batch program that runs on a schedule and does some intense data processing for a short time before either ending or sleeping. It might be a program that listens on a protocol such as AMQP for commands. Or it might be using an embedded HTTP server such as Netty instead of a framework like Spring or JEE.

As we worked through the process of getting this scenario to work, we learned some interesting things about the architecture of Cloud Foundry and Bluemix and how applications are managed in them. It turns out there is an easy one-line answer to the previous question that we cover at the end of this article. However, you won't understand why that one-line answer is true or how to figure out things like this on your own unless you follow us first down a few different side paths.

What you'll need to build your application

This third in a series of tutorials examines how to run stand-alone Java programs in Bluemix. We share some hints on navigating the Cloud Foundry documentation, using the CF command-line tool, and debugging in Cloud Foundry and Bluemix.

The pros and cons of a PaaS

Bluemix is an example of what is called a Platform as a Service (PaaS). Using your platform as a service makes life easier for developers by providing simple tools and runtimes that facilitate the most common tasks developers must perform. However, notice the phrase "most common." Most PaaS layers share the same philosophy: they assume that you are going down a specific, well-marked path in your development. If you deviate from that path, they'll provide you with some guidance, but don't expect those trails to be marked as well as the more well-trodden paths.

That was the problem we faced with our sample application. If you look into many examples of Bluemix applications, you'll see that by far the most common path that is followed in building Java applications are for applications that use the Liberty Application Server. But our case was simpler. We didn't need an application server. We just had a program that had a main() method. To find out how to start, we had to take our first step.

Step 1. Create a Java JAR file

To understand how things work, what can go wrong, and how to debug, we'll start with a simplified version of the Java application we're running. We'll use Eclipse to develop our code, but we will not use the Eclipse plugin for Bluemix for deploying this example. Instead, we use the Cloud Foundry command-line interface, and debug by using the logs.

This example uses two Java JAR files: hellojavamain.jar and hellojavamainrunnable.jar. You can obtain these two files by clicking the "Get the code" link above. Otherwise, if you'd like to build your own (and maybe learn a little more), follow these steps.

  1. Create a new Java Project in Eclipse (File > New > Java Project). Call the example "HelloJava." In the Create a Java Project window, make sure that you set the Execution Environment to JavaSE-1.6 and click Finish.
  2. Create a new Java class (New > Class) called HelloJavaMain. (It's okay for this example to create it in the default package.)
  3. Replace the source code of your class with the following Java source:
    public class HelloJavaMain {
    public static void main(String[] args) {
    	for (int i=0; i<1000; i++) {
    	System.out.println("It worked! Hello World!");
    	try {
    		Thread.sleep(1000);
    	 } catch (InterruptedException e) {
    	// This should not happen
    		e.printStackTrace();
    	}
    	}
    }
    }

    This is meant to be a simple example of a long-running Java process. It will eventually end after 1000 seconds, which is long enough for our example. This code is nothing more than a simplified stand-in for a more complex example that might do something interesting such as process some data, or even listen for connections on some asynchronous protocol.
  4. Test the code by selecting the class and then using the Run As > Java Application menu selection.
  5. You should see lots of output like the following in the Eclipse console:
    It worked! Hello World!
  6. Use the Eclipse Export function to export this project as a JAR file: File > Export.
  7. Select Java > JAR File in the export window, then select your project. Name that JAR file hellojavamain.jar and click Finish.

Step 2. Deploy the application to Bluemix: Attempt #1

Now we get to the interesting part of this simple but naive approach. You would think things would work the way dozens of other examples that use Bluemix and Cloud Foundry work, just using cf push with a few extra parameters.
cf push hellojavamain-ABC -p hellojavamain.jar.

In this case, the first parameter to push is the name of the application to create or update. The –p parameter specifies the location of the code that you want to run (that is, your JAR file).

  1. Log in to Cloud Foundry Tools and enter a command like:
    cf push hellojavamain-<your_initials> -p hellojavamain.jar
    For example,
    cf push hellojavamain-ABC -p hellojavamain.jar
    (Note: Append your initials or any three random letters to avoid having the application fail for not having a unique name.)
  2. If you have written your code correctly, things should look promising. It should start out by identifying your JAR file as Java code, and will select the Java Liberty buildpack. It will then upload the droplet (which is the packaged container with your code plus Java Liberty) and attempt to run it. However, what you will see in the output of the cf push command is a repeating series of the following message:
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 starting

    Eventually, this long series ends with the following crash message:
    FAILED
  3. To find out what failed, enter the following command:
    cf logs hellojavamain-ABC -–recent
  4. When you start going through the logs, you'll find an interesting line deep inside that looks something like:
    2015-08-09T17:09:15.31-0400 [App/0] ERR [ERROR ] CWWKZ0124E: Application myapp does not contain any modules.
    What this line is telling us is that the application expected the JAR file to be one containing JEE modules, and not a Java SE JAR file that contains a main() method. This is our first lesson: the simplest and most naïve deployment mechanism won't work.

Step 3. Deploy the application to Bluemix: Attempt #2

At this point, you might think (as we did), that the problem is that Bluemix is by default selecting the Java Liberty buildpack, when we don't need the Liberty application server at all. If you read Part 1 in this series, you will know that in Bluemix, there is another option for Java development: the standard Java buildpack. You can select a different buildpack than the one that is auto-selected by using the –b command-line option for push.

  1. Log in to Cloud Foundry Tools, and type
    cf push hellojavamain-ABC -p hellojavamain.jar -b java_buildpack
    where ABC is replaced by your initials or any three random letters.
  2. You now see that a new problem has emerged. The command attempts to perform the push, but ends with an error:
    FAILED
    Server error, status code: 400, error code: 170004, message: App staging failed in the buildpack compile phase
  3. Why did it fail? If you again enter
    cf logs hellojavamain-ABC --recent
    you will see the following line, buried deep in the logs:
    2015-08-09T17:25:19.52-0400 [STG] ERR No container can run this application
  4. Again, you might think: What could this mean? I'm not using the IBM Bluemix Container Service at all. Well, this error message actually uses the term "container" a little ambiguously. The message does not refer to Docker containers or the IBM Container Service. The documentation states: "Container components represent the way that an application will be run. Container types range from traditional application servers and servlet containers to simple Java main() method execution."
  5. That is exactly what's happening with this example. The failure is due to the "container component" not understanding how it's supposed to run the application. In fact, digging a little deeper into the documentation reveals the following information: "Java applications with a main() method can be run provided that they are packaged as self-executable JARs."

Step 4. Create a runnable JAR file and deploy the application to Bluemix: Attempt #3

That last line is exactly the clue we needed. In Java programming, you make a JAR file executable by stating in the manifest.mf file which class contains the main() method. You do this in Eclipse by exporting the JAR file not as a regular JAR file but what Eclipse calls a "runnable" JAR file.

  1. Go back into Eclipse, and select File > Export. In the Export window that opens, make sure that you export not as a standard JAR file, but as a Runnable JAR file.
  2. In the window that follows, select the HelloJavaMain class in the drop-down menu under "Launch Configuration". This creates the correct entry in the manifest file in your JAR file when it exports the file. Screenshot showing runnable jar spec
    Screenshot showing runnable jar spec
  3. Does this fix the problem? Before finding out, we should note that if you're not using Eclipse and are just following along with the command line, we've already given you a copy of the modified file: hellojavamainrunnable.jar. Now that you've re-exported the JAR file as a runnable JAR file, you can try again with:
    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b java_buildpack
  4. At first, this process looks promising. The buildpack compiles, the application deploys, and this time it finds the code. However, looking at the output, you see the following information:
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 down
    0 of 1 instances running, 1 down
    Examining the logs again (using the same command as above), you see that the application is actually running and printing output, but not for long. It turns out that you're still missing one crucial piece of information. Note this line in the logs:
    2015-09-07T10:33:35.10-0400 [DEA] ERR Instance (index 0) failed to start accepting connections
  5. In a Java application that does not listen on HTTP (such as our simple example), you must add the -no-route parameter to the push command. Otherwise, Cloud Foundry thinks that you want to route HTTP traffic to your program. Without that parameter, at first the class is loaded into Java code and starts and runs correctly. Eventually, however, the DEA throws a timeout error.

That is why even though the application really has already started on the first try, because it's not listening on the listener port, Cloud Foundry thinks it's down.

Step 5. Specify a worker process

Let's bring it all together with the final command that lets us deploy our Java worker process:
cf push hellojavamain-ABC -p hellojavamainrunnable.jar -no-route

At this point, you might ask, what happened to the –b option specifying the Java buildpack? Well, we wanted to introduce you to the Java buildpack so you would see the documentation on the Cloud Foundry website and understand why the runnable JAR file and the -no-route option were needed. Actually, while you can specify the Java buildpack, you could have done all of this on the default Liberty buildpack, which is built on top of the Java buildpack. You can use either buildpack and switch between them by explicitly using the -b parameter:

  1. Enter:
    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b java_buildpack -no-route
    or
    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b liberty-for-java -no-route
  2. After either of these commands, the console should show a requested status of started, with no associated URL, and a state of running. Screenshot showing program status in console
    Screenshot showing program status in console
  3. And in the logs, you should see a series of success messages, with no errors: Screenshot showing more program status in console
    Screenshot showing more program status in console
  4. Just as in the previous tutorials, you want to clean up the application when you are done. First, stop the application:
    cf stop hellojavamain-ABC
  5. Then, delete it:
    cf delete hellojavamain-ABC and answer Y.

Conclusion

We had to take a few turns along our path, but in the end we found our way to where we wanted to be, and learned a lot about debugging Java applications in Bluemix. At this point, you've seen the start of the process for migrating your standard stand-alone Java applications into Bluemix. You can now take the same approaches that we've covered in earlier articles of this series to bind your application to services and take advantage of the different services that are provided by Bluemix. In a future tutorial, we'll be looking at connecting a Java application to an on-premises database.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Cloud computing, Java development
ArticleID=1018035
ArticleTitle=Move your Java application into a hybrid cloud using Bluemix, Part 3
publish-date=10262015