Search

Recent Posts

Authors

Archives

Blogroll

Subscribe

Is your Internet slow? US != #1 ∴ Change your perception

Why do we always have to be #1? I’ve never understood it – the drive to call yourself #1 – when clearly it is only fleeting or a delusion in the first place (pun intended).

Here’s an example – do you think the US has the fastest Internet speeds? Are we #1? We invented the damn thing (well, Al Gore did and he was almost a US president). Why shouldn’t we have the best internet? It’s our right. Who could possibly touch us in download speed?

Well the facts are not what perception might lead you to believe. The US has slow download speeds on average. Not even in the top 3, not the top 10, – yep we make the “also showed” list in the top 20. (2008 data)

My down load speed is great – I pay for Comcast cable and get at times 30 Mbps (30 Mega bits per second – not bytes). Check your download speed with Speakeasy.


According to The Wall Street Journal, “countries like Japan enjoy download speeds of up to 30 times faster than the average in the U.S.” However your results may vary. I see speeds that are fairly good (30 Mbps) which is 17 X faster than the global average of 1.7 Mbps (Akamai Q1 2009). The USA average is 4.2 Mbps. That places us in 18th place behind South Korea at 11 Mbps.

Obama’s stimulus package ($789 Billion) will allocate $7.2 B for broadband funding. Just in case you’re wonder what broadband is defined as – a measly 768 Kbps. So will that raise us to #1? I don’t think so. Well then, where are we #1? Maybe in internet penetration – the number of people using the internet. Yep! We are #1. We are #1. The US has 116 M unique IP addresses compared to #2 China’s 44 M. But hey – no real Fool would just use the raw numbers – that’s not very informative – what about per capita? Well then the US falls into the #6 spot with 0.38 unique IPs per capita, behind Norway at #1 with 0.46. Damn that #1 spot is so fickle, so illusive.

References:
Akamai Q1 2009 http://www.akamai.com/stateoftheinternet/


Software Craftsmanship Manifesto – Yet Another Manifesto?

Reading ‘Managing Agile’ blog – did you hear about a new  Software Craftsmanship Manifesto?

Charl Dreyer ask if we need a clarifying manifesto for the Agile Manifesto. I vote no. You can cast a vote also on his blog. I’m interested in the outcome.

I like what the Craftsmanship group is saying, I think it well said. But just because you were late to the party, don’t try to start your own party. Thereby spiting or confusing the group of party goers.

I also believe they have started in the middle of a conversation. They are clearly (if you know the secret handshake) talking in reference to the Agile Manifesto, but have not given reference to it. If one doesn’t know the Agile Manifesto then the Craftsmanship Manifesto doesn’t have value.  Is it plagiarism?  At the very least it is poor writing, to start without the context.  Where was the editor (the literary craftsman or person) when the manifesto was written?

Now had they invited me to the Agile Manifesto meeting maybe they would have come up with the craftsmanship angle…. Why – because I would have been skiing up at Alta and having a blast. There is real craftsmanship in my tele-turns! Well, we will never know. However I don’t think that we need another manifesto to clarify the one that has been working so well for 8 years.


The Forgotten Scrum Elements

missing-piece

I have worked with many individuals, teams, and organizations in the use of Scrum. During that time, I have found that 2 parts of Scrum continually overlooked in implementation. Since Scrum is already a minimal framework, just enough to keep a team out of chaos, when a piece of Scrum is left out problems are bound to occur. The 2 most common parts that I see left out are:

  • Product Vision
  • Potentially Shippable Product Increment

Product Vision

There are times that I work with a project team and ask what they are going to be developing. If the answer involves a list of requirements and the team has difficulty in describing how what they develop will deliver value then I know there is a missing product vision. This happens more often than you might think. If you want to check if your project team has a common understanding of the vision, do the following with the entire team:

Each person on the team please write down what the software we are delivering will do for its users in 1 paragraph. After we have all written a paragraph, each person on the team shares their understanding with the rest of the team.

If while going around to each team member there is another person on the team who disagrees with the part or all of someone else’s understanding, then your team might not have a product vision. At the very least, the product vision has not been communicated well to the entire project team.

A simple way to generate a product vision is to use the elevator statement template from Geoffrey Moore’s book “Crossing the Chasm”. Here is how it goes:

FOR (customer) WHO (statement of need) THE (product name) IS A (type of product) THAT (has this compelling reason to buy/use). UNLIKE (competitive products) OUR PRODUCT (is differentiated in these ways).

Filling out this elevator statement template with the information in parenthesis with the entire product team will help them get a common understanding of the product’s vision. If the product does not have a coherent vision or through the filling out of this template the value of the product seems to be missing, then this could also show that the project team should not be working on the product. If that is the case then the team could start working on something that will provide more value.

Potentially Shippable Product Increment

Many teams decide not to create potentially shippable software at the end of some sprints. It is difficult for the project team to work in a manner that would produce a potentially shippable product increment. This could be because:

  • Roles on the team are too specialized
  • Lack of motivation to work together
  • Product Backlog items that can be completed by only one person on team
  • Doing “Scrumerfall” or “FrAgile” (meaning design/code/test phases within a sprint cycle)
  • etc..

Create a Definition of Done with the whole project team is a first step to working towards potentially shippable software each sprint. The Definition of Done involves all team members agreeing upon what they are able to deliver to product consistent internal quality in the software each sprint. The team will include members with backgrounds in programming, testing, analysis, design, and other disciplines within the software development field. The discussion that occurs in developing the Definition of Done will enlighten each member of the team and provide a way for them to keep on top of their internal quality as feature are being delivered iteratively.

In Summary

I hope that people read this and are able to identify whether they are doing these 2 essential parts of Scrum effectively. If a team does not know where they are headed, day-to-day decisions with an iterative and incremental approach such as Scrum will evolve into a messy implementation with no coherent focus for the users of the software. Getting a product vision and communicating it effective throughout the project team and even to stakeholders can help provide guidance along the way. If the team is unable to deliver a potentially shippable product increment after each sprint then the product will always have leftover work to do in order to get a release out to the users. This work will be to stabilize and pull functionality together in a coherent manner which is usually unpredictable leading to decreased quality and missed dates on delivery. Working on a Definition of Done as a first step towards understanding what is meant by potentially shippable product increment each sprint will begin the process of getting to software that is of releasable quality from the technology even though the Product Owner wants to go another sprint or more before actually releasing it to the users. Also, looking at the Extreme Programming (XP) technical practices to help create software in an incremental manner can help put the Definition of Done into action more effectively in some circumstances. Happy Scrum-ing!


How is a Mental Model formed?

Computers should never be compared to a human brain.  Computer just don’t measure up.  What we know about the brain is amazing, what we don’t is unknown (I can just here Rumsfeld now…) [sorry down that path leads to insanity].

http://www.ted.com/talks/tom_wujec_on_3_ways_the_brain_creates_meaning.html

In this video you can watch Autodesk creating a mental model of their future, using old school pen & paper and see some cool technology.  If you have created an Agile Road Map you will recognize the process, but this will explain why it can be so powerful to put all the stickies up on a wall and just look at them.


Hurry! Fetch the 2×4 stretcher.

The mythical 2×4 stretcher analogy.

When I was in high school I worked with the school maintenance crew. This was in the late 1970s when schools were growing and therefore tearing down old buildings to construct new modern building on the site.  Given that construction of the new building would take several years the problem of where to house classrooms durning the destruction/construction years was typically solved by building classrooms in the gym and auditorium. The first summer I worked with the crew we were constructing one of these temporary classrooms in a gym. I was the gopher for Ike, and old codger who was always up to something.  One fellow was measuring and calling out dimensions and Ike and I were cutting 2×4s to length, as fast as we could go.  I would hold the 2×4 on the saw horses and Ike would measure, mark, and cut, then I would run the piece over to a pair that would nail it in place.  We were all working fast, a well functioning team.  When Ike, exclaimed, “$#!T, I cut it too short, Koontz run get the 2×4 stretcher in the back tool box of my truck – hurry!  You’ll know it when you see it.”  So, off I run to find the stretcher.  I pull out every tool in the truck’s toolbox, but the stretcher wasn’t there.  So back in to tell Ike and he said “maybe I was using it at home and didn’t put it back, go get Jim’s, hurry!  So out to Jim’s truck to rummage through his toolbox I went like a flash.

Well if you have every been played for the fool by a master craftsman such as Ike, you know that he can keep it up all day long, as long as you are hooked and on the string he is intense and serious, and has another place to look.  After I finally wised up and “spit out the hook”, the whole crew fell on the floor laughing for 20 minutes.  I joined in after about 15 minutes, of being mad and extremely embarrassed.  That was the first of many exploits that Ike would lead us on that summer.  He worked hard and played hard, all at the same time!

I don’t know of any 2×4 stretcher stories in the software industry, but everyone that has been the young apprentice on a construction site has been asked to go fetch the stretcher.  So why are there no good fish tales in software?  Well for one reason a 2×4 stretcher is possible in software – it is called a refactoring, for example: Extract Interface. Software is soft and malleable, the rest of the world is not.  Therefore a 2×4 stretcher is funny on a construction site, but a real possibility in software.

This doesn’t mean we cannot have fun, however!  Why I remember just starting out and having an upper-classman help me with a sorting algorithm, he took my punch cards and dropped them on the floor.


Fist of Five – What does that mean?

So you use a Fist of Five consensus building technique to make decisions.  That’s great!  Does everyone in your group know what a five really means?

While reading about building a shared vision in the organization today, I ran across several words that the authors made a particular point to define and distinguish between them.  Those words were: commitment, enrollment, and compliant.  When discussing a corporate shared vision the distention between these is very important!  For to have your organization truly committed to the vision is very different that enrolled in the vision or just compliant with the vision.  The author states that real commitment is rare in today’s organizations. In his experience “90 percent of the time, what passes for commitment is compliance” (Senge, 2006).

The committed person brings passion and energy to the endeavor, they don’t play by the rules of the game, they feel responsible for the game itself, and if required change the game to achieve the goals.  When multiple people are truly committed there is an awesome force to be reckoned.

The enrolled individual believes in the cause, and will support the effort, but is not going to great personal effort to ensure success.  They may be nurtured into the committed camp, but that is not where they are starting from.

The compliant person will go along with the group. They do what is required and expected of them but they are not enrolled nor committed.

How would these words be mapped upon the Fist of Five?

5 – I am committed to the idea.
4 – I am enrolling in the group’s idea.
3 – I will be compliant with the idea.
2 – I do not support the idea as stated, and wish to discuss changes.
1 – I am against the idea as stated – period.
0 – I am not sure I understand the idea and need more clarification.

What does your Fist of Five mean?  Is it just a graduated continuum from disagree (1) to agree (5)?  If so you may receive deeper meaning and more passionate dialogs by attaching well defined meaning to the fingers.  Try it, let me know what happens.


Setting Maven Properties With Groovy

Goal

While I generally try to configure, rather than script, Maven builds, sometimes the publicly-available plug-ins do not provide enough flexibility to work-around limitations in third-party libraries through configuration alone. Fortunately, GMaven exposes the flexibility of Groovy in a Maven plug-in. This post demonstrates how to use a Groovy script to transform a Maven project property. Such a transformation is sometimes necessary, for example, for transforming a Windows-style path to Unix. For myself, I formalized this solution while trying to install a jar in PostgreSQL automatically during the artifact deployment phase.

Display a Maven Project Property

We can start by creating a simple m2eclipse project, by adding a single property with a default value and by configuring the pom.xml to display this property on the console during a lifecycle event (here, during compilation).

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>timezra.blog.maven.groovy.properties</groupId>
  <artifactId>timezra.blog.maven.groovy.properties</artifactId>
  <name>timezra.blog.maven.groovy.properties</name>
  <version>0.0.1-SNAPSHOT</version>
  <description>An example of setting Maven properties using Groovy.</description>
  <properties>
    <unixy_build_directory>${project.build.directory}</unixy_build_directory>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <id>show-unixy_build_directory!</id>
            <phase>compile</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <tasks>
                <echo>unixy_build_directory: ${unixy_build_directory}</echo>
              </tasks>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

If we run the compile goal, we will see the bound Maven property in the build output.

  > mvn compile
  ….
  [INFO] [antrun:run {execution: show-unixy_build_directory!}]
  [INFO] Executing tasks
       [echo] unixy_build_directory: C:\programming\workspaces\blog\timezra.blog.maven.groovy.properties\target
  [INFO] Executed tasks
  ….

Setting up the gmaven-plugin is straightforward, as is re-binding the property with Groovy in the pom.xml.

<project .>
  ….
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.groovy.maven</groupId>
        <artifactId>gmaven-plugin</artifactId>
        <executions>
          <execution>
            <id>set-unixy_build_directory!</id>
            <phase>compile</phase>
            <goals>
              <goal>execute</goal>
            </goals>
            <configuration>
              <classpath>
                <element>
                  <groupId>commons-lang</groupId>
                  <artifactId>commons-lang</artifactId>
                  <version>2.4</version>
                 </element>
              </classpath>
              <source>
                if (org.apache.commons.lang.SystemUtils.IS_OS_WINDOWS) {
                  project.properties.unixy_build_directory =
                  project.build.directory.replace("\\", "/");
                }
              </source>
            </configuration>
          </execution>
        </executions>
      </plugin>
      ….
    </plugins>
  </build>
</project>

NB: This example takes a Windows file path and transforms the backslashes to forward slashes. If you are not running Windows, then this example is moot. Please, experiment with the bindings in the pom.xml to demonstrate clearly to yourself that the property has really, really, really been re-bound.

When compiling, we will now see output indicating that the Groovy script has mutated the Maven property.

  > mvn compile
  ….
  [INFO] [antrun:run {execution: show-unixy_build_directory!}]
  [INFO] Executing tasks
       [echo] unixy_build_directory: C:/programming/workspaces/blog/timezra.blog.maven.groovy.properties/target
  [INFO] Executed tasks
  ….

Conclusion

With a few lines of configuration and a simple Groovy script, we are able to modify Maven properties as part of a lifecycle event. This tool adds even more power to your Maven builds, but, as stated above, it should be used cautiously and only when absolutely necessary. If there is a solution already in the Maven toolkit, then that is generally better. Not all project requirements fit in the box, however, and this example exposes a simple way to handle the non-ideal.


When does a tool become a Meta-Tool?

Have you ever found yourself using a tool in a most unusaual way?  A way in which you are sure that the designer of the tool never intend the tool to be used.  Is this behavior a good thing or a bad thing?  Is this new usage a testestimonial to the original design of the tool, or to your lack of judgement in selection of the tool, or perhaps a statement of frustration at the situation?

What do these images bring to mind?

Who needs a box-end wrench when you have channel locks?

Who needs a box-end wrench when you have channel locks?

Is it Hammer-Time? Beat it or pull it.

Is it Hammer-Time? Beat it or pull it.

Who's calling - pardon me while I see if you are on the level?

Who's calling - pardon me while I see if you are on the level?

So which iPhone application do YOU use the most?  Is it the phone? I’ll bet it is not!  Was that the original intention of this wonderful device?

Certainly of the tools above I have used the hammer the most in my life and in the most creative ways beyond the intention of the designer.  After all Mr. Hammer (inventor of the tool) did not intend it to be used as a weight tied to a rope and thrown over a tree limb to hoist a young kid up a tree (reminder to young kids bring the hammer in from the forest before it rains or your father will learn of the rusty hammers use).

Did the cell phone just usurpe the computer as the Meta-Tool of all creation?  Or does the hammer still win?


Maven and Weblogic

Goal

This post is a follow-up to a previous entry on running Weblogic Ant tasks without calling setDomainEnv. The purpose is to perform the same actions from Maven. Fortunately, the weblogic-maven-plugin does not have the same requirement for setting environment variables from outside the build script. Unfortunately, development on the mojos appears to be a few versions behind the latest release of Weblogic. The code and examples here demonstrate how to use this Maven plug-in to run goals for deloying a WAR, building a web service skeleton and generating a web service client for Weblogic 10.3.

Listing the Applications Deployed to Weblogic

We can begin by creating an m2eclipse Maven project, timezra.blog.maven.weblogic, with the webapp-jee5 archetype. The Wizard materializes a simple hello world application that will be packaged as a WAR.

In order to list the applications deployed to Weblogic, we first need to setup a Weblogic domain if we do not already have one. For this example, we can create one called maven_example using the defaults provided by the Configuration Wizard.
There is already a good starting point for configuring the weblogic-maven-plugin in our pom.xml, but for 10.3 these instructions are incomplete. One problem becomes evident when we compose an Eclipse Run Configuration for the weblogic:listapps goal (being sure to use the External Maven 2.10 Runtime).

In our console, we would see a stack trace.


java.lang.NoClassDefFoundError: weblogic/utils/Debug
 at weblogic.Deployer.(Deployer.java:23)
 at org.codehaus.mojo.weblogic.DeployMojoBase.executeDeployer(DeployMojoBase.java:509)
 at org.codehaus.mojo.weblogic.ListAppsMojo.execute(ListAppsMojo.java:51)
 at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:483)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:678)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:553)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:523)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:371)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:332)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:181)
 at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:356)
 at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:137)
 at org.apache.maven.cli.MavenCli.main(MavenCli.java:356)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
 at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
 at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
 at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: java.lang.ClassNotFoundException: weblogic.utils.Debug
 at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
 at org.codehaus.classworlds.RealmClassLoader.loadClassDirect(RealmClassLoader.java:195)
 at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:255)
 at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:274)
 at org.codehaus.classworlds.RealmClassLoader.loadClass(RealmClassLoader.java:214)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
 at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
 … 21 more

We must manually install a few libraries in addition to those the Wiki entry lists into our local Maven repository.


  mvn install:install-file -DgroupId=weblogic -DartifactId=weblogic -Dversion=10.3 -Dpackaging=jar -Dfile=C:\webservers\bea\wlserver_10.3\server\lib\weblogic.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=webservices -Dversion=10.3 -Dpackaging=jar -Dfile=C:\webservers\bea\wlserver_10.3\server\lib\webservices.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.rmi.client -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.rmi.client_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=javax.enterprise.deploy -Dversion=1.2 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\javax.enterprise.deploy_1.2.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.management.core -Dversion=2.3.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.management.core_2.3.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.security.identity -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.security.identity_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.security -Dversion=1.0.0.0_5-0-2-0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.security_1.0.0.0_5-0-2-0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.security.wls -Dversion=1.0.0.0_5-0-2-0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.security.wls_1.0.0.0_5-0-2-0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.workmanager -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.workmanager_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.transaction -Dversion=2.5.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.transaction_2.5.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.logging -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.logging_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.utils.classloaders -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.utils.classloaders_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.timers -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.timers_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.socket.api -Dversion=1.0.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.socket.api_1.0.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.common.security.api -Dversion=1.0.0.0_5-0-2-0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.common.security.api_1.0.0.0_5-0-2-0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.security.digest -Dversion=1.0.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.security.digest_1.0.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.lifecycle -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.lifecycle_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.workarea -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.workarea_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.utils.wrapper -Dversion=1.3.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.utils.wrapper_1.3.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.store -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.store_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.management.jmx -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.management.jmx_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor.wl -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor.wl_1.1.0.0.jar

We will configure the plug-in to depend on these and other publicly available libraries in our project pom.xml.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>timezra.blog.maven.weblogic</groupId>
    <artifactId>timezra.blog.maven.weblogic</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>timezra.blog.maven.weblogic JEE5 Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>weblogic-maven-plugin</artifactId>
                <version>2.9.2-SNAPSHOT</version>
                <configuration>
                    <adminServerHostName>localhost</adminServerHostName>
                    <adminServerPort>7001</adminServerPort>
                    <adminServerProtocol>t3</adminServerProtocol>
                    <userId>weblogic</userId>
                    <password>weblogic</password>
                    <upload>false</upload>
                    <remote>false</remote>
                    <verbose>false</verbose>
                    <debug>false</debug>
                    <targetNames>AdminServer</targetNames>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.utils.full</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.i18n</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.rmi.client</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>javax.enterprise.deploy</artifactId>
                        <version>1.2</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.management.core</artifactId>
                        <version>2.3.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.security.wls</artifactId>
                        <version>1.0.0.0_5-0-2-0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.security</artifactId>
                        <version>1.0.0.0_5-0-2-0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.security.identity</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.workmanager</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.transaction</artifactId>
                        <version>2.5.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.logging</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.utils.classloaders</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.timers</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.socket.api</artifactId>
                        <version>1.0.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.common.security.api</artifactId>
                        <version>1.0.0.0_5-0-2-0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.security.digest</artifactId>
                        <version>1.0.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.lifecycle</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.workarea</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.utils.wrapper</artifactId>
                        <version>1.3.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>javax.transaction</groupId>
                        <artifactId>jta</artifactId>
                        <version>1.1</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.store</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.management.jmx</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor.wl</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
        <finalName>timezra.blog.maven.weblogic</finalName>
    </build>
    <pluginRepositories>
        <pluginRepository>
            <id>Maven Snapshots</id>
            <url>http://snapshots.repository.codehaus.org/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>
</project>

The output from our Eclipse weblogic:listapps launcher should now show

  There is no application to list.

Deploying a WAR

Our Maven archetype has already configured the packaging for our application, and building the WAR is not Weblogic-specific. Deploying to the AdminServer is, however.
If we were to create another Eclipse Run Configuration, here called full_deploy, which calls the package and deploy goals, we would see an error.


[ERROR] BUILD ERROR
[INFO] ————————————————————————
[INFO] Failed to configure plugin parameters for: org.apache.maven.plugins:maven-deploy-plugin:2.4

check that the following section of the pom.xml is present and correct:

<distributionManagement>
  <!– use the following if you’re not using a snapshot version. –>
  <repository>
    <id>repo</id>
    <name>Repository Name</name>
    <url>scp://host/path/to/repo</url>
  </repository>
  <!– use the following if you ARE using a snapshot version. –>
  <snapshotRepository>
    <id>repo</id>
    <name>Repository Name</name>
    <url>scp://host/path/to/repo</url>
  </snapshotRepository>
</distributionManagement>

For this example, it is sufficient for the distribution manager to point to our local repository and to hook into the weblogic:deploy goal in our pom.xml.

<project .>
    ….
    <build>
        <plugins>
            ….
            <plugin>
                <executions>
                    <execution>
                        <id>deploy.to.weblogic</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                    </execution>
                </executions>
                <groupId>org.codehaus.mojo</groupId>
                ….
            </plugin>
        </plugins>
    </build>
    ….
    <distributionManagement>
        <snapshotRepository>
            <id>localRepository</id>
            <name>Local Repository</name>
            <url>file://${HOMEDRIVE}/Docume~1/${USERNAME}/.m2/repository</url>
          </snapshotRepository>
    </distributionManagement>
</project>

If you are developing on Windows, at this point you may see a misleading error about an incorrect protocol.


[INFO] Weblogic Deployment parameters [-adminurl, t3://localhost:7001, -username, weblogic, -password, weblogic, -name, timezra.blog.maven.weblogic, -targets, AdminServer, -source, C:\programming\workspaces\blog\timezra.blog.maven.weblogic\target/timezra.blog.maven.weblogic.war, -deploy]
weblogic.Deployer invoked with options: -adminurl t3://localhost:7001 -username weblogic -name timezra.blog.maven.weblogic -targets AdminServer -source C:\programming\workspaces\blog\timezra.blog.maven.weblogic\target/timezra.blog.maven.weblogic.war -deploy
<Jun 24, 2009 4:36:08 PM PDT> <Info> <J2EE Deployment SPI> <BEA-260121> <Initiating deploy operation for application, timezra.blog.maven.weblogic [archive: C:\programming\workspaces\blog\timezra.blog.maven.weblogic\target\timezra.blog.maven.weblogic.war], to AdminServer .>
no protocol: and

The problem is that weblogic-maven-plugin goals do not properly handle spaces in the classpath. The solution is simply to eliminate these spaces in the ~/$USER/.m2/settings.xml file.

<settings>
    <localRepository>${HOMEDRIVE}/Docume~1/${USERNAME}/.m2/repository</localRepository>
</settings>

The output from our Eclipse weblogic:listapps launcher should now show


   timezra.blog.maven.weblogic
  Number of Applications Found : 1

If we open http://localhost:7001/timezra.blog.maven.weblogic/ in a browser, we will see Hello World!

Compile A Web Service

The trial-and-error process for deploying a Web Service is very similar to publishing our packaged WAR: setup project dependencies, implement the service in Java, call the weblogic:jwsc goal, work out any unresolved dependencies and deploy the application.
Our web service will depend on annotations from the javax.jws library, which is provided by Weblogic. We can install this JAR, as above.


  mvn install:install-file -DgroupId=weblogic -DartifactId=javax.jws -Dversion=2.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\javax.jws_2.0.jar

We will configure this project dependency in our pom.xml.

<project .>
    ….
    <dependencies>
        ….
        <dependency>
            <groupId>weblogic</groupId>
            <artifactId>javax.jws</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    ….
</project>

We can write an echo service with interface /src/main/java/timezra/blog/maven/weblogic/ws/IEcho.java, that simply resonates the client’s input.

package timezra.blog.maven.weblogic.ws;

public interface IEcho {
    String echo(final String holla);
}

We will implement the web service as described in a previous post in /src/main/java/timezra/blog/maven/weblogic/ws/Echo.java.

package timezra.blog.maven.weblogic.ws;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;

@WebService(name = "Echo", targetNamespace = Echo.NAMESPACE, serviceName = "Echo")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public class Echo implements IEcho {
    static final String NAMESPACE = "http://timezra.blog.maven.weblogic";
    private static final String ELLIPSIS = " … ";

    @WebMethod(operationName = "echo")
    @WebResult(name = "holla_back", targetNamespace = NAMESPACE)
    public String echo(@WebParam(name = "holla", targetNamespace = NAMESPACE, mode = Mode.IN) final String holla) {
        if (holla == null) {
            return null;
        }
        final String[] what = holla.split("\\s");
        final StringBuilder echo = new StringBuilder(what[0]);
        for (int i = 1; i < what.length; i++) {
            echo.append(‘ ’);
            echo.append(what[i]);
        }
        final String theLastWord = what[what.length - 1];
        echo.append(ELLIPSIS);
        echo.append(theLastWord);
        echo.append(ELLIPSIS);
        echo.append(theLastWord);
        return echo.toString();
    }
}

The weblogic:jwsc goal has dependencies on more Weblogic modules.


  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.annogen -Dversion=1.2.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.annogen_1.2.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor.j2ee.binding -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor.j2ee.binding_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.xml.staxb.runtime -Dversion=1.3.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.xml.staxb.runtime_1.3.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.xml.beaxmlbeans -Dversion=1.0.0.0_2-4-0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.xml.beaxmlbeans_1.0.0.0_2-4-0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor.j2ee -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor.j2ee_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=javax.ejb -Dversion=3.0.1 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\javax.ejb_3.0.1.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.xml.xmlbeans -Dversion=1.0.0.0_2-4-0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.xml.xmlbeans_1.0.0.0_2-4-0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.stax -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.stax_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=javax.xml.rpc -Dversion=1.2.1 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\javax.xml.rpc_1.2.1.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.xml.staxb.buildtime -Dversion=1.3.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.xml.staxb.buildtime_1.3.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=glassfish.jaxws.rt -Dversion=2.1.3 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\glassfish.jaxws.rt_2.1.3.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor.wl.binding -Dversion=1.1.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor.wl.binding_1.1.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.descriptor.settable.binding -Dversion=1.4.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.descriptor.settable.binding_1.4.0.0.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=com.bea.core.weblogic.saaj -Dversion=1.3.0.0 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\com.bea.core.weblogic.saaj_1.3.0.0.jar

We will add these plug-in dependencies to the pom.xml along with configuration parameters specific to weblogic:jwsc.

<project .>
    ….
    <build>
        <plugins>
            ….
            <plugin>
                ….
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>weblogic-maven-plugin</artifactId>
                <version>2.9.2-SNAPSHOT</version>
                <configuration>
                    ….
                    <outputName>${project.artifactId}</outputName>
                    <contextPath>${project.artifactId}</contextPath>
                    <descriptor>${basedir}/src/main/webapp/WEB-INF/web.xml</descriptor>
                </configuration>
                <dependencies>
                    ….
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.annogen</artifactId>
                        <version>1.2.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor.j2ee.binding</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.xml.staxb.runtime</artifactId>
                        <version>1.3.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.xml.beaxmlbeans</artifactId>
                        <version>1.0.0.0_2-4-0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor.j2ee</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                          <groupId>com.sun</groupId>
                          <artifactId>tools</artifactId>
                          <version>1.6.0</version>
                          <scope>system</scope>
                          <systemPath>${java.home}/../lib/tools.jar</systemPath>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>javax.ejb</artifactId>
                        <version>3.0.1</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.xml.xmlbeans</artifactId>
                        <version>1.0.0.0_2-4-0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.stax</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>javax.xml.rpc</artifactId>
                        <version>1.2.1</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.xml.staxb.buildtime</artifactId>
                        <version>1.3.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>glassfish.jaxws.rt</artifactId>
                        <version>2.1.3</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>javax.mail</groupId>
                        <artifactId>mail</artifactId>
                        <version>1.4.1</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor.wl.binding</artifactId>
                        <version>1.1.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.descriptor.settable.binding</artifactId>
                        <version>1.4.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>com.bea.core.weblogic.saaj</artifactId>
                        <version>1.3.0.0</version>
                        <scope>provided</scope>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
        ….
    </build>
    ….
</project>

Now we can run a new Eclipse launcher that calls weblogic:jwsc in the same way that we setup launchers for weblogic:listapps. We see that the web service artifacts are correctly generated in the target directory, and the URL for the new web service is correctly merged into the target/timezra.blog.maven.weblogic/WEB-INF/web.xml. Unfortunately, if we package and deploy the application, this merging of information in the web.xml will be overwritten with the contents of src/main/webapp/WEB-INF/web.xml (Try it if you do not believe me, if you did not follow or if you would like to discover for yourself why this is the case!). Fortunately, there is a way to automate the generation of web service and the correct packaging of the artifacts and compiled sources with some extra configuration in the pom.xml.

<project .>
    ….
    <build>
        <plugins>
            ….
            <plugin>
                <executions>
                    <execution>
                        <id>generate.web.services</id>
                        <phase>package</phase>
                        <goals>
                            <goal>jwsc</goal>
                        </goals>
                    </execution>
                    ….
                </executions>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>weblogic-maven-plugin</artifactId>
                <version>2.9.2-SNAPSHOT</version>
                ….
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1-beta-1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>war</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        ….
    </build>
    ….
</project>

We can view the published WSDL in a browser at address http://localhost:7001/timezra.blog.maven.weblogic/Echo?WSDL and we can use our favorite web service client application (here, I use soapUI) to run a few tests.
Holla-ing to the Echo Web Service through soapUI.

Generate a Web Service Client

Now that we have a deployment infrastructure and a working web service, we can create a client for that service. The current version of the weblogic-maven-plugin (2.9.2-SNAPSHOT) supports two goals for generating a web service client, weblogic:clientgen and weblogic:clientgen9. Unfortunately, neither works with Weblogic 10. If we were to call weblogic:clientgen9, for example, we would see an error similar to this:


[INFO] ————————————————————————
[ERROR] BUILD ERROR
[INFO] ————————————————————————
[INFO] Internal error in the plugin manager executing goal ‘org.codehaus.mojo:weblogic-maven-plugin:2.9.2-SNAPSHOT:clientgen9′: Unable to find the mojo ‘clientgen9′ (or one of its required components) in the plugin ‘org.codehaus.mojo:weblogic-maven-plugin’
(class: org/codehaus/mojo/weblogic/ClientGen9Mojo, method: execute signature: ()V) Incompatible object argument for function call
[INFO] ————————————————————————

The only remedy I have seen to this issue is to modify the weblogic-maven-plugin and to install it in a local repository. After importing the project into Eclipse, we can simply apply this patch to the project root.


Index: pom.xml
===================================================================
— pom.xml (revision 10022)
+++ pom.xml (working copy)
@@ -11,7 +11,7 @@
<artifactId>weblogic-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Weblogic Maven Plugin</name>
- <version>2.9.2-SNAPSHOT</version>
+ <version>2.9.3-SNAPSHOT</version>
<inceptionYear>2005</inceptionYear>
<description>
This plugin will support various tasks within the Weblogic 8.1
@@ -95,6 +95,12 @@
<artifactId>webservices</artifactId>
<version>[9.0,11.0)</version>
</dependency>
+ <dependency>
+ <groupId>weblogic</groupId>
+ <artifactId>com.bea.core.utils.full</artifactId>
+ <version>1.4.0.0</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
@@ -126,4 +132,11 @@
</plugin>
</plugins>
</reporting>
+ <distributionManagement>
+ <snapshotRepository>
+ <id>localRepository</id>
+ <name>Local Repository</name>
+ <url>file://${HOMEDRIVE}/Docume~1/${USERNAME}/.m2/repository</url>
+ </snapshotRepository>
+ </distributionManagement>
</project>
\ No newline at end of file
Index: .settings/org.eclipse.jdt.core.prefs
===================================================================
--- .settings/org.eclipse.jdt.core.prefs (revision 0)
+++ .settings/org.eclipse.jdt.core.prefs (revision 0)
@@ -0,0 +1,5 @@
+#Sat Jun 20 17:00:42 PDT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.source=1.3
Index: .settings/org.maven.ide.eclipse.prefs
===================================================================
--- .settings/org.maven.ide.eclipse.prefs (revision 0)
+++ .settings/org.maven.ide.eclipse.prefs (revision 0)
@@ -0,0 +1,9 @@
+#Sat Jun 20 17:00:25 PDT 2009
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
Index: src/main/java/org/codehaus/mojo/weblogic/ClientGen10Mojo.java
===================================================================
--- src/main/java/org/codehaus/mojo/weblogic/ClientGen10Mojo.java (revision 0)
+++ src/main/java/org/codehaus/mojo/weblogic/ClientGen10Mojo.java (revision 0)
@@ -0,0 +1,402 @@
+package org.codehaus.mojo.weblogic;
+
+/*
+ * Copyright 2008 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.codehaus.mojo.weblogic.util.WeblogicMojoUtilities;
+import weblogic.wsee.tools.anttasks.ClientGenTask;
+
+import java.io.File;
+
+/**
+ * Runs Client Gen on a given WSDL. This client gen uses the BEA refactored client gen tool
+ * first appearing in weblogic 9. This is the preferred client gen tool for Weblogic 9.0 and
+ * newer.
+ *
+ * @author <a href="mailto:josborn@belltracy.com">Jon Osborn</a>
+ * @version $Id: ClientGen10Mojo.java 8652 2009-01-13 01:13:28Z jonnio $
+ * @description This mojo will run client gen on a given WSDL. This client gen uses the BEA refactored client gen tool
+ * first appearing in weblogic 9. This is the preferred client gen tool for Weblogic 10.0 and newer.
+ * @goal clientgen10
+ * @requiresDependencyResolution compile
+ */
+public class ClientGen10Mojo
+ extends AbstractWeblogicMojo
+{
+
+ /**
+ * The filename of the war file to find the services. The file path is
+ * extracted from the artifact list.
+ *
+ * @parameter
+ */
+ private String warFileName;
+
+ /**
+ * The wsdl to client gen from. If warFileName is specified, this parameter
+ * is the root relative file to use when creating the URI for the wsdl.
+ *
+ * @parameter
+ */
+ private String inputWSDL;
+
+ /**
+ * The directory to output the generated code to.
+ *
+ * @parameter default-value="${basedir}/src/main/java"
+ */
+ private String outputDir;
+
+ /**
+ * The package name of the output code.
+ *
+ * @parameter default-value="com.test.webservice"
+ */
+ private String packageName;
+
+ /**
+ * The name of the service.
+ *
+ * @parameter
+ */
+ private String serviceName;
+
+ /**
+ * Output verbose messages
+ *
+ * @parameter default-value="false"
+ */
+ private boolean verbose;
+
+ /**
+ * Whether or not to use server types from the ear file in the client jar.
+ *
+ * @parameter default-value="false"
+ */
+ private boolean useServerTypes;
+
+ /**
+ * Sets whether or not to create the type conversions for a web service in
+ * the client.
+ *
+ * @parameter default-value="true"
+ */
+ private boolean autotype;
+
+ /**
+ * Sets whether or not to use the jaxRPCWrappedArrayStyle
+ *
+ * @parameter default-value="true"
+ */
+ private boolean jaxRPCWrappedArrayStyle;
+
+ /**
+ * This method will run client gen on the given WSDL.
+ *
+ * @throws MojoExecutionException Thrown if we fail to obtain the WSDL.
+ */
+ public void execute()
+ throws MojoExecutionException
+ {
+ super.execute();
+
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( "Weblogic client gen beginning " );
+ }
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( " Detailed client gen settings information " + this.toString() );
+ }
+
+ try
+ {
+ final ClientGenTask clientGen = new ClientGenTask();
+ // Set the classpath
+ final Project project = new Project();
+ project.setName( "clientgen" );
+ final Path path = new Path( project, WeblogicMojoUtilities
+ .getDependencies( this.getArtifacts(), this.getPluginArtifacts() ) );
+ clientGen.setProject( project );
+ clientGen.setClasspath( path );
+ clientGen.setVerbose( this.verbose );
+ clientGen.setDestDir( new File( this.outputDir ) );
+ clientGen.setPackageName( this.packageName );
+ clientGen.setIncludeGlobalTypes( this.useServerTypes );
+ clientGen.setJaxRPCWrappedArrayStyle( this.jaxRPCWrappedArrayStyle );
+ String wsdlUri;
+ if ( this.warFileName != null )
+ {
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info(
+ " calculating wsdl URI from warFileName " + this.warFileName + " with wsdl " + this.inputWSDL );
+ }
+ wsdlUri = "jar:file:" + WeblogicMojoUtilities.getWarFileName( this.getArtifacts(), this.warFileName ) +
+ "!" + this.inputWSDL;
+ new File( this.inputWSDL ).toURI().toString();
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( " using " + wsdlUri + " for clientgen." );
+ }
+ }
+ else if ( this.inputWSDL.startsWith( "http" ) )
+ {
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( " using " + this.inputWSDL + " for clientgen." );
+ }
+ wsdlUri = this.inputWSDL;
+ }
+ else
+ {
+ wsdlUri = new File( this.inputWSDL ).toURI().toString();
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( " using " + wsdlUri + " for clientgen." );
+ }
+ }
+ clientGen.setWsdl( wsdlUri );
+ // set the service name if it is specified
+ if ( this.serviceName != null )
+ {
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( " generating client for service '" + this.serviceName + "'." );
+ }
+ clientGen.setServiceName( this.serviceName );
+ }
+ clientGen.execute();
+ }
+ catch ( Exception ex )
+ {
+ getLog().error( "Exception encountered during client gen", ex );
+ throw new MojoExecutionException( "Exception encountered during listapps", ex );
+ }
+ finally
+ {
+ WeblogicMojoUtilities.unsetWeblogicProtocolHandler();
+ }
+
+ if ( getLog().isInfoEnabled() )
+ {
+ getLog().info( "Weblogic client gen successful " );
+ }
+ }
+
+ /**
+ * Getter for property input WSDL.
+ *
+ * @return The value of input WSDL.
+ */
+ public String getInputWSDL()
+ {
+ return this.inputWSDL;
+ }
+
+ /**
+ * Setter for the input WSDL.
+ *
+ * @param inInputWSDL The value of input WSDL.
+ */
+ public void setInputWSDL( final String inInputWSDL )
+ {
+ this.inputWSDL = inInputWSDL;
+ }
+
+ /**
+ * Getter for property output dir.
+ *
+ * @return The value of output dir.
+ */
+ public String getOutputDir()
+ {
+ return this.outputDir;
+ }
+
+ /**
+ * Setter for the output dir.
+ *
+ * @param inOutputDir The value of output dir.
+ */
+ public void setOutputDir( final String inOutputDir )
+ {
+ this.outputDir = inOutputDir;
+ }
+
+ /**
+ * Getter for property package name.
+ *
+ * @return The value of package name.
+ */
+ public String getPackageName()
+ {
+ return this.packageName;
+ }
+
+ /**
+ * Setter for the package name.
+ *
+ * @param inPackageName The value of package name.
+ */
+ public void setPackageName( String inPackageName )
+ {
+ this.packageName = inPackageName;
+ }
+
+ /**
+ * Getter for property service name.
+ *
+ * @return The value of service name.
+ */
+ public String getServiceName()
+ {
+ return this.serviceName;
+ }
+
+ /**
+ * Setter for the service name.
+ *
+ * @param inServiceName The value of service name.
+ */
+ public void setServiceName( final String inServiceName )
+ {
+ this.serviceName = inServiceName;
+ }
+
+ /**
+ * toString method: creates a String representation of the object
+ *
+ * @return the String representation
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "ClientGen10Mojo[" );
+ buffer.append( "inputWSDL = " ).append( inputWSDL );
+ buffer.append( ", outputDir = " ).append( outputDir );
+ buffer.append( ", packageName = " ).append( packageName );
+ buffer.append( ", serviceName = " ).append( serviceName );
+ buffer.append( ", useServerTypes = " ).append( useServerTypes );
+ buffer.append( ", autotype = " ).append( autotype );
+ buffer.append( "]” );
+ return buffer.toString();
+ }
+
+ /**
+ * Getter for server types
+ *
+ * @return true if the client gen should use server type information
+ */
+ public boolean isUseServerTypes()
+ {
+ return useServerTypes;
+ }
+
+ /**
+ * Setter for server types
+ *
+ * @param useServerTypes – true if the client gen should use server types
+ */
+ public void setUseServerTypes( boolean useServerTypes )
+ {
+ this.useServerTypes = useServerTypes;
+ }
+
+ /**
+ * Getter for verbose messages
+ *
+ * @return true if the client gen should use verbose output
+ */
+ public boolean isVerbose()
+ {
+ return this.verbose;
+ }
+
+ /**
+ * Setter for verbose messages
+ *
+ * @param verbose – true of the clientgen should use verbose output
+ */
+ public void setVerbose( boolean verbose )
+ {
+ this.verbose = verbose;
+ }
+
+
+ /**
+ * Getter for autoType
+ *
+ * @return true if clientgen shoud autotype from the wsdl
+ */
+ public boolean isAutotype()
+ {
+ return this.autotype;
+ }
+
+ /**
+ * Setter for autoType
+ *
+ * @param autotype – true if the client should autotype
+ */
+ public void setAutotype( boolean autotype )
+ {
+ this.autotype = autotype;
+ }
+
+ /**
+ * Getter for warFileName
+ *
+ * @return the warFileName
+ */
+ public String getWarFileName()
+ {
+ return this.warFileName;
+ }
+
+ /**
+ * Setter for warFileName
+ *
+ * @param warFileName – the warFileName to set
+ */
+ public void setWarFileName( String warFileName )
+ {
+ this.warFileName = warFileName;
+ }
+
+ /**
+ * Getter for jaxRPCWrappedArrayStyle
+ *
+ * @return the jaxRPCWrappedArrayStyle
+ */
+ public boolean isJaxRPCWrappedArrayStyle()
+ {
+ return jaxRPCWrappedArrayStyle;
+ }
+
+ /**
+ * Setter for jaxRPCWrappedArrayStyle
+ *
+ * @param jaxRPCWrappedArrayStyle the jaxRPCWrappedArrayStyle to set
+ */
+ public void setJaxRPCWrappedArrayStyle( boolean jaxRPCWrappedArrayStyle )
+ {
+ this.jaxRPCWrappedArrayStyle = jaxRPCWrappedArrayStyle;
+ }
+}
Index: src/main/java/org/codehaus/mojo/weblogic/util/WeblogicMojoUtilities.java
===================================================================
— src/main/java/org/codehaus/mojo/weblogic/util/WeblogicMojoUtilities.java (revision 10022)
+++ src/main/java/org/codehaus/mojo/weblogic/util/WeblogicMojoUtilities.java (working copy)
@@ -48,7 +48,7 @@
{
if ( “weblogic.utils”.equals(System.getProperty(”java.protocol.handler.pkgs”) ) )
{
- System.setProperty( “java.protocol.handler.pkgs”, null );
+ System.clearProperty( “java.protocol.handler.pkgs” );
}
}

Index: src/test/java/org/codehaus/mojo/weblogic/SimpleGoalMojoTest.java
===================================================================
— src/test/java/org/codehaus/mojo/weblogic/SimpleGoalMojoTest.java (revision 10022)
+++ src/test/java/org/codehaus/mojo/weblogic/SimpleGoalMojoTest.java (working copy)
@@ -128,6 +128,21 @@
}

/**
+ * Test that we can find the deploy goal
+ *
+ * @throws Exception when the lookup fails
+ * @see org.codehaus.mojo.weblogic.ClientGen10Mojo
+ */
+ public void testMojoClientGen10Goal()
+ throws Exception
+ {
+
+ final ClientGen10Mojo mojo = (ClientGen10Mojo) lookupMojo( “clientgen10″, this.testPom );
+
+ assertNotNull( mojo );
+ }
+
+ /**
* Test an invalid goal to be sure the valid ones are ‘real’.
*
* @throws Exception – throws exception when something fails.

NB: This patch has been submitted as a bug report. Please comment or vote on this bug to get it pushed through.
We will deploy this update to the plug-in (here, with version number 2.9.3-SNAPSHOT) by simply running the goal as Maven install from Eclipse.

Now that we have a working client generation goal in our updated and installed plug-in, again, we will need to register a few more Weblogic libraries for our project.


  mvn install:install-file -DgroupId=weblogic -DartifactId=javax.jms -Dversion=1.1.1 -Dpackaging=jar -Dfile=C:\webservers\bea\modules\javax.jms_1.1.1.jar
  mvn install:install-file -DgroupId=weblogic -DartifactId=wseeclient -Dversion=10.3 -Dpackaging=jar -Dfile=C:\webservers\bea\wlserver_10.3\server\lib\wseeclient.jar

We can add these new project and plug-in dependencies, along with necessary configuration parameters to the pom.xml. Generally, I do not automate client generation, as published WSDLs infrequently change. You may have different project requirements, however.

<project .>
    ….
    <dependencies>
        ….
        <dependency>
            <groupId>weblogic</groupId>
            <artifactId>wseeclient</artifactId>
            <version>10.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>weblogic</groupId>
            <artifactId>javax.xml.rpc</artifactId>
            <version>1.2.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            ….
            <plugin>
                ….
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>weblogic-maven-plugin</artifactId>
                <version>2.9.3-SNAPSHOT</version>
                <configuration>
                    ….
                    <inputWSDL>http://localhost:7001/timezra.blog.maven.weblogic/Echo?WSDL</inputWSDL>
                    <packageName>timezra.blog.maven.weblogic.ws.client</packageName>
                    <serviceName>Echo</serviceName>
                </configuration>
                <dependencies>
                    ….
                    <dependency>
                        <groupId>weblogic</groupId>
                        <artifactId>javax.jms</artifactId>
                        <version>1.1.1</version>
                        <scope>provided</scope>
                    </dependency>
                </dependencies>
            </plugin>
            ….
        </plugins>
        ….
    </build>
    ….
</project>

Our business component, src/main/java/timezra/blog/maven/weblogic/service/EchoService.java invokes the generated client.

package timezra.blog.maven.weblogic.service;

import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import timezra.blog.maven.weblogic.ws.client.Echo_Service;
import timezra.blog.maven.weblogic.ws.client.Echo_Service_Impl;

public class EchoService {

    public String say(final String phrase) {
        try {
            final Echo_Service echoService = new Echo_Service_Impl();
            return echoService.getEchoSoapPort().echo(phrase);
        } catch (final RemoteException e) {
            return "Putter, ka-chunk, piff.";
        } catch (final ServiceException e) {
            return "Gurgle, burble, glug.";
        }
    }
}

We will need a way to mediate the client invokation and the display of the response, so we will create a src/main/java/timezra/blog/maven/weblogic/controller/IsAnybodyThere.java controller.

package timezra.blog.maven.weblogic.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import timezra.blog.maven.weblogic.service.EchoService;

public class IsAnybodyThere extends HttpServlet {

    private static final long serialVersionUID = -8205256394812150098L;

    @Override
    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        final String echo = new EchoService().say("Is there anybody in there?");
        req.setAttribute("echo", echo);
        req.getRequestDispatcher("echo.jsp").forward(req, resp);
    }
}

Our view, src/main/webapp/echo.jsp, will simply show the result of calling the service.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>${echo}</h1>
    </body>
</html>

Finally, we will register our view in the web descriptor, web.xml.

….
<web-app .>
    ….
    <servlet>
        <servlet-name>IsAnybodyThere</servlet-name>
        <servlet-class>timezra.blog.maven.weblogic.controller.IsAnybodyThere</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>IsAnybodyThere</servlet-name>
        <url-pattern>/IsAnybodyThere</url-pattern>
    </servlet-mapping>
    ….
    </web-app>

Now, when we run full_deploy and open http://localhost:7001/timezra.blog.maven.weblogic/IsAnybodyThere in a browser, we will see the message “Is there anybody in there? … there? … there?”.

Conclusion

While it certainly would have been possible to hook the Maven Ant plugin to the build script presented in a previous post for executing tasks that disguise the need to run the setDomainEnv script, this post provides a different approach through the existing weblogic-maven-plugin and thus eliminates the need for manipulating setDomainEnv entirely with a manageable amount of configuration in the pom.xml.

A Maven project that compiles a web service, generates a web service client, and deploys a WAR to Weblogic.


Maintain One List of Work

During an interview at the Better Software conference this week, I mentioned that I thought maintaining a single list of work prioritized by the business was important for our industry to improve. The following text is an excerpt, in first draft form, from chapter 2, “Architecture Integrity”, of my upcoming book “Architecture in an Agile Organization” that is relevant to this topic.


In Scrum, the Product Backlog is a list of desired features prioritized by the Product Owner. Prioritization is done by the Product Owner to optimize value of the software delivered to the users. Instead of prioritizing within levels of importance such as high, medium, and low the Product Owner must prioritize in “stack-rank” order. This means that no Product Backlog item has the same priority as another item. This form of prioritization gives clear directions to development teams about what the most important feature is next to work on.

A healthy Product Backlog contains not only new features but also technical requirements to support the next Product Backlog items in priority. The development team is expected to review the Product Backlog frequently to provide cost estimates for Product Backlog items to help the Product Owner prioritize based on both cost and benefit. During the development team’s review they will suggest Product Backlog items that are missing from a technical point of view in the product definition. These technical Product Backlog items will be discussed with the Product Owner so they are able to prioritize them effectively. It is essential that the development team explain why each technical Product Backlog item is important to support other upcoming items. If this is not expressed the Product Owner could be inclined to demote those technical Product Backlog items because the value of them is not understood enough.

When issues are found in the software they usually come in three varieties:

  • Enhancement – a suggestion for improving the current state of the software from a user’s point of view
  • Defect – a system fault that occurs while using the software
  • Fire – a system fault that is inhibiting significant usage scenarios in the software and must be fixed immediately

Enhancements are requests for improvements to the software based on the perspective of the user. These improvements should be prioritized based on their value against all other Product Backlog items. An enhancement and defect issues are hard to distinguish from one another at times but that is fine. Defects are system faults that users are able to workaround but should not be happening from a user experience and/or technical perspective. Since we are able to work around these defects and the development team is able to provide a fix in the next iteration they are placed into the Product Backlog and prioritized against all other Product Backlog items. Fires are defects that cannot be worked around and cause serious problems for users of the software. In healthy software applications, fires should be a rare occurrence. It is important that a fix is implemented right away and may interrupt the work getting done in the current iteration.

issuetriage

Figure: This flow diagram describes how an identified issue is triaged in an iterative and incremental approach such as Scrum. If the issue is an enhancement or defect that can be worked around for now it goes into the Product Backlog and prioritized based on its value. If the issue is a “fire” or defect that cannot be worked around then it must be fixed immediately. The development will put the fire into their current list of work in the Sprint Backlog and figure out how it effects their commitment to deliver on their current iteration.

Defects are captured in bug databases in many organizations. Teams using the Scrum process to manage their software development find themsves in a predicament. Do we continue working from two lists, the Product Backlog of desired features and bug database? Or do we incorporate items from the bug database into the Product Backlog? I suggest all teams should incorporate defects into the Product Backlog. There are multiple reasons to do this:

  • Development team does not make priority decisions for the business stakeholders. If the development team decides to work on defects rather than desired features then they are deciding the defects are higher priority than the desired features without including the Product Owner in the decision-making process.
  • Minimizes the amount of hidden work done by the development team. By providing visibility into the defects, the development team is being transparent about the state of the software they are working on.
  • Provides the Product Owner with an opportunity to prioritize the defect lower. The Product Owner could decide the defect is not important enough to fix at this time.
  • Allows development team and Product Owner to design a solution for dealing with defects. From time to time the defect provides insight into a design flaw that the Product Owner would like to improve.

Ultimately, the development is able to maintain alignment with business priorities for the software. Priorities are decided based upon the full reality of the software, new features and defects included.

A single work queue, such as the Product Backlog, provides visibility to the development team about current expectations about upcoming work. The Product Owner should share the Product Backlog with the development team and discuss the direction of the product beyond the next iteration. As the development team gains knowledge about the direction of the product they will be able to provide input into the Product Backlog. This visibility is important so Product Backlog items do not surprise the development team when it is too late to prepare a proper solution.