Sunday, December 20, 2009

E V O L V E D - Find Your Next Boss

Corporate culture is often full of bureaucracy and mismanagement. This is an underpinning theme in mainstream media; from TV shows like The Office to movies like Office Space to comic strips like Dilbert. The incompetence of managers is also a recurring sentiment expressed in the chatter on tech news sites like Slashdot, Ars Technica and Reddit again and again and again. This makes for great comedy and fodder for ranting, but it's also a pretty sad reality for far too many people. Bad management is an issue in every profession, but it seems to be a particularly acute problem in the field of software development.

I'm going to attempt to outline the characteristics an ideal manager. These characteristics should be universally applicable, regardless of your field. My focus for identifying these traits, however, will come from a software engineering perspective. If you're currently employed, these characteristics should serve as a quick and easy scoring system for your boss. If they earn a failing grade, please stop wasting your time and go work on your résumé right now. For those who are currently the boss, I hope these characteristics can serve as a self-assessment test of sorts as well as a benchmark for anyone on your team who manages others. What I really want to focus on though, is how to avoid working for a mediocre manager in the first place by making the most of your job interview.

I've conducted A LOT of interviews and I'm consistently surprised at how few thought provoking questions candidates pose. The interview is a two way street and if you're good at what you do and confident in your abilities, you must recognize that you have a great deal of control over the structure of an interview and ought be doing your damnedest to influence the subject matter, cadence and tone. This prospective employer should be challenged with proving themselves to you, just as you must prove yourself to them. Your career is important, isn't it? You can't afford to waste precious time reporting to someone who isn't capable of helping you strive to be better at what you do! The trick then, is to devise a way to test for these qualities over the course of an interview. This is no small feat and I won't pretend to know all the answers. I will just offer up some guidance based on my experience and hope that others will find it useful.

When looking for your next boss, I think you should be looking for someone who exemplifies seven easy to define but difficult to master qualities. I'm going to dub this archetypal manager EVOLVED. The seven qualities are:

  • Enabler
  • SaVvy
  • Hands On
  • Leader
  • Visionary
  • Energetic
  • Decisive

Now let's dissect each of these qualities with an eye towards an interview setting.

The Enabler
Bruce Eckel has a great blog post that defines two kinds of management - Guidance & Inspiration vs. Directing & Controlling. Along a similar vein, Martin Fowler has discussed the two kinds of software development attitudes - Directing Attitude vs. Enabling Attitude. It should come as no surprise that they are both promoting the guidance / inspiration / enabling side of the coin. Enablers know to trust their people and avoid micromanagement. I believe that some of this is dictated by the person's personality and natural tendencies but experience also plays heavily on a manager's ability to enable others. Skillful managers that I've encountered surround themselves with talented people and know how to trust their team and focus on setting the proper context so their team is poised for success.

This is a great characteristic to try to identify first since it may be discernible in natural interview conversation. If you need to dig deeper, you get to kick things off with some classic interviewee questions in an effort to find out more and morph the interview session into a more conversational format. Asking "What is your management style?" is a great open ended question to start off with since it allows the interviewer to talk about themselves a bit and it will allow you to pick up on what traits this person thinks is important in a manager. His or her answer will likely set the stage for a smooth segue into questions about the other characteristics I'll be discussing. Be on the lookout for red flags right out of the gate that warrant ad hoc follow up questions.

From there, I like to ask "How are priorities managed for people on your team?" That question tends to highlight a lot about their style and the dynamics of the team. Lastly, I'd suggest a question along the lines of "How do you disseminate information to your team?" Does this person conduct staff meetings? 1 on 1's? Daily stand-ups? Other interesting communication tools? If they do staff meetings, I'd encourage you to ask "How do you prepare for them?" You're trying to get a sense of how important they feel it is to communicate well with their team. A great manager who strives to enable their team will treat communication (whether it's top-down, inter-team or intra-team) as something that requires conscious and consistent attention.

The Savvy Politician
Politics is generally a dirty word in the work place. This is especially true of engineers who tend to regard politics and red tape as a waste of everyone's fucking time and a massive impediment to actually getting anything accomplished. I appreciate that sentiment but what I've found is that politics plays a big role in every company setting, big or small. It's an unavoidable component of human nature that is to be ignored at your own peril. What you can do though, is ensure that you're shielded from as much of the politics as you'd like. This can only happen if your manager has the chops to navigate the political mine fields that exist in an organization.

This is one of the tougher characteristics to judge from conversation alone. One great way to gain some insight is to find out if the person has ever participated in layoffs. Given the Dot Com Bust and the Great Recession of 2009, this is something that a lot of managers in the field of software development have exposure to. There are very few universally applicable corporate processes that are as politically explosive as layoffs. Ask your prospective manager "Have you ever participated in layoffs?" If they have, follow up with "How was your team was affected?" You want to know that the person did all they could for their team. You want to know that they were well plugged in and knew what was happening before it happened. Better still, you'd like to hear that they anticipated what was to come and shaped their superior's thinking about the composition of the reorganization early and often. Managing during good times is easy. Managing a team when shit is hitting the fan is a different matter entirely.

If you come up empty asking about reorgs, another approach I like to take is to try to tease out signs of political savvy by asking, "How do you influence decision making and prioritization at your company?" or "Are their any areas where you and your peers have overlapping responsibility?" and "How do you deal with sharing those responsibilities?" You're looking for someone who portrays an ability to create consensus. The consummate politician knows how to establish and nurture trust within their organization. He or she can push their agenda one moment and keep evil turf mongers at bay the next.

One thing to be wary of is the manager who is detached from reality and thinks they are actually very good at navigating corporate politics - only they aren't. I haven't devised a clever gambit to detect this form of delusion in an interview, but have noticed that such managers tend to not only be ineffective, they actually inspire others to work against them!

Dilbert.com

The Hands On Coder
This one is incredibly important. Our industry seems to lend itself to people in high-ranking positions that can't write a line of code. The tech manager may be a brilliant meeting general, communicator or "people person", but in my not so humble opinion, if they can't prove a degree of hands on competency, you don't want to work for them. I'm talking about every technical position of authority all the way up the hierarchy. The possible tittles are numerous; Manager, Director, VP, CTO, CIO, Architect, Scientist. What's important as that this person really does have the capacity to do hands on work. Do I expect the CTO to be writing code on projects? Unless it's a small start up, of course not! But every good manager I've been around, at every level, has had the desire to tinker and has found ways to stay hands on without committing to time sensitive project work. Maybe they write small applications or scripts on the side for personal use. Or maybe they write utilities that help enable their employees to be more effective. If they've made a conscious choice to let their technical skills evaporate, you should be alarmed.

Luckily, you can often determine a person's technical aptitude by doing some investigative work before you even meet them. Does the person have a blog? Do they have a decent profile on LinkedIn? Are they on Twitter? Are they published? Maybe they have a public github or bitbucket repository? The tiny amount of time spent scouring the web to see what this manager is all about before your interview is invaluable.

During the interview, please don't presume that the person is technical just because they ask you a few technical questions - unless of course they happen to be really insightful questions that spark good conversation. You'll want to attempt to turn the tables a bit to garner some information. One of my favorite tactics is to get my interviewer onto a computer. It's rare for an interview to take place in a room with no computer. If you're lucky enough to be talking in the person's office, you're really well positioned to get a glimpse into this person's natural habitat. Can you get them to show you the code base? Or maybe demo an application that is being worked on? Anything you can dream up to get them navigating on a computer will suffice. Take the opportunity to observe them. Do they maneuver around their machine effortlessly? How many monitors do they have? What OS are they running? Do they have an IDE installed? If all I see is evidence of Excel and PowerPoint, I'm worried.

Every technologist I know is really passionate about their working environment and will happily go off on a tangent talking about their favorite tools for getting stuff done. If all else fails or you're running low on time, there's no shame in asking straight up, "How do you stay hands on?" and see what they say.

The Leader
The optimal boss is someone who knows how to motivate and empower a team. A leader knows how to earn and more importantly, deserve the respect of their team. Leadership extends far beyond spreadsheets and pivot tables to manage your people, budgets, vacation schedules and other typical HR tasks.

I've had great success gauging potential suitors by asking them "Why do the members of your team love working for you?" and "How do you keep your team motivated?" There are many good answers to these sorts of questions, so I'll just rattle off a few of the things I'm listening for. A leader knows how to mix in social interactions to alleviate tension within a stressed out team working on a tough project. They know how to inspire camaraderie in the trenches through clearly articulated goals and meaningful public praise. They know how to eliminate obstacles. They know how to provide tools to make people more productive. They go out of their way to shield folks from distractions. They recognize that the people on their team are trying to create great software and that their time is an invaluable resource that shouldn't be wasted in nonessential meetings. They know how to earn the respect of their peers and others within their organization over whom they have no positional authority. They are the type of person for whom you'd fall all over yourself to accommodate a requested favor.

A CTO I met with some time ago still stands out in my mind for providing the best answer to my question on keeping a team motivated. He compared his role to that of a trainer at a gym. He was there to be your "spotter". He was going to put as much weight on the bar as possible and make sure the weights didn't fall on you while also convincing you to push out those extra repetitions that you didn't think you had in you. That's exactly the type of leader I want to work for.

Dilbert.com

The Visionary
Vision comes in many shapes and forms. Any manager worth working for has it. Those who are lacking a vision of something better are either completely uninspiring or their modus operandi is to jump from one messy adrenaline rush to the next. The ideal manager should be a bit cliché in that they should be able to see the forest from the trees.

Ask a question along the lines of "What are your goals for your team in the next year?" Perhaps they're looking to change the world with their product? Or open source some great software they've built? Maybe they're looking to eliminate waste and evolve their development processes towards something more mature? The possible answers here are endless. Your best bet is to come up with follow up questions on the fly after you ask about their goals.

Whatever the plans are, you want to identify original thought. You want to know that the person is sharing his or her own vision rather than regurgitating that of someone else.

The Energizer
Does this person love the shit out of what he or she does day in and day out? If they don't, you don't want to work for them. Period. I love to ask questions like, "How did you end up working on xyz technology?" and "How did you come to work at xyz company?" I'm testing the person to make sure that he or she isn't just doing something that they fell into out of convenience or happenstance. One of my favorite questions is to ask the person "What technologies are you most excited about right now?" You want to steer them towards talking about interests that go beyond what they use in their day-to-day work, even if they're working on bleeding edge technologies.

The best managers I've worked with have been really well rounded and read incessantly. Their passion for their profession has lead them to acquire working knowledge of a wide variety of subjects. In software engineering I have found that this manifests itself in specific technologies as well as various processes. Maybe the person knows all the ins and outs of the various Agile movements; from XP to Scrum to Kanban, etc. A vanilla question like "What is your development methodology and why?" can be quite illuminating.

Managers who are passionate about what they do are a huge asset to their organization. That passion is infectious and offers a team plenty of opportunity to rally together towards common goals. People who are passionate about what they do with have no trouble talking about these things. You're biggest danger would be spending too much interview time talking about their passions before you assess the other 6 characteristics.

The Decider
A common problem I've noticed amongst some of the better managers I've been around is that they're often just too damned nice for their own good. This manifests itself in many ways but there are two things that really irk me. One is subjecting me to coworkers who aren't exceptional at their job. The other is working for someone who is uncomfortable being the "bad cop" when the situation demands it.

I want to know that my future boss will hold their team members accountable. They also need to be capable of questioning authority if need be. I've had some success by asking questions like "What's an example of something your manager or executive management team asked you to do that you disagreed with and what did you do about it?" I'm looking to ensure that they are neither overly deferential nor overly combative. Another question I've had good success with since I'm focused on web development is "Tell me about your last production outage and what was done about it?" I want to get a sense that there's no ambiguity when such situations arise. I want to know there are consequences for repeat offenders. And I want to know that they drive actions to prevent recurrence. I'm also paying close attention for signs of a reliance on just a few heroes. Detecting that the manager demands accountability can be tough, but it's a really important benchmark.

Luckily, identifying a decisive manager with that killer instinct is much easier on the staffing front. Hiring is hard. I don't take that for granted at all. But I sure as hell expect a manager to remedy the situation as fast as humanly possible when a hiring mistake is made. I was really inspired by the Netflix presentation that was making the rounds earlier this summer. Treating your business like a pro sports team is a brilliant metaphor that almost no company I've seen attempts to adhere to. We live in a pretty litigious society, so I'm curious how Netflix is able to purge so freely but I love the sentiment. I was also really inspired by this segment on This American Life about bad apples, which asserts that a team is only as strong as its weakest member. Please ask your potential boss, "What was your best and worst hire?" and follow up by asking, "What did you do about your worst hire?" I really want to know that this person is decisive and knows how to cut bait. Managers that turn every bad employee into a "fix it" project are trouble. Managers who are oblivious to their own hiring mistakes and can't cite examples of bad hires are even worse.

Next Steps
I would encourage you to actually put the questions that resonate with you on paper and use them as a guide when interviewing. Very few people who I've interviewed actually take notes during the interview. Fewer still show up with a concrete list of questions they want answered. I don't understand this phenomenon at all. Interviews are highly subject to tangents so a good script can only help you stay on track and ensure that you get the answers you need. And it'll even make you seem really prepared for the interview, which can only help your cause. Best of all, the preparation work I'm suggesting is entirely reusable from interview to interview. You'll find that you hone your queries over time and develop a knack for selecting the right mix of things to ask in the time allotted for an interview.

Finding a great manager to work for is no easy feat but I hope that I've inspired you to insist that your next manager is EVOLVED. Who you report to is the most important ingredient for job happiness. I'm confident that if you can identify a manager who meets these criteria, you will have found an ideal place to work. What's more, I firmly believe that these characteristics will help you find a boss who is destined for future success. They are the perfect person to report to because as they succeed and advance their career, more opportunities for success will open up for you as well.

Friday, July 17, 2009

Consuming Scala, Groovy and Java OSGi Bundles with Spring DM

In Part 1 of this series, we used Maven and PAX to set up and run an OSGi project with three hello world bundles; one for Java, one for Groovy and one for Scala. In Part 2 we introduced Spring Dynamic Modules to help maintain a clean separation of our bundles in addition to abstracting away the plumbing normally required for developing OSGi applications. For this third installment, I'll show you how service consumption works in Spring DM so that our services can interact with each other.

If you'd prefer to look at the code as you go, you can grab it from bitbucket. Be sure to update your working copy to revision 2 to see the code as it would look at the completion of this third article in the series.

        hg clone http://bitbucket.org/brimurph/helloworld

        cd helloworld

        hg update -r 2
    

Refactoring

The examples I provided in part 1 were sufficient for demonstrating individual bundles written in Java, Groovy and Scala that could stand on their own. However, the way our interfaces are currently coded would force the bundles to explicitly import each other in order to interact. We don't want our bundles to be so tightly coupled so we'll embark on a bit of refactoring.

We're going to factor our Hello interface out into its own bundle. Remember that an OSGi bundle is, in its simplest form, just a JAR that incorporates OSGi-specific headers in the MET-INF/MANIFEST.MF. Continuing with the hello world theme, we'll call this bundle hello-osgi. Just as in Part 1, we'll let Maven and Pax do the dirty work. From the root directory of the project, execute:

        mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=com.domain.osgi -DbundleName=hello-osgi
    

Our interface can be in any language you'd like. It's all bytecode at the end of the day. I've elected to use Scala for no particular reason. This interface is identical to the one used in Part 1 with the exception of the package declaration. We'll go ahead and remove the generated code under hello-osgi/src/main/java* and create ./hello-osgi/src/main/scala/com/domain/osgi/HelloOsgiService.scala like so:

        package com.domain.osgi
        
        trait HelloOsgiService {
          def hello()
        }
    

As a result of this new factored out interface as well as the introduction of Spring DM, there are several bits that we can now simply remove from our bundles. create-bundle generated a readme.txt file to help you get your bearings. My OCD won't allow me to leave a file in the source tree that's no longer useful so that's got to go. Our classes that implement the BundleActivator class will no longer be required since Spring DM provides it's own mechanisms for lifecycle management which we'll get to shortly. And since we were only using the BND configuration files to declare our BundleActivator classes, that too can go. Finally, the interfaces in each bundle have now been replaced by the HelloOsgiService trait above. All of this will allow us to prune 14 files from our source tree. Here's the final listing showing what should be removed:

        rm hello-osgi/src/main/resources/readme.txt;
        rm hello-osgi/osgi.bnd;

        rm hello-java/src/main/java/com/domain/osgi/java/HelloJavaService.java;
        rm hello-java/src/main/java/com/domain/osgi/java/internal/HelloJavaActivator.java;
        rm hello-java/src/main/resources/readme.txt;
        rm hello-java/osgi.bnd;

        rm hello-groovy/src/main/groovy/com/domain/osgi/groovy/HelloGroovyService.groovy;
        rm hello-groovy/src/main/groovy/com/domain/osgi/groovy/internal/HelloGroovyActivator.groovy;
        rm hello-groovy/src/main/resources/readme.txt;
        rm hello-groovy/osgi.bnd;

        rm hello-scala/src/main/scala/com/domain/osgi/scala/HelloScalaService.scala;
        rm hello-scala/src/main/scala/com/domain/osgi/scala/internal/HelloScalaActivator.scala;
        rm hello-scala/src/main/resources/readme.txt;
        rm hello-scala/osgi.bnd;
    

One final bit of work we need to do for this example is to ensure that Maven is using JDK 1.5 for compilation. This is easily accomplished by updating ./poms/compiled/pom.xml to include:

        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <source>1.5</source>
            <target>1.5</target>
          </configuration>
        </plugin>
    

Introduce a Dependency on the hello-osgi Bundle

After purging all of those files, we now have a bunch of code that won't compile. To get back on track, we'll use the mvn pax:import-bundle command so that hello-java, hello-groovy and hello-scala all depend on the hello-osgi-bundle. Change into ./hello-java/, ./hello-groovy/, and ./hello-scala/ respectively and execute the following:

        mvn pax:import-bundle -DgroupId="com.domain.osgi.helloworld" -DartifactId="hello-osgi" -Dversion="1.0-SNAPSHOT"
    

Once that's done, we'll update each of our implementation classes so that they implement our new interface and define a member variable so we can inject a HelloOsgiService.

Java Service

Here's our refactored HelloJavaServiceImpl. It's a nice simple POJO.

./hello-java/src/main/java/com/domain/osgi/java/internal/HelloJavaServiceImpl.java

        package com.domain.osgi.java.internal;
        
        import com.domain.osgi.HelloOsgiService;
        
        public final class HelloJavaServiceImpl implements HelloOsgiService {
            
            private HelloOsgiService helloOsgiService;
            
            public void hello() {
                System.out.println("Hello, in Java");
            }
            
            public void start() {
                if (helloOsgiService != null) {
                    helloOsgiService.hello();
                } else {
                    System.out.println("No service available to greet the java bundle");
                }
            }
            
            public void setHelloOsgiService(HelloOsgiService helloOsgiService) {
                this.helloOsgiService = helloOsgiService;
            }
            
        }
    

Groovy Service

Here's the updated Groovy implementation. It's a little more concise, but does the same as our Java implementation.

./hello-groovy/src/main/groovy/com/domain/osgi/groovy/internal/HelloGroovyServiceImpl.groovy

        package com.domain.osgi.groovy.internal
        
        import com.domain.osgi.HelloOsgiService
        
        class HelloGroovyServiceImpl implements HelloOsgiService {
            
            def helloOsgiService
            
            void hello() {
                println "Hello, in Groovy"
            }
            
            void start() {
                if (helloOsgiService != null) {
                    service.hello()
                } else {
                    println("No service available to greet the groovy bundle")
                }
            }
            
        }
    

Scala Service

Our refactored Scala service does have some interesting bits to discuss.

./hello-scala/src/main/scala/com/domain/osgi/scala/internal/HelloScalaServiceImpl.scala

        package com.domain.osgi.scala.internal;
        
        import reflect.BeanProperty
        
        import com.domain.osgi._
        
        class HelloScalaServiceImpl extends HelloOsgiService {
          
          @BeanProperty
          var helloOsgiService:HelloOsgiService = null
          
          def hello() = {
            Console.println("Hello, in Scala")
          }
          
          def start() = {
            if (helloOsgiService != null) {
              helloOsgiService.hello()
            } else {
              Console.println("No service available to greet the scala bundle")
            }
          }
          
        }
    

Spring DM relies on the JavaBeans pattern for dependency injection. Scala employs property access rather than JavaBeans style accessors so we'll want to provide a quick work around using scala.reflect.BeanProperty. The instance property, helloOsgiService is defined as a var so it's mutable and is annotated with @BeanProperty so that the generated bytecode contains a getter accessor and setter mutator. Without @BeanProperty, you would need to write your own setter like so:

        def setHelloOsgiService(helloOsgiService:HelloOsgiService):Unit = {
          this.helloOsgiService = helloOsgiService
        }
    

Service Consumption with Spring DM

Now that we've refactored our code base, we'll return to our Spring configurations. We've worked our way through a lot of concepts and we're now ready to configure these services to interact with each other. For demonstration purposes, our Java service will consume the Scala service and our Scala service will consume the Groovy service. The Groovy service won't consume any other services because we need to be careful to avoid circular dependencies.

Since we know that we're publishing multiple services that adhere to the same interface, we'll set properties (name / value pairs) that clients may use as a discriminator when consuming our services. This is a painless process with Spring DM courtesy of the service-properties tag. Update the bundle-context-osgi.xml configuration for Groovy so that our service specifies that its language is groovy.

./hello-groovy/src/main/resources/META-INF/spring/bundle-context-osgi.xml

        <beans:beans xmlns="http://www.springframework.org/schema/osgi" 
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <service ref="helloGroovyService" interface="com.domain.osgi.HelloOsgiService">
                <service-properties>
                    <beans:entry key="language" value="groovy"></beans:entry>
                </service-properties>
            </service>
            
        </beans:beans>
    

In Spring DM, we can get a handle on a service from the OSGi service registry using the reference declaration. The reference declaration requires a unique id and the fully qualified interface that the service is published under. The optional filter attribute is used to specify an OSGi filter expression to bind only the service instance we want. Here's how our bundle-context-osgi.xml configuration evolves for our Scala bundle.

./hello-scala/src/main/resources/META-INF/spring/bundle-context-osgi.xml

        <beans:beans xmlns="http://www.springframework.org/schema/osgi" 
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <reference id="helloOsgiService" interface="com.domain.osgi.HelloOsgiService" filter="(language=groovy)">
            </reference>
            
            <service ref="helloScalaService" interface="com.domain.osgi.HelloOsgiService">
                <service-properties>
                    <beans:entry key="language" value="scala"></beans:entry>
                </service-properties>
            </service>
            
        </beans:beans>
    

Our Java configuration follows the same structure as our Scala configuration.

./hello-java/src/main/resources/META-INF/spring/bundle-context-osgi.xml

        <beans:beans xmlns="http://www.springframework.org/schema/osgi" 
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <reference id="helloOsgiService" interface="com.domain.osgi.HelloOsgiService" filter="(language=scala)">
            </reference>
            
            <service ref="helloJavaService" interface="com.domain.osgi.HelloOsgiService">
                <service-properties>
                    <beans:entry key="language" value="java"></beans:entry>
                </service-properties>
            </service>
            
        </beans:beans>
    

Lifecycle Management with Spring DM

As I mentioned previously, we're no longer making use of BundleActivators and will instead rely upon Spring DM to manage the lifecycle of our bundles. The Spring DM extender finds bundles in the RESOLVED state and initializes the bundle's spring context. We can make use of the init-method declaration to specify what code should be executed when our beans are instantiated. Update bundle-context.xml for the Groovy bundle so that the start() method is called when the bundle is started.

./hello-groovy/src/main/resources/META-INF/spring/bundle-context.xml

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                                      http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloGroovyService" class="com.domain.osgi.groovy.internal.HelloGroovyServiceImpl" init-method="start">
            </bean>
            
        </beans>
    

Next, add init-method="start" for the Scala service implementation. This is also where we ensure that the Groovy reference declaration we defined above gets injected.

./hello-scala/src/main/resources/META-INF/spring/bundle-context.xml

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                                      http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloScalaService" class="com.domain.osgi.scala.internal.HelloScalaServiceImpl" init-method="start">
                <property name="helloOsgiService" ref="helloOsgiService"></property>
            </bean>
            
        </beans>
    

Finally, we'll configure an init-method for our Java service implementation and we inject the Scala service.

./hello-java/src/main/resources/META-INF/spring/bundle-context.xml

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                                      http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloJavaService" class="com.domain.osgi.java.internal.HelloJavaServiceImpl" init-method="start">
                <property name="helloOsgiService" ref="helloOsgiService"></property>
            </bean>
            
        </beans>
    

Provision One Last Time

Let's call upon Maven and PAX on last time to see our bundles in action.

        mvn install pax:provision -Dprofiles=spring.dm
    

If everything has gone according to plan, you'll see the output from each bundle's start method buried in between all the DEBUG logging that Spring DM spits out.

        ...
        
        [SpringOsgiExtenderThread-4] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking init method  'start' on bean with name 'helloGroovyService'
        No service available to greet the groovy bundle
        
        ...
        
        [SpringOsgiExtenderThread-5] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking init method  'start' on bean with name 'helloScalaService'
        Hello, in Groovy
        
        ...
        
        [SpringOsgiExtenderThread-6] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking init method  'start' on bean with name 'helloJavaService'
        Hello, in Scala
        ...
    

I'd encourage you to play around with the configurations and see how easy it is to have these three services consume each other.

Conclusion

In this post we refactored the bundles we built in parts 1 and 2 to ensure that our final product would be loosely coupled and got a feel for how one can consume OSGi services with Spring DM. In addition, thanks to Spring DM, we didn't have to code against the OSGi API directly /at all/. We also saw how simply we could define an interface that can be implemented in a variety of languages with minimal code or configuration magic. Throughout this series, we've seen how useful the offerings from the OPS4J folks are for developing OSGi applications all the while leaning heavily on Maven for managing our runtime. We've only scratched the surface however. There seem to be several books popping up that go much deeper on the subject of OSGi with Spring Dynamic Modules and the push to use these technologies for web development continues to drive innovation. I'm very curious to see how long it will take adoption to catch up with the buzz.

Wednesday, July 15, 2009

Publishing Scala, Groovy and Java OSGi Bundles with Spring DM

In Part 1 of this series, we used Maven and PAX to set up and run an OSGi project with three hello world bundles; one for Java, one for Groovy and one for Scala. This time around, I'd like to show you how to incorporate Spring Dynamic Modules so we can build a Spring application that is deployed in an OSGi framework. Spring DM will help maintain a clean separation of our bundles in addition to abstracting away the plumbing normally required for developing OSGi applications.

There have been minor releases for several of the components highlighted in this tutorial including Pax Runner and Scala since the last post. In the interest of consistency, I'm not going to upgrade anything at this point. The only new component we're adding is version 1.2.0 of Spring DM.

If you'd prefer to look at the code as you go, you can grab it from bitbucket. Be sure to update your working copy to revision 1 to see the code as it would look at the completion of this second article in the series.

        hg clone http://bitbucket.org/brimurph/helloworld

        cd helloworld

        hg update -r 1
    

Spring Dynamic Modules for OSGi

Using Spring DM implies that we're using Spring framework JARs as OSGi bundles as well as these OSGi Spring bundles: spring-osgi-extender, spring-osgi-core, spring-osgi-io and spring-osgi-annotation.

The first thing we need to do is update our maven configuration to include the SpringSource Enterprise Bundle Repository.

        mvn pax:add-repository -DrepositoryId=com.springsource.repository.bundles.release -DrepositoryURL=http://repository.springsource.com/maven/bundles/release
        
        mvn pax:add-repository -DrepositoryId=com.springsource.repository.bundles.external -DrepositoryURL=http://repository.springsource.com/maven/bundles/external
    

When the Spring DM Extender bundle is started, it examines all of the resolved OSGi bundles to determine if they contain a Spring context. META-INF/spring is the default location the Spring DM extender will scan looking for these application context definition files so let's create that directory for each bundle:

        mkdir -p hello-java/src/main/resources/META-INF/spring;
        mkdir -p hello-groovy/src/main/resources/META-INF/spring;
        mkdir -p hello-scala/src/main/resources/META-INF/spring;
    

Within each bundle, we'll create two spring definition files. We want to separate our basic bean definitions from those that need to be defined within an OSGi namespace. This convention is especially useful when writing tests as it allows you to draw a distinction between tests that must take place within an OSGi framework and those that may take place outside of OSGi. bundle-context.xml will be our standard Spring configuration and bundle-context-osgi.xml will contain Spring DM specific configuration.

Publishing Hello Java with Spring DM

In the vanilla spring context configuation, ./hello-java/src/main/resources/META-INF/spring/bundle-context.xml, we define our POJO implementation.

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloJavaService" class="com.domain.osgi.java.internal.HelloJavaServiceImpl">
            </bean>
            
        </beans>
    

And in the file ./hello-java/src/main/resources/META-INF/spring/bundle-context-osgi.xml we will define our helloJavaService service for consumption by other bundles. This service definition refers to the implementation above.

        <beans:beans xmlns="http://www.springframework.org/schema/osgi"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <service ref="helloJavaService" interface="com.domain.osgi.java.HelloJavaService">
            </service>
            
        </beans:beans>
    

That's all there is to it. helloJavaService will be published by Spring DM without any need to use the OSGi API directly.

Publishing Hello Groovy with Spring DM

The configuration for Groovy is identical to what we've done for Java. We simply reference the Groovy code that parallels our Java example.

./hello-groovy/src/main/resources/META-INF/spring/bundle-context.xml

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloGroovyService" class="com.domain.osgi.groovy.internal.HelloGroovyServiceImpl">
            </bean>
            
        </beans>
    

./hello-groovy/src/main/resources/META-INF/spring/bundle-context-osgi.xml

        <beans:beans xmlns="http://www.springframework.org/schema/osgi"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <service ref="helloGroovyService" interface="com.domain.osgi.groovy.HelloGroovyService">
            </service>
            
        </beans:beans>
    

Publishing Hello Scala with Spring DM

Our scala configuration follows suit. It's exactly the same as both our Java and Groovy configurations. This is all nice and simple to get going.

./hello-scala/src/main/resources/META-INF/spring/bundle-context.xml

        <beans xmlns="http://www.springframework.org/schema/beans"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns:p="http://www.springframework.org/schema/p"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans
                  http://www.springframework.org/schema/beans/spring-beans.xsd">
            
            <bean id="helloScalaService" class="com.domain.osgi.scala.internal.HelloScalaServiceImpl">
            </bean>
            
        </beans>
    

./hello-scala/src/main/resources/META-INF/spring/bundle-context-osgi.xml

        <beans:beans xmlns="http://www.springframework.org/schema/osgi"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:beans="http://www.springframework.org/schema/beans"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                                            http://www.springframework.org/schema/beans/spring-beans.xsd
                                            http://www.springframework.org/schema/osgi
                                            http://www.springframework.org/schema/osgi/spring-osgi.xsd">
            
            <service ref="helloScalaService" interface="com.domain.osgi.scala.HelloScalaService">
            </service>
            
        </beans:beans>
    

Putting It All Together

At this point, the basics are in place. Once again, PAX is really going to shine as we'll install and provision our bundles. Aside from adding the appropriate Spring repositories in the beginning of this post, we haven't done anything to satisfy the Spring DM dependencies. Thanks to PAX Runner's notion of profiles we can provision all of the bundles required for Spring DM with a simple command line switch:

Update: Newer versions of PAX Runner don't install the compendium bundle by default so we need to explicitly import it:

        pax-import-bundle -g org.osgi -a org.osgi.compendium -v 4.2.0
    

Then we can safely start everything up with pax:provision:

        mvn install pax:provision -Dprofiles=spring.dm
    

Voilà! As the logging indicates, Maven was able to fetch all the bundles we require and our three services have been published by Spring DM.

        ...
        
        [SpringOsgiExtenderThread-5] INFO org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean - Publishing service under classes [{com.domain.osgi.scala.HelloScalaService}]
        
        ...
        
        [SpringOsgiExtenderThread-4] INFO org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean - Publishing service under classes [{com.domain.osgi.groovy.HelloGroovyService}]
        
        ...
        
        [SpringOsgiExtenderThread-6] INFO org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean - Publishing service under classes [{com.domain.osgi.java.HelloJavaService}]
        
        ...
    

Conclusion

We've seen how we can incorporate Spring DM to completely abstract away the OSGi API for defining and publishing OSGi services. Spring DM is wiring our bundles together using compiled bytecode so we needn't do anything fancy whether we're using use Java, Groovy, Scala or any other language than may be run on the JVM. Up next, we'll walk through the Spring DM configuration for consuming these services.

Check out Part 3 here

Wednesday, May 6, 2009

OSGi With Scala, Java, Groovy, Maven and PAX

In this first installment, I'm going to attempt to walk you through the setup of an OSGi project that is comprised of three OSGi bundles; one for Java, one for Groovy and one for Scala. In an effort to keep it simple, I'm going to employ a trivial hello world example in each bundle. The emphasis of this post is to introduce some concepts and illustrate how to get an environment up and running. I'm going to leverage maven and the extremely useful PAX maven plugin to automate much of the grunt setup work, packaging and runtime management. In subsequent posts, I'll show how we can leverage Spring DM to eliminate the OSGi API from our code and I'll show how to get these bundles to actually interact with each other.

I think that OSGi has an enormous amount of potential. There are many high profile commercial and open source projects that make exceptional use of the framework already. The buzz is finally catching up and support for OSGi from a tooling and bundle availability standpoint continue to improve. I think Patrick Paulin's recent post addressing the question Why is OSGi Important sums things up nicely.

These technologies are all advancing at a pretty rapid pace, so in an attempt to future-proof this post I'd like to take a quick moment to identify precisely what versions I'm using for these toolsets. From a maven perspective, I'm using version 2.0.10 of maven itself, version 1.0-rc5 of the gmaven-plugin and the gmaven-runtime-1.6, version 2.9.1 of the maven-scala-plugin and version 1.4 of the maven-pax-plugin. I'm also using java version 1.5.0_16 on Mac OS X with Groovy 1.6.2 and Scala 2.7.4.

If you'd prefer to look at the code as you go, you can grab it from bitbucket. Be sure to update your working copy to revision 0 to see the code as it would look at the completion of this first article.

        hg clone http://bitbucket.org/brimurph/helloworld

        cd helloworld

        hg update -r 0
    

Java

OK. enough with the words. Let's get into some code. As I mentioned, we're going to leverage PAX to automate a lot of the boilerplate maven setup work. Please be sure that you've got maven installed and that it's in your $PATH. The first step is to go ahead and create our project.

        mvn org.ops4j:maven-pax-plugin:create-project -DgroupId=com.domain.osgi -DartifactId=helloworld -Dversion=1.0-SNAPSHOT
    

I'd encourage you at this point to peruse everything that pax generated. There's a parent pom.xml that outlines the settings for the maven-pax-plugn. It also defines maven modules named poms and provision. The poms module goes on to define two more modules for wrappers and compiled. I have a love / hate relationship with maven. There's an enourmous amount of flexibility provided, but it comes at a cost of complexity. I could devote entire articles detailing the ins and outs of all the configuration options provided by the various pom.xml files created. Fortunately, as you'll see throughout this article, PAX will do most of the dirty work for us.

An OSGi project generated by PAX may contain 1 or more bundles. Each bundle we create simply gets registered as another independent maven module. To get started, cd into the helloworld project directory that PAX created and issue the following command to create a bundle:

        mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=com.domain.osgi.java -DbundleName=hello-java
    

That's it. We now have a fully functional Java OSGi bundle. It can be compiled and run as is. Feel free to peruse what was generated and see what the ExampleService is all about before proceeding.

For our purposes, I'd like to remove the generated code so we can start anew. cd into the helloworld/hello-java bundle directory that PAX created and let's tidy up and then write some Java code.

        rm -rf src/main/java;
        
        mkdir -p src/main/java/com/domain/osgi/java/internal;
        
        cd src/main/java/com/domain/osgi/java;
    

First up, we'll create an interface named HelloJavaService.java. This interface will be registered and exposed in our OSGi BundleContext.

        package com.domain.osgi.java;
        
        public interface HelloJavaService {
            void hello();
        }
    

Again, this is a trivial example. All we're doing is defining a hello() method with no return value. Notice that there's nothing about this interface that is specific to OSGi. Next we'll cd into the internal package and create an implementation of our service named HelloJavaServiceImpl.java

        package com.domain.osgi.java.internal;
        
        import com.domain.osgi.java.HelloJavaService;
        
        public final class HelloJavaServiceImpl implements HelloJavaService {
            
            public void hello() {
                System.out.println("Hello, in Java");
            }
        }
    

Here we implement our HelloJavaService and say hello to System.out. Things are still very straight forward with no traces of OSGi code. Now let's create a BundleActivator named HelloJavaActivator.java so that we can actually register our service for consumption by other bundles.

        package com.domain.osgi.java.internal;
        
        import org.osgi.framework.BundleActivator;
        import org.osgi.framework.BundleContext;
        import org.osgi.framework.ServiceRegistration;
        
        import com.domain.osgi.java.HelloJavaService;
        
        public final class HelloJavaActivator implements BundleActivator {
            
            ServiceRegistration serviceRegistration;
            
            public void start(BundleContext bundleContext) throws Exception {
                System.out.println("STARTING com.domain.osgi.java");
                serviceRegistration = bundleContext.registerService(HelloJavaService.class.getName(), new HelloJavaServiceImpl(), null);
                System.out.println("REGISTERED com.domain.osgi.java.HelloJavaService");
            }
            
            public void stop(BundleContext bundleContext) throws Exception {
                System.out.println("STOPPING com.domain.osgi.java");
                serviceRegistration.unregister();
                System.out.println("UNREGISTERED com.domain.osgi.java.HelloJavaService");
            }
            
        }
    

Here things get a bit more interesting. org.osgi.framework.BundleActivator is an interface that may be implemented when a bundle is started or stopped. In the start method, we're registering our service with the framework via the BundleContext. Then we tie up all the loose ends in the stop method. Note that unregistering the service in the stop method isn't really required since the OSGi life cycle will manage that automatically.

Lastly, we'll need to update the osgi.bnd file in the root bundle directory; hello-java. The Bundle-Activator property was automatically generated by PAX and pointed to the Activator class that was automatically generated. Update it as follows so that our HelloJavaActivator implementation will be invoked when our bundle is started or stopped.

        #-----------------------------------------------------------------
        # Use this file to add customized Bnd instructions for the bundle 
        #-----------------------------------------------------------------
        
        Bundle-Activator: ${bundle.namespace}.internal.HelloJavaActivator
    

Now let's start things up with PAX Runner which will leverage Felix by default. This is accomplished with the pax:provision maven goal. In order for our bundle to be accessible at runtime, we need to package it up and install it in our local maven repository. Thanks to maven and the pax plugin, this is all accomplished with a simple one line command:

        mvn install pax:provision
        
        ...
        
        Welcome to Felix.
        =================
        
        -> STARTING com.domain.osgi.java
        REGISTERED com.domain.osgi.java.HelloJavaService
    

If you've done everything properly, and I haven't neglected any important details in this blog post, you should see the output from our start method in your BundleActivator. Now go ahead and execute the shutdown command to exit out of Felix and return to your shell:

        -> shutdown
        -> STOPPING com.domain.osgi.java
        UNREGISTERED com.domain.osgi.java.HelloJavaService
    

Good stuff so far. I won't dwell on it here, since folks like Craig Walls have covered it so well, but another huge advantage of using PAX is that it makes switching between the various OSGi frameworks incredibly simple. pax:provision is utilizing Pax Runner behind the scenes. Using the --platform switch (-Dframework=equinox in maven), you can easily fire up this example in Equinox or Knopflerfish or Concierge without /any/ changes to your code or configuration. I think that speaks volumes about the maturity of OSGi. Let's not forget that OSGi has been around for 10 years now! Don't be fooled by the nay-sayers who claim that OSGi isn't ready for prime time.

Groovy

So we've got a pretty cool little Java OSGi bundle working. But that's not why you're here. You're thinking beyond Java and the cool kids are talking your ears off about all these other languages that you can leverage on the JVM like Groovy, Scala, Fan, Clojure, JRuby, Jython, etc, etc, etc. And all these new toys are touting big productivity gains to boot. I'm not going to weigh in on which language you should use. I had to limit the scope of this article, so I selected the languages that I'm already using regularly.

So let's branch out and set up a bundle using Groovy. First, be sure to cd back to the helloworld project root directory and then execute:

        mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=com.domain.osgi.groovy -DbundleName=hello-groovy
    

As before, PAX will happily go ahead and create a new bundle for us. However, the out of the box PAX stuff is very Java-centric. As such, there are several modifications that must be made to our maven configuration to get Groovy working. First, in order to get compilation working for Groovy scripts, add the following gmaven-plugin definition into the <plugins> section of the helloworld/poms/compiled/pom.xml file.

        <plugin>
          <groupId>org.codehaus.groovy.maven</groupId>
          <artifactId>gmaven-plugin</artifactId>
          <version>1.0-rc-5</version>
          <executions>
            <execution>
              <goals>
                <goal>generateStubs</goal>
                <goal>compile</goal>
                <goal>generateTestStubs</goal>
                <goal>testCompile</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
    

Edit the parent pom.xml file located at helloworld/pom.xml and add a <dependency> for gmaven-runtime-1.6 like so:

        <dependency>
          <groupId>org.codehaus.groovy.maven.runtime</groupId>
          <artifactId>gmaven-runtime-1.6</artifactId>
          <version>1.0-rc-5</version>
        </dependency>
    

Lastly, we need to add a bundle dependency in order to have a proper Groovy bundle available to the OSGi framework at runtime.

        mvn pax:import-bundle -DgroupId=org.codehaus.groovy -DartifactId=groovy-all -Dversion=1.6.2
    

That will add the following to helloworld/provision/pom.xml:

        <dependencies>
          <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>1.6.2</version>
          </dependency>
        </dependencies>
    

With the maven configuration out of the way, cd into your hello-groovy bundle remove the generated Java sources and then we'll add 3 groovy scripts that are analogous to the Java classes we added earlier. Note that there are quite a number of ways you could package all of this stuff up to reduce the number of lines of code. I'm showing complete examples, each broken into their own bundle, so that you could take any one of these bundle examples independently and be off and running.

        rm -rf src/main/java;
        
        mkdir -p src/main/groovy/com/domain/osgi/groovy/internal;
        
        cd src/main/groovy/com/domain/osgi/groovy;
    

Here's our HelloGroovyService.groovy interface:

        package com.domain.osgi.groovy
        
        interface HelloGroovyService {
            void hello()
        }
    

And the corresponding HelloGroovyServiceImpl.groovy implementation:

        package com.domain.osgi.groovy.internal
        
        import com.domain.osgi.groovy.HelloGroovyService
        
        class HelloGroovyServiceImpl implements HelloGroovyService {
            void hello() {
                println "Hello, from Groovy"
            }
        }
    

Then we'll create our HelloGroovyActivator.groovy script. There's another small catch related to Groovy and OSGi. As noted in the Groovy documentation, publishing an OSGi service written in Groovy requires one extra step that a Java service does not. This is because of the way Groovy makes extensive use of ClassLoaders and reflection. When registering a service with the BundleContext, you must be sure to temporarily set the current thread's ContextClassLoader to the target object's ClassLoader, and then set it back when you're done.

        package com.domain.osgi.groovy.internal
        
        import org.osgi.framework.BundleActivator
        import org.osgi.framework.BundleContext
        import org.osgi.framework.ServiceRegistration
        
        import com.domain.osgi.groovy.HelloGroovyService
        
        class HelloGroovyActivator implements BundleActivator {
            
            ServiceRegistration serviceRegistration
            
            void start(BundleContext bundleContext) {
                ClassLoader originalClassLoader = Thread.currentThread().contextClassLoader
                try {
                    println "STARTING com.domain.osgi.groovy"
                    
                    Thread.currentThread().contextClassLoader = getClass().classLoader
                    HelloGroovyService helloGroovyService = new HelloGroovyServiceImpl()
                    serviceRegistration = bundleContext.registerService(HelloGroovyService.class.getName(), helloGroovyService, null)
                    
                    println "REGISTERED com.domain.osgi.groovy.HelloGroovyService"
                } finally {
                    Thread.currentThread().contextClassLoader = originalClassLoader
                }
            }
            
            void stop(BundleContext bc) {
                println "STOPPING com.domain.osgi.groovy"
                serviceRegistration.unregister()
                println "UNREGISTERED com.domain.osgi.groovy.HelloGroovyService"
            }
            
        }
    

Aside from the Classloader wizardry, this BundleActivator code should feel very familiar given the Java example above. Our final step is to update the helloworld/hello-groovy/osgi.bnd configuration so that everything gets packaged up properly:

        #-----------------------------------------------------------------
        # Use this file to add customized Bnd instructions for the bundle 
        #-----------------------------------------------------------------
        
        Bundle-Activator: ${bundle.namespace}.internal.HelloGroovyActivator
    

Then go ahead and fire everything up once more.

        mvn install pax:provision
        
        ...
        
        Welcome to Felix.
        =================
        
        -> STARTING com.domain.osgi.java
        REGISTERED com.domain.osgi.java.HelloJavaService
        STARTING com.domain.osgi.groovy
        REGISTERED com.domain.osgi.groovy.HelloGroovyService
    

And then shut everything down once more.

        -> shutdown
        -> STOPPING com.domain.osgi.groovy
        UNREGISTERED com.domain.osgi.groovy.HelloGroovyService
        STOPPING com.domain.osgi.java
        UNREGISTERED com.domain.osgi.java.HelloJavaService
    
Scala

I'm not going to get into any detail on the language specifics for Scala. If you're coming from a Java background and you're interested in a primer I would highly recommend Daniel Spiewak's series on Scala for Java Refugees.

We've been through the creation of two bundles so far so I'll pick up the pace a bit. The mechanics to generate the bundle are the same:

       mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=com.domain.osgi.scala -DbundleName=hello-scala
    

We'll need to remove the Java sources and set up our package structure for Scala:

        rm -rf src/main/java;
        
        mkdir -p src/main/scala/com/domain/osgi/scala/internal;
        
        cd src/main/scala/com/domain/osgi/scala;
    

Then, to get compilation working for Scala, re-edit the helloworld/poms/compiled/pom.xml file and add the maven-scala-plugin.

        <plugin>
            <groupId>org.scala-tools</groupId>
            <artifactId>maven-scala-plugin</artifactId>
            <version>2.9.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>testCompile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    

The parent pom.xml file in the helloworld project directory gets tweaked to add a <dependency> for scala-library like so:

        <dependency>
            <groupId>org.scala-lang-osgi</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.7.4</version>
        </dependency>
    

As with our Groovy configuration, we need to add a bundle dependency in order to have a proper Scala bundle available to the OSGi framework at runtime.

        mvn pax:import-bundle -DgroupId=org.scala-lang-osgi -DartifactId=scala-library -Dversion=2.7.4
    

That will add the following to helloworld/provision/pom.xml:

        <dependency>
            <groupId>org.scala-lang-osgi</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.7.4</version>
        </dependency>
    

And then we'll stamp out some code:

HelloScalaService.scala:

        package com.domain.osgi.scala
        
        trait HelloScalaService {
          def hello()
        }
    

HelloScalaServiceImpl.scala:

        package com.domain.osgi.scala.internal
        
        import com.domain.osgi.scala._
        
        class HelloScalaServiceImpl extends HelloScalaService {
            def hello() = {
                Console.println("Hello, from Scala")
            }
        }
    

HelloScalaActivator.scala:

        package com.domain.osgi.scala.internal
        
        import org.osgi.framework._
        import com.domain.osgi.scala.HelloScalaService
        
        class HelloScalaActivator extends BundleActivator {
          
          var serviceRegistration:ServiceRegistration = _
          
          def start(bundleContext: BundleContext) {
            Console.println("STARTING com.domain.osgi.scala")
            serviceRegistration = bundleContext.registerService("com.domain.osgi.scala.HelloScalaService", new HelloScalaServiceImpl(), null)
            Console.println("REGISTERED com.domain.osgi.scala.internal.HelloScalaService")
          }
          
          def stop(context: BundleContext) {
            Console.println("STOPPED com.domain.osgi.scala")
            if (serviceRegistration != null) serviceRegistration.unregister
            Console.println("UNREGISTERED com.domain.osgi.scala.internal.HelloScalaService")
          }
          
        }
    

As with the previous bundles, our final step is to update the helloworld/hello-scala/osgi.bnd configuration so that it reads:

        #-----------------------------------------------------------------
        # Use this file to add customized Bnd instructions for the bundle 
        #-----------------------------------------------------------------
        
        Bundle-Activator: ${bundle.namespace}.internal.HelloScalaActivator
    

While we didn't need to jump through any coding hoops for Scala in the way we did for Groovy, there's /is/ one final maven configuration detail that we need to wrangle before this Scala example will work. If you were paying really close attention, you may have noticed that the Scala OSGi bundle that we imported had a groupId of org.scala-lang-osgi. At the time of this writing, the scala jars aren't packaged with OSGi support. Proper support is forthcoming, but in the mean time, the good folks behind Scala are releasing jars in parallel that /do/ work with OSGi. In order to pick those up, we need to add the scala-tools.org repository to our project. A quick call to pax:add-repository from the parent helloworld project directory will save some typing.

        mvn pax:add-repository -DrepositoryId=scala-tools.org -DrepositoryURL=http://scala-tools.org/repo-releases
    

This repository definition will be appended to your pom.xml.

        <repositories>
          <repository>
            <id>scala-tools.org</id>
            <url>http://scala-tools.org/repo-releases</url>
            <snapshots>
              <enabled>false</enabled>
            </snapshots>
          </repository>
        </repositories>
    

Now, we can install and provision one last time to see all three bundles activated.

        mvn install pax:provision
        
        ...
        
        Welcome to Felix.
        =================
        
        -> STARTING com.domain.osgi.java
        REGISTERED com.domain.osgi.java.HelloJavaService
        STARTING com.domain.osgi.groovy
        REGISTERED com.domain.osgi.groovy.HelloGroovyService
        STARTING com.domain.osgi.scala
        REGISTERED com.domain.osgi.scala.internal.HelloScalaService
    

As expected, issuing the shutdown command will yield all the proper shutdown messaging.

        -> shutdown
        -> STOPPED com.domain.osgi.scala
        UNREGISTERED com.domain.osgi.scala.internal.HelloScalaService
        STOPPING com.domain.osgi.groovy
        UNREGISTERED com.domain.osgi.groovy.HelloGroovyService
        STOPPING com.domain.osgi.java
        UNREGISTERED com.domain.osgi.java.HelloJavaService
    

Conclusion

This ended up being a much longer article than I anticipated but we've covered a lot of ground. Maven has worked it's dependency voodoo which saved an enormous amount of time downloading jars and messing with classpaths. We've seen how the PAX toolkit from OPS4J makes creating, modifying and provisioning OSGi bundles a breeze. While the actual code examples were pretty trivial, we successfully managed to code up bundles in Java, Scala and Groovy. I think this displays a lot of the power that is offered by OSGi and points to a bright future for enterprise development on the JVM.

Check out Part 2 here

Tuesday, January 27, 2009

println "hello, world"

So I'm going to take the plunge and see if this whole weblogging thing is for me. I've been in the field of software development for quite a few years now, and I think I know a thing or two about a thing or two. I offer to my future reader (hi mom!) a vague assurance that the "insight" captured here comes straight from an authentic walking, talking Dilbert comic strip.

Dilbert.com

You see, as a Java guy, some would argue that I was never a real coder. But I'm a Manager now baby! So I spend my days getting in the way of folks who do real work. In an effort to cement the reputation of do-nothing managers everywhere, I shall set out to prove that we have lots of time on our hands to blog away when we're not surfing for pr0n or harassing our minions for TPS reports. We'll see if my cynical and sarcastic views of the world will entertain anyone else enough to find and frequent my little corner of the web.

So what's with the name? Turmoil a word that I've been fond of for a long, long time. Defined as a state of great disturbance, confusion, or uncertainty; it was the perfect fit for an online gaming identity. So it became my handle from 1993 until just a few years ago. My online gaming ranged from a mechanized warfare game called CyberStrike to a host of FPS games like Quake and Tribes to the John Madden Football series on PS2. It became readily apparent that playing said games competitively online with all the young whippersnappers simply wasn't something that I could accomplish without devoting mass amounts of practice time, so it had to go. And yes, that means I was losing. I'm fiercely competitive. I don't like losing. I do miss playing though. It's greatly rewarding to punish your opponent in a game like Madden, all the while trash talking the 12 year old on the other end of the line with your dorky headset on. The time will come to pick up the sticks again. My son is only 3 months old, but I'm putting him on notice now: I will kick your ass in all video games, at all costs.

OK, where the hell was I? Oh yes, the name. So as an engineer working in a world where everyone is regurgitating old ideas with snazzy new names, I think Turmoil Driven Development or TDD is a nice play on Test Driven Development. I also hope it'll be an appropriate name as I blather on about software craftsmanship and managing people because turmoil is synonymous with chaos and while I'm not sure who to credit with the creation of the phrase, I fully prescribe to the assertion that projects should live on the Chaordic Edge. To paraphrase, a project is most healthy when it is perfectly teetering on the very fine edge between chaos and order. There's just enough adrenaline and uncertainty flying about to keep folks engaged and pissed off but there's also just the right amount of process and oversight to make sure that the team doesn't kill each other on their way to producing software art.