Posts Tagged oracle google lawsuit

Oracle, Android and the copy claims: SCO all over again?

Second important update: After quite some digging, I have finally found out that the file had the following history:

  • An initial import, from a private branch to the public git repo, with this commitdiff, at Sat, 10 Jan 2009 01:50:54
  • A deletion of the file and of most of the imported branch at Wed, 4 Mar 2009 02:28:14, with this commitdiff
  • The branch got re-imported, with all new files, at Wed, 4 Mar 2009 03:28:47, with this commitdiff, without PolicyNodeImpl.java

So the file was present in the git repo from Jan, 10 to March, 4; after checking the test execution code, it is clear that the code itself was not included in the final build (delivered to handsets) but was part of a test harness, that (funnily) was mostly silenced during the development period due to the majority of tests failing :-) It is however clear that the code itself was distributed, as it was freely accessible online and through the git tree (and – funnily – it is still available under the same means). It was, however, not part of the Android SDK release, as Android 1.6 rel2 was released in December 2009, while rel3 was released in May, with the commit diff already applied.

Important update: I have verified that the code included in Android is actually a decompilation of an old Java 1.5 class file, and my own comparison is invalid, as it was done with a recent Java edition (that does have more changes – thus suggesting a reimplementation). Also, it seems that Harmony actually has not that code in its repo – despite the fact that in Android is part of the initial import under the “Harmony” subproject. My apologies.

Sigh. I had higher hopes for Oracle – while the initial complaint was dull and unsubstantial, the claims of actual copying of source code was an interesting twist (apart from the patents, of course – but that is a totally different world). Now, as ZDnet promptly writes, Oracle amended the complaint, and published the scribd link with the entire text (by the way: the HTML5 version of Scribd really, really rocks. End of parenthesis.) The relevant parts are:

40. Android includes infringing class libraries and documentation. Approximately one third of Android’s Application Programmer Interface (API) packages (available at http://developer.android.com/reference/packages.html) are derivative of Oracle America’s copyrighted Java API packages (available at http://download-llnw.oracle.com/javase/1.5.0/-docs/api/ and http://download-llnw.oracle.com/javase/1.4.2/docs/api/) and corresponding documents. The infringed elements of Oracle America’s copyrighted work include Java method and class names, definitions, organization, and parameters; the structure, organization and content of Java class libraries; and the content and organization of Java’s documentation. Examples of this copying are illustrated in Exhibit I to this complaint. In at least several instances, Android computer program code also was directly copied from copyrighted Oracle America code. For example, as may be readily seen in Exhibit J, the source code in Android’s “PolicyNodeImpl.java” class is nearly identical to “PolicyNodeImpl.java” in Oracle America’s Java, not just in name, but in the source code on a line-for-line basis.”

Hm. First of all, the definition of line-for-line equality is not correct here, as the lines are different (but quite similar). I have not developed for quite some time, but I would say that it is not strange to see similarities within the API constraints. Second, while technically part of Android, the code is Apache Harmony, a reimplementation of J2SE that tried (for many, many years) to get the compliance toolkit from Sun, but never did (and now will never do).

But the relevant point is different: the PolicyNodeImpl.java that is presented comes from the OpenJDK distribution, and was as such released under the GPL+ClassPath exception (something that is not mentioned anywhere within the complaint, by the way). Here, the claims are two and different: the first is that Android (actually, Harmony) copied its API that Oracle claims is copyrighted. The second claim is that the actual source code of the PolicyNodeImpl.java file has been copied verbatim.

Let’s start with the first one: the claim that Oracle Java APIs are protected and copyrighted. On this, it seem to me that the interface definition themselves (not the actual source code) as a mere interface does not fall within the copyright provisions, unless the actual names are trademarked, and thus its implementation requires the actual copying of a protected name in a way that is deemed incompatible by its licensee (something similar was done by Autodesk, embedding a copyrighted phrase that if not included in the file prevented the application from opening it directly). I believe that this is not the case, as the names within the source code seem to lack any “TM” or the direct use of “Java” in a way that may suggest its direct protection as a trademark.I(t should be noted that both “Java” and “OpenJDK” are trademarked, and its use is explicitly forbidden unless the code is a

And now, for the claim that the code is actually copied, here is in its glory the full diff (note: if you download the OpenJDK source you don’t get the file; I had to grab it from here in the Mercurial publication site, the raw file is this one). It seem to me that this is actually a reimplementation and not a straight copy as Oracle claims – but I would like to ask my readers for their opinion.

A disclaimer: I am not a Oracle hater, a Google or Apache fanboy, and I have no relationship with them all.

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or moreCopyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 atDO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 *     http://www.apache.org/licenses/LICENSE-2.0This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the LicenseThis code is distributed on an "AS IS" BASIS,in the hope that it will be useful, but WITHOUT
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressWARRANTY; without even the implied warranty of MERCHANTABILITY or implied.
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the specific language governing permissionsLICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package sun.security.provider.certpath;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.security.cert.*;
/**
 * Implements the <code>PolicyNode</code> interface.
 * <p>
 * This class provides an implementation of the <code>PolicyNode</code>
 * interface, and is used internally to build and search Policy Trees.
 *  limitations underWhile the License.implementation is mutable during construction, it is immutable
 * before returning to a client and no mutable public or protected methods
 * are exposed by this implementation, as per the contract of PolicyNode.
 *
 * @since       1.4
 * @author      Seth Proctor
 * @author      Sean Mullan
 */
package org.apache.harmony.security.tests.support.cert;
import java.security.cert.PolicyNode;
import java.util.*;
publicfinal class PolicyNodeImpl implements PolicyNode {
    /**
     * Use to specify the special policy "Any Policy"
     */
    private static final String ANY_POLICY = "2.5.29.32.0";
    // every node has one parent, and zero or more children
    private PolicyNodeImpl mParent;
    private HashSetHashSet<PolicyNodeImpl> mChildren;
    // the 4 fields specified by RFC 3280
    private String mValidPolicy;
    private HashSetHashSet<PolicyQualifierInfo> mQualifierSet;
    private boolean mCriticalityIndicator;
    private HashSetHashSet<String> mExpectedPolicySet;
    private boolean mOriginalExpectedPolicySet;
    // the tree depth
    private int mDepth;
    private// immutability flag
    private boolean isImmutable;
    public PolicyNodeImpl(PolicyNodeImpl policynodeimpl,isImmutable = false;
    /**
     * Constructor which takes a <code>PolicyNodeImpl</code> representing the
     * parent in the Policy Tree to this node. If null, this is the
     * root of the tree. The constructor also takes the associated data
     * for this node, as found in the certificate. It also takes a boolean
     * argument specifying whether this node is being created as a result
     * of policy mapping.
     *
     * @param parent the PolicyNode above this in the tree, or null if this
     *               node is the tree's root node
     * @param validPolicy a String s,representing this node's valid policy OID
     * @param qualifierSet the Set set,
                   boolean flag,of qualifiers for this policy
     * @param criticalityIndicator a boolean representing whether or not the
     *                             extension is critical
     * @param expectedPolicySet a Set set1,of expected policies
     * @param generatedByPolicyMapping a boolean flag1)indicating whether this
     * node was generated by a policy mapping
     */
    PolicyNodeImpl(PolicyNodeImpl parent, String validPolicy,
                Set<PolicyQualifierInfo> qualifierSet,
                boolean criticalityIndicator, Set<String> expectedPolicySet,
                boolean generatedByPolicyMapping) {
        isImmutable = false;
        mParent = policynodeimpl;parent;
        mChildren = new HashSet();
        if(sHashSet<PolicyNodeImpl>();
        if (validPolicy != null) {
            mValidPolicy = s;
        } else {validPolicy;
        else
            mValidPolicy = "";
        }
        if(setif (qualifierSet != null) {
            mQualifierSet = new HashSet(set);
        } else {HashSet<PolicyQualifierInfo>(qualifierSet);
        else
            mQualifierSet = new HashSet();
        }HashSet<PolicyQualifierInfo>();
        mCriticalityIndicator = flag;
        if(set1criticalityIndicator;
        if (expectedPolicySet != null) {
            mExpectedPolicySet = new HashSet(set1);
        } else {HashSet<String>(expectedPolicySet);
        else
            mExpectedPolicySet = new HashSet();
        }HashSet<String>();
        mOriginalExpectedPolicySet = !flag1;
        if(mParent!generatedByPolicyMapping;
        // see if we're the root, and act appropriately
        if (mParent != null) {
            mDepth = mParent.getDepth() + 1;
            mParent.addChild(this);
        } else {
            mDepth = 0;
        }
    }
    PolicyNodeImpl(PolicyNodeImpl policynodeimpl,
                   PolicyNodeImpl policynodeimpl1)/**
     * Alternate constructor which makes a new node with the policy data
     * in an existing <code>PolicyNodeImpl</code>.
     *
     * @param parent a PolicyNode that's the new parent of the node, or
     *               null if this is the root node
     * @param node a PolicyNode containing the policy data to copy
     */
    PolicyNodeImpl(PolicyNodeImpl parent, PolicyNodeImpl node) {
        this(policynodeimpl, policynodeimpl1.mValidPolicy, ((Set) (policynodeimpl1.mQualifierSet)), policynodeimpl1.mCriticalityIndicator, ((Set) (policynodeimpl1.mExpectedPolicySet)),
        this(parent, node.mValidPolicy, node.mQualifierSet,
             node.mCriticalityIndicator, node.mExpectedPolicySet, false);
    }
    public PolicyNode getParent() {
        return mParent;
    }
    public IteratorIterator<PolicyNodeImpl> getChildren() {
        return Collections.unmodifiableSet(mChildren).iterator();
    }
    public int getDepth() {
        return mDepth;
    }
    public String getValidPolicy() {
        return mValidPolicy;
    }
    public SetSet<PolicyQualifierInfo> getPolicyQualifiers() {
        return Collections.unmodifiableSet(mQualifierSet);
    }
    public SetSet<String> getExpectedPolicies() {
        return Collections.unmodifiableSet(mExpectedPolicySet);
    }
    public boolean isCritical() {
        return mCriticalityIndicator;
    }
    /**
     * Return a printable representation of the PolicyNode.
     * Starting at the node on which this method is called,
     * it recurses through the tree and prints out each node.
     *
     * @return a String describing the contents of the Policy Node
     */
    public String toString() {
        StringBuffer stringbufferbuffer = new StringBuffer(asString());
        for(Iterator iteratorStringBuffer(this.asString());
        Iterator<PolicyNodeImpl> it = getChildren(); iterator.hasNext(); stringbuffer.append((PolicyNodeImpl)iterator.next()));
        while (it.hasNext()) {
            buffer.append(it.next());
        }
        return stringbuffer.toString();buffer.toString();
    }
    // private methods and package private operations
    boolean isImmutable() {
        return isImmutable;
    }
    /**
     * Sets the immutability flag of this node and all of its children
     * to true.
     */
    void setImmutable() {
        if(isImmutable)  return;
        PolicyNodeImpl policynodeimpl;
        for(Iterator iterator = mChildren.iterator(); iterator.hasNext(); policynodeimpl.setImmutable())
            policynodeimpl = (PolicyNodeImpl)iterator.next();if (isImmutable)
            return;
        for (PolicyNodeImpl node : mChildren) {
            node.setImmutable();
        }
        isImmutable = true;
    }
    private/**
     * Private method sets a child node. This is called from the child's
     * constructor.
     *
     * @param child new <code>PolicyNodeImpl</code> child node
     */
    private void addChild(PolicyNodeImpl policynodeimpl)child) {
        if(isImmutable)
        if (isImmutable) {
            throw new IllegalStateException("PolicyNode is immutable");
        } else {
            mChildren.add(policynodeimpl);
            return;
        }
        mChildren.add(child);
    }
    void/**
     * Adds an expectedPolicy to the expected policy set.
     * If this is the original expected policy set initialized
     * by the constructor, then the expected policy set is cleared
     * before the expected policy is added.
     *
     * @param expectedPolicy a String representing an expected policy.
     */
    void addExpectedPolicy(String s)expectedPolicy) {
        if (isImmutable) {
        if(isImmutable)
            throw new IllegalStateException("PolicyNode is immutable");
        if(mOriginalExpectedPolicySet)}
        if (mOriginalExpectedPolicySet) {
            mExpectedPolicySet.clear();
            mOriginalExpectedPolicySet = false;
        }
        mExpectedPolicySet.add(s);mExpectedPolicySet.add(expectedPolicy);
    }
    void/**
     * Removes all paths which don't reach the specified depth.
     *
     * @param depth an int representing the desired minimum depth of all paths
     */
    void prune(int i)depth) {
        if(isImmutable)
        if (isImmutable)
            throw new IllegalStateException("PolicyNode is immutable");
        if(mChildren.size()// if we have no children, we can't prune below us...
        if (mChildren.size() == 0)
            return;
        Iterator iteratorIterator<PolicyNodeImpl> it = mChildren.iterator();
        do
        while (it.hasNext()) {
            if(!iterator.hasNext())  break;
            PolicyNodeImpl policynodeimplnode = (PolicyNodeImpl)iterator.next();
            policynodeimpl.prune(i);
            if(policynodeimpl.mChildren.size()it.next();
            node.prune(depth);
            // now that we've called prune on the child, see if we should
            // remove it from the tree
            if ((node.mChildren.size() == 00) && i(depth > mDepth + 1)
                iterator.remove();1))
                it.remove();
        } while(true);
    }
    void/**
     * Deletes the specified child node of this node, if it exists.
     *
     * @param childNode the child node to be deleted
     */
    void deleteChild(PolicyNode policynode)childNode) {
        if(isImmutable)
        if (isImmutable) {
            throw new IllegalStateException("PolicyNode is immutable");
        } else {
            mChildren.remove(policynode);
            return;
        }
        mChildren.remove(childNode);
    }
    /**
     * Returns a copy of the tree, without copying the policy-related data,
     * rooted at the node on which this was called.
     *
     * @return a copy of the tree
     */
    PolicyNodeImpl copyTree() {
        return copyTree(null);
    }
    private PolicyNodeImpl copyTree(PolicyNodeImpl policynodeimpl)parent) {
        PolicyNodeImpl policynodeimpl1newNode = new PolicyNodeImpl(policynodeimpl,PolicyNodeImpl(parent, this);
        PolicyNodeImpl policynodeimpl2;
        for(Iterator iterator = mChildren.iterator(); iterator.hasNext(); policynodeimpl2.copyTree(policynodeimpl1))
            policynodeimpl2 = (PolicyNodeImpl)iterator.next();
        for (PolicyNodeImpl node : mChildren) {
            node.copyTree(newNode);
        }
        return policynodeimpl1;newNode;
    }
    Set/**
     * Returns all nodes at the specified depth in the tree.
     *
     * @param depth an int representing the depth of the desired nodes
     * @return a <code>Set</code> of all nodes at the specified depth
     */
    Set<PolicyNodeImpl> getPolicyNodes(int i)depth) {
        HashSet hashset
        Set<PolicyNodeImpl> set = new HashSet();
        getPolicyNodes(i, ((Set) (hashset)));HashSet<PolicyNodeImpl>();
        getPolicyNodes(depth, set);
        return hashset;set;
    }
    private/**
     * Add all nodes at depth depth to set and return the Set.
     * Internal recursion helper.
     */
    private void getPolicyNodes(int i, Setdepth, Set<PolicyNodeImpl> set) {
        if(mDepth
        // if we've reached the desired depth, then return ourself
        if (mDepth == i)depth) {
            set.add(this);
        } else {
            PolicyNodeImpl policynodeimpl;
            for(Iterator iterator = mChildren.iterator(); iterator.hasNext(); policynodeimpl.getPolicyNodes(i, set))
                policynodeimpl = (PolicyNodeImpl)iterator.next();for (PolicyNodeImpl node : mChildren) {
                node.getPolicyNodes(depth, set);
            }
        }
    }
    Set getPolicyNodesExpected(int i,/**
     * Finds all nodes at the specified depth whose expected_policy_set
     * contains the specified expected OID (if matchAny is false)
     * or the special OID "any value" (if matchAny is true).
     *
     * @param depth an int representing the desired depth
     * @param expectedOID a String s,encoding the valid OID to match
     * @param matchAny a boolean flag)indicating whether an expected_policy_set
     * containing ANY_POLICY should be considered a match
     * @return a Set of matched <code>PolicyNode</code>s
     */
    Set<PolicyNodeImpl> getPolicyNodesExpected(int depth,
        String expectedOID, boolean matchAny) {
        if (expectedOID.equals(ANY_POLICY)) {
        if(s.equals("2.5.29.32.0"))
            return getPolicyNodes(i);
        elsegetPolicyNodes(depth);
        } else {
            return getPolicyNodesExpectedHelper(i, s, flag);getPolicyNodesExpectedHelper(depth, expectedOID, matchAny);
        }
    }
    private SetSet<PolicyNodeImpl> getPolicyNodesExpectedHelper(int i, String s,depth,
        String expectedOID, boolean flag)matchAny) {
        HashSet hashset
        HashSet<PolicyNodeImpl> set = new HashSet();
        if(mDepthHashSet<PolicyNodeImpl>();
        if (mDepth < i)depth) {
            PolicyNodeImpl policynodeimpl;
            for(Iterator iterator = mChildren.iterator(); iterator.hasNext(); hashset.addAll(policynodeimpl.getPolicyNodesExpectedHelper(i, s, flag)))
                policynodeimpl = (PolicyNodeImpl)iterator.next();
            for (PolicyNodeImpl node : mChildren) {
                set.addAll(node.getPolicyNodesExpectedHelper(depth,
                                                             expectedOID,
                                                             matchAny));
            }
        } else if(flag) {
            if(mExpectedPolicySet.contains("2.5.29.32.0"))
                hashset.add(this);
        }
            if (matchAny) {
                if (mExpectedPolicySet.contains(ANY_POLICY))
                    set.add(this);
            } else if(mExpectedPolicySet.contains(s)) {
            hashset.add(this);
                if (mExpectedPolicySet.contains(expectedOID))
                    set.add(this);
            }
        }
        return hashset;set;
    }
    Set/**
     * Finds all nodes at the specified depth that contains the
     * specified valid OID
     *
     * @param depth an int representing the desired depth
     * @param validOID a String encoding the valid OID to match
     * @return a Set of matched <code>PolicyNode</code>s
     */
    Set<PolicyNodeImpl> getPolicyNodesValid(int i,depth, String s)validOID) {
        HashSet hashset
        HashSet<PolicyNodeImpl> set = new HashSet();
        if(mDepthHashSet<PolicyNodeImpl>();
        if (mDepth < i)depth) {
            PolicyNodeImpl policynodeimpl;
            for(Iterator iterator = mChildren.iterator(); iterator.hasNext(); hashset.addAll(policynodeimpl.getPolicyNodesValid(i, s)))
                policynodeimpl = (PolicyNodeImpl)iterator.next();
            for (PolicyNodeImpl node : mChildren) {
                set.addAll(node.getPolicyNodesValid(depth, validOID));
            }
        } else if(mValidPolicy.equals(s)) {
            hashset.add(this);
            if (mValidPolicy.equals(validOID))
                set.add(this);
        }
        return hashset;set;
    }
    private static String policyToString(String s)oid) {
        if(s.equals("2.5.29.32.0"))
        if (oid.equals(ANY_POLICY)) {
            return "anyPolicy";
        } else {
            return s;oid;
        }
    }
    /**
     * Prints out some data on this node.
     */
    String asString() {
        if(mParentif (mParent == null) {
            return "anyPolicy  ROOT\n";
        StringBuffer stringbuffer} else {
            StringBuffer sb = new StringBuffer();
        int
            for (int i = 0;
        for(int j0, n = getDepth(); i < j;n; i++)
            stringbuffer.append(" {
                sb.append("  ");
        stringbuffer.append(policyToString(getValidPolicy()));
        stringbuffer.append("
            }
            sb.append(policyToString(getValidPolicy()));
            sb.append("  CRIT: ");
        stringbuffer.append(isCritical());
        stringbuffer.append("
            sb.append(isCritical());
            sb.append("  EP: ");
        for(Iterator iterator = getExpectedPolicies().iterator(); iterator.hasNext(); stringbuffer.append(" "))
            for (String policy : getExpectedPolicies()) {
            String s = (String)iterator.next();
            stringbuffer.append(policyToString(s));
                sb.append(policyToString(policy));
                sb.append(" ");
            }
            sb.append(" (");
            sb.append(getDepth());
            sb.append(")\n");
            return sb.toString();
        }
        stringbuffer.append(" (");
        stringbuffer.append(getDepth());
        stringbuffer.append(")\n");
        return stringbuffer.toString();
    }
}

,

19 Comments

Oracle/Google: the strategy behind Sun, Oracle and the OSS implications

In my previous post, I tried to provide some details on what in my opinion were the most relevant legal and licensing aspects of the recently launched Oracle lawsuit against Google. I would like now to provide some perspective on what may have been the motives behind this lawsuit, and what are the possible implications for the Java and Open Source communities.

First of all, it is clear that, as I mentioned before, Google turned the lawsuit into a positive event for their (slightly battered) public image. By turning the lawsuit against Android into an attack to the open source community, Google effectively created a positive image, as David unjustly accused by the Oracle giant. It is also clear that the lawsuit itself is actually quite weak, focusing on a copyright claim that is very vague (given the fact that Google never claimed to use Java), and a set of patent claims for techniques that are probably not relevant anymore (especially in the post-Bilski era). One of the possible reasons for this is to be sure that even the widely different Dalvik machine would be at least partially covered; the other is the fact that all of Classpath was included in the OIN “System Components” covered technologies. Since both Oracle and Google are part of OIN, I suspect that Oracle wanted to avoid any potential complication coming from this “broken marriage”.

But – this is not the only relevant aspect. Actually, an angle that is probably more important is the impact of the lawsuit on Java, Java for mobile, Android and the OSS communities that were part of the Sun technology landscape.

Enterprise Java: no change at all. Java is a very strong brand among corporate developers, and I doubt that the lawsuit will change anything at all; in fact, all the various licensee of the Java full specification are on perfectly legal grounds, and face no problem at all. Despite the opportunistic claims by Miguel De Icaza (that suggests that Mono/C# would have been a better choice), there is nothing in the lawsuit that would imply that other Java or Java-related technologies may be impacted (actually, Mono and the CLR are in the same situation as Dalvik, actually).

Mobile Java: as I mentioned before, the lawsuit put the last stone on the JavaME grave. The only potentially relevant route away from the land of the dead could have been JavaFX; that was too little, too late – incomplete, missing several pieces, missing a roadmap, and uselessly released as a binary-only project. Android  used the Java language, extended it with mobile-specific classes that were more modern and more useful for recent smartphones and even non-phone applications (like entertainment devices, automotive and navigation devices). It is not a surprise, that coupled with the Google brand name, Android surged in popularity so much as to become a threat.

Oracle OSS projects: Oracle has always been an opportunistic user of open source. With the term “opportunistic” I am not implying any negative connotation: simply the observation that Oracle dabbled in open source whenever there was an opportunity to reduce its own research and development costs. If you look at oracle projects, it is clear that all projects are related to infrastructural functionality for the Oracle run-time and for developers tools (using Eclipse as a basis). I was not able to find any “intrinsic” open source project started or adopted by Oracle that was not focused on this approach. So, for those projects, I believe that there will be no difference; for example, I believe that the activity on the Oracle-sponsored BTRFS project will not change significantly. Oracle, actually does not care at all if they are seen as “enemies”, or if their projects are not used anymore by others. What they care for is for their patches to be included in Linux. Remember that Oracle is an “old style” company; it does have two basic product lines: its database and its set of enterprise applications. Everything else is not quite necessary, and probably will be abandoned.

Sun OSS projects: as for Sun, there is a long preamble first. Sun has always been, first and foremost, an engineering company – something like Silicon Graphics in the past, or more recently Google. Sun had open sourced something of value whenever it was necessary to establish a common platform or protocol, like NFS or NIS+; but it was the advent of Jonathan Schwartz that actually turned things towards open source. The ponytailed CEO tried to turn the Sun behemoth towards a fully open strategy, but was unable to manage the conversion before being ousted out. It is a pity, actually – Sun could have leveraged its size, large number of technical partners and amount of technologies to become a platform provider like RedHat – but 10 times larger. The problem of this strategy is that it implies a large amount of cooperative development, and thus a substantial downsizing of the company itself. The alternative could have been the use of an open-core like strategy, for example creating a scalable JVM designed to auto-partition code execution on network of computers. The basic JVM could have been dual licensed, with the enhanced one released on a proprietary basis; this could have leveraged the exceptional Sun expertise in grid and parallel computing, filesystems and introspection systems.

But Sun never managed to complete the path – it dwindled left and right, with lots of subprojects that were started and abandoned. The embracing of PostgreSQL, its later abandonment, the latter embrace of MySQL, that was then not integrated anywhere; the creation of substantial OSS projects from their proprietary offering, but then losing interest as soon as a project started to become a threat for the proprietary edition. There is no surprise that despite the incredible potential, Sun never recouped much of their OSS investment (despite the great growth in their latest quarters, the OSS services remained a small portion of their revenues). Now that Oracle has taken control, I believe that Sun “openness” will quickly fade towards small, utilitarian projects – so, even if now everyone looks at Oracle with anger, noone at Oracle could care less.

Why oracle sued? The blogosphere is exploding with possible answers; my own two hypothesis are:

  • Oracle found a substantial technology it acquired (Java) losing value in what is the hottest tech market today, namely mobile systems. Sun had no credible plan to update JavaME, no credible alternative, and thus Android (that is loosely java based) is at the same time a threat to an acquired asset and (from their point of view) a stolen technology. Since anyone can follow the same path, Oracle wants to make sure that noone else would try to leverage Java to create an unlicensed (and uncontrolled) copy.
  • Oracle wants a piece of the mobile enterprise market, and the alternatives are unavailable (Apple does not want anything to do with Java, Blackberry is a JavaME licensee, Windows Mobile is backed by arch-rival Microsoft). Android is working well, grows incredibly fast, and Oracle wants a piece of it; Google probably rebuffed initial contacts, and now Oracle is showing the guns to make Google obey. I am skeptical, however, that Google would back down on what is becoming its most important growth path. The lawsuit itself is quite weak, and Google would risk too much by licensing the TCK from Oracle; they would basically destroy their opportunity for independent development. It is never a good idea to corner someone – if you leave no alternative, fight is the only answer.

I believe that the first one is the most probable one; Larry Ellison should know that cornering Google would not be sufficient to make them capitulate – they have too much to lose. But this will not be sufficient to create an opportunity for Oracle; I believe that the lawsuit will actually bring nothing to Oracle, and lots of advantages to Google. But only time will tell; the only thing that I can predict for sure right now is that Solaris will quickly fade from sight (as it will be unable to grow at the same rate of Linux) exactly like AIX and HP-UX: a mature and backroom tech, but nothing that you can base a growth strategy upon.

,

14 Comments