Package com.sun.jdo.spi.persistence.support.ejb.model

Source Code of com.sun.jdo.spi.persistence.support.ejb.model.DeploymentDescriptorModel$MemberWrapper

/*
* 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.
*/

/*
* DeploymentDescriptorModel.java
*
* Created on December 3, 2001, 3:43 PM
*/

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

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import com.sun.jdo.api.persistence.model.RuntimeModel;
import com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement;
import com.sun.jdo.api.persistence.model.jdo.RelationshipElement;
import com.sun.jdo.spi.persistence.support.ejb.model.util.NameMapper;
import com.sun.jdo.spi.persistence.utility.JavaTypeHelper;
import org.glassfish.ejb.deployment.descriptor.EjbCMPEntityDescriptor;
import org.glassfish.ejb.deployment.descriptor.FieldDescriptor;
import org.glassfish.ejb.deployment.descriptor.PersistenceDescriptor;

/** This is a subclass of RuntimeModel which uses the deployment descriptor
* to augment the java metadata for a non-existent persistence-capable
* java/class file.  It is primarily used at ejbc time, though it could be
* used at any time as long as sufficient mapping and deployment descriptor
* information is available.  See the javadoc for individual methods below
* for differences and translations between persistence-capable and ejb
* names and behavior.  There are different answers to methods depending
* on whether they are called on the persistence-capable or the ejb.  These
* are primarily for the handling of serializable, non-primitive, non-wrapper
* type fields: isByteArray, getFieldType (returning byte array),
* isPersistentTypeAllowed and isPersistentAllowed (returning true) which
* return answers about the byte array when called on the persistence-capable
* and return answers about the serializable type when called on the ejb.
*
* @author Rochelle Raccah
*/
public class DeploymentDescriptorModel extends RuntimeModel
{
  private ClassLoader _classLoader;
  private NameMapper _nameMapper;
       
    /**
     * Signature with CVS keyword substitution for identifying the generated code
     */
    public static final String SIGNATURE = "$RCSfile: DeploymentDescriptorModel.java,v $ $Revision: 1.2 $"; //NOI18N
       
  /** Creates a new instance of DeploymentDescriptorModel
   * @param nameMapper the name mapper to be used as a helper for
   * translation between persistence class and ejb names.
   * @param classLoader the class loader object which is used for the
   * application.
   */
  public DeploymentDescriptorModel (NameMapper nameMapper,
    ClassLoader classLoader)
  {
    super();
    _classLoader = classLoader;
    _nameMapper = nameMapper;
  }

  private ClassLoader getClassLoader () { return _classLoader; }
  private NameMapper getNameMapper () { return _nameMapper; }

  /** Returns the input stream with the supplied resource name found with
   * the supplied class name.  This method overrides the one in
   * RuntimeModel to enforce using the class loader provided at construction
   * time instead of the one specified in this method.
   * @param className the fully qualified name of the class which will be
   * used as a base to find the resource
   * @param classLoader the class loader used to find mapping information
   * This parameter is ignored in this implementation - instead the
   * class loader supplied at construction time is used.
   * @param resourceName the name of the resource to be found
   * @return the input stream for the specified resource, <code>null</code>
   * if an error occurs or none exists
   */
  protected BufferedInputStream getInputStreamForResource (String className,
    ClassLoader classLoader, String resourceName)
  {
    return super.getInputStreamForResource(
      className, getClassLoader(), resourceName);
  }

  /** Returns the name of the second to top (top excluding java.lang.Object)
   * superclass for the given class name.  This method overrides the one in
   * RuntimeModel in order to return the supplied className if it 
   * represents a persistence-capable class.  This is because the
   * persistence-capable classes don't mirror the inheritance
   * hierarchy of the ejbs.
   * @param className the fully qualified name of the class to be checked
   * @return the top non-Object superclass for className,
   * <code>className</code> if an error occurs or none exists
   */
  protected String findPenultimateSuperclass (String className)
  {
    return (isPCClassName(className) ? className :
      super.findPenultimateSuperclass(className));
  }

  /** Returns the name of the superclass for the given class name.  This
   * method overrides the one in RuntimeModel in order to return
   * java.lang.Object if the supplied className represents a
   * persistence-capable class.  This is because the persistence-capable
   * classes don't mirror the inheritance hierarchy of the ejbs.
   * @param className the fully qualified name of the class to be checked
   * @return the superclass for className, <code>null</code> if an error
   * occurs or none exists
   */
  protected String getSuperclass (String className)
  {
    return (isPCClassName(className) ? "java.lang.Object" // NOI18N
      super.getSuperclass(className));
  }

  /** Creates a file with the given base file name and extension
   * parallel to the supplied class (if it does not yet exist).  This
   * method overrides the one in RuntimeModel and throws
   * UnsupportedOperationException in the case where the file
   * doesn't yet exist.  If the file exists (even if it has
   * just been "touched"), this method will return that output stream,
   * but it is not capable of using the supplied class as a sibling location.
   * @param className the fully qualified name of the class
   * @param baseFileName the name of the base file
   * @param extension the file extension
   * @return the output stream for the specified resource, <code>null</code>
   * if an error occurs or none exists
   * @exception IOException if there is some error creating the file
   */
  protected BufferedOutputStream createFile (String className, String baseFileName,
    String extension) throws IOException
  {
    BufferedOutputStream outputStream =
      super.createFile(className, baseFileName, extension);

    if (outputStream != null)
      return outputStream;

    throw new UnsupportedOperationException();
  }

  /** Deletes the file with the given file name which is parallel
   * to the supplied class.  This method overrides the one in RuntimeModel
   * and throws UnsupportedOperationException.
   * @param className the fully qualified name of the class
   * @param fileName the name of the file
   * @exception IOException if there is some error deleting the file
   */
  protected void deleteFile (String className, String fileName)
    throws IOException
  {
    throw new UnsupportedOperationException();
  }

  /** Returns the class element with the specified className.  If the
   * specified className represents a persistence-capable class, the
   * abstract bean class for the corresponding ejb is always returned
   * (even if there is a Class object available for the
   * persistence-capable).  If there is an ejb name and an abstract bean
   * class with the same name, the abstract bean class which is associated
   * with the ejb will be returned, not the abstract bean class which 
   * corresponds to the supplied name (directly).  If the specified
   * className represents a persistence-capable key class name, the
   * corresponding bean's key class is returned.
   * @param className the fully qualified name of the class to be checked
   * @param classLoader the class loader used to find mapping information
   * @return the class element for the specified className
   */
  public Object getClass (final String className,
    final ClassLoader classLoader)
  {
    String testClass = className;

    // translate the class name to corresponding ejb name's abstract
    // bean or key class if necessary
    if (className != null)
    {
      NameMapper nameMapper = getNameMapper();
      String ejbName =
        (isPCClassName(className) ? getEjbName(className) : className);

      if (nameMapper.isEjbName(ejbName))
        testClass = nameMapper.getAbstractBeanClassForEjbName(ejbName);
      else
      {
        String keyClass =
          nameMapper.getKeyClassForPersistenceKeyClass(className);

        if (keyClass != null)
        {
          // if it's a pk field of type primitive, byte[],
          // or other array, return the primitive class or a
          // dummy class
          if (NameMapper.PRIMARY_KEY_FIELD ==
            getPersistenceKeyClassType(className))
          {
            if (isPrimitive(keyClass))
              return JavaTypeHelper.getPrimitiveClass(keyClass);
            if (isByteArray(keyClass) || keyClass.endsWith("[]"))
              return byte[].class;
          }

          testClass = keyClass;
        }
      }
    }

    return super.getClass(testClass, getClassLoader());
  }

  /** Returns a wrapped constructor element for the specified argument types
   * in the class with the specified name.  If the specified class name is
   * a persistence-capable key class name which corresponds to a bean
   * with an unknown primary key class a dummy constructor will also be
   * returned.  Types are specified as type names for primitive type
   * such as int, float or as fully qualified class names.
   * @param className the name of the class which contains the constructor
   * to be checked
   * @param argTypeNames the fully qualified names of the argument types
   * @return the constructor element
   * @see #getClass
   */
  public Object getConstructor (final String className, String[] argTypeNames)
  {
    Object returnObject = null;

    if ((NameMapper.PRIMARY_KEY_FIELD ==
      getPersistenceKeyClassType(className)) &&
      Arrays.equals(argTypeNames, NO_ARGS))
    {
      returnObject = new MemberWrapper(className, null, Modifier.PUBLIC,
        (Class)getClass(className));
    }

    if (returnObject == null)
    {
      returnObject = super.getConstructor(className, argTypeNames);

      if (returnObject instanceof Constructor)    // wrap it
        returnObject = new MemberWrapper((Constructor)returnObject);
    }

    return returnObject;
  }

  /** Returns a wrapped method element for the specified method name and
   * argument types in the class with the specified name.  If the
   * specified className represents a persistence-capable class and
   * the requested methodName is readObject or writeObject, a dummy
   * method will be returned.  Similarly, if the specified class name is
   * a persistence-capable key class name which corresponds to a bean
   * with an unknown primary key class or a primary key field (in both
   * cases there is no user defined primary key class) and the requested
   * method is equals or hashCode, a dummy method will also be returned. 
   * Types are specified as type names for primitive type such as int,
   * float or as fully qualified class names.  Note, the method does not
   * return inherited methods.
   * @param className the name of the class which contains the method
   * to be checked
   * @param methodName the name of the method to be checked
   * @param argTypeNames the fully qualified names of the argument types
   * @return the method element
   * @see #getClass
   */
  public Object getMethod (final String className, final String methodName,
    String[] argTypeNames)
  {
    int keyClassType = getPersistenceKeyClassType(className);
    Object returnObject = null;

    if (isPCClassName(className))
    {
      if ((methodName.equals("readObject") &&   // NOI18N
                    Arrays.equals(argTypeNames, getReadObjectArgs())) ||
        (methodName.equals("writeObject") &&   // NOI18N
                        Arrays.equals(argTypeNames, getWriteObjectArgs())))
      {
        returnObject = new MemberWrapper(methodName,
          Void.TYPE, Modifier.PRIVATE, (Class)getClass(className));
      }
    }
    if ((NameMapper.UNKNOWN_KEY_CLASS == keyClassType) ||
      (NameMapper.PRIMARY_KEY_FIELD == keyClassType))
    {
      if (methodName.equals("equals") &&   // NOI18N
                    Arrays.equals(argTypeNames, getEqualsArgs()))
      {
        returnObject = new MemberWrapper(methodName,
          Boolean.TYPE, Modifier.PUBLIC, (Class)getClass(className));
      }
      else if (methodName.equals("hashCode") &&   // NOI18N
                    Arrays.equals(argTypeNames, NO_ARGS))
      {
        returnObject = new MemberWrapper(methodName,
          Integer.TYPE, Modifier.PUBLIC, (Class)getClass(className));
      }
    }

    if (returnObject == null)
    {
      returnObject = super.getMethod(className, methodName, argTypeNames);

      if (returnObject instanceof Method)    // wrap it
        returnObject = new MemberWrapper((Method)returnObject);
    }

    return returnObject;
  }

  /** Returns the inherited method element for the specified method
   * name and argument types in the class with the specified name. 
   * Types are specified as type names for primitive type such as
   * int, float or as fully qualified class names.  Note that the class
   * with the specified className is not checked for this method, only
   * superclasses are checked.  This method overrides the one in
   * Model in order to do special handling for a persistence-capable key
   * class name which corresponds to a bean with a primary key
   * field.  In that case, we don't want to climb the inheritance
   * of the primary key field type.
   * @param className the name of the class which contains the method
   * to be checked
   * @param methodName the name of the method to be checked
   * @param argTypeNames the fully qualified names of the argument types
   * @return the method element
   * @see #getClass
   */
  public Object getInheritedMethod (String className, String methodName,
    String[] argTypeNames)
  {
    // If the class name corresponds to a pk field (which means that
    // there is no user defined primary key class, we don't want to
    // climb the inheritance hierarchy, we only process this class.
    return ((NameMapper.PRIMARY_KEY_FIELD ==
      getPersistenceKeyClassType(className)) ?
      getMethod(className, methodName, argTypeNames) :
      super.getInheritedMethod(className, methodName, argTypeNames));
  }

  /** Returns a list of names of all the declared field elements in the
   * class with the specified name.  If the specified className represents
   * a persistence-capable class, the list of field names from the 
   * corresponding ejb is returned (even if there is a Class object
   * available for the persistence-capable).
   * @param className the fully qualified name of the class to be checked
   * @return the names of the field elements for the specified class
   */
  public List getFields (final String className)
  {
    final EjbCMPEntityDescriptor descriptor = getCMPDescriptor(className);
    String testClass = className;

    if (descriptor != null)    // need to get names of ejb fields
    {
      Iterator iterator = descriptor.getFieldDescriptors().iterator();
      List returnList = new ArrayList();

      while (iterator.hasNext())
        returnList.add(((FieldDescriptor)iterator.next()).getName());

      return returnList;
    }
    else
    {
      NameMapper nameMapper = getNameMapper();
      String ejbName =
        nameMapper.getEjbNameForPersistenceKeyClass(className);

      switch (getPersistenceKeyClassType(className))
      {
        // find the field names we need in the corresponding
        // ejb key class
        case NameMapper.USER_DEFINED_KEY_CLASS:
          testClass = nameMapper.getKeyClassForEjbName(ejbName);
          break;
        // find the field name we need in the abstract bean
        case NameMapper.PRIMARY_KEY_FIELD:
          return Arrays.asList(new String[]{
            getCMPDescriptor(ejbName).
            getPrimaryKeyFieldDesc().getName()});
        // find the field name we need in the persistence capable
        case NameMapper.UNKNOWN_KEY_CLASS:
          String pcClassName =
            nameMapper.getPersistenceClassForEjbName(ejbName);
          PersistenceFieldElement[] fields =
            getPersistenceClass(pcClassName).getFields();
          int i, count = ((fields != null) ? fields.length : 0);

          for (i = 0; i < count; i++)
          {
            PersistenceFieldElement pfe = fields[i];

            if (pfe.isKey())
              return Arrays.asList(new String[]{pfe.getName()});
          }
          break;
      }
    }

    return super.getFields(testClass);
  }

  /** Returns a list of names of all the field elements in the
   * class with the specified name.  This list includes the inherited
   * fields.  If the specified className represents a
   * persistence-capable class, the list of field names from the 
   * corresponding ejb is returned (even if there is a Class object
   * available for the persistence-capable).  This method overrides
   * the one in Model in order to do special handling for a
   * persistence-capable key class name which corresponds to a bean
   * with a primary key field.  In that case, we don't want to
   * climb the inheritance hierarchy of the primary key field type.
   * @param className the fully qualified name of the class to be checked
   * @return the names of the field elements for the specified class
   */
  public List getAllFields (String className)
  {
    // If the class name corresponds to a pk field (which means that
    // there is no user defined primary key class, we don't want to
    // climb the inheritance hierarchy, we only process this class.
    return ((NameMapper.PRIMARY_KEY_FIELD ==
      getPersistenceKeyClassType(className)) ? getFields(className) :
      super.getAllFields(className));
  }

  /** Returns a wrapped field element for the specified fieldName in the
   * class with the specified className.  If the specified className
   * represents a persistence-capable class, a field representing the
   * field in the abstract bean class for the corresponding ejb is always
   * returned (even if there is a Field object available for the
   * persistence-capable).  If there is an ejb name and an abstract bean
   * class with the same name, the abstract bean class which is associated
   * with the ejb will be used, not the abstract bean class which 
   * corresponds to the supplied name (directly).
   * @param className the fully qualified name of the class which contains
   * the field to be checked
   * @param fieldName the name of the field to be checked
   * @return the wrapped field element for the specified fieldName
   */
  public Object getField (final String className, String fieldName)
  {
    String testClass = className;
    Object returnObject = null;

    if (className != null)
    {
      NameMapper nameMapper = getNameMapper();
      boolean isPCClass = isPCClassName(className);
      boolean isPKClassName = false;
      String searchClassName = className;
      String searchFieldName = fieldName;

      // translate the class name & field names to corresponding
      // ejb name's abstract bean equivalents if necessary
      if (isPCClass)
      {
        searchFieldName = nameMapper.
          getEjbFieldForPersistenceField(className, fieldName);
        searchClassName = getEjbName(className);
      }
      else  // check if it's a pk class without a user defined key class
      {
        String ejbName =
          nameMapper.getEjbNameForPersistenceKeyClass(className);

        switch (getPersistenceKeyClassType(className))
        {
          // find the field we need in the corresponding
          // abstract bean (translated below from ejbName)
          case NameMapper.PRIMARY_KEY_FIELD:
            testClass = ejbName;
            searchClassName = ejbName;
            isPKClassName = true;
            break;
          // find the field we need by called updateFieldWrapper
          // below which handles the generated field for the
          // unknown key class - need to use the
          // persistence-capable class name and flag to call that
          // code, so we configure it here
          case NameMapper.UNKNOWN_KEY_CLASS:
            testClass = nameMapper.
              getPersistenceClassForEjbName(ejbName);
            isPCClass = true;
            isPKClassName = true;
            break;
        }
      }

      if (nameMapper.isEjbName(searchClassName))
      {
        searchClassName = nameMapper.
          getAbstractBeanClassForEjbName(searchClassName);
      }

      returnObject = super.getField(searchClassName, searchFieldName);

      if (returnObject == null// try getting it from the descriptor
        returnObject = getFieldWrapper(testClass, searchFieldName);
      else if (returnObject instanceof Field)    // wrap it
        returnObject = new MemberWrapper((Field)returnObject);

      if (isPCClass)
      {
        returnObject = updateFieldWrapper(
          (MemberWrapper)returnObject, testClass, fieldName);
      }
      // when asking for these fields as part of the
      // persistence-capable's key class, we need to represent the
      // public modifier which will be generated in the inner class
      if (isPKClassName && (returnObject instanceof MemberWrapper))
        ((MemberWrapper)returnObject)._modifiers = Modifier.PUBLIC;
     
    }

    return returnObject;
  }

  /** Returns the field type for the specified fieldName in the class
   * with the specified className.  This method is overrides the one in
   * Model in order to do special handling for non-collection relationship
   * fields.  If it's a generated relationship that case, the returned
   * MemberWrapper from getField contains a type of the abstract bean and
   * it's impossible to convert that into the persistence capable class name, so here
   * that case is detected, and if found, the ejb name is extracted and
   * used to find the corresponding persistence capable class.  For a
   * relationship which is of type of the local interface, we do the
   * conversion from local interface to persistence-capable class.  In the
   * case of a collection relationship (generated or not), the superclass'
   * implementation which provides the java type is sufficient.
   * @param className the fully qualified name of the class which contains
   * the field to be checked
   * @param fieldName the name of the field to be checked
   * @return the field type for the specified fieldName
   */
  public String getFieldType (String className, String fieldName)
  {
    String returnType = super.getFieldType(className, fieldName);

    if (!isCollection(returnType) && isPCClassName(className))
    {
      NameMapper nameMapper = getNameMapper();
      String ejbName =
        nameMapper.getEjbNameForPersistenceClass(className);
      String ejbField =
        nameMapper.getEjbFieldForPersistenceField(className, fieldName);

      if (nameMapper.isGeneratedEjbRelationship(ejbName, ejbField))
      {
        String[] inverse =
          nameMapper.getEjbFieldForGeneratedField(ejbName, ejbField);
           
        returnType = nameMapper.
          getPersistenceClassForEjbName(inverse[0]);
      }

      if (nameMapper.isLocalInterface(returnType))
      {
        returnType = nameMapper.getPersistenceClassForLocalInterface(
          className, fieldName, returnType);
      }
    }

    return returnType;
  }

  /** Returns the string representation of declaring class of
   * the specified member element.  Note, the member element is
   * either a class element as returned by getClass, a field element
   * as returned by getField, a constructor element as returned by
   * getConstructor, or a method element as returned by getMethod
   * executed on the same model instance.  This implementation expects
   * the member element to be a reflection instance or a wrapped member
   * instance.
   * @param memberElement the member element to be checked
   * @return the string representation of the declaring class of
   * the specified memberElement
   * @see #getClass
   * @see #getField
   * @see #getConstructor
   * @see #getMethod
   */
  public String getDeclaringClass (Object memberElement)
  {
    if ((memberElement != null) && (memberElement instanceof MemberWrapper))
    {
      Class classElement =
        ((MemberWrapper)memberElement).getDeclaringClass();

      return ((classElement != null) ? classElement.getName() : null);
    }

    return super.getDeclaringClass(memberElement);
  }

  /** Returns the modifier mask for the specified member element.
   * Note, the member element is either a class element as returned by
   * getClass, a member wrapper element as returned by getField or
   * getMethod, a constructor element as returned by getConstructor
   * executed on the same model instance.
   * This implementation expects the member element being a reflection
   * instance or a wrapped member instance.
   * @param memberElement the member element to be checked
   * @return the modifier mask for the specified memberElement
   * @see java.lang.reflect.Modifier
   * @see #getClass
   * @see #getField
   * @see #getConstructor
   * @see #getMethod
   */
  public int getModifiers (Object memberElement)
  {
    if ((memberElement != null) && (memberElement instanceof MemberWrapper))
      return ((MemberWrapper)memberElement).getModifiers();

    return super.getModifiers(memberElement);
  }

  /** Returns the modifier mask for the specified className.  This method
   * overrides the one in Model to strip out the abstract modifier when
   * the persistence capable class is represented by the abstract bean.
   * It also adds the static modifier when the specified class represents
   * the persistence capable key class which will be generated.
   * @param className the fully qualified name of the class to be checked
   * @return the modifier mask for the specified class
   * @see java.lang.reflect.Modifier
   */
  public int getModifiersForClass (String className)
  {
    int modifiers = super.getModifiersForClass(className);

    if (isPCClassName(className))
      modifiers &= ~Modifier.ABSTRACT;
    else if (getNameMapper().
      getKeyClassForPersistenceKeyClass(className) != null)
    {
      modifiers |= Modifier.STATIC;
    }

    return modifiers;
  }

  /** Determines if the specified className and fieldName pair represent a
   * field which has a type which is valid for key fields.  Valid key
   * field types include non-collection SCOs (wrappers, Date, Time, etc.)
   * and primitives for user defined key classes.  This method overrides
   * the one in Model in order to do special handling for a
   * persistence-capable key class name which corresponds to a bean
   * with a primary key field.  In that case, we want to restrict the
   * list of allowable types not to include primitives.
   * @param className the fully qualified name of the class which contains
   * the field to be checked
   * @param fieldName the name of the field to be checked
   * @return <code>true</code> if this field name represents a field
   * with a valid type for a key field; <code>false</code> otherwise.
   */
  public boolean isValidKeyType (String className, String fieldName)
  {
    return (((NameMapper.PRIMARY_KEY_FIELD ==
      getPersistenceKeyClassType(className)) &&
      isPrimitive(className, fieldName)) ? false :
      super.isValidKeyType(className, fieldName));
  }

  /** Returns the Class type of the specified element.
   * If element denotes a field, it returns the type of the field.
   * If element denotes a method, it returns the return type of the method.
   * Note, element is either a field element as returned by getField, or a
   * method element as returned by getMethod executed on the same model
   * instance.
   * @param element the element to be checked
   * @return the Class type of the element
   * @see #getField
   * @see RuntimeModel#getMethod
   */
  protected Class getTypeObject (Object element)
  {
    Class type = super.getTypeObject(element);

    if ((element != null) && (element instanceof MemberWrapper))
      type = ((MemberWrapper)element).getType();

    return type;
  }

  /**
   * This method returns the class loader used to find mapping information
   * for the specified className.  This implementation overrides the one in
   * RuntimeModel so that it always returns the ClassLoader provided at
   * construction time.
   * @param className the fully qualified name of the class to be checked
   * @param classLoader the class loader used to find mapping information
   * @return the class loader used to find mapping information for the
   * specified className
   */
  protected ClassLoader findClassLoader (String className,
    ClassLoader classLoader)
  {
    return getClassLoader();
  }

  // return true if a conversion to a ejb class is needed for
  // java.lang.reflect metadata
  private boolean isPCClassName (String className)
  {
    return (getEjbName(className) != null);
  }

  private String getEjbName (String className)
  {
    return getNameMapper().getEjbNameForPersistenceClass(className);
  }

  private EjbCMPEntityDescriptor getCMPDescriptor (String className)
  {
    String descriptorName = (isPCClassName(className) ?
      getEjbName(className) : className);

    return getNameMapper().getDescriptorForEjbName(descriptorName);
  }

  private int getPersistenceKeyClassType (String className)
  {
    int returnValue = -1;

    if (getCMPDescriptor(className) == null)
    {
      NameMapper nameMapper = getNameMapper();
      String ejbName =
        nameMapper.getEjbNameForPersistenceKeyClass(className);

      if (ejbName != null)
        returnValue = nameMapper.getKeyClassTypeForEjbName(ejbName);
    }

    return returnValue;
  }

  private MemberWrapper getFieldWrapper (String className, String fieldName)
  {
    EjbCMPEntityDescriptor descriptor = getCMPDescriptor(className);
    MemberWrapper returnObject = null;

    if (descriptor != null)
    {
      PersistenceDescriptor persistenceDescriptor =
        descriptor.getPersistenceDescriptor();

      if (persistenceDescriptor != null)
      {
        Class fieldType = null;

        try
        {
          fieldType = persistenceDescriptor.getTypeFor(fieldName);
        }
        catch (RuntimeException e)
        {
          // fieldType will be null - there is no such field
        }

        returnObject = ((fieldType == null) ? null :
          new MemberWrapper(fieldName, fieldType,
          Modifier.PRIVATE, (Class)getClass(className)));
      }
    }

    return returnObject;
  }

  private MemberWrapper updateFieldWrapper (MemberWrapper returnObject,
    String className, String fieldName)
  {
    NameMapper nameMapper = getNameMapper();

    if (returnObject == null)
    {
      // can't call isPersistent or isKey because that calls
      // hasField which calls getField and that would end up
      // in an endless loop
      PersistenceFieldElement field =
        getPersistenceFieldInternal(className, fieldName);

      if (field != null)
      {
        String ejbName = getEjbName(className);
        String ejbFieldName = nameMapper.
          getEjbFieldForPersistenceField(className, fieldName);

        // Check if this is the auto-added field for unknown pk
        // support.  If so, return a private field of type Long.
        if (field.isKey() && (ejbName != null) &&
          (nameMapper.getKeyClassTypeForEjbName(ejbName) ==
          NameMapper.UNKNOWN_KEY_CLASS))
        {
          returnObject = new MemberWrapper(ejbFieldName,
            Long.class, Modifier.PRIVATE,
            (Class)getClass(className));
        }

        // Check if this is the auto-added field for 2 way managed rels
        // support.  If so, return a private field of type according to
        // cardinality of the relationship.
        else if ((field instanceof RelationshipElement) &&
          nameMapper.isGeneratedEjbRelationship(ejbName,
          ejbFieldName))
        {
          RelationshipElement rel = (RelationshipElement)field;
          Class classType = null;

          // figure out the type
          if (rel.getUpperBound() > 1)
            classType = java.util.HashSet.class;
          else
          {
            String[] inverse = nameMapper.
              getEjbFieldForGeneratedField(ejbName, ejbFieldName);

            classType = (Class)getClass(inverse[0]);
          }

          if (classType != null)
          {
            returnObject = new MemberWrapper(ejbFieldName,
              classType, Modifier.PRIVATE,
              (Class)getClass(className));
          }
        }
        // Check if this is the auto-added version field.
        // If so, return a private field of type long.
        else if (ejbFieldName.startsWith(
          NameMapper.GENERATED_VERSION_FIELD_PREFIX) &&
          nameMapper.isGeneratedField(ejbName, ejbFieldName))
        {
          returnObject = new MemberWrapper(ejbFieldName,
            Long.TYPE, Modifier.PRIVATE,
            (Class)getClass(className));
        }
      }
    }

    // if the field in the corresponding ejb is a serializable,
    // non-primitive, non-wrapper type, convert it to byte[] here
    if (!isPersistentTypeAllowed(getType(returnObject),
      getClassLoader()) && isSerializable(returnObject))
    {
      returnObject.setType(byte[].class);
    }

    return returnObject;
  }

  private class MemberWrapper
  {
    private String _name;
    private Class _type;
    private int _modifiers;
    private Class _declaringClass;

    private MemberWrapper (Member member)
    {
      this(member.getName(), ((member instanceof Field) ?
        ((Field)member).getType() : ((member instanceof Method) ?
        ((Method)member).getReturnType() : null)),
        member.getModifiers(), member.getDeclaringClass());
    }

    private MemberWrapper (String name, Class type, int modifiers,
      Class declaringClass)
    {
      _name = name;
      _type = type;
      _modifiers = modifiers;
      _declaringClass = declaringClass;
    }

    private Class getType () { return _type; }
    private void setType (Class type) { _type = type; }
    private String getName () { return _name; }
    private int getModifiers () { return _modifiers; }
    private Class getDeclaringClass () { return _declaringClass; }

    /** Returns a string representation of this object.
     * @return a string reprentation of the member wrapper object.
     */   
    public String toString () { return getName(); }
  }
}
TOP

Related Classes of com.sun.jdo.spi.persistence.support.ejb.model.DeploymentDescriptorModel$MemberWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.