FileDocCategorySizeDatePackage
EjbConversionHelper.javaAPI DocGlassfish v2 API16691Fri May 04 22:34:48 BST 2007com.sun.jdo.spi.persistence.support.ejb.ejbc

EjbConversionHelper.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. 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.html
 * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [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.
 */

/*
 * EjbConversionHelper.java
 *
 * Created on March 19, 2002
 */

package com.sun.jdo.spi.persistence.support.ejb.ejbc;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.sun.enterprise.deployment.CMRFieldInfo;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.PersistenceDescriptor;
import com.sun.enterprise.deployment.PersistentFieldInfo;
import com.sun.enterprise.deployment.RelationshipDescriptor;
import com.sun.enterprise.deployment.RelationRoleDescriptor;

import com.sun.enterprise.deployment.IASEjbCMPEntityDescriptor;

import com.sun.jdo.api.persistence.mapping.ejb.ConversionHelper;

import com.sun.jdo.spi.persistence.support.ejb.model.util.NameMapper;

/*
 * This class implements ConversionHelper interface by using data from
 * IASEjbBundleDescriptor.
 *
 * @author Shing Wai Chan
 */
public class EjbConversionHelper implements ConversionHelper {

    private NameMapper nameMapper = null;
    private EjbBundleDescriptor bundle = null;
    private HashMap ejbDescMap = new HashMap();
    private HashMap ejbFieldMap = new HashMap();
    private HashMap ejbKeyMap = new HashMap();
    private HashMap ejbPerDescMap = new HashMap();
    private HashMap ejbRelMap = new HashMap();
    boolean generateFields = true;
    boolean ensureValidation = true;

    public EjbConversionHelper(NameMapper nameMapper) {
        this.nameMapper = nameMapper;
        this.bundle = nameMapper.getBundleDescriptor();

        Iterator iter = bundle.getEjbs().iterator();
        while (iter.hasNext()) {
            Object desc = iter.next();
            if (desc instanceof IASEjbCMPEntityDescriptor) {
                IASEjbCMPEntityDescriptor ejbDesc =
                        (IASEjbCMPEntityDescriptor)desc;

                String ejbName = ejbDesc.getName();
                //collect all ejbdesc
                ejbDescMap.put(ejbName, ejbDesc);

                //collect PersistenceDescriptor
                PersistenceDescriptor pers = ejbDesc.getPersistenceDescriptor();
                ejbPerDescMap.put(ejbName, pers);

                //collect pers fields
                Collection pFields = ejbDesc.getPersistentFields();
                HashMap fieldMap = new HashMap();
                Iterator fIter = pFields.iterator();
                while (fIter.hasNext()) {
                    String fieldName = ((PersistentFieldInfo)fIter.next()).name;
                    fieldMap.put(fieldName, fieldName);
                }
                ejbFieldMap.put(ejbName, fieldMap);

                //collect pseudo cmr fields
                List pseudoFields = nameMapper.getGeneratedRelationshipsForEjbName(ejbName);
                Iterator pIter = pseudoFields.iterator();
                while (pIter.hasNext()) {
                    addField(ejbName, (String)pIter.next());
                }

                //collect all keys
                Collection pKeys = ejbDesc.getPrimaryKeyFields();
                HashMap pKeyMap = new HashMap();
                Iterator kIter = pKeys.iterator();
                while (kIter.hasNext()) {
                    String fieldName = ((PersistentFieldInfo)kIter.next()).name;
                    pKeyMap.put(fieldName, fieldName);
                }
                ejbKeyMap.put(ejbName, pKeyMap);
            }
        }

        //collect relationship
        Set rels = bundle.getRelationships();
        Iterator relIter = rels.iterator();
        while (relIter.hasNext()) {
            RelationshipDescriptor rel = (RelationshipDescriptor)relIter.next();
            RelationRoleDescriptor source = rel.getSource();
            RelationRoleDescriptor sink = rel.getSink();

            //collect source RelationshipDescriptor
            String sourceEjbName = source.getOwner().getName();
            ArrayList sourceRels = (ArrayList)ejbRelMap.get(sourceEjbName);
            if (sourceRels == null) {
                sourceRels = new ArrayList();
                ejbRelMap.put(sourceEjbName, sourceRels);
            }
            sourceRels.add(rel);

            //collect source cmr field
            String sourceCMRField = source.getCMRField();
            if (sourceCMRField != null) {
                addField(sourceEjbName, sourceCMRField);
            }

            //collect sink RelationshipDescriptor
            String sinkEjbName = sink.getOwner().getName();
            ArrayList sinkRels = (ArrayList)ejbRelMap.get(sinkEjbName);
            if (sinkRels == null) {
                sinkRels = new ArrayList();
                ejbRelMap.put(sinkEjbName, sinkRels);
            }
            sinkRels.add(rel);

            //collect sink cmr field
            String sinkCMRField = sink.getCMRField();
            if (sinkCMRField != null) {
                addField(sinkEjbName, sinkCMRField);
            }
        }
    }

    //---- implements interface ConversionHelper ----

    public String getMappedClassName(String ejbName) {
        return nameMapper.getPersistenceClassForEjbName(ejbName);
    }

    /** 
     * If {@link #generateFields} is <code>true</code>, then this method will 
     * check if the field is one of the cmp + cmr + pseudo cmr fields, otherwise
     * the method will check if the field is one of the cmp + cmr fields.
     * @param ejbName The ejb-name element for the bean
     * @param fieldName The name of a container managed field in the named bean 
     * @return <code>true</code> if the bean contains the field, otherwise
     * return <code>false</code> 
     */
    public boolean hasField(String ejbName, String fieldName) {
        if (!generateFields && isGeneratedRelationship(ejbName, fieldName))
            return false;
        else {
            HashMap fieldMap = (HashMap)ejbFieldMap.get(ejbName);
            return (fieldMap != null) ? 
                (fieldMap.get(fieldName) != null) : false;
        }
    }

    /** 
     * If {@link #generateFields} is <code>true</code>, then this method will 
     * return an array of cmp + cmr + pseudo cmr fields, otherwise 
     * the method will return an array of cmp + cmr fields.
     * @param ejbName The ejb-name element for the bean
     * @param fieldName The name of a container managed field in the named bean 
     * @return an array of fields in the ejb bean 
     */
    public Object[] getFields(String ejbName) {
        HashMap fieldMap = (HashMap)ejbFieldMap.get(ejbName);
        if (fieldMap != null) {
            List fields = new ArrayList(fieldMap.keySet());
            if (!generateFields) {
                fields.removeAll(getGeneratedRelationships(ejbName));
            }
            return fields.toArray();
        }
        return null;
    }

    /**
     * The boolean argument candidate is ignored in this case.
     */
    public boolean isKey(String ejbName, String fieldName, boolean candidate) {
        HashMap keyMap = (HashMap)ejbKeyMap.get(ejbName);
        return (keyMap != null) ? (keyMap.get(fieldName) != null) : false;
    }

    /**
     * This API will only be called from MappingFile when multiplicity is Many
     * on the other role.
     */
    public String getRelationshipFieldType(String ejbName, String fieldName) {
        if (isGeneratedRelationship(ejbName, fieldName)) {
            return java.util.Collection.class.getName();
        } else {
            PersistenceDescriptor pers =
                (PersistenceDescriptor)ejbPerDescMap.get(ejbName);
            return pers.getCMRFieldReturnType(fieldName);
        }
    }

    /**
     * getMultiplicity of the other role on the relationship
     * Please note that multiplicity is JDO style
     */
    public String getMultiplicity(String ejbName, String fieldName) {
        RelationRoleDescriptor oppRole = getRelationRoleDescriptor(ejbName,
                fieldName, false);
        return (oppRole.getIsMany()) ? MANY : ONE;
    }

    public String getRelationshipFieldContent(String ejbName, String fieldName) {
        RelationRoleDescriptor oppRole = getRelationRoleDescriptor(ejbName,
                fieldName, false);
        return oppRole.getOwner().getName();
    }

    /**
     * This method return the fieldName of relation role on the other end.
     */
    public String getInverseFieldName(String ejbName, String fieldName) {
        RelationRoleDescriptor oppRole = getRelationRoleDescriptor(ejbName,
                fieldName, false);
        String inverseName = oppRole.getCMRField();

        // if we are generating relationships, check for a generated inverse
        if ((generateFields) && (inverseName == null))
            inverseName = nameMapper.getGeneratedFieldForEjbField(
                ejbName, fieldName)[1];

        return inverseName;
    }

    /**
     * Returns flag whether the mapping conversion should apply the default
     * strategy for dealing with unknown primary key classes. This method will
     * only be called when {@link #generateFields} returns <code>true</code>.
     * @param ejbName The value of the ejb-name element for a bean.
     * @return <code>true</code> to apply the default unknown PK Class Strategy,
     * <code>false</code> otherwise
     */
    public boolean applyDefaultUnknownPKClassStrategy(String ejbName) {
        IASEjbCMPEntityDescriptor ejbDesc =
                (IASEjbCMPEntityDescriptor)ejbDescMap.get(ejbName);
        String keyClassName = ejbDesc.getPrimaryKeyClassName();
        return keyClassName != null &&
                keyClassName.equals(Object.class.getName());
    }
  
    /**
     * Returns the name used for generated primary key fields.
     * @return a string for key field name
     */
    public String getGeneratedPKFieldName() {
        return nameMapper.GENERATED_KEY_FIELD_NAME;
    }

    /**
     * Returns the prefix used for generated version fields.
     * @return a string for version field name prefix
     */
    public String getGeneratedVersionFieldNamePrefix() {
        return nameMapper.GENERATED_VERSION_FIELD_PREFIX;
    }

    public boolean relatedObjectsAreDeleted(String beanName, String fieldName) {
        RelationRoleDescriptor oppRole = getRelationRoleDescriptor(beanName, fieldName, false);
        return oppRole.getCascadeDelete();
    }

    /**
     * Returns the flag whether the mapping conversion should generate
     * relationship fields and primary key fields to support run-time.
     * The version field is always created even {@link #generateFields} is 
     * <code>false</code> because it holds version column information.
     * @return <code>true</code> to generate fields in the dot-mapping file
     * (if they are not present).
     */
    public boolean generateFields() {
        return generateFields;
    }

    /**
     * Sets the flag whether the mapping conversion should generate relationship
     * fields, primary key fields, and version fields to support run-time.
     * @param generateFields a flag which indicates whether fields should be
     * generated
     */
    public void setGenerateFields(boolean generateFields) {
        this.generateFields = generateFields;
    }

    /** Returns the flag whether the mapping conversion should validate
     * all fields against schema columns.
     * @return <code>true</code> to validate all the fields in the dot-mapping
     * file.
     */
    public boolean ensureValidation() {
        return ensureValidation;
    }

    /**
     * Sets the flag whether the mapping conversion should validate all fields
     * against schema columns.
     * @param isValidating a boolean of indicating validating fields or not
     */
    public void setEnsureValidation(boolean isValidating) {
        ensureValidation = isValidating;
    }

    /**
     * Returns <code>true</code> if the field is generated. There are three
     * types of generated fields: generated relationships, unknown primary key
     * fields, and version consistency fields.
     * @param ejbName The ejb-name element for the bean
     * @param fieldName The name of a container managed field in the named bean 
     * @return <code>true</code> if the field is generated; <code>false</code>
     * otherwise.
     */

    public boolean isGeneratedField(String ejbName, String fieldName) {
        return nameMapper.isGeneratedField(ejbName, fieldName);
    }

    public boolean isGeneratedRelationship(String ejbName, String fieldName) {
        return nameMapper.isGeneratedEjbRelationship(ejbName, fieldName);
    }

    /**
     * Returns a list of generated relationship field names.
     * @param ejbName The ejb-name element for the bean
     * @return a list of generated relationship field names
     */
    public List getGeneratedRelationships(String ejbName) {
        return nameMapper.getGeneratedRelationshipsForEjbName(ejbName);
 
    }

    //-------------------------------------
    private RelationRoleDescriptor getRelationRoleDescriptor(String ejbName,
            String cmrFieldName, boolean self) {
        String myEjbName = ejbName;
        String myCMRFieldName = cmrFieldName;
        boolean myself = self;
        if (isGeneratedRelationship(ejbName, cmrFieldName)) {
            String[] nfPair = nameMapper.getEjbFieldForGeneratedField(
                    ejbName, cmrFieldName);
            myEjbName = nfPair[0];
            myCMRFieldName = nfPair[1];
            myself = !self;
        }
        return getRealRelationRoleDescriptor(myEjbName, myCMRFieldName, myself);
    }

    private RelationRoleDescriptor getRealRelationRoleDescriptor(
            String ejbName, String cmrFieldName, boolean self) {
        ArrayList rels = (ArrayList)ejbRelMap.get(ejbName);
        for (int i = 0; i < rels.size(); i++) {
            RelationshipDescriptor rel = (RelationshipDescriptor)rels.get(i);
            RelationRoleDescriptor source = rel.getSource();
            RelationRoleDescriptor sink = rel.getSink();
            if (ejbName.equals(source.getOwner().getName()) &&
                    cmrFieldName.equals(source.getCMRField())) {
                return (self) ? source : sink;
            } else if (ejbName.equals(sink.getOwner().getName()) &&
                    cmrFieldName.equals(sink.getCMRField())) {
                return (self) ? sink : source;
            }
        }
        throw new IllegalArgumentException();
    }

    private void addField(String ejbName, String fieldName) {
        HashMap fieldMap = (HashMap)ejbFieldMap.get(ejbName);
        if (fieldMap == null) {
            fieldMap = new HashMap();
            ejbFieldMap.put(ejbName, fieldMap);
        }
        fieldMap.put(fieldName, fieldName);
    }
}