/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2012 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. */ /* * 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.jdo.api.persistence.mapping.ejb.ConversionHelper; import com.sun.jdo.spi.persistence.support.ejb.model.util.NameMapper; import org.glassfish.ejb.deployment.descriptor.EjbBundleDescriptorImpl; import org.glassfish.ejb.deployment.descriptor.IASEjbCMPEntityDescriptor; import org.glassfish.ejb.deployment.descriptor.PersistenceDescriptor; import org.glassfish.ejb.deployment.descriptor.PersistentFieldInfo; import org.glassfish.ejb.deployment.descriptor.RelationRoleDescriptor; import org.glassfish.ejb.deployment.descriptor.RelationshipDescriptor; /* * This class implements ConversionHelper interface by using data from * IASEjbBundleDescriptor. * * @author Shing Wai Chan */ public class EjbConversionHelper implements ConversionHelper { private NameMapper nameMapper = null; private EjbBundleDescriptorImpl 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 * @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); } }