You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2003/07/08 03:04:39 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess AbstractPersistentField.java PersistentFieldDirectAccessImpl.java PersistentFieldPrivilegedImpl.java

arminw      2003/07/07 18:04:39

  Added:       src/java/org/apache/ojb/broker/metadata/fieldaccess
                        AbstractPersistentField.java
                        PersistentFieldDirectAccessImpl.java
                        PersistentFieldPrivilegedImpl.java
  Log:
  add new PersistentField implementations
  
  Revision  Changes    Path
  1.1                  db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/AbstractPersistentField.java
  
  Index: AbstractPersistentField.java
  ===================================================================
  package org.apache.ojb.broker.metadata.fieldaccess;
  
  import org.apache.commons.lang.builder.ToStringBuilder;
  import org.apache.commons.lang.builder.ToStringStyle;
  import org.apache.ojb.broker.metadata.MetadataException;
  import org.apache.ojb.broker.util.ProxyHelper;
  import org.apache.ojb.broker.util.logging.Logger;
  import org.apache.ojb.broker.util.logging.LoggerFactory;
  
  import java.lang.reflect.Field;
  
  /**
   * Abstract {@link PersistentField} implementation.
   *
   * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
   * @version $Id: AbstractPersistentField.java,v 1.1 2003/07/08 01:04:39 arminw Exp $
   */
  public abstract class AbstractPersistentField implements PersistentField
  {
      public static final String PATH_TOKEN = "::";
      public static final Class PERSISTENT_FIELD_IMPL_FOR_NESTED = PersistentFieldDirectAccessImpl.class;
  
      private static final int NORMAL_FIELD = 1;
      private static final int NESTED_FIELD = 2;
      private static final Class[] METHOD_TYPES = {Class.class, String.class};
  
      private transient Field field;
      private String fieldName;
      private Class rootObjectType;
      /**
       * 0 - not initialized
       * 1 - normal field
       * 2 - nested field
       */
      private int isNestedField;
  
      /**
       * For internal use only!!
       */
      protected AbstractPersistentField()
      {
      }
  
      public AbstractPersistentField(Class clazz, String fieldname)
      {
          this.rootObjectType = clazz;
          this.fieldName = fieldname;
      }
  
      /**
       * Set value for target object.
       */
      public abstract void doSet(Object targetObject, Object value);
  
      /**
       * Get value for field extracted from given target object.
       */
      public abstract Object doGet(Object targetObject);
  
      /**
       * A value of true indicates that this field should
       * suppress Java language access checking when it is used.
       */
      public abstract boolean makeAccessible();
  
      /**
       * do not override this method, have a look at {@link doSet}
       */
      public void set(Object targetObject, Object value) throws MetadataException
      {
          if (isNestedField())
          {
              setNestedObject(targetObject, fieldName, value);
          }
          else
          {
              doSet(targetObject, value);
          }
      }
  
      /**
       * do not override this method, have a look at {@link doGet}
       */
      public Object get(Object targetObject) throws MetadataException
      {
          if (isNestedField())
          {
              return getNestedObject(targetObject, fieldName);
          }
          else
          {
              return doGet(targetObject);
          }
      }
  
      protected Logger getLog()
      {
          return LoggerFactory.getLogger("PersistentField");
      }
  
      /**
       * Returns the underlying field object.
       * If parameter <tt>setAccessible</tt> is true the
       * field access checking was suppressed.
       */
      protected Field getField()
      {
          if (field == null)
          {
              field = computeField(rootObjectType, fieldName);
          }
          return field;
      }
  
      /**
       * Tries to compute a Field object using getFieldRecursive.
       * @throws MetadataException if there is an error computing the field
       * ( No Field was found into the class hierarchy)
       */
      private Field computeField(Class c, String fieldname)
      {
          try
          {
              Field f = getFieldRecursive(c, fieldname);
              if (makeAccessible()) f.setAccessible(true); // allow access to private members
              return f;
          }
          catch (NoSuchFieldException e)
          {
              throw new MetadataException("Can't find member " + fieldname + " in " + c.getName(), e);
          }
      }
  
      /**
       * try to find a field in class c, recurse through class hierarchy if necessary
       * @throws NoSuchFieldException if no Field was found into the class hierarchy
       */
      private Field getFieldRecursive(Class c, String name) throws NoSuchFieldException
      {
          try
          {
              Field f = c.getDeclaredField(name);
              return f;
          }
          catch (NoSuchFieldException e)
          {
              // if field  could not be found in the inheritance hierarchy, signal error
              if (c == Object.class)
              {
                  throw e;
              }
              // if field could not be found in class c try in superclass
              else
              {
                  return getFieldRecursive(c.getSuperclass(), name);
              }
          }
      }
  
      protected boolean isNestedField()
      {
          if (isNestedField == 0) // not initialized
          {
              if (fieldName == null)
              {
                  throw new MetadataException(
                          "Unexpected behaviour: fieldName is null, can not calculate field rootObjectType");
              }
              if (fieldName.indexOf(PATH_TOKEN) >= 0)
              {
                  isNestedField = NESTED_FIELD;
              }
              else
              {
                  isNestedField = NORMAL_FIELD;
              }
          }
          return isNestedField == NESTED_FIELD;
      }
  
      /**
       * Get nested attribute with given field name.
       * @param obj object from which the represented field's value is to be extracted
       * @param fieldName nested attribute name
       * @return Object the value of the represented field in object obj
       */
      protected Object getNestedObject(Object obj, String fieldName)
      {
          Object result = null;
          int index = fieldName.indexOf(PATH_TOKEN);
          if (index >= 0)
          {
              String name = fieldName.substring(0, index);
              PersistentField pField = createInternPersistentField(ProxyHelper.getRealClass(obj), name);
              Object attrib = pField.get(ProxyHelper.getRealObject(obj));
  
              if (attrib != null)
              {
                  String nestedName = fieldName.substring(index + PATH_TOKEN.length());
                  result = getNestedObject(attrib, nestedName);
              }
          }
          else
          {
              PersistentField pField = createInternPersistentField(ProxyHelper.getRealClass(obj), fieldName);
              result = pField.get(ProxyHelper.getRealObject(obj));
          }
          return result;
      }
  
      /**
       * Set nested attribute with given value.
       * @param obj the object whose field should be modified
       * @param fieldName nested attribute name
       * @param value the new value for the field of obj being modified
       */
      protected void setNestedObject(Object obj, String fieldName, Object value)
      {
          int index = fieldName.indexOf(PATH_TOKEN);
          if (index >= 0)
          {
              String name = fieldName.substring(0, index);
              AbstractPersistentField pField = createInternPersistentField(ProxyHelper.getRealClass(obj), name);
              Object attrib = pField.get(ProxyHelper.getRealObject(obj));
  
              if (attrib == null)
              {
                  try
                  {
                      attrib = pField.getType().newInstance();
                  }
                  catch (InstantiationException e)
                  {
                      throw new MetadataException("Error instantiate field: "
                              + name + " in object:" + obj.getClass().getName(), e);
                  }
                  catch (IllegalAccessException e)
                  {
                      throw new MetadataException("Error getting field:"
                              + name + " in object:" + obj.getClass().getName(), e);
                  }
                  Class type = pField.getType();
                  if ((value != null) || !type.isPrimitive())
                  {
                      pField.doSet(ProxyHelper.getRealObject(obj), attrib);
                  }
              }
              //
              String nestedName = fieldName.substring(index + PATH_TOKEN.length());
  
              setNestedObject(attrib, nestedName, value);
          }
          else
          {
  
              PersistentField pField = createInternPersistentField(ProxyHelper.getRealClass(obj), fieldName);
              pField.set(ProxyHelper.getRealObject(obj), value);
          }
  
      }
  
      private AbstractPersistentField createInternPersistentField(Class fieldType, String fieldName)
      {
  //        try
  //        {
  //            Object[] args = {fieldType, fieldName};
  //            return (AbstractPersistentField) ClassHelper.newInstance(PERSISTENT_FIELD_IMPL_FOR_NESTED, METHOD_TYPES, args);
  //        }
  //        catch (Exception e)
  //        {
  //            throw new MetadataException("Cannot create PersistentField for field '" + fieldName + "' of class " +
  //                    fieldType.getName(), e);
  //        }
  
          try
          {
              return (AbstractPersistentField) PersistentFieldFactory.createPersistentField(fieldType, fieldName);
          }
          catch (Exception e)
          {
              throw new MetadataException("Cannot create PersistentField for field '" + fieldName + "' of class " +
                      fieldType.getName(), e);
          }
      }
  
      public String toString()
      {
          ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE);
          buf.append("isNestedField", isNestedField());
          buf.append("fieldName", fieldName);
          buf.append("field", field);
          return buf.toString();
      }
  
      public String getName()
      {
          return fieldName;
      }
  
      public Class getType()
      {
          return getField().getType();
      }
  
      public Class getDeclaringClass()
      {
          return getField().getDeclaringClass();
      }
  }
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldDirectAccessImpl.java
  
  Index: PersistentFieldDirectAccessImpl.java
  ===================================================================
  package org.apache.ojb.broker.metadata.fieldaccess;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import org.apache.ojb.broker.metadata.MetadataException;
  import org.apache.ojb.broker.util.BrokerHelper;
  import org.apache.ojb.broker.util.ProxyHelper;
  import org.apache.ojb.broker.util.logging.Logger;
  import org.apache.ojb.broker.util.logging.LoggerFactory;
  
  import java.lang.reflect.Field;
  
  /**
   * This class is a wrapper around java.lang.reflect.Field objects.
   * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
   * @version $Id: PersistentFieldDirectAccessImpl.java,v 1.1 2003/07/08 01:04:39 arminw Exp $
   */
  public class PersistentFieldDirectAccessImpl extends AbstractPersistentField
  {
      public PersistentFieldDirectAccessImpl()
      {
      }
  
      public PersistentFieldDirectAccessImpl(Class type, String fieldname)
      {
          super(type, fieldname);
      }
  
      /**
       * Sets the field represented by this PersistentField object on the specified object argument to the specified new value.
       * The new value is automatically unwrapped if the underlying field has a primitive type.
       * This implementation invokes set() on its underlying Field object if the argument <b>is not null</b>.
       * OBS IllegalArgumentExceptions are wrapped as PersistenceBrokerExceptions.
       *
       * @throws MetadataException if there is an error setting this field value on obj
       * @see java.lang.reflect.Field
       */
      public void doSet(Object obj, Object value) throws MetadataException
      {
          Field field = getField();
          Class type = field.getType();
          try
          {
              /**
               * MBAIRD
               * we need to be able to set values to null. We can only set something to null if
               * the type is not a primitive (assignable from Object).
               */
              // thanks to Tomasz Wysocki for this trick
              if ((value != null) || !type.isPrimitive())
              {
  //System.out.println("## set: "+obj+" -- "+value);
                  field.set(ProxyHelper.getRealObject(obj), value);
              }
          }
          catch (NullPointerException ignored)
          {
              getLog().info("Value for field " + (field != null ? field.getName() : null) +
                      " of type " + type.getName() + " is null. Can't write into null.", ignored);
          }
          catch (IllegalAccessException e)
          {
              getLog().error("while set field: " + BrokerHelper.buildMessageString(obj, value, field));
              throw new MetadataException("IllegalAccess error setting field:" +
                      (field != null ? field.getName() : null) + " in object:" + obj.getClass().getName(), e);
          }
          catch (Exception e)
          {
              getLog().error("while set field: " + BrokerHelper.buildMessageString(obj, value, field), e);
              throw new MetadataException("Error setting field:" + (field != null ? field.getName() : null) +
                      " in object:" + obj.getClass().getName(), e);
          }
      }
  
      /**
       * Returns the value of the field represented by this PersistentField, on the specified object.
       * This implementation invokes get() on its underlying Field object.
       *
       * @param obj - the object instance which we are trying to get the field value from
       * @throws MetadataException if there is an error getting this field value from obj
       * @see java.lang.reflect.Field
       */
      public Object doGet(Object obj) throws MetadataException
      {
          Field field = getField();
          try
          {
              Object result = field.get(ProxyHelper.getRealObject(obj));
              return result;
          }
          catch (IllegalAccessException e)
          {
              throw new MetadataException(
                      "IllegalAccess error getting field:" +
                      (field != null ? field.getName() : null) + " in object:" + obj.getClass().getName(), e);
          }
          catch (Throwable e)
          {
              throw new MetadataException("Error getting field:" +
                      (field != null ? field.getName() : null) + " in object:" + obj.getClass().getName(), e);
          }
      }
  
      /**
       * try to find a field in class c, recurse through class hierarchy if necessary
       *
       * @throws NoSuchFieldException if no Field was found into the class hierarchy
       */
      protected Field getFieldRecursive(Class c, String fieldname) throws NoSuchFieldException
      {
          try
          {
              Field f = c.getDeclaredField(fieldname);
              return f;
          }
          catch (NoSuchFieldException e)
          {
              // if field  could not be found in the inheritance hierarchy, signal error
              if (c == Object.class)
              {
                  throw e;
              }
              // if field could not be found in class c try in superclass
              else
              {
                  return getFieldRecursive(c.getSuperclass(), fieldname);
              }
          }
      }
  
      /**
       * This implementation returns always 'false'.
       * @see AbstractPersistentField#makeAccessible()
       */
      public boolean makeAccessible()
      {
          return true;
      }
  
      /**
       * Always returns 'false'.
       * @see PersistentField#usesAccessorsAndMutators
       */
      public boolean usesAccessorsAndMutators()
      {
          return false;
      }
  }
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldPrivilegedImpl.java
  
  Index: PersistentFieldPrivilegedImpl.java
  ===================================================================
  package org.apache.ojb.broker.metadata.fieldaccess;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import org.apache.ojb.broker.metadata.MetadataException;
  import org.apache.ojb.broker.util.BrokerHelper;
  import org.apache.ojb.broker.util.ProxyHelper;
  import org.apache.ojb.broker.util.logging.Logger;
  import org.apache.ojb.broker.util.logging.LoggerFactory;
  
  import java.io.Serializable;
  import java.lang.reflect.Field;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  
  /**
   * This class is a wrapper around java.lang.reflect.Field objects.
   * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
   * @version $Id: PersistentFieldPrivilegedImpl.java,v 1.1 2003/07/08 01:04:39 arminw Exp $
   */
  public class PersistentFieldPrivilegedImpl extends PersistentFieldDirectAccessImpl
  {
      private SetAccessibleAction setAccessibleAction = new SetAccessibleAction();
  
      public PersistentFieldPrivilegedImpl()
      {
      }
  
      public PersistentFieldPrivilegedImpl(Class type, String fieldname)
      {
          super(type, fieldname);
      }
  
      /**
       *
       */
      public synchronized void doSet(Object obj, Object value) throws MetadataException
      {
          int accessibleState = 0;
          Field field = getField();
          if(!field.isAccessible()) accessibleState = 1;
          if(accessibleState == 1)
          {
              accessibleState = 2;
              AccessController.doPrivileged(setAccessibleAction);
          }
          try
          {
              super.doSet(obj, value);
          }
          finally
          {
              if(accessibleState == 2) field.setAccessible(false);
          }
      }
  
      /**
       *
       */
      public synchronized Object doGet(Object obj) throws MetadataException
      {
          int accessibleState = 0;
          Field field = getField();
          Object result = null;
          if(!field.isAccessible()) accessibleState = 1;
          if(accessibleState == 1)
          {
              accessibleState = 2;
              AccessController.doPrivileged(setAccessibleAction);
          }
          try
          {
              result = super.doGet(obj);
          }
          finally
          {
              if(accessibleState == 2) field.setAccessible(false);
          }
          return result;
      }
  
      /**
       * This implementation returns always 'false'.
       * @see AbstractPersistentField#makeAccessible()
       */
      public boolean makeAccessible()
      {
          return false;
      }
  
      /**
       * Always returns 'false'.
       * @see PersistentField#usesAccessorsAndMutators
       */
      public boolean usesAccessorsAndMutators()
      {
          return false;
      }
  
      //************************************************************
      // inner class
      //************************************************************
      private class SetAccessibleAction implements PrivilegedAction, Serializable
      {
          public Object run()
          {
              getField().setAccessible(true);
              return null;
          }
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org