Summary of Investigation

This document summarizes the results of the investigation into the allegations of similarity between JBoss code and Geronimo code.   The original allegations are detailed in the letter dated October 31, 2003.

This document attempts to describe and characterize the technical issues surrounding the allegations.  This is not a formal response by the Apache Software Foundation.

In the letter there are three named exhibits, A, B and C, and a fourth similarity that for the purposes of this discussion we will refer to as Assertion D.

Specifically, the exhibits :

Notes

  1. The source code for Apache Geronimo is accessible via CVS at http://cvs.apache.org/view.cvs/incubator-geronimo/  and all Geronimo code references are relative to this root.
  2. The source code for JBoss is accessible via CVS at http://cvs.sourceforge.net/viewcvs.py/jboss/jboss/src/main/ and all JBoss code references are relative to this root.
  3. The Apache Software License is a business-friendly license that allows others to take our software and use it as they please, as long as they respect the terms of our license.  This will be important for Exhibits A and B - the license clearly states that
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 

Summary for Exhibit A

Exhibit A is concerned with similarity between org.apache.geronimo.core.log.XLevel and org.jboss.logging.XLevel rev 1.3.2.1.

This issue has been exhaustively researched (http://www.qos.ch/logging/jboss.html) by the founder of the log4j project, Ceki Gülcü.  His summary :

"In summary, the source code incriminated by Exhibit A existed at the Apache Software Foundation at least 6 months before it made its first appearance at JBoss. Thus, in relation to this exhibit, I cannot see how JBoss LLC has any valid claims against the ASF for this particular code. In fact, it appears that by neglecting to attribute the code and follow the Apache License for this example, the violation of copyright would be the exact reverse. "

Ceki has traced back the history of the XLevel class, and thus we claim that the XLevel code originated at the ASF as part of the log4j project. Thus, we believe that Exhibit A is invalid due to the fact that the original source of the code in question is copyrighted by the ASF.

Summary for Exhibit B

Exhibit B in concerned with similarity between org.apache.geronimo.core.log.PatternParser and  org.jboss.logging.layout.PatternParserEx

According to the same research for Exhibit A by Ceki Gülcü :

"The PatternParserEx class, cited in Mr. David J. Byer's letter to the ASF, very closely follows the pattern established MyPatternParser and AppServerPatternParser classes. The earliest record of this class in JBoss source code repository dates to September 15th, 2002. Unless JBoss LLC claims that PatternParserEx predates MyPatternParser or AppServerPatternParser classes found in log4j, it looks like the JBoss LLC removed the existing Apache copyright when it based PatternParserEx class on modified versions of MyPatternParser and AppServerPatternParser. This is prohibited by the first clause of the Apache Software License.

We believe that the claims in Exhibit B are invalid owing to the fact that the code in question was based on code in the Apache log4j codebase.

Summary for Exhibit C

Exhibit C is concerned with the similarity between org.apache.geronimo.common.InvocationType and org.jboss.invocation.InvocationType.  The following summary is based on discussion from the geronimo-dev list.

The initial version of org.jboss.invocation.InvocationType in the JBoss CVS repository can be found at the following location:

http://cvs.sourceforge.net/viewcvs.py/jboss/jboss/src/main/org/jboss/invocation/InvocationType.java?rev=1.1&view=markup

This contains a very similar code excerpt to that cited in the letter from JBoss Group LLC:

   public static final InvocationType REMOTE =
         new InvocationType("REMOTE");
   public static final InvocationType LOCAL =
         new InvocationType("LOCAL");
   public static final InvocationType HOME =
         new InvocationType("HOME");
   public static final InvocationType LOCALHOME =
         new InvocationType("LOCALHOME");

This code was contributed to the JBoss project by dsundstrom (Dain Sundstrom) on 7/14/2002. As the original copyright holder, Dain would be free to contribute this code to Geronimo as well.

The JBoss version of this code was modified exclusively by dsundstrom up to and including the 1.3 revision (dated 10/30/2002) in the JBoss CVS, where the code had evolved to the following:

   public static final InvocationType REMOTE =
         new InvocationType("REMOTE", false, false);
   public static final InvocationType LOCAL =
         new InvocationType("LOCAL", false, true);
   public static final InvocationType HOME =
         new InvocationType("HOME", true, false);
   public static final InvocationType LOCALHOME =
         new InvocationType("LOCALHOME", true, true);


Dain had the right to contribute to Geronimo the code up to (but not including) the changes made by Scott or anyone else

Dain's last rev is

http://cvs.sourceforge.net/viewcvs.py/*checkout*/jboss/jboss/src/main/org/jboss/invocation/InvocationType.java?content-type=text%2Fplain&rev=1.3

The latest rev in JBoss is v 1.5, so we need to figure out what happened between v1.3, which Dain had the right to contribute to the ASF

JBoss 1.3 :
    committed by Dain, for which he has the rights to contribute and re-license here in Geronimo under the ASL

JBoss v1.3 -> v1.4 :
    a) Switched from using a static int to a final static int as the max value for the InvocationType array.  We see the same in the Geronimo code. This is common, accepted practice for creating constants in Java, and would be suggested by any code inspector (like Idea or Eclipse).  In my opinion, Dain should have his hand slapped for not doing it this way in the first place.
    b) Switched to a statically allocated array [] rather than an ArrayList for holding the invocationType objects.  This change is in the Geronimo code.
    c) Changed the signature of the InvocationType from the Dain way (new InvocationType("LOCAL", false, true)) that is in Geronimo now, to a different way ( new InvocationType("HOME", 2)).  Clearly the Geronimo code didn't copy this change.
    d) Removed  two booleans isLocal and isHome, present in the Dain-contributed 1.3.  These variables persist in the Geronimo version as local and home.  This change was not adopted by Dain for Geronimo.

Jboss v1.4 -> v1.5 :
   Added a new invocation type 'SERVICE_ENDPOINT', which is not present in the Geronimo code.  I conclude that any changes between v1.4 and 1.5 of the JBoss code were not co-opted into the geronimo codebase.


Here's my conclusion.  I would appreciate commentary :

Conclusion
==========

Dain contributed the same code to Geronimo that he contributed to JBoss.

The only difference between his JBoss contributions, for which he has complete rights to contribute and relicense elsewhere, is that he changed the Geronimo implementation to use an array of rather than an ArrayList to hold the InvocationType objects, and a static final int 'constant' to keep the size of that array rather than a static int field.

Summary of Assertion D

Assertion D is concerned with the similarity between org.apache.geronimo.common.Invocation and org.jboss.invocation.Invocation.  Further, the claim is that both files contain "AsIs", "Transient" and "Marshalled", which are believed to be JBoss-specific payloads, and thus could only be there via copying. Further, the Invocation file is central to the JBoss architecture, and thus copying could have great impact throughout Geronimo.

The file org.apache.geronimo.core.service.Invocation currently is a riff on java.util.Map, namely :

public interface Invocation {

    Object get(InvocationKey key);
    void put(InvocationKey key, Object value);
}

Clearly this can't be what the lawyers are talking about.  However, it used to be, when the code first placed into Geronimo, slightly different :

http://cvs.apache.org/viewcvs/incubator-geronimo/modules/core/src/java/org/apache/geronimo/common/Attic/Invocation.java?rev=1.1&content-type=text/vnd.viewcvs-markup

public interface Invocation {
    Object getMarshal(Object key);

    void putMarshal(Object key, Object value);

    Object getAsIs(Object key);

    void putAsIs(Object key, Object value);

    Object getTransient(Object key);

    void putTransient(Object key, Object value);
}

This is still an interface, but dealing with the three notions of 'Marshal', 'AsIs', and 'Transient'.  This is what the JBoss Group LLCs lawyers are referring to.  Now, looking at the Invocation class in JBoss, and looking at the version in their CVS at the time of the import into Geronimo, 1.10.2.6, there is an implementation of the same notion in a method - following snipped out for brevity :

/**
    * Advanced store
    * Here you can pass a TYPE that indicates where to put the value.
    * TRANSIENT: the value is put in a map that WON'T be passed
    * AS_IS: no need to marshall the value when passed (use for all JDK
    *    java types)
    * PAYLOAD: we need to marshall the value as its type is application specific
    */
   public void setValue(Object key, Object value, PayloadKey type)
   {
      if(type == PayloadKey.TRANSIENT)
      {
          transient_payload.put(key,value);
      }
      else if(type == PayloadKey.AS_IS)
      {
          as_is_payload.put(key,value);
      }
      else if(type == PayloadKey.PAYLOAD)
      {
          payload.put(key,value);
      }
      else
      {
         throw new IllegalArgumentException("Unknown PayloadKey: " + type);
      }
   }

It appears that this is a storage class for moving bits through their invocation/interceptor mechanism, and that they are doing what appears to be an early optimization by having the caller define via the keytype if a) the data doesn't need to be marshalled as it's staying put on this side of the wire (TRANSIENT), b) the data doesn't need to have any special care and feeding as it's a JDK data type (ASIS), or c) it will need to be marshalled (PAYLOAD).

So it's clear to me that the code originally in Geronimo (and now in the Attic) implemented this *idea* in their interface, moving it outside of the Invocation implementation and into the interface.  This is an implementation of the idea.

Now, I guess we have to come back to the code as it exists today in the o.a.g.core.service package.  Repeating for Invocation.java, it is now much simpler - the Geronimo developers got rid of the 'Asis', 'Marshal' and 'Transient' 'modifiers' on the methods and reduced it to

public interface Invocation {

    Object get(InvocationKey key);
    void put(InvocationKey key, Object value);
}

where

public interface InvocationKey {

    boolean isTransient();
}

so now the idea of declaring something as not going over the wire (my assumption) is taken care of in the key itself into this map, letting (I assume again) the endpoint doing the serialization decide if the element in the map needs to go based on the isTransient() method, and how marshalled based on the class.

Summary so far : the original code had an expression of the idea of 'Marshall', 'AsIs' and 'Transient'.  Most of the idea was dropped.  All that remains of the idea is letting the caller declare the data as transient.

While the JBoss lawyers assert that "the Invocation file is central to the architecture of both JBoss and Geronimo", we believe that this claim is invalid  because if this notion of AsIs, Transient and Marshalled was 'central to the architecture', it couldn't be dropped to the degree that the Geronimo developers did.  IOW, the notions of AsIs and Marshalled are NOT central to the architecture at all - they don't exist anymore.  So to summarize :

1) The original code in Geronimo (w/ getAsIs()) is not a copy of JBoss code  - it's a different implementation of an idea in the JBoss implementation.

2) The current code has thrown out all but the idea that the user of an Invocation implementation declare that data placed into that implementation is transient.