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 2004/06/25 20:08:06 UTC

cvs commit: db-ojb build.properties release-notes.txt

arminw      2004/06/25 11:08:06

  Modified:    src/test/org/apache/ojb/broker/metadata
                        PersistentFieldPerfTest.java
               src/test/org/apache/ojb OJB.properties
               .        build.properties release-notes.txt
  Added:       src/java/org/apache/ojb/broker/metadata/fieldaccess
                        PersistentFieldDirectAccessImplNew.java
                        PersistentFieldPrivilegedImplNew.java
  Log:
  - add new rewritten PersistentField implementations
  - write notice to release-notes
  - prepare for 1.0
  
  Revision  Changes    Path
  1.1                  db-ojb/src/java/org/apache/ojb/broker/metadata/fieldaccess/PersistentFieldDirectAccessImplNew.java
  
  Index: PersistentFieldDirectAccessImplNew.java
  ===================================================================
  package org.apache.ojb.broker.metadata.fieldaccess;
  
  /* Copyright 2003-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.lang.reflect.Field;
  import java.util.List;
  
  import org.apache.ojb.broker.core.proxy.ProxyHelper;
  import org.apache.ojb.broker.metadata.MetadataException;
  import org.apache.ojb.broker.util.ClassHelper;
  
  /**
   * This {@link PersistentField} implementation
   * is the high-speed version of the access strategies.
   * <br/>
   * It does not cooperate with an AccessController,
   * but accesses the fields directly. This implementation persistent
   * attributes don't need getters and setters
   * and don't have to be declared public or protected. Only the the
   * metadata field names have to match the class fields.
   *
   * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
   * @version $Id: PersistentFieldDirectAccessImplNew.java,v 1.1 2004/06/25 18:08:05 arminw Exp $
   */
  public class PersistentFieldDirectAccessImplNew extends PersistentFieldBase
  {
      private static final long serialVersionUID = -5458024240998909205L;
  
      private static int NESTED_UNKOWM = 0;
      private static int NESTED_TRUE = 1;
      private static int NESTED_FALSE = 2;
  
      private transient List fieldsList;
      private transient Field field;
      private transient int isNestedField;
  
      public PersistentFieldDirectAccessImplNew()
      {
      }
  
      public PersistentFieldDirectAccessImplNew(Class type, String fieldname)
      {
          super(type, fieldname);
      }
  
      public Class getType()
      {
          return getField().getType();
      }
  
      public Class getDeclaringClass()
      {
          return getField().getDeclaringClass();
      }
  
      /**
       * Returns the underlying field object.
       * If parameter <tt>setAccessible</tt> is true the
       * field access checking was suppressed.
       */
      protected Field getField()
      {
          if (field == null)
          {
              /*
              first we build a graph of fields for nested fields support,
              but for best performance on non-nested fields we also keep
              the latest field separate and build a 'isNested' flag.
              */
              fieldsList = getFieldGraph(makeAccessible());
              field = (Field) fieldsList.get(fieldsList.size() - 1);
              isNestedField = fieldsList.size() > 1 ? NESTED_TRUE : NESTED_FALSE;
          }
          return field;
      }
  
      private List getFieldsList()
      {
          // make sure class is init
          if (field == null) getField();
          return fieldsList;
      }
  
      protected boolean isNestedField()
      {
          // make sure class is init
          if(isNestedField == NESTED_UNKOWM)
          {
              getField();
          }
          return isNestedField == NESTED_TRUE;
      }
  
      /**
       * do not override this method, have a look at {@link #setValueFor(java.lang.reflect.Field, java.lang.Object, java.lang.Object)}
       */
      public void set(Object target, Object value) throws MetadataException
      {
          Object current = target;
          if (isNestedField())
          {
              List fields = getFieldsList();
              int size = fields.size() - 1;
              Field field;
              for (int i = 0; i < size; i++)
              {
                  field = (Field) fields.get(i);
                  Object attribute = null;
                  try
                  {
  //                    System.out.println("" + (field != null ? field.getName() : null)
  //                            + "/" + (field != null ? field.getType() : null)
  //                            + "    " + (current != null ? current.getClass() : null));
                      //attribute = field.get(current);
                      attribute = getValueFrom(field, current);
                  }
                  catch (Exception e)
                  {
                      throw new MetadataException("Can't read field '" + field.getName() + "' of type " + field.getType().getName(), e);
                  }
                  if (attribute != null || value != null)
                  {
                      if (attribute == null)
                      {
                          try
                          {
                              attribute = ClassHelper.newInstance(field.getType());
                          }
                          catch (Exception e)
                          {
                              throw new MetadataException("Can't create nested object of type '"
                                      + field.getType() + "' for field '"
                                      + field.getName() + "'", e);
                          }
                      }
                      try
                      {
                          //field.set(current, attribute);
                          setValueFor(field, current, attribute);
                      }
                      //catch (IllegalAccessException e)
                      catch (Exception e)
                      {
                          throw new MetadataException("Can't set nested object of type '"
                                      + field.getType() + "' for field '"
                                      + field.getName() + "'", e);
                      }
                  }
                  else
                  {
                      return;
                  }
                  current = attribute;
              }
          }
          if(current != null) setValueFor(getField(), current, value);
      }
  
      /**
       * do not override this method, have a look at {@link #getValueFrom(java.lang.reflect.Field, java.lang.Object)}
       */
      public Object get(Object target) throws MetadataException
      {
          Object result = target;
          if (isNestedField())
          {
              List fields = getFieldsList();
              for (int i = 0; i < fields.size(); i++)
              {
                  result = getValueFrom((Field) fields.get(i), result);
                  if (result == null) break;
              }
          }
          else
          {
              result = result != null ? getValueFrom(getField(), result) : null;
          }
          return result;
      }
  
  
  
      protected Object getValueFrom(Field field, Object target)
      {
          try
          {
              return field.get(ProxyHelper.getRealObject(target));
          }
          catch (IllegalAccessException e)
          {
              throw new MetadataException(
                      "IllegalAccess error getting field:" +
                      (field != null ? field.getName() : null) + " in object:"
                      + target != null ? target.getClass().getName() : null, e);
          }
      }
  
      protected void setValueFor(Field field, Object target, final Object value)
      {
          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) || !field.getType().isPrimitive())
              {
                  // System.err.println("## t: " + target + "  v: " + value);
                  field.set(ProxyHelper.getRealObject(target), value);
              }
          }
          catch (NullPointerException ignored)
          {
              getLog().info("Target object '" + (target != null ? target.getClass().getName() : null)
                      + "' for field '" + (field != null ? field.getName() : null)
                      + "' of type '" + (field != null ? field.getType().getName() : null)
                      + "' seems to be null. Can't write into null.", ignored);
          }
          catch (Exception e)
          {
              getLog().error("while set field: " + buildMessageString(target, value, field));
              throw new MetadataException("IllegalAccess error setting field:" +
                      (field != null ? field.getName() : null) + " in object:" + target.getClass().getName(), e);
          }
      }
  
      /**
       * This implementation returns always 'true'.
       * @see AbstractPersistentField#makeAccessible()
       */
      protected 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/PersistentFieldPrivilegedImplNew.java
  
  Index: PersistentFieldPrivilegedImplNew.java
  ===================================================================
  package org.apache.ojb.broker.metadata.fieldaccess;
  
  /* Copyright 2003-2004 The Apache Software Foundation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.io.Serializable;
  import java.lang.reflect.Field;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  
  /**
   * A {@link PersistentField} implementation using
   * reflection to access but does cooperate with
   * AccessController and do not suppress the java
   * language access check.
   *
   * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
   * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
   * @version $Id: PersistentFieldPrivilegedImplNew.java,v 1.1 2004/06/25 18:08:05 arminw Exp $
   * @see PersistentFieldDirectAccessImpl
   */
  public class PersistentFieldPrivilegedImplNew extends PersistentFieldDirectAccessImplNew
  {
      private static final long serialVersionUID = -6110158693763128846L;
  
      private SetAccessibleAction setAccessibleAction = new SetAccessibleAction();
      private UnsetAccessibleAction unsetAccessibleAction = new UnsetAccessibleAction();
      private static final int ACCESSIBLE_STATE_UNKOWN = 0;
      private static final int ACCESSIBLE_STATE_FALSE = 1;
      private static final int ACCESSIBLE_STATE_SET_TRUE = 2;
  
      public PersistentFieldPrivilegedImplNew()
      {
      }
  
      public PersistentFieldPrivilegedImplNew(Class type, String fieldname)
      {
          super(type, fieldname);
      }
  
      protected Object getValueFrom(Field field, Object target)
      {
          int accessibleState = ACCESSIBLE_STATE_UNKOWN;
          Object result = null;
          if (!field.isAccessible()) accessibleState = ACCESSIBLE_STATE_FALSE;
          if (accessibleState == ACCESSIBLE_STATE_FALSE)
          {
              accessibleState = ACCESSIBLE_STATE_SET_TRUE;
              setAccessibleAction.current = field;
              AccessController.doPrivileged(setAccessibleAction);
          }
          try
          {
              result = super.getValueFrom(field, target);
          }
          finally
          {
              if (accessibleState == ACCESSIBLE_STATE_SET_TRUE)
              {
                  unsetAccessibleAction.current = field;
                  AccessController.doPrivileged(unsetAccessibleAction);
              }
          }
          return result;
      }
  
      protected void setValueFor(Field field, Object target, Object value)
      {
          int accessibleState = ACCESSIBLE_STATE_UNKOWN;
          if (!field.isAccessible()) accessibleState = ACCESSIBLE_STATE_FALSE;
          if (accessibleState == ACCESSIBLE_STATE_FALSE)
          {
              accessibleState = ACCESSIBLE_STATE_SET_TRUE;
              setAccessibleAction.current = field;
              AccessController.doPrivileged(setAccessibleAction);
          }
          try
          {
              super.setValueFor(field, target, value);
          }
          finally
          {
              if (accessibleState == ACCESSIBLE_STATE_SET_TRUE)
              {
                  unsetAccessibleAction.current = field;
                  AccessController.doPrivileged(unsetAccessibleAction);
              }
          }
      }
  
      /**
       * 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
      {
          static final long serialVersionUID = 8152025069698028050L;
          Field current;
  
          public Object run()
          {
              current.setAccessible(true);
              return null;
          }
      }
  
      private class UnsetAccessibleAction implements PrivilegedAction, Serializable
      {
          static final long serialVersionUID = -2284913657454430305L;
          Field current;
  
          public Object run()
          {
              current.setAccessible(false);
              return null;
          }
      }
  }
  
  
  
  1.2       +8 -9      db-ojb/src/test/org/apache/ojb/broker/metadata/PersistentFieldPerfTest.java
  
  Index: PersistentFieldPerfTest.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/broker/metadata/PersistentFieldPerfTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PersistentFieldPerfTest.java	25 Jun 2004 13:26:49 -0000	1.1
  +++ PersistentFieldPerfTest.java	25 Jun 2004 18:08:05 -0000	1.2
  @@ -6,7 +6,10 @@
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldAutoProxyImpl;
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectAccessImpl;
  +import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectAccessImplNew;
   import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl;
  +import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldPrivilegedImpl;
  +import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldPrivilegedImplNew;
   import org.apache.ojb.broker.util.ClassHelper;
   import org.apache.ojb.junit.OJBTestCase;
   
  @@ -40,7 +43,7 @@
       Class testClass = NestedFieldsTest.NestedMain.class;
       String fieldName = "name";
       String fieldNameNested = "nestedDetail::nestedDetailDetail::realDetailName";
  -    int numberOfOperations = 0;
  +    int numberOfOperations = 30000;
       int repeat = 5;
   
       public static void main(String[] args)
  @@ -49,17 +52,15 @@
           junit.textui.TestRunner.main(arr);
       }
   
  -//    Class[] persistentFieldClasses = new Class[] {
  -//            PersistentFieldDirectAccessImpl_2.class
  -//            , PersistentFieldDirectAccessImpl.class
  -//            , PersistentFieldIntrospectorImpl.class
  -//            , PersistentFieldAutoProxyImpl.class};
  -
       Class[] persistentFieldClasses = new Class[]{
           PersistentFieldDirectAccessImpl.class
  +        , PersistentFieldDirectAccessImplNew.class
           , PersistentFieldIntrospectorImpl.class
  +        , PersistentFieldPrivilegedImpl.class
  +        , PersistentFieldPrivilegedImplNew.class
           , PersistentFieldAutoProxyImpl.class};
   
  +
       private PersistentField newInstance(Class pfClass, Class testClass, String fieldName) throws Exception
       {
           Class[] types = new Class[]{Class.class, String.class};
  @@ -69,7 +70,6 @@
   
       public void testFieldPerformance() throws Exception
       {
  -        numberOfOperations = 300000;
           System.out.println();
           System.out.println("=========================================");
           System.out.println("Field performance, set/get " + numberOfOperations + " times a field");
  @@ -92,7 +92,6 @@
   
       public void testNestedFieldPerformance() throws Exception
       {
  -        numberOfOperations = 300000;
           System.out.println();
           System.out.println("=========================================");
           System.out.println("Nested Field performance, set/get " + numberOfOperations + " times a nested field");
  
  
  
  1.71      +6 -1      db-ojb/src/test/org/apache/ojb/OJB.properties
  
  Index: OJB.properties
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/OJB.properties,v
  retrieving revision 1.70
  retrieving revision 1.71
  diff -u -r1.70 -r1.71
  --- OJB.properties	3 Jun 2004 23:46:08 -0000	1.70
  +++ OJB.properties	25 Jun 2004 18:08:05 -0000	1.71
  @@ -399,6 +399,11 @@
   #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl
   #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDynaBeanAccessImpl
   #PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldAutoProxyImpl
  +# Here you can try the new upcoming PersistentField implementations. These classes will replace the
  +# old ones on next release. They pass the test-suite, but should be tested by community too.
  +# The new implementations are about 50 times faster in handling nested fields.
  +#PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldDirectAccessImplNew
  +#PersistentFieldClass=org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldPrivilegedImplNew
   #
   #
   #----------------------------------------------------------------------------------------
  
  
  
  1.64      +3 -3      db-ojb/build.properties
  
  Index: build.properties
  ===================================================================
  RCS file: /home/cvs/db-ojb/build.properties,v
  retrieving revision 1.63
  retrieving revision 1.64
  diff -u -r1.63 -r1.64
  --- build.properties	22 Jun 2004 20:46:48 -0000	1.63
  +++ build.properties	25 Jun 2004 18:08:05 -0000	1.64
  @@ -168,9 +168,9 @@
   project-name=db-ojb
   major=1
   minor=0
  -build=rc7
  +build=0
   version=${major}.${minor}.${build}
  -versiondate=2004-06-13
  +versiondate=2004-06-25
   ojb-filename-prefix=${project-name}-${version}
   
   #
  
  
  
  1.53      +60 -2     db-ojb/release-notes.txt
  
  Index: release-notes.txt
  ===================================================================
  RCS file: /home/cvs/db-ojb/release-notes.txt,v
  retrieving revision 1.52
  retrieving revision 1.53
  diff -u -r1.52 -r1.53
  --- release-notes.txt	25 Jun 2004 13:11:35 -0000	1.52
  +++ release-notes.txt	25 Jun 2004 18:08:05 -0000	1.53
  @@ -8,8 +8,28 @@
   relational databases. OJB provides ODMG and JDO interfaces.
   
   ---------------------------------------------------------------------
  -Release 1.0 ??
  +Release 1.0
   ---------------------------------------------------------------------
  +NEW FEATURES:
  +--
  +
  +NOTES:
  +- We introduce new PersistentField implementations in OJB.properties file called
  +PersistentFieldXXXXImplNew. PersistentField implementations responsible for read/write
  +to object attributes. The new versions has much better performance in read/write nested
  +fields (up to 50 times faster than the old implementions) and will replace the old
  +classes on next version. Because PersistentField is an important kernel class we
  +wait for community response before change. Feel free to try the new upcoming versions.
  +
  +
  +CHANGES:
  +--
  +
  +BUG FIXES:
  +Please refer to our Bug tracking site (http://issues.apache.org/scarab/servlet/scarab/)
  +under http://issues.apache.org/scarab/servlet/scarab/issues/id/OJBxxx
  +to see details for a bug with id OJBxxx.
  +
   
   KNOWN ISSUES:
   - The default ojb escape character '\' does not work for database using the same default as well and
  @@ -20,6 +40,44 @@
   	crit.addLike("firstname", "h%|%");
   
   This issue is fixed for MySql and PostgreSql so far.
  +
  +- odmg-api: If a user exchange already existing objects in 1:n references without changing the size
  +of the collection, the main object will not become dirty and the FK values of the exchanged objects
  +will not be updated.
  +E.g. two objects obj_1 anf obj_2 with 1:n reference to ref objects, each with one
  +existing/persistent reference object, obj_1{ref_1} and obj_2{ref_2}.
  +Lock objects and exchange the references in collection obj_1{ref_2}
  +and obj_2{ref_1} and commit --> FK values of ref_1 and ref_2 will not be updated.
  +
  +- odmg-api: Creation of m:n relation only works when objects created step by step (or use PB-api
  +as workaround), persist a whole object graph seems not to work proper.
  +
  +- ReportQueries should not be used with columns referencing Classes with extents:
  +
  +    ReportQueryByCriteria q = QueryFactory.newReportQuery(ProductGroup.class, crit);
  +    q.setAttributes(new String[] { "groupName", "sum(allArticlesInGroup.stock)", "sum(allArticlesInGroup.price)" });
  +    q.addGroupBy("groupName");
  +
  +    ProductGroup.allArticlesInGroup points to class Article having multiple extents.
  +
  +    As a workaround the query can be 'reversed' :
  +
  +    ReportQueryByCriteria q = QueryFactory.newReportQuery(Article.class, crit);
  +    q.setAttributes(new String[] { "productGroup.groupName", "sum(stock)", "sum(price)" });
  +    q.addGroupBy("productGroup.groupName");
  +
  +    Due to the fact the Article has extents multiple selects will be executed,
  +    so the same ProductGroup may show up more than once.
  +
  +    Please see the testcases QueryTest#testReportQueryGroupByExtents1 and
  +    QueryTest#testReportQueryGroupByExtents2.
  +
  +- A count on ReportQueries containing groupBy does not deliver a correct result.
  +
  +- Batch handling doesn't work proper with optimistic locking. This will be fixed
  +before long after 1.0
  +
  +
   
   ---------------------------------------------------------------------
   Release 1.0 rc7
  
  
  

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