Upgrading Egnyte Infrastructure to Java 7
Not all upgrades are created equal.Well, I had that feeling getting into one of the projects where we were going to change a major version for a language used in 53% of the product.We recently decided to focus on a long overdue upgrade - moving from Java 6 to Java 7. After skimming through the guidelines on Java 6 and Java 7 compatibility, my first thought was that it should not take too long, and I probably would be in and out of this project in a few days.The first test was to quickly change the runtime environment to Java 7 and that held up. So far, so good. The next task was to run the build, and that is where the first set of problems started showing up. The build and test process showed the following error message in multiple places:“Expecting a stackmap frame at branch target 73 in method”The underlying problem indicated by this error message is that Java 7 uses a new bytecode verifier, which works fine with Java 7, classfile version 51 and is backward compatible with Java 6, classfile version 50. It turned out that the verifier was still failing because some bytecode manipulation libraries that we use, read code tagged as Java 7 format but generated code in the Java 6 format.The easiest solution was to force the old verifier to run all the time by using -XX:-UseSplitVerifier. However, looking at the long-term possibility of Java 8 dropping support for this flag, I went ahead and upgraded all the bytecode manipulation libraries used in our codebase. That fixed all the immediate build and server startup problems.Time to run the shiny new Java 7 build!To try out some of the Java 7 features, I quickly rewrote some unnatural string-forced-into-enum usage, replacing those with switch based on string and further reduced a few more lines by combining catch clauses and replacing resource handling with the new style. The build was completed without issues, and the application worked as expected.At Egnyte, we take code quality very seriously. In addition to a couple of static code analyzers, we have about 87% code coverage using test cases that can be executed locally in dev environments. So, as the last and natural step for this exercise, I kicked off our test harness to run against my local build. That highlighted one more issue in our integration with a third party where incoming XML did not have the ID element marked correctly, causing the Java 7 XML handling code to barf. After fixing this last issue, I pushed the build to QA and the Ops team who deploy it in production.After all that not-so-much hard work, it was time to reap the benefits. While we will continue to update our codebase and coding style guide to use Java 7 constructs, I did get a couple of somewhat obscure wins. With the help of the new NIO library, I immediately got rid of a piece of code I had not liked for a long time - JNI code to create hard links from Java. Eight lines of easily testable code replaced 150 lines of code spread across Java and C!I also found that Java 7 added a big performance boost for AES on-chip support, and after executing performance tests against our encryption engine running with Java 7, we were able to get rid of a relatively more complex setup for Mozilla NSS with APR.Lesson learned: while all upgrades are not created equal, they should be done in a timely manner!