alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (IASEjbCMPEntityDescriptor.java)

This example Glassfish source code file (IASEjbCMPEntityDescriptor.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

class, collection, collection, hashmap, hashset, log, logging, map, method, method, noi18n, noi18n, persistentfieldinfo, reflection, string, string, stringbuffer, util

The Glassfish IASEjbCMPEntityDescriptor.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.deployment;

import com.sun.enterprise.deployment.interfaces.QueryParser;
import com.sun.enterprise.deployment.runtime.IASEjbCMPFinder;
import com.sun.enterprise.deployment.runtime.PrefetchDisabledDescriptor;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.util.LocalStringManagerImpl;

import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/** 
 * This class contains information about EJB1.1 and EJB2.0 CMP EntityBeans.
 */

public  class IASEjbCMPEntityDescriptor extends EjbCMPEntityDescriptor {

    private transient Class ejbClass = null;
    private String pcImplClassName = null;
    private String concreteImplClassName = null;
    private String ejbImplClassName = null;
    private String mappingProperties;
    private transient ClassLoader jcl = null;
    private String uniqueName = null;

    private String moduleDir = null;

    // for i18N
    private static LocalStringManagerImpl localStrings =
        new LocalStringManagerImpl(IASEjbCMPEntityDescriptor.class);
    private static final Logger _logger = DOLUtils.getDefaultLogger();

    // Standard String and Character variables.
    private static final char DOT                  = '.';   // NOI18N
    private static final char LIST_START           = '(';// NOI18N   
    private static final char LIST_END             = ')';   // NOI18N
    private static final char LIST_SEPARATOR       = ',';   // NOI18N
    private static final char NAME_PART_SEPARATOR  = '_';   // NOI18N
    private static final char NAME_CONCATENATOR    = ' ';   // NOI18N
    private static final String FIND               = "find"; // NOI18N
    private static final String EJB_SELECT         = "ejbSelect"; // NOI18N
    private static final String JDOSTATE           = "_JDOState"; // NOI18N
    private static final String CONCRETE_IMPL      = "_ConcreteImpl"; // NOI18N
    private static final String MAPPINGEXT         = DOT + "mapping"; // NOI18N

    private transient Collection finders = null;
    private transient Collection selectors = null;
    private transient QueryParser queryParser = null;
    private PrefetchDisabledDescriptor prefetchDisabledDescriptor = null;
    private static final Map conversionTable = createConversionTable();
    private Map oneOneFinders = new HashMap();
    private List arrOneOneFinders = new ArrayList();
    
    private void addAllInterfaceMethodsIn(Collection methodDescriptors, Class c) {
        Method[] methods = c.getMethods();
        for (int i=0; i<methods.length; i++) {
            methodDescriptors.add(methods[i]);
        }
    }

    private void addAllUniqueInterfaceMethodsIn(Collection methodDescriptors, Class c) {
        Method[] methods = c.getMethods();
        for (int i=0; i<methods.length; i++) {
        if(findEquivalentMethod(methodDescriptors, methods[i]) == null)
            methodDescriptors.add(methods[i]);
        }
    }

    public Collection getAllUniqueMethods() {
        HashSet methods = new HashSet();

        try {
            if (isRemoteInterfacesSupported()) {
                addAllUniqueInterfaceMethodsIn(methods, jcl.loadClass(getHomeClassName()));
                addAllUniqueInterfaceMethodsIn(methods, jcl.loadClass(getRemoteClassName()));
            }
            if (isLocalInterfacesSupported()) {
                addAllUniqueInterfaceMethodsIn(methods, jcl.loadClass(getLocalHomeClassName()));
                addAllUniqueInterfaceMethodsIn(methods, jcl.loadClass(getLocalClassName()));
            }
        } catch (Throwable t) {
            _logger.log( Level.WARNING,
                "enterprise.deployment_error_loading_class_excp", t ); // NOI18N
            throw new RuntimeException(t.getMessage());
        }
        return methods;

    }

    public Collection getAllMethods() {

        HashSet methods = new HashSet();

        try {
            if (isRemoteInterfacesSupported()) {
                addAllInterfaceMethodsIn(methods, jcl.loadClass(getHomeClassName()));
                addAllInterfaceMethodsIn(methods, jcl.loadClass(getRemoteClassName()));
            }

            if (isLocalInterfacesSupported()) {
                addAllInterfaceMethodsIn(methods, jcl.loadClass(getLocalHomeClassName()));
                addAllInterfaceMethodsIn(methods, jcl.loadClass(getLocalClassName()));
            }
        } catch (Throwable t) {
            _logger.log( Level.WARNING,
                    "enterprise.deployment_error_loading_class_excp", t ); // NOI18N
            throw new RuntimeException(t.getMessage());
        }
        return methods;
    }


    private Method findEquivalentMethod(Collection methods,
                                        Method methodToMatch) {
        if(methods == null)
            return null;

        Method matchedMethod = null;
        for(Iterator iter = methods.iterator(); iter.hasNext();) {
            Method next = (Method) iter.next();
            // Compare methods, ignoring declaring class.
            if( methodsEqual(next, methodToMatch, false) ) {
                matchedMethod = next;
                break;
            }
        }
        return matchedMethod;
    }

     /**
     * Checks whether two methods that might have been loaded by
     * different class loaders are equal.
     * @param compareDeclaringClass if true, declaring class will
     * be considered as part of equality test.
     */
    private boolean methodsEqual(Method m1, Method m2,
                                 boolean compareDeclaringClass) {
        boolean equal = false;

        do {
            String m1Name = m1.getName();
            String m2Name = m2.getName();

            if( !m1Name.equals(m2Name) ) { break; }
        
            String m1DeclaringClass = m1.getDeclaringClass().getName();
            String m2DeclaringClass = m2.getDeclaringClass().getName();

            if( compareDeclaringClass ) {
                if( !m1DeclaringClass.equals(m2DeclaringClass) ) { break; }
            }

            Class[] m1ParamTypes = m1.getParameterTypes();
            Class[] m2ParamTypes = m2.getParameterTypes();

            if( m1ParamTypes.length != m2ParamTypes.length ) { break; }

            equal = true;
            for(int pIndex = 0; pIndex < m1ParamTypes.length; pIndex++) {
                String m1ParamClass = m1ParamTypes[pIndex].getName();
                String m2ParamClass = m2ParamTypes[pIndex].getName();
                if( !m1ParamClass.equals(m2ParamClass) ) {
                    equal = false;
                    break;
                }
            }

        } while(false);

        return equal;
    }

    /**
     * The method returns the class instance for the ejb class.
     * @return ejb class
     */
    private Class getEjbClass() {
        if (ejbClass == null) {
            String ejbClassName = getEjbClassName();
            if(_logger.isLoggable(Level.FINE)) 
                _logger.fine("@@@@@@ Ejb name is  "+ ejbClassName); //NOI18N
            if (jcl == null) {
                String msg = localStrings.getLocalString(
                    "enterprise.deployment.error_missing_classloader", //NOI18N
                    "IASEjbCMPEntityDescriptor.getEjbClass"); //NOI18N
                _logger.log(Level.WARNING, msg);
                throw new RuntimeException(msg);
            }

            try {
                ejbClass=Class.forName(ejbClassName, true, jcl);

            } catch(ClassNotFoundException e) {
                String msg = localStrings.getLocalString(
                    "enterprise.deployment.error_cannot_find_ejbclass", //NOI18N
                        ejbClassName);
                _logger.log(Level.WARNING, msg);
                throw new RuntimeException(msg);
            }
        }
        return ejbClass;
    }

    /** 
     * Returns a collection of finder method instances.
     */
    public Collection getFinders() {
        if (finders == null) {
            String ejbClassName = getEjbClassName();
            Class ejbClass = getEjbClass();
                
            if ( super.isRemoteInterfacesSupported() ) {
                Class remoteHomeIntf = null;
                if(_logger.isLoggable(Level.FINE)) 
                    _logger.fine("@@@@@@ " + ejbClassName + //NOI18N 
                         " : Remote Interface is supported "); //NOI18N 

                try {
                    remoteHomeIntf = ejbClass.getClassLoader().loadClass(
                        super.getHomeClassName());
                } catch (ClassNotFoundException ex) {
                    _logger.log( Level.WARNING,
                         "enterprise.deployment_class_not_found", ex ); //NOI18N

                    return null;
                }

                finders = getFinders(remoteHomeIntf);
                if(_logger.isLoggable(Level.FINE)) {
                    for(Iterator iter = finders.iterator(); iter.hasNext();) {
                        Method remoteHomeMethod=(Method)iter.next();
                        _logger.fine("@@@@ adding Remote interface method " + //NOI18N
                                     remoteHomeMethod.getName() );
                    }
                }
            } //end of isRemoteInterfaceSupported

            if ( super.isLocalInterfacesSupported() ) {
                Class localHomeIntf = null;

                if(_logger.isLoggable(Level.FINE)) 
                    _logger.fine("@@@@@@ " + ejbClassName + ":  Local Interface is supported "); //NOI18N

                try {
                    localHomeIntf = ejbClass.getClassLoader().loadClass(
                        super.getLocalHomeClassName());
                } catch (ClassNotFoundException ex) {
                    _logger.log( Level.WARNING,
                         "enterprise.deployment_class_not_found", ex ); //NOI18N
                    return null;
                }
        
                Collection localFinders = getFinders(localHomeIntf);
                if(finders == null) {
                    // if there were no finders specified in the remote
                    // home, the local finders are the finders  
                    finders = localFinders;

                } else if(localFinders != null) {
                    // Remove the Common Elements from the collections
                    // and keep only unique methods
                    if(_logger.isLoggable(Level.FINE)) 
                        _logger.fine("@@@@@@ Trying to remove the Common Elements from HashSet....... "); //NOI18N

                    for(Iterator iter = localFinders.iterator(); iter.hasNext();) {
                        Method localHomeMethod=(Method)iter.next();
                        if(findEquivalentMethod(finders, localHomeMethod) == null) {
                            if(_logger.isLoggable(Level.FINE)) 
                                _logger.fine("@@@@ adding local interface method " + //NOI18N
                                     localHomeMethod.getName() ); 

                            finders.add(localHomeMethod);
                        }
                    }
                }
            } //end of isLocalInterfaceSupported

            if (finders == null)
                // still not initialized => empty set
                finders = new HashSet();
        }

        return finders;
    }

    /** 
     * Returns a collection of finder methods declared by the home 
     * interface given by a class object.
     */
    public Collection getFinders(Class homeIntf) {
        Method[] methods = homeIntf.getMethods();
        Collection finders = new HashSet();
        for(int i=0; i<methods.length; i++) {
           if(methods[i].getName().startsWith(FIND)) {
               finders.add(methods[i]);
           }
        }
        
        return finders;
    }

    public void setClassLoader(ClassLoader jcl) {
        this.jcl = jcl;
    } 

    public ClassLoader getClassLoader() {
        return jcl;
    } 

    public Collection getAllPersistentFields() {
        PersistenceDescriptor pers = getPersistenceDescriptor();
        PersistentFieldInfo[] persFields = pers.getPersistentFieldInfo();
        PersistentFieldInfo[] pkeyFields = pers.getPkeyFieldInfo();
        HashMap fields = new HashMap();

        for(int i=0; i<persFields.length; i++) {
            fields.put(persFields[i].name, persFields[i]);
        }
        
        for(int i=0; i<pkeyFields.length; i++) {
            fields.put(pkeyFields[i].name, pkeyFields[i]);
        }
        
        return fields.values();        
    }
    
    public Collection getPersistentFields() {
        
        PersistenceDescriptor pers = getPersistenceDescriptor();
        PersistentFieldInfo[] persFields = pers.getPersistentFieldInfo();
        
        HashMap fields = new HashMap();

        for(int i=0; i<persFields.length; i++) {
            fields.put(persFields[i].name, persFields[i]);
        }
        
        return fields.values();        
    }

    
    public Collection getPrimaryKeyFields() {
        
        PersistenceDescriptor pers = getPersistenceDescriptor();
        PersistentFieldInfo[] pkeyFields = pers.getPkeyFieldInfo();
        
        HashMap pkey = new HashMap();
        for(int i=0; i<pkeyFields.length; i++) {
            pkey.put(pkeyFields[i].name, pkeyFields[i]);
        }
        
        return pkey.values();        
        
    }

    /**
     * Returns a collection of selector methods.
     */
    public Collection getSelectors() {
        if (selectors == null) {
            selectors = new HashSet();
            Class ejbClass = getEjbClass();
            Method[] methods = ejbClass.getMethods();
            for(int i=0; i<methods.length; i++) {
                if(methods[i].getName().startsWith(EJB_SELECT)) { //NOI18N
                    selectors.add(methods[i]);
                }
            }
        }
        
        return selectors;
    }
    
    

    public String getBaseName(String className) {
        if (className == null)
            return null;

        int dot = className.lastIndexOf(DOT);
        if (dot == -1)
            return className;
        return className.substring(dot+1);
    }
    
    public IASEjbCMPEntityDescriptor() {
    }
    
    /** 
     * The copy constructor.Hopefully we wont need it;)
     */
    public IASEjbCMPEntityDescriptor(EjbDescriptor other) {
           super(other);

           setPersistenceType(CONTAINER_PERSISTENCE);

           if ( other instanceof EjbCMPEntityDescriptor ) {
             EjbCMPEntityDescriptor entity = (EjbCMPEntityDescriptor)other;
           }
    }
 
  
    /**
     * Sets the State class implementation classname. 
     */
     public void setPcImplClassName(String name) {
         pcImplClassName = name;
    }
  
    public String getUniqueName() {
        if(uniqueName == null) {
            BundleDescriptor bundle = getEjbBundleDescriptor();
            Application application = bundle.getApplication();

            // Add ejb name and application name.
            StringBuffer rc = new StringBuffer().
                    append(getName()).
                    append(NAME_CONCATENATOR).
                    append(application.getRegistrationName());

            // If it's not just a module, add a module name.
            if (!application.isVirtual()) {
                rc.append(NAME_CONCATENATOR).
                   append(bundle.getModuleDescriptor().getArchiveUri());
            }

            uniqueName = getBaseName(getEjbClassName()) 
                    + getUniqueNumber(rc.toString());
        }

        return uniqueName;
    }

    public String getUniqueNumber(String num) {
        //Modified to decrease the possibility of collision
        String newNum= "" + num.hashCode(); // NOI18N
        newNum = newNum.replace('-', NAME_PART_SEPARATOR); // NOI18N
        return newNum;
     }


    public String getPcImplClassName() {
       if (pcImplClassName == null) { 
           // Check for Null added 
           pcImplClassName = getUniqueName() + JDOSTATE;
           String packageName = getPackageName(getEjbClassName());
           if(packageName != null)
               pcImplClassName = packageName + DOT + pcImplClassName;

            if(_logger.isLoggable(Level.FINE)) 
                _logger.fine("##### PCImplClass Name is " + pcImplClassName); // NOI18N
        }
        return pcImplClassName;
    }


      /**
     * Sets the State class implementation classname. 
     */
    public void setConcreteImplClassName(String name) {
         concreteImplClassName = name;
    }
    
    public String getPackageName(String className) {
        int dot = className.lastIndexOf(DOT);
        if (dot == -1)
            return null;
        return className.substring(0, dot);
     }


    /** IASRI 4725194
     * Returns the Execution class, which is sam as the user-specified class
     * in case of Message, Session and Bean Managed Persistence Entity Beans
     * but is different for Container Mananged Persistence Entity Bean
     * Therefore, the implementation in the base class is to return
     * getEjbClassName() and the method is redefined in IASEjbCMPDescriptor.
     *
     */
    public String getEjbImplClassName() {
        if (ejbImplClassName == null) {
            String packageName = getPackageName(getEjbClassName());
            ejbImplClassName = getConcreteImplClassName();
            if(packageName != null)
                ejbImplClassName = packageName + DOT + ejbImplClassName;
        }
        return ejbImplClassName;
    }

    /**
     * Returns the classname of the State class impl. 
     */
 
    public String getConcreteImplClassName() {
        if (concreteImplClassName == null) {
        /**    The Ear may contain two jar files with beans with same ejb names
        */
             concreteImplClassName = getUniqueName() + CONCRETE_IMPL;
        }

        return concreteImplClassName;
    }

    public void setModuleDir(String moduleRootDir) {
        moduleDir = moduleRootDir;
    }

    /**
    * Returns the Module root of this module.
    */
    public String getModuleDir() {
        //FIXME:this needs to be changed when the API is available.
        if(moduleDir != null)
            return moduleDir;
        else
            return null;
    }

    public void setMappingProperties(String mappingProperties) {
         this.mappingProperties = mappingProperties;
    }
    
    
    /**
     * Returns the classname of the State class impl. 
     */
    public String  getMappingProperties() {
         return mappingProperties;
    }
    
    
    /**     
     * Called from EjbBundleDescriptor/EjbBundleArchivist 
     * when some classes in this bean are updated.
     */         
    public boolean classesChanged() {

        /**        No Implementation Yet
        boolean superChanged = super.classesChanged();

        boolean persChanged = pers.classesChanged();

        // Send changed event only if parent didn't already do it.
        if( !superChanged && persChanged ) {
            changed();
        }

        return (superChanged || persChanged);
        */
        
        return false;
    }

    /**
     * This method sets the parser which would be used to parse the query
     * parameter declaration given in sun-ejb-jar.xml.
     * This method is called from JDOCodenerator class 's generate() method.
     */
    public void setQueryParser(QueryParser inParser) {
        queryParser = inParser;
    }
    
    /** 
     * Returns the query parser object 
     */
    public QueryParser getQueryParser() {
        return queryParser;
    }

    /**
     * This method returns the conversion table which maps the unqualified
     * name (e.g., String) of the java.lang classes to their fully qualified
     * name (e.g., java.lang.String)
     */    
    private static Map createConversionTable () {

        HashMap conversionTable = new HashMap();
        conversionTable.put("Boolean", "java.lang.Boolean"); //NOI18N
        conversionTable.put("Byte", "java.lang.Byte"); //NOI18N
        conversionTable.put("Character", "java.lang.Character"); //NOI18N
        conversionTable.put("Double", "java.lang.Double"); //NOI18N
        conversionTable.put("Float", "java.lang.Float"); //NOI18N
        conversionTable.put("Integer", "java.lang.Integer"); //NOI18N
        conversionTable.put("Long", "java.lang.Long"); //NOI18N
        conversionTable.put("Number", "java.lang.Number"); //NOI18N
        conversionTable.put("Short", "java.lang.Short"); //NOI18N
        conversionTable.put("String", "java.lang.String"); //NOI18N
        conversionTable.put("Object", "java.lang.Object"); //NOI18N
        return conversionTable;
    }
    
    private String getFullyQualifiedType(String type) {
        String knownType=(String)conversionTable.get(type);
        return knownType == null ? type : knownType;
    }

     /**
      * Getter for prefetch-disabled
      * @return Value of prefetchDisabledDescriptor
      */
    public PrefetchDisabledDescriptor getPrefetchDisabledDescriptor() {
        return prefetchDisabledDescriptor;
    }

    /**
     * Setter for prefetch-disabled
     * @param prefetchDisabledDescriptor 
     * New value of prefetchDisabledDescriptor.
     */
    public void setPrefetchDisabledDescriptor(
        PrefetchDisabledDescriptor prefetchDisabledDescriptor) {
        this.prefetchDisabledDescriptor = prefetchDisabledDescriptor;
    }

    
    /*
     * Adds the given OneOneFinder to the HashMap
     * @Param finder represents the EJB 1.1 Finder 
     */
    public  void addOneOneFinder (IASEjbCMPFinder finder) {
        arrOneOneFinders.add(finder);
    }
    
    /**
     * Returns a Map which maps between a method signature and the 
     * corresponding IASEjbCMPFinder instance. The key is the method
     * signature as a string and consists of methodName(type1, type2.....).
     */
    public Map getOneOneFinders() {
        // update the oneOneFinders map if there are any entries pending in
        // the array arrOneOneFinders.
        if (!arrOneOneFinders.isEmpty()) {
            if (queryParser == null) {
                String msg = localStrings.getLocalString(
                    "enterprise.deployment.error_missing_queryparser", //NOI18N
                    "IASEjbCMPEntityDescriptor.getOneOneFinders"); //NOI18N
                _logger.log(Level.WARNING, msg);
                throw new RuntimeException(msg);
            }
            
            //parse the query declaration parameter and store the query object
            for ( Iterator i = arrOneOneFinders.iterator(); i.hasNext(); ) {
                IASEjbCMPFinder finder = ( IASEjbCMPFinder )i.next();
                String key = generateKey(finder, queryParser);
                oneOneFinders.put(key, finder);
            }
            arrOneOneFinders.clear();
        }
        return oneOneFinders;
    }
    
    /*
     * @returns the key used to store 1.1 Finder Object.
     * the key is methodName(param0, param1.....)
     * @param finder is the object which represents the EJB 1.1 Finder 
     */
    private String generateKey(IASEjbCMPFinder finder, QueryParser parser)     {
        
        StringBuffer key = new StringBuffer();
        key.append(finder.getMethodName()).append(LIST_START);

        String queryParams = finder.getQueryParameterDeclaration();
        Iterator iter = parser.parameterTypeIterator(queryParams);
        while ( iter.hasNext() )  {
            String type = ( String ) iter.next() ;
            key.append(getFullyQualifiedType(type)) ;
            if( iter.hasNext() ) {
                key.append(LIST_SEPARATOR); 
            }
        }
        key.append(LIST_END);

        return key.toString().intern();
    }
    
    /*
     * @returns The finder object for the particular Method object.
     * @param method object for which the Finder Object needs to be found
     */
    public IASEjbCMPFinder getIASEjbCMPFinder(Method method) {
        //Checks if the given method is present in the interfaces.
        if(findEquivalentMethod(getFinders(), method) == null ) {
            return null;
        }
        String methodName = method.getName();
        
        //key is of the form methodName(param0, param1, ....)
        StringBuffer key = new StringBuffer();
        key.append(methodName);
        key.append(LIST_START);
        Class paramList[] = method.getParameterTypes();
        for (int index = 0 ; index < paramList.length ; index++ ) {
            if(index>0) {
                key.append(LIST_SEPARATOR);
            }
            key.append(paramList[index].getName());
        }
        key.append(LIST_END);
        return (IASEjbCMPFinder)getOneOneFinders().get(key.toString());
    } 
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish IASEjbCMPEntityDescriptor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.