User: dirk    
  Date: 01/02/12 01:23:00

  Modified:    src/main/org/jboss/ejb/plugins/jaws/metadata
                        CMPFieldMetaData.java JawsEntityMetaData.java
  Log:
  JAWS patch for using nested fields.
  
  Revision  Changes    Path
  1.3       +219 -6    
jboss/src/main/org/jboss/ejb/plugins/jaws/metadata/CMPFieldMetaData.java
  
  Index: CMPFieldMetaData.java
  ===================================================================
  RCS file: 
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/jaws/metadata/CMPFieldMetaData.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CMPFieldMetaData.java     2000/12/07 15:44:40     1.2
  +++ CMPFieldMetaData.java     2001/02/12 09:23:00     1.3
  @@ -19,7 +19,10 @@
   import org.jboss.metadata.MetaData;
   import org.jboss.metadata.EjbRefMetaData;
   
  +import java.util.*;
   
  +import org.jboss.logging.Log;
  +import org.jboss.logging.Logger;
   
   /**
    *   This class holds all the information jaws needs to know about a CMP field
  @@ -27,7 +30,8 @@
    *      
    *   @see <related>
    *   @author <a href="[EMAIL PROTECTED]">Sebastien Alborini</a>
  - *   @version $Revision: 1.2 $
  + *  @author <a href="mailto:[EMAIL PROTECTED]">Dirk Zimmermann</a>
  + *   @version $Revision: 1.3 $
    */
   public class CMPFieldMetaData extends MetaData implements XmlLoadable {
        // Constants -----------------------------------------------------
  @@ -57,6 +61,22 @@
        private boolean isAPrimaryKeyField;
        
        
  +     /**
  +      * We need this for nested field retrieval.
  +      */
  +     private String ejbClassName;
  +
  +     /**
  +      * We need this for nested fields. We could compute it from ejbClassName on 
the fly,
  +      * but it's faster to set it once and cache it.
  +      */
  +     private Class ejbClass;
  +
  +     /**
  +      * Is true for fields like "data.categoryPK".
  +      */
  +     private boolean isNested;
  +
        // Static --------------------------------------------------------
      
        // Constructors --------------------------------------------------
  @@ -64,18 +84,23 @@
                this.name = name;
                this.jawsEntity = jawsEntity;
                
  -             String ejbClassName = jawsEntity.getEntity().getEjbClass();
  +             // save the class name for nested fields
  +             ejbClassName = jawsEntity.getEntity().getEjbClass();
  +             ejbClassName = jawsEntity.getEntity().getEjbClass();
  +
                try {
  -                     Class ejbClass = 
jawsEntity.getJawsApplication().getClassLoader().loadClass(ejbClassName);
  +                     // save the class for nested fields
  +                     ejbClass = 
jawsEntity.getJawsApplication().getClassLoader().loadClass(ejbClassName);
                    field = ejbClass.getField(name);
                } catch (ClassNotFoundException e) {
                        throw new DeploymentException("ejb class not found: " + 
ejbClassName);
                } catch (NoSuchFieldException e) {
  -                     throw new DeploymentException("cmp-field " + name + " is not a 
field in ejb class " + ejbClassName);
  +                     // we can't throw an Exception here, because we could have a 
nested field
  +                     checkField();
                }
                
                // default, may be overridden by importXml
  -             columnName = name;
  +             columnName = getLastComponent(name);
                
                // cannot set defaults for jdbctype/sqltype, type mappings are not 
loaded yet.
        }
  @@ -111,7 +136,185 @@
        
        public JawsEntityMetaData getJawsEntity() { return jawsEntity; }
                
  -     
  +     /**
  +      * Returns the last component of a composite fieldName. E.g., for 
"data.categoryPK" it
  +      * will return "categoryPK".
  +      */
  +     public static String getLastComponent(String name) {
  +             String fieldName = name;
  +             StringTokenizer st = new StringTokenizer(name, ".");
  +             while(st.hasMoreTokens()) {
  +                     fieldName = st.nextToken();
  +             }
  +             return fieldName;
  +     }
  +
  +     /**
  +      * Returns the first component of a composite fieldName. E.g., for 
"data.categoryPK" it
  +      * will return "data".
  +      */
  +     public static String getFirstComponent(String name) {
  +             String fieldName;
  +             StringTokenizer st = new StringTokenizer(name, ".");
  +             if (st.hasMoreTokens()) {
  +                     fieldName = st.nextToken();
  +             }
  +             else {
  +                     fieldName = null;
  +             }
  +             return fieldName;
  +     }
  +
  +     /**
  +      * Detects the actual field of a nested field and sets field accordingly.
  +      * If field doesn't exist, throws a DeploymentException.
  +      */
  +     private void checkField()       throws DeploymentException {
  +             try {
  +                     field = verifyNestedField();
  +             }
  +             catch(DeploymentException e) {
  +                     // try it again, but debug Class before :))
  +                     debugClass(ejbClass);
  +                     field = verifyNestedField();
  +                     Log.getLog().warning("!!! using buggy hotspot, try to upgrade 
... !!!");
  +             }
  +             Log.getLog().warning("mapping " + name + " to " + 
getLastComponent(name));
  +     }
  +
  +     /**
  +      * Traverses and verifies a nested field, so that every field given in jaws.xml
  +      * exists in the Bean.
  +      */
  +     private Field verifyNestedField() throws DeploymentException {
  +             String fieldName = null;
  +             Field tmpField = null;
  +             Class tmpClass = ejbClass;
  +             StringTokenizer st = new StringTokenizer(name, ".");
  +
  +             if (st.countTokens() > 1) {
  +                     isNested = true;
  +             }
  +
  +             while(st.hasMoreTokens()) {
  +                     fieldName = st.nextToken();
  +                     try {
  +                             //debugClass(tmpClass);
  +                             tmpField = tmpClass.getField(fieldName);
  +                             tmpClass = tmpField.getType();
  +                     }
  +                     catch (NoSuchFieldException e) {
  +                             throw new DeploymentException("cmp-field " + name + " 
is not a field in ejb class " + ejbClassName);
  +                     }
  +             }
  +             return tmpField;
  +     }
  +
  +     /**
  +      * We don't rely on the field alone for getting the type since we support 
nested field
  +      * like 'data.categoryPK'.
  +      */
  +     public Class getFieldType()     {
  +             if (field != null) {
  +                     // The default case as it always was :)
  +                     return field.getType();
  +             }
  +                             
  +             // We obviously have a nested field (or an erroneous one)
  +             Field tmpField = null;
  +             Class tmpClass = ejbClass;
  +             String fieldName = null;
  +             StringTokenizer st = new StringTokenizer(name, ".");
  +             while(st.hasMoreTokens()) {
  +                     fieldName = st.nextToken();
  +                     try {
  +                             tmpField = tmpClass.getField(fieldName);
  +                             tmpClass = tmpField.getType();
  +                     }
  +                     catch (NoSuchFieldException e) {
  +                             Log.getLog().warning("!!! Deployment Failure !!!");
  +                     }
  +             }
  +             return tmpField.getType();
  +     }
  +
  +     /**
  +      * Is used mainly for nested fields. Sets the value of a nested field.
  +      */
  +     public void set(Object instance, Object value) {
  +             Field tmpField = null;
  +             String fieldName = null;
  +             Object currentObject = instance;
  +             Object oldObject;
  +             StringTokenizer st = new StringTokenizer(name, ".");
  +
  +             try {
  +                     for (int i = 0; i < st.countTokens() - 1; ++i) {
  +                             st.hasMoreTokens();
  +                             fieldName = st.nextToken();
  +                             tmpField = 
currentObject.getClass().getField(fieldName);
  +                             oldObject = currentObject;
  +                             currentObject = tmpField.get(currentObject);
  +                             // On our path, we have to instantiate every 
intermediate object
  +                             if (currentObject == null) {
  +                                     currentObject = 
tmpField.getType().newInstance();
  +                                     tmpField.set(oldObject, currentObject);
  +                             }
  +                     }
  +                     Field dataField = 
currentObject.getClass().getField(getLastComponent(name));
  +                     dataField.set(currentObject, value);
  +             }
  +             catch (NoSuchFieldException e) {
  +                     Log.getLog().warning("!!! Deployment Failure !!!");
  +             }
  +             catch (IllegalAccessException e) {
  +                     Log.getLog().warning("!!! Deployment Failure !!!");
  +             }
  +             catch (InstantiationException e) {
  +                     Log.getLog().warning("could not instantiate " + tmpField);
  +             }
  +     }
  +
  +     /**
  +      * Returns the value of this field.
  +      */
  +     public Object getValue(Object instance) {
  +             String fieldName;
  +             Object currentObject = instance;
  +             Field currentField;
  +             //Object currentValue = null;
  +
  +             try {
  +                     if (!isNested()) {
  +                             return getField().get(instance);
  +                     }
  +                     else {
  +                             StringTokenizer st = new StringTokenizer(name, ".");
  +                             while(st.hasMoreTokens()) {
  +                                     fieldName = st.nextToken();
  +                                     currentField = 
currentObject.getClass().getField(fieldName);
  +                                     currentObject = 
currentField.get(currentObject);
  +                             }
  +                             return currentObject;
  +                     }
  +             }
  +             catch (IllegalAccessException e) {
  +                     // We have already checked the presence of this field in the 
constructor,
  +                     // so there is no need to throw an exception here.
  +                     Log.getLog().warning("!!! CMPFieldMetaData.getValue() ERROR 
!!! " + e);
  +             }
  +             catch (NoSuchFieldException e) {
  +                     // We have already checked the presence of this field in the 
constructor,
  +                     // so there is no need to throw an exception here.
  +                     Log.getLog().warning("!!! CMPFieldMetaData.getValue() ERROR 
!!! " + e);
  +             }
  +             return null;
  +     }
  +
  +     public boolean isNested() { 
  +             return isNested; 
  +     }
  +
        // XmlLoadable implementation ------------------------------------
        public void importXml(Element element) throws DeploymentException {
                
  @@ -141,6 +344,16 @@
        // Protected -----------------------------------------------------
       
        // Private -------------------------------------------------------
  +
  +     /**
  +      * Workaround for certain Hotspot problems. Just traverse all the fields
  +      * in the Class, so Hotspot won't optimize to bad ...
  +      */
  +     private void debugClass(Class debugClass) {
  +             Field[] fields = debugClass.getFields();
  +             for (int i = 0; i < fields.length; ++i) {
  +             }
  +     }
                
        // Inner classes -------------------------------------------------
   }
  
  
  
  1.6       +53 -5     
jboss/src/main/org/jboss/ejb/plugins/jaws/metadata/JawsEntityMetaData.java
  
  Index: JawsEntityMetaData.java
  ===================================================================
  RCS file: 
/products/cvs/ejboss/jboss/src/main/org/jboss/ejb/plugins/jaws/metadata/JawsEntityMetaData.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- JawsEntityMetaData.java   2001/01/24 20:36:43     1.5
  +++ JawsEntityMetaData.java   2001/02/12 09:23:00     1.6
  @@ -9,6 +9,7 @@
   import java.util.ArrayList;
   import java.util.Hashtable;
   import java.util.Iterator;
  +import java.util.HashMap;
   
   import java.lang.reflect.Field;
   
  @@ -24,13 +25,16 @@
   import org.jboss.metadata.MetaData;
   import org.jboss.metadata.XmlLoadable;
   
  +// TODO
  +import org.jboss.logging.Logger;
   
   /**
    *   <description> 
    *      
    *   @see <related>
    *   @author <a href="[EMAIL PROTECTED]">Sebastien Alborini</a>
  - *   @version $Revision: 1.5 $
  + *  @author <a href="mailto:[EMAIL PROTECTED]">Dirk Zimmermann</a>
  + *   @version $Revision: 1.6 $
    */
   public class JawsEntityMetaData extends MetaData implements XmlLoadable {
        // Constants -----------------------------------------------------
  @@ -78,7 +82,18 @@
        // finders for this bean
        private ArrayList finders = new ArrayList();
        
  -     
  +     /**
  +      * Here we store the basename of all detailed fields in jaws.xml
  +      * (e.g., "data" for "data.categoryPK").
  +      */
  +     private HashMap detailedFieldDescriptions = new HashMap();
  +     
  +     /**
  +      * This is the Boolean we store as value in detailedFieldDescriptions.
  +      */
  +     private static final Boolean detailedBoolean = new Boolean(true);
  +
  +
        // Static --------------------------------------------------------
      
        // Constructors --------------------------------------------------
  @@ -229,9 +244,20 @@
                        String fieldName = getElementContent(getUniqueChild(cmpField, 
"field-name"));
                        
                        CMPFieldMetaData cmpFieldMetaData = 
getCMPFieldByName(fieldName);
  -            if (cmpFieldMetaData == null) 
  -                             throw new DeploymentException("cmp-field 
'"+fieldName+"' found in jaws.xml but not in ejb-jar.xml");
  -                             
  +                     if (cmpFieldMetaData == null) {
  +                             // Before we throw an exception, we have to check for 
nested cmp-fields.
  +                             // We just add a new CMPFieldMetaData.
  +                             if (isDetailedFieldDescription(fieldName)) {
  +                                     // We obviously have a cmp-field like 
"data.categoryPK" in jaws.xml
  +                                     // and a cmp-field "data" in ejb-jar.xml.
  +                                     // In this case, we assume the 
"data.categoryPK" as a detailed description for "data".
  +                                     cmpFieldMetaData = new 
CMPFieldMetaData(fieldName, this);
  +                                     cmpFields.put(fieldName, cmpFieldMetaData);    
             
  +                             }
  +                             else {
  +                                     throw new DeploymentException("cmp-field 
'"+fieldName+"' found in jaws.xml but not in ejb-jar.xml");
  +                             }
  +                     }
                        cmpFieldMetaData.importXml(cmpField);
                }
                
  @@ -246,6 +272,28 @@
                        finders.add(finderMetaData);
                }
                
  +     }
  +
  +     /**
  +      * @return true For a fieldname declared in jaws.xml like "data.categoryPK" if
  +      * there was a fieldname declared in ejb-jar.xml like "data".
  +      */
  +     private boolean isDetailedFieldDescription(String fieldName) {
  +             String fieldBaseName = CMPFieldMetaData.getFirstComponent(fieldName);
  +
  +             if (detailedFieldDescriptions.containsKey(fieldBaseName)) {
  +                     return true;
  +             }
  +
  +             CMPFieldMetaData cmpFieldMetaData = getCMPFieldByName(fieldBaseName);
  +             if (cmpFieldMetaData == null) {
  +                     return false;
  +             }
  +             else {
  +                     detailedFieldDescriptions.put(fieldBaseName, detailedBoolean);
  +                     cmpFields.remove(fieldBaseName);
  +                     return true;
  +             }
        }
                
                
  
  
  

Reply via email to