Monday, 14 January 2013

A Garbage Collection Analysis of PCGen, the popular Open Source Character Generator


Introduction

I decided to combine two software loves of mine and perform some analysis on PCGen, a popular Java based open source character generator for role-playing games. I used Censum, our (jClarity's) new Garbage Collection log analysis tool to perform the analysis.

This write-up assumes you have a passing familiarity with Garbage Collection (GC) on the JVM. If you're not familiar with GC then I recommend you join our Friends of jClarity programme. We're building up a knowledge base around GC to share freely with the whole Java community, we'd love for you to come and validate this!

The projects

The two projects I'm using are are PCGen (the project I'm doing the analysis on) and Censum (the GC analysis tool).

PCGen


PCGen is a popular character generator and maintenance program for d20 role playing systems such as Star Wars and Dungeons & Dragons. It's a long running project (> 10 years) and consists of a large (~750,000 LOC) Java Swing desktop tool that has a ton of proprietary format data files. Disclaimer: I'm the Chairperson for PCGen.


PCGen is a data intensive tool. In order to drive its rules engine and to meet the requirement of a responsive UI (with lots of detail) much of this data is loaded up front and held in memory. Users have reported the following issues in the past.
  1. Pauses often occur when dealing with multiple characters and/or high level characters.
  2. When creating a character of a high level or if more than 2 characters were created, PCGen simply died. More tech savvy users report that they saw an OutOfMemoryError in the pcgen log file.
Some work has been done to mitigate this poor performance in the latest version of PCGen (6.0) and so I decided to use Censum to determine if those changes had improved matters.

Censum


Censum is jClarity's new Garbage Collection analysis tool. It's focus is to use powerful analytics to crunch through the raw log data and give busy developers (like contributors to PCGen!) plain english answers quickly. Disclaimer: I'm the CTO of jClarity.



Censum is a new product that is free for Open Source projects and of course if you wish to purchase a copy you can get a free trial license (click on Start Your Free Trial) today!

TLDR - The Conclusion

We have good news, some information and bad news.

The Good News


The positive news is that the default heap settings that PCGen starts with (-Xms256m -Xmx512m) are now adequate in terms of being sized well enough to keep PCGen running. Even after creating a 5th complex character, there was no OutOfMemoryError.

Censum shows that once a full GC is run (typically after each new character has been created), a large percentage of the heap is recovered and each the character takes up about 25-50MB of heap space. We can very roughly extrapolate that with a starting (data loaded) point of ~125MB that PCGen can comfortably hold about 10-15 characters open at any one time without crashing. This is perhaps not enough for a GM to have his Goblin horde up and running, but certainly enough for most regular parties!

The Bad News


The slightly more negative news is Censum reporting that PCGen has relatively high pause times, likely triggered by too much premature promotion.

Too much premature promotion pushes memory into the old gen space more quickly that we'd like. This can have the knock-on effect of causing more old gen collections as well as full GCs, naturally leading to more pause times.

See the full analysis section for extra details on high pause times, premature promotion and what PCGen can do about it.

Where to from here?


PCGen could follow Censum's "stop-gap" recommendation to alter the size of the young generational space. By using the -XX:NewSize flag and setting that to ~256M, the high pause times problem is alleviated.

However, the longer term solution is for PCGen to continue reducing the impact of their data structures (in particular the representation of a player character). This is in fact an ongoing project for PCGen today!

The technical setup

PCGen is typically run from a shell script with the default heap settings of -Xms256m and -Xmx512m. The script was altered to provide the minimum set of flags that are required to produce GC log that can be analysed. The flags that were added to the java command were:

-verbose:gc -Xloggc:pcgen_gc.log -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
  • -verbose:gc and -Xloggc:pcgen_gc.log produce a basic log that outputs to a file called pcgen_gc.log.
  • -XX:+PrintGCDetails provides the absolute minimum set of GC allocation information that Censum needs to perform an analysis.
  • Finally -XX:+PrintTenuringDistribution gives useful information on when objects are moving from a young generational space (eden, survivor 1 and survivor 2) to an old generation space (tenured).
All of these options have little to no impact on a running JVM. You should always have these switched on in Production!

PCGen was run with Oracle's Java 7u10 on a MBP running Mac OS 10.7.5, with 8GB of RAM, a 256MB SSD drive and a hyperthreaded Dual Core 2.8Ghz i7 processor.

The PCGen activities

PCGen begins by loading up basic game mode and system files + the basic UI to load data sources. The next step is for the user to select which data sources to load (roleplaying game rule sets). The popular SRD 3.5 with Monsters set was loaded (Dungeons and Dragons 3.5e).

A Character (Karianna) was created level by level into a 20th Wizard with fully loaded spells, equipment, and a Cat familiar (effectively a 2nd character in PCGen). Several more complex characters were added after that, including a Great Wyrm Blue Dragon (loads of data!).

Analysis

I'll cover the initial data loading use case and then general on going usage (character creation).

Data Loading


I was curious about the memory impact of the initial data load. Although I get fast loading times with my SSD drive having PCGen load its data without memory problems is certainly a project goal! Here is what Censum showed in terms of heap allocation after GC's.


As you can see, the initial load of data caused a number of young generational collections and one old (tenured) GC event at the end of the data load. The heap usage climbed to a max of about 325MB, but after garbage was collected, the heap usage fell back to about 100MB. Not too bad for loading about 15 thick rule books worth of data!

However, data loading for PCGen is a little like the start-up period for an web/application server such as Tomcat. In terms of your GC analysis it's generally best to be excluded as part of a one-off start-up as opposed to analysing your running application.

Creating characters


Creating Karianna and advancing her to 20th level involves filling in details of 13 main tabs ~20 sub tabs and a good deal of data! Another 4 characters were created of similar complexity, some friendly (a Cat familiar) and some not (a Great Wyrm Blue Dragon).

A few screenshots of the process follow:

Skills



Equipment



The Embedded Character Sheet


Censum's Analysis

On opening the log file, Censum took me immediately to its Analytics Summary screen, which lets me know at a glance as to how PCGen's garbage collection is going.


The good news


Immediately I know that:
  1. I have the right flags to collect enough GC data for analytics to work properly
  2. My GC throughput is good (PCGen spends it's time running, not garbage collecting)
  3. There are no nasty System.gc() calls (generally not good practice).

The informational news


Memory Utilisation (which a memory leak is a subset of) and Memory Pool Sizes are informational as the log has not yet gathered 24 hours of data (our recommended minimum to see a full working day's cycle for an application).

The bad news


PCGen appears to have high pause times as well as a premature promotion problem. Let's dive into those a bit further!

High Pause Times

High pause times are caused by GC collectors having to pause application threads in order to clean up object references in a safe manner. The more object references that the collectors have to scan over and clean up, the longer the pause! The longest pauses are usually caused by full GC collections, where the entire Java Heap (e.g. Both young and old gen spaces are getting really full) are cleaned up.

As a user I noticed pauses a couple of times, not enough to really disturb me, but I am aware that I have extremely good hardware and that these pause times may be significantly worse for other users.


As Censum points out, the 0.15% time spent paused is not a major concern, it's the 0.666 second pause time that's concerning. However, I remembered that the highest pause time could come from the initial data load in PCGen. To correlate this, Censum provides a graph of pause times.


The data load was the worst offender, but certainly for each character created there was a good ½ second pause around each character creation point due to a full GC. Again ½ a second wasn't too annoying for me in the context of using PCGen, but as Censum shows, full GCs take time and so PCGen should look to reduce the number of full GC's.

In this case we know that we are probably getting more full GC's than we'd like due to the other warning that Censum gives us - too much premature promotion.

Premature Promotion

Premature promotion basically means that objects that should be getting collected in the young gen space are being promoted into the old gen space before their age is up. This 'age' is known as the tenuring threshold, and is based on a combination of software research done in the 1980's and the JVM's runtime heuristics. Premature promotion can occur due to:
  1. The rate of new objects being created overwhelming the young gen space
  2. The size of the objects being created are too large to fit into the young gen space. e.g. Large contiguous blocks of memory.
This has a knock on effect of putting pressure on the old gen space. It fills up more quickly and therefore more old gen collections and eventually full GCs occur, leading to more frequent pause times.


When I go to take a look and see how soon objects should be promoted and how early they are getting promoted, I get an answer immediately. The Tenuring Summary screen shows us that the Tenuring threshold is set to 15 (objects can survive ~15 collections in young gen before being promoted naturally to old gen). Note also that 100% of objects are being prematurely promoted!


I then go and look and see when objects are being promoted. Censum tells me that as majority are being promoted almost as soon as they arrive in young gen (Tenuring Threshold of 1). That value indicates to me that the arriving objects are too large for the current young gen size. However, I double check and make sure object allocation isn't extremely high, Censum tells me that object allocation peaks at about 2.5GB/s, which is only about ⅔ of the capability of my MBP, so we're OK there.


Steps for PCGen to take

The next step for the PCGen team would be to take a look at something like the histogram from jmap to see what large objects are being created. A quick check of jmap output means that I know that we have large (multi-MB) contiguous arrays of String, char and byte.

An option for PCGen at this point is to resize the young gen space in order to fit these large objects into young gen space using the -XX:NewRatio or -XX:NewSize flags. The size to set either of these two values would depend on the results discovered from the jmap usage. In this case setting -XX:NewSize to ~256M is required to alleviate the the number of pauses.

However, that's generally not a great long term solution. The PCGen project is better off reducing the usage of these large contiguous memory allocations. Lead by Tom Parker and James Dempsey, this is exactly what the PCGen team is doing, taking out large memory structures from the monolithic PlayerCharacter class into smaller more flexible facets.

Summary

It's fantastic to see that the incredibly hard work the PCGen volunteers have put in for the 6.0 release has paid real dividends for the end users!

A couple of years ago I was tracking down a 30+ second pause that a PCGen user had reported when loading up her 25th level Kobold Shaman. It took me several days to track down that it was a GC/memory problem as I only had raw GC log files (which are multithreaded, indeterminant beasts). Going forwards I'll definitely be using tooling like Censum to solve these issues more quickly, which means I can get on with adding new features to PCGen!

Don't forget to check out PCGen for your d20 role-playing game needs and Censum if you want to solve thorny GC problems!

Cheers,
Martijn (Chairperson - PCGen, CTO - jClarity)
aka "The Diabolical Developer"

Tuesday, 11 December 2012

My 2012 - including a new Garbage Collection Tool

Hi all,

So I haven't written here for over a year!  Why?


TLDR

Well because several amazing things have happened in the last year or so. I am truly, truly blessed to be part of an amazing, vibrant community of hackers, dreamers and doers. If you've been following me on Twitter then hopefully you'll have had an idea of what's been going on.  If not, or if you were after more details then read on!


I'm the CTO of a new Start-up called jClarity

I co-founded a new start-up called jClarity with industry legends Ben Evans and Kirk Pepperdine along with a host of other exceptional engineers. We're focusing on intelligent products to optimise Java/JVM applications and ensure the stability of the Cloud during its infancy. Basically we decided to try science, basing our analytics off empirical science as opposed to guesswork.

Today, existing performance tools give you lots of data, lots of graphs and no real answers. They also impact heavily on your running system and become a major bottleneck themselves. Having suffered on the wrong end of this for years, we decided to do something about it! We're focusing on simple, light-weight and easy to use tools that give answers as opposed to making you scratch around in deep computer science and Java/JVM theory.

Of course community and supporting FOSS is a strong part of this, we're passionate fans of fun tech communities. If you're interested in performance tuning, cloud, virtualisation, the internals of the JVM, how Java really works etc then sign-up to our Friends of jClarity programme and join in the fun!


The London Java Community continues to kick butt!

We won two awards this year for our work in the Java Standards space.  Our two programmes Adopt a JSR and Adopt OpenJDK continue to thrive and make a real difference to the ~9 million Java developers out there today.

For example, you can thank Stephen Colebourne and also Richard Warburton/James Gough for ensuring that Java 8 gets some great new date and time APIs via JSR 310!


I spoke at 10+ conferences

I was privileged to be invited to speak at a large variety of conferences this year, from intimate rooms at regional events in their first year to keynotes at some of the largest Java conferences in the world. It was (as always) a learning curve, dealing with different audience sizes, cultures and areas of interest.

My technical talks focused on Java and the Machine - looking at where the language and the JVM hit the Operating system and the hardware and why that matters again. For those of you who missed the 2012 trend on this, basically multi-core CPUs and virtualisation/cloud means that Java developers have to really think about the hardware they are coding on top of again, no more free lunch!


The Well-Grounded Java Developer was released!

After ~2 years of elapsed time Ben Evans and myself are very proud that our first book The Well-Grounded Java Developer has been released.  So far it's all 5 star reviews in Amazon, some even by people we don't know ;-)!


I was honoured to be counted as a Java Champion

The Java Champions are a group of Java luminaries that I've looked up to my entire career. To be named in their number is still bewildering to me, but there you have it.

We built a solution to figure out your Garbage Collection problems

We've released Censum, a new tool for analysing Garbage Collection logs, telling you exactly what you need to change in order to stop those mysterious pauses and the OutOfMemoryErrors (amongst other things).

Garbage Collection often causes production problems, and is a difficult, specialised area that can be very frustrating for busy developers, devops and operations teams. Censum analyses complex logs and tells you about your GC performance problems in plain English, along with the fix!

Censum is available to download at www.jclarity.com
.

So that's been my year in a nutshell - I hope yours was as much fun and that you got to write more code than I did, something I need to rectify in 2013 :-)

Tuesday, 4 October 2011

JavaOne 2011 - Days 1 and 2 (Sunday/Monday)

Hi all,

So I'm at JavaOne and it's been an interesting first couple of days!  I'm live tweeting a number of live announcements and insights but I thought I'd try to round-up my experiences so far on Days 1 and 2.

Apologies for anyone/thing I've missed - it's been a whirlwind! 

Sunday


My Walk

I started the day with an interesting walk from my apartment to "The Zone".  First thing that struck me was the vast numbers of homeless people on the streets, really sad to see and not what I expected from San Fran at all.  They say that Britain is a broken society, I think I'm seeing worse here in San Fran.

JUG Leaders Brunch

The JUG Leaders and Java Champions brunch was the first thing up on Sunday morning.  It was fantastic to put names to faces (a bunch of us only knew each other from the mailing list) and of course to see familiar friendly faces including Stephen Chin, Bruno Souza, Fabiane Nardon, Kirk Pepperdine, Stephan Janssen and many more! Oracle gave us a briefing on what was going to be announced in the keynotes, one of the focuses being on Java FX 2.0. I'm still personally not sure whether it's going to be 'too little, too late' given the rise of HTML5, but then again I'm not heavily involved in the UI space.

User Group Sunday

The rest of Sunday was spent with the JUG leaders and other community members for a bunch of Open Conference style sessions.  It's always good to discuss the issues that we all commonly face, thanks to John Yeary for organising.

The Duke awards were presented that evening outside in the Mason Street tent/cafe area and LJC's Trisha Gee accepted a Duke innovation award for the Disruptor framework that her company (LMAX) has been working on.  The Zero Turnaround guys also picked up their well deserved award for JRebel.

The evening ended with us meeting up with Charles Nutter and some of the other JRuby crowd at the Glassfish party in the Thirsty Bear, it never hurts to get free beer! Was also nice to see Dan Hardiker and a certain Mr Gosling there.

Monday

The Good

1. Oracle's stance and genuine efforts with the community.
  • The Duke awards on Sunday night
  • The free coffee and beer
  • Featuring non Oracle speakers on the JavaOne front page
  • The technical content of the overall program being determined in conjunction with a community committee.
  • Their community interviews
  • And more!
Credit goes to all of the Oracle team behind this including Nichole Scott, Sharat Chandar, Mark Reinhold, Henrik Stahl, Adam Messinger, Mary-Lou, Tori Weildt, Dalibor, Donald and many more!

2. Parts of the Keynote were really good.  Mark Reinhold was very clear explaining Java 7 and 8, the Java FX 2.0 demo with the Kinect controlled Duke went down well and they involved the JRuby guys to explain invokedynamic and what it means for non-Java languages.

3. The Mason Street area and the hangout spaces in the hotels are pretty cool

4. Attendance was way up from last year, real buzz about the place, it's pretty clear that the Java platform is going through an upsurge, exciting to see.

5.  JCP matters again.  We had lots of people turning up to the JCP events, buoyed by the results of JSR-348 (step one in reforming the JCP) with lots of feedback and interactive Q&A.  Even the public EC meeting was packed out!  I was on the panel for a number of these events and was really happy with the amount of interest and feedback, especially considering they're effectively non-technical sessions.

6. Good talks on Lambda (Alex Buckley) and Jigsaw (Mark Reinhold) for Java 8 from experts who actually engaged the audience!

7. The O'Reilly cocktail party, was able to talk shop with fellow authors and catch up with friends from OSCON such as Laurel Ruma, Sarah Novotny and the rest of the O'Reilly crew.

The Indifferent

1. Oracle have tried their best with "The Zone", but the fact remains that running around the 3 hotels is still fairly difficult and trying to find certain rooms inside the hotels also leaves attendees missing out on their events.  I haven't put this into "The Bad" section as the sign posting and extra helpers made it bearable (just).

2. The speakers room was very small and has limited WiFi signal, Oracle, please talk to the OSCON folks on their set-up!

3. Getting my photo taken in an alleyway in the rain for a tech magazine - us developers don't usually make good models, as was proven today!

4. Some of the even rooms are still small and pokey and seem to be stuck in a basement level (Parc55 in particular)

The Bad

1.  The WiFi constantly drops in and out, ruining some presenters demos and causing immense frustration for attendees.  Lessons need to be learned from some of the European conferences such as Devoxx and FOSDEM.  Hoping this improves tomorrow.

2. The Intel part of the keynote.  Caused the entire keynote to be late (they rambled on), was boring (some pretty hokey bar/line graphs) and the its content was better suited to OOW as opposed to JavaOne.

Phew - busy days so far, looking forward to sleep :-)

Cheers,
Martijn

Thursday, 15 September 2011

My Interview with MyFear

I was humbled to be interviwed as part of MyFear's Java Hero's series - If you want to know some of my motivations then go here

Saturday, 10 September 2011

The OpenJDK as the default Java on Linux

Hi All,  (this post is x-posted to the java7developer blog and the ljc blog)

Recently I've received a bunch of private correspondence from people confused/worried over the change in the default Java packaging for Linux. For many Linux distributions, the official Sun/Oracle version of Java has been packaged up as the default Java for the platform. However, due to a recent licensing change, this will no longer be the case! So, is this a positive or a negative thing for the Java and open source ecosystem? Read on for my take on it :-)

Background

Dalibor Topic announced that With Java SE 7 and JDK 7 being released, and with OpenJDK as the official Java SE 7 reference implementation, that it was finally time to retire the non open source "Operating System Distributor License for Java" (DLJ).

What does it mean for me?

The knock on effect of this is that Linux distributions will on longer package Oracle's Java (== OpenJDK wrapped up in some proprietary bits and pieces) as the default Java. This can/will cause problems for some Java users initially as there are a smattering of bugs (especially in the Swing UI libs) still left in the OpenJDK that affect programs like PCGen. However, some Linux distributions had already taken this path some years ago, most notably Ubuntu and the last remaining bugs are being cleaned up pretty quickly.

Positive or Negative?

Overall, I think this is a positive step in the right direction for free and open Java on Linux platforms. This sentiment was welcomed by well known open source advocate Simon Phipps in a twitter post. The fact the the OpenJDK is now the reference implementation (combined with efforts to open up the issue tracker for the OpenJDK) means that means that a vast host of Java/Linux end users can now directly improve 'official Java' for all of us. 

I want the Oracle version!

Linux users who need to use the proprietary parts of the Oracle JDK 6 or Oracle JDK 7 binaries can of course as usual simply get the gratis download at http://oracle.com/java under the same terms as users on other platforms. However, if it is due to a 'bug' that is discovered I strongly encourage those users to submit a bug report to the OpenJDK project, so that any issues can be fixed for all of us.

Opinions and further questions are welcome!

Thanks,
Martijn

Thursday, 1 September 2011

JavaOne schedule

Here is my JavaOne schedule:  I can't mimic the nice colouring that Steve On Java has, but hey :-).


Please note the JCP EC meeting is open and free for all to join (Sunday 15:45) - we need the voice of the community there, so come along!


I'll actually be speaking at:


  • 30440 - Java User Groups and the JCP (Sunday 14:30)
  • 23647 - JCP and the Developer Community (Monday 11:00)
  • 23641 - Meet the Executive Committee Candidates (Monday 1900)
  • 23645 - Lightning Talks: JSRs in Progress (Wednesday 0830)
  • 25303 - The Diabolical Developer (Redux)  (Wednesday 1500)
  • 25303 - The Diabolical Developer (Redux) - repeat!  (Wednesday 1630)
  • 37780 - Java Community Keynote (Thursday 0845)


Let me know if you want to catch up!  I'll be fairly flexible about turning up to most sessions, the benefit of attending a conference like JavaOne is as much isn't catching up with friends an colleagues as much as anything else :-)


Tuesday, 19 April 2011

The Data Grid JSR Backlash and why you should support the JCP reforms


The recent backlash against Red Hat's data grid JSR proposal sparked an interest as I know the JCP is going under reform right now.


For those of you who have missed the debates, here's some background reading for you:


So, here are my thoughts on the subject!

Technical merits

On technical merit the JSR proposal certainly seems sound enough to be a solid starting point for discussion (I'm no expert mind you).


Open standards are good

It's a laudable goal to standardise this space, and Red Hat have got 
my support on that front. Just like vendor lock-in was bad for databases and app servers, it's also bad for developers and users of data grids.

This area is potentially worth Billions and so I can understand why some vendors may be reluctant to form an open std 
around it, but really, it's a good thing! I believe the vendors should be competing on performance and other factors, not basic get and put type API calls.

Where the proposal went wrong

Politically, Red Hat went about this in an unusual way, hence the backlash. Sadly, that sort of backlash can be enough to sink a JSR before it even sets sail.

I was a surprised that an organisation with so much JCP experience presented this JSR without the usual pre-collaboration that typically goes on in these cases. So I dug a little deeper to find out why Red Hat had gone about it this way.

The root cause

Without knowing all of the ins and outs, the new data grid JSR was proposed partly because of Red Hat's frustration with trying to get JSR-107 (data caching) back to an active state (it's been an inactive JSR for some time).

A std caching API (JSR-107) would be a natural base for any agreements around standardising any further data grid APIs on top of that.

Red Hat (and others?) had tried to re-vitalise the JSR-107 Expert Group to get 
the JSR re-opened, ratified and released. That would've been a great start, as it meant that there would be collaboration amongst the same vendors that are then needed for a subsequent data grid JSR.

Why did that attempt fail?

We don't really know. Unfortunately nobody on the outside can confirm what was/is going on as the JSR-107 mailing list is closed to the public!


This is the crux of the problem with the existing JCP rules, in that 'open standards' are being decided behind closed doors. Thankfully Patrick Curran is working on changing this (see! Oracle isn't always evil ;p).

So what happens next?

By raising the new JSR, Red Hat has gotten their desired result of getting JSR-107 moving again to complete the caching work. It's a 
shame that they were seemingly forced into this stance.  We'd all much rather see deliberate community collaboration, it's certainly not a model of how we want to see inactive JSRs moving again!


Red Hat's intentions are almost certainly completely honourable, but as some of the other vendor's stated, the raising of the new data grid JSR came across as a great surprise and was therefore not as welcomed as it could have been.


So, JSR-107 will go ahead, but it'll take some amount of bridge mending before data grid JSR gets off the ground.

Lets avoid this in the future and support Patrick Curran's JCP reforms!


Cheers,
Martijn

Thursday, 3 March 2011

OSGi - Are we there yet?

A few nights ago John Stevenson (@jR0cket) and I were fortunate enough to be taken through a explanation of OSGi by some of its key proponents: Neil Barlett (@njbarlett), Zoe Slattery (@zoe_slattery) and Alasdair Nottingham.

I have certainly battled JAR hell and have also experienced problems with keeping web and enterprise applications isolated from each other (manipulating parent delegation and CLASSPATHs anyone?). This has been throughout my Java career (~10 years now), but I had never investigated OSGi properly as an alternative. Why? Because I never spent the time investigating OSGi properly and I was under the strong impression that it was better suited for IDE, App Server and tooling development as opposed to application development.

So after a good couple of hours of discussion I came out with a greater appreciation for OSGi and the following conclusions.

The Good

OSGi's core principles are pretty sound

OSGi is a sound solution for modularity, it clearly breaks the developer away from the artificial JAR model of 'modularity' and instead gets you to think about what Java packages you are dependent on. Through some simple metadata information in your manifest file you can specify the packages that you are dependent on (including a version range). For example, your test code may rely on the org.junit.core package within JUnit. Normally you would reference the entire JAR, but with OSGi you can reference just the package org.junit.core, as well as the version range that you want (e.g. 4.7.1 to 4.8.2). That package can then be supplied by any bundle (which still uses the JAR construct) which 'exports' it. You can probably already envision that a much smaller bundle can be provided than the default large JUnit JAR file.

OSGi actually encourages you to design better APIs

For those following the various clean code or software craftsmanship movements will appreciate the fact that by utilising OSGi, the developer is actually encouraged to think about splitting their public API into loosely coupled 'bundles'. The analogy here is that of Maven, which although polarises developers, does encourage them to use a correct build life cycle (clean, compile, test, package, environmentalise). good API developers should certainly look at supporting OSGi in order to help them designed better APIs

OSGi is relatively easy to get started with

You can start with an existing application and simply provide the OSGi bundle information in the manifest file for that JAR. You will tend to find that a vast majority of the dependencies already have OSGi bundle versions and it is not difficult to swap to an OSGi based build using Maven or Ant. In fact, as OSGi is already a well established technology it probably pays to have an OSGi bundled version of any project artifacts you produce. The tooling is adequate on most major IDEs (especially Eclipse) although the OSGi community would still like to see improvements in this area.

What the OSGi alliance is working on improving

A common/std tool for deploying OSGi applications to runtime environments

OSGi does have a std API for deployments, but this does mean that developers need to implement a deployment mechanism for deploying their apps to runtime environments. Most modern application servers do have OSGi container support, but the deployment mechanism is arguably different each time. This is an area that the OSGi alliance is working on and hopefully some standard tooling around this standard will come out soon. Although it seems like a small usability gap for OSGi, my guess is that this is a real adoption blocker.

Like Java apps in general, OSGi bundles are not Linux/UNIX distro friendly

A major complaint from Linux and UNIX distros over the years has been the fact that Java is not installed according to their packaging standards. Java is also an relatively large installation, which is the source for further criticism. Whilst OSGi certainly helps with the size aspect of Java-based programs, as it is also a late-binding runtime container it does not lend itself to the static, early binding packaging systems that the distros use.

As John pointed out, the existing Iced Tea (OenJDK) project does already produce bundle data that looks a good deal like OSGi bundle data:

Looking into the meta-data of the openjdk-6-jdk package, you can see there is a lot of scope for using OSGi style information.

Package: openjdk-6-jdk
Priority: extra
Section: devel
Installed-Size: 34100
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: OpenJDK Team <openjdk@lists.launchpad.net>
Architecture: amd64
Source: openjdk-6
Version: 6b20-1.9-0ubuntu1
Provides: java-compiler, java-sdk, java2-sdk, java5-sdk, java6-sdk
Depends: openjdk-6-jre (>= 6b20-1.9-0ubuntu1), libc6 (>= 2.4), libx11-6, zlib1g (>= 1:1.1.4)
Recommends: libxt-dev
Suggests: openjdk-6-demo, openjdk-6-source, visualvm
Conflicts: openjdk-6-jre (<< 6b17~pre3-1), openjdk-6-jre-headless (<< 6b17~pre3-1)
Description: OpenJDK Development Kit (JDK)


However, this does need to be investigated further and perhaps if OSGi and project Jigsaw can interoperate and some tooling is built then I could see bundles being deployed according to distribution standards. This would help Java and OSGi applications gain even more acceptance amongst the Linux/UNIX community. This leas us onto the Jigsaw issue...

The (Potentially) Ugly

Project Jigsaw (Java modularity) is coming as part of JDK 8 and at this stage is not going to work hand-in-hand with OSGi. It is not beyond the realms of possibility that the two will interoperate cleanly in the future and I'm hopeful that the two communities can continue to find common areas despite their fundamentally different approaches.

However, if they do not come together in some simple to use form then it is likely that the Java modularisation space will be fragmented which will only harm the end developer, end user and the Java ecosystem.

You can read more on this topic on a blog post by my co-author for "The Well-Grounded Java Developer" Ben Evans. This post has also been cross posted to the LJC blog.

So are we there yet?

For mainstream adoption by application developers, probably not _yet_. But I think when the tooling gap is closed and as more application developers release OSGi apps, it might just become a de-facto standard for modularity in Java apps. However, there still remains the looming specter of Jigsaw integration/interoperability. There have been signs of the two sides discussing how they can meet in the middle, lets hope that continues.

Cheers,
Martijn

Wednesday, 2 February 2011

Bit of a hiatus

Hi all,

With "The Well-Grounded Java Developer" deadlines approaching and my arms starting to feel the strain I'll be taking a break from writing any blog posts for a few months.  Not that it's been real busy here anyhow, but I thought you should know :-).

Cheers,
Martijn

Wednesday, 8 December 2010

JBoss - separating application logs without using monolithic jboss-log4j.xml

A minor irritant we've discovered in implementing applications for Jboss AS is that that the logging configuration for applications has to go through their monolithic jboss-log4j.xml file.

So we've managed to find a work-around (after some investigation of the Jboss class loaders and some trial and error).  This technique has been confirmed for jboss-eap-4.3 and jboss-4.2.3.GA but will likely work for other versions.

If you want to have split application logs and have that log4j.xml based configuration separated out (e.g. Not have it all in the jboss-log4j.xml file) then you can do the following.

1.) Your WAR/EAR must contain log4j-1.2.16.jar. It must be 1.2.16 or later as earlier versions don't work.

2.) The class loading for that WAR or EAR must have its java2ParentDelegation=false. So for example the jboss-app.xml file will look something like this:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-app PUBLIC
      "-//JBoss//DTD J2EE Application 1.4//EN"
      "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
<jboss-app>
  <loader-repository>${your domain}:archive=${your app name}.ear
    <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
  </loader-repository>
</jboss-app>

Now this means that the WAR/EAR will use the log4j-1.2.16.jar for logging within its own classloader, i.e. It will not use Jboss's log4j.jar library (and therefore the jboss-log4j.xml won't be used).

3.) In the MANIFEST.MF file in your WAR/EAR archive you need to set a Class-Path: entry that shows the location (directory) where the log4j.xml file that you want to use will reside. For example if your EAR file is deployed in the deploy directory, your Class-Path reference might be something like this:

Class-Path: ../conf/log/${application name}/

4.) Your log4j.xml file should just be an ordinary one, with no references to any special jboss classes. However, it will have an appender with the specifc name for the log file for the application you want to log for, e.g.


  <appender name="${module.name}" class="org.apache.log4j.RollingFileAppender">
    <param name="File" value="${jboss.server.home.dir}/log/${module.name}.log"/>
    <param name="Threshold" value="INFO"/>
    <param name="Append" value="true"/>
    <param name="MaxFileSize" value="2MB"/>
    <param name="MaxBackupIndex" value="20"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{yyyyMMdd HH:mm:ss.SSS} %-5p [%t] %C{1}.%M(): %x %m%n"/>
    </layout>
  </appender>

5.) OPTIONAL: You can still have all of your logging also go to the shared central $JBOSS_HOME/${instance}/log/server.log file by adding the following to your log4j.xml file:


  <appender name="all" class="org.apache.log4j.RollingFileAppender">
    <param name="File" value="${jboss.server.home.dir}/log/server.log"/>
    <param name="Threshold" value="INFO"/>
    <param name="Append" value="true"/>
    <param name="MaxFileSize" value="2MB"/>
    <param name="MaxBackupIndex" value="20"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{yyyyMMdd HH:mm:ss.SSS} %-5p [%t] %C{1}.%M(): %x %m%n"/>
    </layout>
  </appender>

I've updated the Jboss community wiki with this information (thanks for pointing out the location Jaikiran!).

Tuesday, 16 November 2010

Java is dead, long live the Java developer! - Part II


Hi all,
This is an updated post based on the recent announcements and events in November, enjoy!

Well, what a few months it has been in the Java space!  It started with Oracle announcing that the best plan to move the Java language forward was to split the existing openJDK work into Java 7 (for summer 2011), followed by a Java 8 (for summer 2012?).  You can see the current feature list for JDK7 at http://openjdk.java.net/projects/jdk7/features/.  Now that a decision has been made I think we'll see some good progress on this front.

This of course threw our plans for the book into a bit of a spin and so Ben Evans and I are now writing "The Well-Grounded Java Developer (covers Java 7)", a subtle yet important shift in the emphasis for the book.  This has caused some material to be thrown out (bye bye Date and Time, Closures and more) and other bits to be re-written.  If you're interested in the book or what is going on with Java 7, then head on over to http://www.java7developer.com for more details!

But that of course was not all!

The Oracle vs Google lawsuit continues to gather pace with Google counter suing Oracle.  It's watch this space for everyone at the moment, but it seems that at this stage the lawyers are going to be kept rather (happily one suspects) busy.  Another recent paper filed by Google appears to be a multi-layered defence, no quick resolution here then.  You can keep an eye on this over at groklaw

Oracle also announced a partnership with IBM in terms of developing the openJDK, a bit of a coup for Oracle, but understandably there was some backlash as the Java community as a whole realised that the formerly IBM backed Apache Harmony and all it stood for (a truly open Java) was effectively doomed.  This has been well covered in the blogosphere, so I'll leave it at that (repeat after me "pragmatic").

Then came some JCP nomination and election hooha!  Some prominent people have sadly left (Doug Lea foremost amongst them) and there are also accusations flying about the JCP election process being gamed somewhat.

Apple stated that they would no longer be providing their own version of Java for Mac OS 10.7 and beyond.  However, much to the relief of the Java community they then announced that they were gifting a vast majority of their work to the OpenJDK and would help Oracle integrate that.  So although the steward has changed, it's still likely we'll get a first class Java on the Mac.  I guess I'll buy a Macbook pro after all.

Last but not least we have the Apache foundation vs Oracle battle.  Remember the bit about Apache Harmony above?  Apache wrote a public letter thanking IBM for their efforts, it was all very professional and seemed as amicable as possible. However, they then went on to bluntly tell Oracle that they would vote against the JSR for Java 7 SE unless Harmony was granted access to the TCK without restrictions.  Yo can follow the conversation roughly via the links below

Apache's opening salvo --> Oracle's response --> Apache's response

So we have IBM, Apple and Oracle all pretty much playing in the openJDK/Java 7 sandpit, with Google and Apache firmly on the outer, still some interesting times ahead.

Are we there yet?
All in all this has of course led to many pundits claiming that Java is dying if not dead already.  I disagree with that assessment, but with a bit of a twist.

On the enterprise side of things I think that Java will continue to have a strong presence, especially now that the JVM ecosystem has matured and allowed languages such as Clojure, Scala and Groovy to flourish.  This is one of the cruxes that "The Well-Grounded Java 7 Developer" falls on.

On the desktop I think that JavaFX 2.0 may have come too late to the party and certainly Swing is looking very aged as a relevant desktop client library.

Mobile?  This is probably the big one for the future, we'll have to wait and see what the Google and Oracle lawsuit brings out. Android is 'Java based' and has moved well ahead in terms of mind share (if not devices) over J2ME. If it at least remains 'Java based', then the Java language will continue to do well in this space, especially when all the new young developers continue to build software for the Android.  If not, we may see a move towards Java (& JVM langauges) being seen purely as a specialised server side language.

Java's not dead - it's just got new plumage and there's _plenty_ of excitement for the 'Java' developer :)

Monday, 1 November 2010

Java is dead, long live the Java developer!

Hi all,

Well, what a few months it has been in the Java space!  It started with Oracle announcing that the best plan to move the Java language forward was to split the existing openJDK work into Java 7 (for summer 2011), followed by a Java 8 (for summer 2012?).  You can see the current feature list for JDK7 at http://openjdk.java.net/projects/jdk7/features/.  Now that a decision has been made I think we'll see some good progress on this front.

This of course threw our plans for the book into a bit of a spin and so Ben Evans and I are now writing "The Well-Grounded Java Developer (covers Java 7)", a subtle yet important shift in the emphasis for the book.  This has caused some material to be thrown out (bye bye Date and Time, Closures and more) and other bits to be re-written.  If you're interested in the book or what is going on with Java 7, then head on over to http://www.java7developer.com for more details!

But that of course was not all!

The Oracle vs Google lawsuit continues to gather pace with Google counter suing Oracle.  No quick resolution here then.  It's watch this space for everyone at the moment, but it seems that at this stage the lawyers are going to be kept rather (happily one suspects) busy.  You can keep an eye on this over at groklaw

Oracle also announced a partnership with IBM in terms of developing the openJDK, a bit of a coup for Oracle, but understandably there was some backlash as the Java community as a whole realised that the formerly IBM backed Apache Harmony and all it stood for (a truly open Java) was effectively doomed.  This has been well covered in the blogosphere, so I'll leave it at that (repeat after me "pragmatic").

Then came some JCP nomination and election hooha!  Some prominent people have sadly left (Doug Lea foremost amongst them) and there are also accusations flying about the JCP election process being gamed somewhat.

Last but not least, Apple stated that they would no longer be providing their own version of Java for Mac OS 10.7 and beyond.  Given the work that it takes to 'macify' the Java experience this may prove to be an issue for Oracle to give the same user experience with Java on the Mac.  We'll hopefully see lots of job postings for this role as I personally love developing on my Macbook Pro :).

Are we there yet?

All in all this has of course led to many pundits claiming that Java is dying if not dead already.  I disagree with that assessment, but with a bit of a twist.

On the enterprise side of things I think that Java will continue to have a strong presence, especially now that the JVM ecosystem has matured and allowed languages such as Clojure, Scala and Groovy to flourish.  This is one of the cruxes that "The Well-Grounded Java 7 Developer" falls on.

On the desktop I think that JavaFX 2.0 may have come too late to the party and certainly Swing is looking very aged as a relevant desktop client library.

Mobile?  This is probably the big one for the future, we'll have to wait and see what the Google and Oracle lawsuit brings out. Android is 'Java based' and has moved well ahead in terms of mind share (if not devices) over J2ME. If it at least remains 'Java based', then the Java language will continue to do well in this space, especially when all the new young developers continue to build software for the Android.  If not, we may see a move towards Java (& JVM langauges) being seen purely as a specialised server side language.

Java's not dead - it's just got new plumage and there's _plenty_ of excitement for the 'Java' developer :)

Monday, 23 August 2010

Dependency Injection in Java 7

Hi all,


So apart from recovering from a long bout of the stomach flu, enjoying good food again at a "Come dine with me" night (our parents would be so proud) and planning a rush trip to Vegas I've managed to get out a first draft of the Dependency Injection chapter for the Well Grounded Java 7 Developer.


Java 7 unifies some of the basic standards that the various Dependency Injection frameworks (Spring, Guice, PicoContainer etc) have, making it easier for developers to move between the frameworks as needed.


A reminder of what DI is with regards to Java[1]

The javax.inject package specifies a means for obtaining objects in such a way as to maximize re-usability, testability and maintainability compared to traditional approaches such as constructors, factories, and service locators (e.g., JNDI). This process, known as Dependency Injection, is beneficial to most nontrivial applications.


So without further preamble, here's a short section from the chapter, let me know what you think!


Inject annotation

The @Inject annotation interface can be used in three places to indicate where you'd like a dependency to be injected.  Below are the types of members that can be injected, in the order that they are processed at runtime:

1.   Constructors
2.   Methods
3.   Fields

You can annotate a constructor with @Inject and expect its parameters to be provided at runtime by your configured IoC container e.g:

@Inject public MurmurMessage(Header header, Content content)
{
    this.header = header;
    this.content = content;
}

In this case both the Header and Content parameters would be injected at runtime.  The specification allows for 0+ parameters to be injected for constructors, so injecting a zero-parameter constructor is still valid.

WARNING As per the specification there can only be one constructor in a class with an @Inject annotation, this makes sense as the JRE would not be able to decide which injected constructor took precedence.

You can annotate a method with @Inject and like a constructor, expect its 0+ number of parameters to be injected at runtime.  There are some restrictions in that injected methods cannot be declared abstract and cannot declare type parameters of their own[1].  The short code sample below demonstrates the use of @Inject with a setter method, a common technique when using Dependency Injection.

@Inject public void setContent(Content content)
{
    this.content = content;
}

This technique of method parameter injection is especially powerful when it comes to providing service methods with the resources they need to do their job.  For example you could pass a DAO argument to a finder service method that was tasked to retrieve some data.

TIP It has become a default best-practice to use constructor injection for setting mandatory dependencies for a class and to used setter injection for non-mandatory dependencies, e.g. fields that already have sensible defaults.

It is also possible to inject fields (as long as they are not final), however the practice is not common.  The syntax again is quite simple.

public class MurmurMessenger
{
    @Inject private MurmurMessage murmurMessage;
    ...
}

You can read further about the @Inject annotation in the Javadoc, where you can discover some nuances about what types of values can be injected and how circular dependencies are dealt with.

Cheers,