Sunday, June 10, 2012

JRebel for Remote debugging from Eclipse

As I have posted before there are ways to do agile Java Web development through hot code replacement so you do not have to say "Java sucks because you need to recompile to see your changes, that is why I code in you-name-it language". However if you are serious about agility in Java as I said you must consider JRebel. The JVM Hot Swap misses a lot of features provided by JRebel. Sure JRebel is not free but for a buck a day you can get a floating license for 10 team members, or for a buck per three days get your personal license, or if you do not have a company and are trying to get in business with zero capital there is also an option for you: Just open source your project and get JRebel for free, then provide consulting services, make money and pay for JRebel: It is worth it.

I personally do not like servers running in IDEs. I prefer my local environment to be as close as possible to the production environment, so I run SSL, Apache with mod-jk , different IPs for different website projects etc. I also debug all of them and in some cases at the same time without an IDE crashing or giving me extra trouble. Clearly the second advantage of this method is that when you are in needs to debug your real deployment environment you follow the same procedure: Just prepare your server to listen to a debug port and connect to it from Eclipse.

Here are the steps I followed to get JRebel replace the included HotSwap JVM capability to allow remote hot code replacement. This was tested with JRebel 4.6.2 + Eclipse Helios + Tomcat 7.0.22 + Maven 1.6.0-31.
  1. Hit Eclipse "Help-Eclipse Marketplace" menu option. Look for JRebel and install it
  2. From Eclipse Preferences choose JRebel and launch the configuration wizard (In version 5 "JRebel Config Centre" link will open all you need within Eclipse interface while previous versions would open a separate java app for configurations). Click on the link so you register and get your license key. Get back and paste it.
  3. You are presented with some options like running your tomcat locally in Eclipse. I use an external tomcat instance so I unchecked that option, then I ignored the instructions to create a new startup and catalina shell scripts. I want to use the original server scripts.
  4. Look at the "Embedded JRebel plug-in" link to find out where jrebel.jar is in your system
  5. Add jrebel.jar and necessary options to
    JAVA_OPTS="-javaagent:/Users/nestor/eclipse-helios/plugins/org.zeroturnaround.eclipse.embedder_4.6.2.201205021255/jrebel/jrebel.jar -Drebel.remoting_plugin=true -Drebel.hotswap=false $JAVA_OPTS" 
  6. From Eclipse Preferences - Java - Debug uncheck all "Hot Code Replace" options
  7. Right click on Project and select properties, locate "Maven-Lifecycle Mapping" and insert "clean" as the first goal to "Goals to invoke after project clean"
  8. Make sure Eclipse will build your project automatically: Check "Project-Build Automatically" menu option
  9. Right click the project and choose "JRebel - Generate rebel.xml" It will generate the file inside the main resources folder
  10. If your server JVM is running in a different machine than your Eclipse IDE then right click the project and choose "JRebel - Generate rebel-remote.xml" It will prompt for the url you use to reach your project. Like above the file gets generated by default in main resources which means they both will end up in the classpath. Review the files for correct URLs and id. I use as id the name of the project. If you change id please look into my previous post.
  11. Recompile and redeploy your project so the xml file(s) get to the server
  12. Exclude rebel.xml (and rebel-remote.xml if it applies) from your versioning control. You do not want to mess with other developers settings unless you all use the same IDE, OS etc.
  13. If your server JVM is running in a different machine than your Eclipse IDE then right click the project and chose "JRebel - JRebel Remoting: Automatic Sync". You should get a "Jrebel-Remoting uploaded changes successfully, have fun!" message
  14. Connect to the remote debug port from Eclipse (From Java Perspective, Menu | Run | Debug Configurations | Remote Java Application | Right click and select New | give it a name like "Local" | set Host like localhost | Port like 8000 | click Debug. From that moment on the option will be available when clicking the bug icon arrow), set your break point and hit the page associated to it. You will be able to debug just as you are used to
  15. Now overload the method holding the breakpoint or create a new one that gets called as well, that way you can see that adding a new method does work. Both the the old and the new methods will be accepted by the server and available locally for debugging. No more redeployments.
If you (like I do) use external maven to build then you will need to make sure you either refresh the Eclipse project to get latest from target folder or you will have to use clean option *only* from Eclipse.

Notice that you need to install the rebel xml files in every project you want to hot deploy. For instance if you divide your project in a WAR and a JAR then both will need to be configured to use jrebel properly.

Finally it is always better to make your changes when a breakpoint has already being reached by the debugger, in that way the change will trigger the reload and you can even say so from the changes in the Eclipse code line debugger pointer. However this option might be broken in version 4 as reflected in this "apparent" bug. Apparently it has been fixed in version 5 as i documented there.

Buying JRebel

A license key will be sent to you and from Eclipse Preferences, JRebel, open the link to configure. In the latest JRebel 5 licences are activated from the "JRebel Config Centre" which is the only link. In previous versions there were a couple of links, one of which would open a custom Applet. Now the whole process is integrated inside the Eclipse GUI. In order to activate the new license in the server click "Add External Server" or "Add remote Server" depending if you are running the external server locally or remotely then the JAVA_OPT options will show up. Note that I had to tweak the hints as explained in this possible bug:
-javaagent:"/Users/nestor/eclipse-helios/plugins/org.zeroturnaround.eclipse.embedder_5.0.0.RELEASE-201206201947/jrebel/jrebel.jar" -Drebel.workspace.path="/Users/nestor/eclipse-workspace-test" -Drebel.log.file="/Users/nestor/.jrebel/jrebel.log""/Users/nestor/.jrebel/"

Updating JRebel for Eclipse

In Eclipse go to "Menu|Help|Eclipse Marketplace" and click the "Update" button for JRebel. An Eclipse restart will be needed. I have tested this going from JRebel 4 to 5. Do not forget to update the JAVA_OPTS to point to the newest version of the library. For example below is the path for the new JRebel5 in my local OSX Eclipse dev environment:


Unknown said...

If the application server is running on the same machine as your IDE, meaning it is external server rather than remote, the you don't really need the remoting plugin to be activated. It is just a matter of setting the correct path in rebel.xml

However, if the application server is located at remote host, the for sure - the remoting plugin is designed specifically for this kind of environments.

Enjoy! :)

Nestor Urquiza said...

@Anton You are correct. I have now clarified that in the steps. Thanks! - Nestor

Abyss said...

How do I get eclipse debugger to recognize code changes that I can get to hot deploy on an external server running on the same machine as the IDE with the JRebel agent in its JAVA_OPTS.

Nestor Urquiza said...

@Abyss I have updated the step. That is pretty standard way to work with eclipse (attaching to remote JVM debug port). Basically: (From Java Perspective, Menu | Run | Debug Configurations | Remote Java Application | Right click and select New | give it a name like "Local" | set Host like localhost | Port like 8000 | click Debug. From that moment on the option will be available when clicking the bug icon arrow)