db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject cvs commit: db-ojb/src/java/org/apache/ojb/broker/cache CacheHelper.java ObjectCacheDefaultImpl.java ObjectCacheEmptyImpl.java
Date Tue, 14 Sep 2004 16:16:36 GMT
arminw      2004/09/14 09:16:36

  Modified:    src/java/org/apache/ojb/broker/core ValueContainer.java
                        PoolablePersistenceBroker.java
                        PersistenceBrokerFactoryFactory.java Factories.java
                        MtoNBroker.java DelegatingPersistenceBroker.java
                        PersistenceBrokerImpl.java
               src/java/org/apache/ojb/broker/cache CacheHelper.java
                        ObjectCacheDefaultImpl.java
                        ObjectCacheEmptyImpl.java
  Added:       src/java/org/apache/ojb/broker/core GenericObject.java
  Log:
  - add new batch handling
  - update/refactoring Statement classes
  - add new PB.update(Object obj, String[] fields)
  - change insert order of m:n relations
  - change repository.dtd, add element 'batch', rename element
  'connection-pool' to 'connection-factory', remove implementation
  dependent attributes and add custom-attributes instead
  
  Revision  Changes    Path
  1.8       +6 -6      db-ojb/src/java/org/apache/ojb/broker/core/ValueContainer.java
  
  Index: ValueContainer.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/ValueContainer.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ValueContainer.java	4 Apr 2004 23:53:33 -0000	1.7
  +++ ValueContainer.java	14 Sep 2004 16:16:35 -0000	1.8
  @@ -1,7 +1,6 @@
   package org.apache.ojb.broker.core;
   
   import org.apache.ojb.broker.metadata.JdbcType;
  -import org.apache.commons.lang.builder.EqualsBuilder;
   import org.apache.commons.lang.builder.HashCodeBuilder;
   
   /* Copyright 2003-2004 The Apache Software Foundation
  @@ -53,19 +52,20 @@
           this.m_value = value;
       }
   
  -    public boolean equals(Object obj)
  +    public boolean equals(Object other)
       {
  -        if(obj == this) return true;
  +        if(other == this) return true;
           boolean result = false;
  -        if(obj instanceof ValueContainer)
  +        if(other instanceof ValueContainer)
           {
  -            ValueContainer container = (ValueContainer) obj;
  +            ValueContainer container = (ValueContainer) other;
               // if jdbcType was null, we can't compare
               result = this.m_jdbcType != null ? this.m_jdbcType.equals(container.getJdbcType()) : false;
               if(result)
               {
                   result = this.m_value == null ? null == container.getValue() : this.m_value.equals(container.getValue());
  -                result = new EqualsBuilder().append(this.m_value, container.getValue()).isEquals();
  +                // result = new EqualsBuilder().append(this.m_value, container.getValue()).isEquals();
  +                // System.out.println("this.value="+m_value + "   other.value=" + container.getValue() + "  result="+result);
               }
           }
           return result;
  
  
  
  1.6       +0 -1      db-ojb/src/java/org/apache/ojb/broker/core/PoolablePersistenceBroker.java
  
  Index: PoolablePersistenceBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PoolablePersistenceBroker.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- PoolablePersistenceBroker.java	11 Aug 2004 00:41:45 -0000	1.5
  +++ PoolablePersistenceBroker.java	14 Sep 2004 16:16:35 -0000	1.6
  @@ -1,6 +1,5 @@
   package org.apache.ojb.broker.core;
   
  -import org.apache.commons.pool.KeyedObjectPool;
   import org.apache.commons.pool.ObjectPool;
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
  
  
  
  1.6       +1 -6      db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerFactoryFactory.java
  
  Index: PersistenceBrokerFactoryFactory.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerFactoryFactory.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- PersistenceBrokerFactoryFactory.java	11 Aug 2004 00:41:45 -0000	1.5
  +++ PersistenceBrokerFactoryFactory.java	14 Sep 2004 16:16:35 -0000	1.6
  @@ -15,15 +15,10 @@
    * limitations under the License.
    */
   
  -import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PersistenceConfiguration;
  -import org.apache.ojb.broker.util.ClassHelper;
   import org.apache.ojb.broker.util.factory.ConfigurableFactory;
  -import org.apache.ojb.broker.util.configuration.Configuration;
   import org.apache.ojb.broker.util.configuration.Configurator;
   import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
  -import org.apache.ojb.broker.util.logging.Logger;
  -import org.apache.ojb.broker.util.logging.LoggerFactory;
   
   /**
    *
  
  
  
  1.2       +9 -9      db-ojb/src/java/org/apache/ojb/broker/core/Factories.java
  
  Index: Factories.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/Factories.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Factories.java	11 Aug 2004 00:41:45 -0000	1.1
  +++ Factories.java	14 Sep 2004 16:16:35 -0000	1.2
  @@ -2,9 +2,9 @@
   
   import org.apache.ojb.broker.IdentityFactory;
   import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.accesslayer.batch.BatchManagerFactory;
   import org.apache.ojb.broker.accesslayer.ConnectionFactoryFactory;
   import org.apache.ojb.broker.accesslayer.ConnectionManagerFactory;
  -import org.apache.ojb.broker.accesslayer.JdbcAccessFactory;
   import org.apache.ojb.broker.accesslayer.StatementManagerFactory;
   import org.apache.ojb.broker.accesslayer.sql.SqlGeneratorFactory;
   import org.apache.ojb.broker.cache.LocalCache;
  @@ -39,10 +39,10 @@
       private IdentityFactoryFactory identityFactoryFactory;
       private ConnectionManagerFactory connectionManagerFactory;
       private ConnectionFactoryFactory connectionFactoryFactory;
  -    private JdbcAccessFactory jdbcAccesFactory;
       private StatementManagerFactory statementManagerFactory;
       private SqlGeneratorFactory sqlGeneratorFactory;
       private PlatformFactory platformFactory;
  +    private BatchManagerFactory batchManagerFactory;
   
       public Factories()
       {
  @@ -51,10 +51,10 @@
           identityFactoryFactory = new IdentityFactoryFactory();
           connectionManagerFactory = new ConnectionManagerFactory();
           connectionFactoryFactory = new ConnectionFactoryFactory();
  -        jdbcAccesFactory = new JdbcAccessFactory();
           statementManagerFactory = new StatementManagerFactory();
           sqlGeneratorFactory = new SqlGeneratorFactory();
           platformFactory = new PlatformFactory();
  +        batchManagerFactory = new BatchManagerFactory();
       }
   
       //======================================================
  @@ -85,11 +85,6 @@
           return identityFactoryFactory;
       }
   
  -    public JdbcAccessFactory getJdbcAccesFactory()
  -    {
  -        return jdbcAccesFactory;
  -    }
  -
       public StatementManagerFactory getStatementManagerFactory()
       {
           return statementManagerFactory;
  @@ -103,6 +98,11 @@
       public PlatformFactory getPlatformFactory()
       {
           return platformFactory;
  +    }
  +
  +    public BatchManagerFactory getBatchManagerFactory()
  +    {
  +        return batchManagerFactory;
       }
   
       //======================================================
  
  
  
  1.11      +123 -67   db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java
  
  Index: MtoNBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- MtoNBroker.java	9 Apr 2004 13:22:28 -0000	1.10
  +++ MtoNBroker.java	14 Sep 2004 16:16:35 -0000	1.11
  @@ -24,10 +24,10 @@
   import org.apache.commons.lang.builder.EqualsBuilder;
   import org.apache.commons.lang.builder.HashCodeBuilder;
   import org.apache.ojb.broker.MtoNImplementor;
  -import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
  -import org.apache.ojb.broker.accesslayer.ResultSetAndStatement;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
  +import org.apache.ojb.broker.accesslayer.ResultSetAndStatement;
  +import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
   import org.apache.ojb.broker.metadata.DescriptorRepository;
  @@ -51,55 +51,81 @@
   {
       private Logger log = LoggerFactory.getLogger(MtoNBroker.class);
   
  -    private PersistenceBroker pb;
  +    private PersistenceBrokerImpl pb;
  +    /**
  +     * Used to store {@link GenericObject} while transaction running, used as
  +     * workaround for m:n insert problem.
  +     * TODO: find better solution for m:n handling
  +     */
  +    private List tempObjects = new ArrayList();
   
  -    public MtoNBroker(final PersistenceBroker broker)
  +    public MtoNBroker(final PersistenceBrokerImpl broker)
       {
           this.pb = broker;
       }
   
  +    public void reset()
  +    {
  +        tempObjects.clear();
  +    }
  +
       /**
        * Stores new values of a M:N association in a indirection table.
  +     *
  +     * @param cod        The {@link org.apache.ojb.broker.metadata.CollectionDescriptor} for the m:n relation
  +     * @param realObject The real object
  +     * @param otherObj   The referenced object
  +     * @param mnKeys     The all {@link org.apache.ojb.broker.core.MtoNBroker.Key} matching the real object
        */
  -    public void storeMtoNImplementor(CollectionDescriptor cod, Object obj, Object otherObj, Collection mnKeys)
  +    public void storeMtoNImplementor(CollectionDescriptor cod, Object realObject, Object otherObj, Collection mnKeys)
       {
  -        ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
  -        ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj);
  +        ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(realObject.getClass());
  +        ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, realObject);
           String[] pkColumns = cod.getFksToThisClass();
   
  -        otherObj = ProxyHelper.getRealObject(otherObj);
  -        ClassDescriptor otherCld = pb.getDescriptorRepository().getDescriptorFor(otherObj.getClass());
  +        ClassDescriptor otherCld = pb.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(otherObj));
           ValueContainer[] otherPkValues = pb.serviceBrokerHelper().getKeyValues(otherCld, otherObj);
   
           String[] otherPkColumns = cod.getFksToItemClass();
           String table = cod.getIndirectionTable();
           MtoNBroker.Key key = new MtoNBroker.Key(otherPkValues);
   
  -        if (mnKeys.contains(key))
  +        if(mnKeys.contains(key))
           {
               return;
           }
   
  -        String insertStmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkColumns, otherPkColumns);
  -        pb.serviceJdbcAccess().executeUpdateSQL(insertStmt, cld, pkValues, otherPkValues);
  +        String[] cols = mergeColumns(pkColumns, otherPkColumns);
  +        String insertStmt = pb.serviceSqlGenerator()
  +                .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_INSERT, table, cols, null);
  +        ValueContainer[] values = mergeContainer(pkValues, otherPkValues);
  +        GenericObject gObj = new GenericObject(table, cols, values);
  +        if(! tempObjects.contains(gObj))
  +        {
  +            pb.serviceJdbcAccess().executeUpdateSQL(insertStmt, cld, values);
  +            tempObjects.add(gObj);
  +        }
       }
   
       /**
        * get a Collection of Keys of already existing m:n rows
  +     *
        * @param cod
        * @param obj
        * @return Collection of Key
        */
  -    public Collection getMtoNImplementor(CollectionDescriptor cod, Object obj)
  +    public List getMtoNImplementor(CollectionDescriptor cod, Object obj)
       {
           ResultSetAndStatement rs = null;
  -        List result = new ArrayList();
  +        ArrayList result = new ArrayList();
           ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
           ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj);
           String[] pkColumns = cod.getFksToThisClass();
           String[] fkColumns = cod.getFksToItemClass();
           String table = cod.getIndirectionTable();
  -        String selectStmt = pb.serviceSqlGenerator().getSelectMNStatement(table, fkColumns, pkColumns);
  +
  +        String selectStmt = pb.serviceSqlGenerator()
  +                .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_SELECT, table, fkColumns, pkColumns);
   
           ClassDescriptor itemCLD = pb.getDescriptorRepository().getDescriptorFor(cod.getItemClass());
           Collection extents = pb.getDescriptorRepository().getAllConcreteSubclassDescriptors(itemCLD);
  @@ -112,24 +138,24 @@
           {
               throw new PersistenceBrokerException("All pk fields of the element-class need to" +
                       " be declared in the indirection table. Element class is "
  -                    + itemCLD.getClassNameOfObject() + " with "+itemClassPKFields.length + " pk-fields." +
  +                    + itemCLD.getClassNameOfObject() + " with " + itemClassPKFields.length + " pk-fields." +
                       " Declared 'fk-pointing-to-element-class' elements in collection-descriptor are"
                       + fkColumns.length);
           }
           try
           {
  -            rs = pb.serviceJdbcAccess().executeSQL(selectStmt, cld, pkValues, Query.NOT_SCROLLABLE);
  -            while (rs.m_rs.next())
  +            rs = pb.serviceJdbcAccess().executeSQL(selectStmt, pkValues, Query.NOT_SCROLLABLE);
  +            while(rs.m_rs.next())
               {
                   ValueContainer[] row = new ValueContainer[fkColumns.length];
  -                for (int i = 0; i < row.length; i++)
  +                for(int i = 0; i < row.length; i++)
                   {
                       row[i] = new ValueContainer(rs.m_rs.getObject(i + 1), itemClassPKFields[i].getJdbcType());
                   }
                   result.add(new MtoNBroker.Key(row));
               }
           }
  -        catch (Exception e)
  +        catch(Exception e)
           {
               throw new PersistenceBrokerException(e);
           }
  @@ -141,22 +167,25 @@
       }
   
       /**
  -    * delete all rows from m:n table belonging to obj
  -    * @param cod
  -    * @param obj
  -    */
  +     * delete all rows from m:n table belonging to obj
  +     *
  +     * @param cod
  +     * @param obj
  +     */
       public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj)
       {
           ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
           ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj);
           String[] pkColumns = cod.getFksToThisClass();
           String table = cod.getIndirectionTable();
  -        String deleteStmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkColumns, null);
  -        pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues, null);
  +        String deleteStmt = pb.serviceSqlGenerator()
  +                .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_DELETE, table, null, pkColumns);
  +        pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues);
       }
   
       /**
        * deletes all rows from m:n table that are not used in relatedObjects
  +     *
        * @param cod
        * @param obj
        * @param collectionIterator
  @@ -164,7 +193,7 @@
        */
       public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj, Iterator collectionIterator, Collection mnKeys)
       {
  -        if (mnKeys.isEmpty() || collectionIterator == null)
  +        if(mnKeys.isEmpty() || collectionIterator == null)
           {
               return;
           }
  @@ -174,7 +203,7 @@
           Object relatedObj;
   
           // remove keys of relatedObject from the existing m:n rows in workList
  -        while (collectionIterator.hasNext())
  +        while(collectionIterator.hasNext())
           {
               relatedObj = collectionIterator.next();
               relatedObjKeys = new MtoNBroker.Key(pb.serviceBrokerHelper().getKeyValues(relatedCld, relatedObj, true));
  @@ -190,40 +219,42 @@
           String table = cod.getIndirectionTable();
           String deleteStmt;
   
  +        String[] columns = mergeColumns(pkColumns, fkColumns);
           ValueContainer[] fkValues;
           Iterator iter = workList.iterator();
  -        while (iter.hasNext())
  +        while(iter.hasNext())
           {
  -            fkValues = ((MtoNBroker.Key)iter.next()).m_containers;
  -            deleteStmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkColumns, fkColumns);
  -            pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues, fkValues);
  +            fkValues = ((MtoNBroker.Key) iter.next()).m_containers;
  +            deleteStmt = pb.serviceSqlGenerator()
  +                    .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_DELETE, table, null, columns);
  +            pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, mergeContainer(pkValues, fkValues));
           }
       }
   
  -	/**
  -	 * @param m2n
  -	 */
  -	public void storeMtoNImplementor(MtoNImplementor m2n)
  -	{
  -		if(log.isDebugEnabled()) log.debug("Storing M2N implementor ["+m2n+"]");
  -		insertOrDeleteMtoNImplementor(m2n,true);
  -	}
  -
  -	/**
  -	 * @param m2n
  -	 */
  -	public void deleteMtoNImplementor(MtoNImplementor m2n)
  -	{
  -		if(log.isDebugEnabled()) log.debug("Deleting M2N implementor ["+m2n+"]");
  -		insertOrDeleteMtoNImplementor(m2n,false);
  -	}
  +    /**
  +     * @param m2n
  +     */
  +    public void storeMtoNImplementor(MtoNImplementor m2n)
  +    {
  +        if(log.isDebugEnabled()) log.debug("Storing M2N implementor [" + m2n + "]");
  +        insertOrDeleteMtoNImplementor(m2n, true);
  +    }
  +
  +    /**
  +     * @param m2n
  +     */
  +    public void deleteMtoNImplementor(MtoNImplementor m2n)
  +    {
  +        if(log.isDebugEnabled()) log.debug("Deleting M2N implementor [" + m2n + "]");
  +        insertOrDeleteMtoNImplementor(m2n, false);
  +    }
   
   
       /**
        * @see org.apache.ojb.broker.PersistenceBroker#deleteMtoNImplementor
        */
       private void insertOrDeleteMtoNImplementor(MtoNImplementor m2nImpl, boolean insert)
  -    	throws PersistenceBrokerException
  +            throws PersistenceBrokerException
       {
           //look for a collection descriptor on left  such as left.element-class-ref='right'
           DescriptorRepository dr = pb.getDescriptorRepository();
  @@ -233,9 +264,9 @@
           Object rightObject = m2nImpl.getRightObject();
           Class rightClass = rightObject.getClass();
   
  -        //
           //are written per class, maybe referencing abstract classes or interfaces
  -        //so let's look for collection descriptors on the left class and try to handle extents on teh right class
  +        //so let's look for collection descriptors on the left class and try to
  +        // handle extents on teh right class
           ClassDescriptor leftCld = dr.getDescriptorFor(leftClass);
           ClassDescriptor rightCld = dr.getDescriptorFor(rightClass);
           Vector leftColds = leftCld.getCollectionDescriptors();
  @@ -250,29 +281,38 @@
           {
               //delete only one row
               ValueContainer[] leftPkValues = pb.serviceBrokerHelper().getKeyValues(leftCld, leftObject);
  -            ValueContainer[] rightPkValues = pb.serviceBrokerHelper().getKeyValues(rightCld,rightObject);
  +            ValueContainer[] rightPkValues = pb.serviceBrokerHelper().getKeyValues(rightCld, rightObject);
               String[] pkLeftColumns = wanted.getFksToThisClass();
               String[] pkRightColumns = wanted.getFksToItemClass();
               String table = wanted.getIndirectionTable();
  -            if(table == null) throw new PersistenceBrokerException("Can't remove MtoN implementor withou an indirection table");
  +            if(table == null) throw new PersistenceBrokerException("Can't remove MtoN implementor without an indirection table");
   
               String stmt = null;
  +            String[] cols = mergeColumns(pkLeftColumns, pkRightColumns);
  +            ValueContainer[] values = mergeContainer(leftPkValues, rightPkValues);
               if(insert)
               {
  -				stmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkLeftColumns, pkRightColumns);
  +                stmt = pb.serviceSqlGenerator()
  +                        .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_INSERT, table, cols, null);
  +                GenericObject gObj = new GenericObject(table, cols, values);
  +                if(!tempObjects.contains(gObj))
  +                {
  +                    pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, values);
  +                    tempObjects.add(gObj);
  +                }
               }
               else
               {
  -				stmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkLeftColumns, pkRightColumns);
  +                stmt = pb.serviceSqlGenerator()
  +                        .getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_DELETE, table, null, cols);
  +                pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, values);
               }
  -
  -            pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues, rightPkValues);
           }
       }
   
       private CollectionDescriptor findCollectionDescriptor(Class leftClass, Class rightClass, Vector leftColds)
       {
  -        for (Iterator iter = leftColds.iterator(); iter.hasNext();)
  +        for(Iterator iter = leftColds.iterator(); iter.hasNext();)
           {
               CollectionDescriptor element = (CollectionDescriptor) iter.next();
   
  @@ -283,8 +323,24 @@
                   return element;
               }
           }
  -		throw new PersistenceBrokerException("Can't find reasonable collection descriptor for MtoN implementor left["+leftClass
  -			+"] right["+rightClass+"]");
  +        throw new PersistenceBrokerException("Can't find reasonable collection descriptor for MtoN implementor left[" + leftClass
  +                + "] right[" + rightClass + "]");
  +    }
  +
  +    private String[] mergeColumns(String[] first, String[] second)
  +    {
  +        String[] cols = new String[first.length + second.length];
  +        System.arraycopy(first, 0, cols, 0, first.length);
  +        System.arraycopy(second, 0, cols, first.length, second.length);
  +        return cols;
  +    }
  +
  +    private ValueContainer[] mergeContainer(ValueContainer[] first, ValueContainer[] second)
  +    {
  +        ValueContainer[] values = new ValueContainer[first.length + second.length];
  +        System.arraycopy(first, 0, values, 0, first.length);
  +        System.arraycopy(second, 0, values, first.length, second.length);
  +        return values;
       }
   
   
  @@ -304,7 +360,7 @@
           {
               m_containers = new ValueContainer[containers.length];
   
  -            for (int i = 0; i < containers.length; i++)
  +            for(int i = 0; i < containers.length; i++)
               {
                   Object value = containers[i].getValue();
                   JdbcType type = containers[i].getJdbcType();
  @@ -315,9 +371,9 @@
                   //
                   // could lead to problems when Floats are used as key
                   // converting to String could be a better alternative
  -                if (value instanceof Number)
  +                if(value instanceof Number)
                   {
  -                    value = new Long(((Number)value).longValue());
  +                    value = new Long(((Number) value).longValue());
                   }
   
                   m_containers[i] = new ValueContainer(value, type);
  @@ -326,11 +382,11 @@
   
           public boolean equals(Object other)
           {
  -            if (other == this)
  +            if(other == this)
               {
                   return true;
               }
  -            if (!(other instanceof Key))
  +            if(!(other instanceof Key))
               {
                   return false;
               }
  
  
  
  1.14      +5 -0      db-ojb/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java
  
  Index: DelegatingPersistenceBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- DelegatingPersistenceBroker.java	11 Aug 2004 00:41:45 -0000	1.13
  +++ DelegatingPersistenceBroker.java	14 Sep 2004 16:16:35 -0000	1.14
  @@ -182,6 +182,11 @@
   		getBroker().store(obj, modification);
   	}
   
  +    public void update(Object obj, String[] fields)
  +    {
  +        getBroker().update(obj, fields);
  +    }
  +
   	public PBKey getPBKey()
   	{
   		return getBroker().getPBKey();
  
  
  
  1.91      +194 -53   db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
  
  Index: PersistenceBrokerImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v
  retrieving revision 1.90
  retrieving revision 1.91
  diff -u -r1.90 -r1.91
  --- PersistenceBrokerImpl.java	27 Aug 2004 19:55:42 -0000	1.90
  +++ PersistenceBrokerImpl.java	14 Sep 2004 16:16:35 -0000	1.91
  @@ -15,6 +15,8 @@
    * limitations under the License.
    */
   
  +import java.util.ArrayList;
  +import java.util.Arrays;
   import java.util.Collection;
   import java.util.Collections;
   import java.util.Enumeration;
  @@ -30,10 +32,10 @@
   import org.apache.ojb.broker.PBKey;
   import org.apache.ojb.broker.PBState;
   import org.apache.ojb.broker.PersistenceBrokerException;
  +import org.apache.ojb.broker.PersistenceConfiguration;
   import org.apache.ojb.broker.TransactionAbortedException;
   import org.apache.ojb.broker.TransactionInProgressException;
   import org.apache.ojb.broker.TransactionNotInProgressException;
  -import org.apache.ojb.broker.PersistenceConfiguration;
   import org.apache.ojb.broker.accesslayer.ChainingIterator;
   import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
   import org.apache.ojb.broker.accesslayer.JdbcAccess;
  @@ -43,9 +45,11 @@
   import org.apache.ojb.broker.accesslayer.RsIteratorFactory;
   import org.apache.ojb.broker.accesslayer.RsIteratorFactoryFactory;
   import org.apache.ojb.broker.accesslayer.StatementManagerIF;
  +import org.apache.ojb.broker.accesslayer.batch.BatchManager;
   import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
   import org.apache.ojb.broker.cache.LocalCache;
   import org.apache.ojb.broker.cache.ObjectCache;
  +import org.apache.ojb.broker.core.proxy.CollectionProxy;
   import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
  @@ -109,7 +113,7 @@
       /**
        * m_DbAccess is used to do all Jdbc related work: connecting, executing...
        */
  -    private JdbcAccess dbAccess;
  +    private BatchManager dbAccess;
       /**
        * holds mapping information for all classes to be treated by PersistenceBroker
        */
  @@ -174,7 +178,7 @@
           brokerHelper = new BrokerHelper(this);
           connectionManager = factories.getConnectionManagerFactory().createConnectionManager(this);
           sequenceManager = SequenceManagerFactory.getSequenceManager(this);
  -        dbAccess = factories.getJdbcAccesFactory().createJdbcAccess(this);
  +        dbAccess = factories.getBatchManagerFactory().createBatchManager(this);
           statementManager = factories.getStatementManagerFactory().createStatementManager(this);
           sqlGenerator = factories.getSqlGeneratorFactory().createSqlGenerator(connectionManager.getSupportedPlatform());
           mtoNBroker = new MtoNBroker(this);
  @@ -193,6 +197,11 @@
           return this.localCache;
       }
   
  +    public BatchManager ojbBatchManager()
  +    {
  +        return dbAccess;
  +    }
  +
       public IdentityFactory serviceIdentity()
       {
           return this.identityFactory;
  @@ -515,9 +524,6 @@
               AFTER_DELETE_EVENT.setTarget(obj);
               fireBrokerEvent(AFTER_DELETE_EVENT);
               AFTER_DELETE_EVENT.setTarget(null);
  -
  -            // let the connection manager to execute batch
  -            connectionManager.executeBatchIfNecessary();
           }
       }
   
  @@ -717,9 +723,6 @@
               {
                   deletedDuringTransaction.remove(oid);
               }
  -
  -            // let the connection manager to execute batch
  -            connectionManager.executeBatchIfNecessary();
           }
           // if Object == null do nothing
           else
  @@ -840,8 +843,8 @@
           - on insert we link and insert the referenced objects, because the proxy
           collection maybe "inherited" from the object before the PK was replaced
           */
  -        if(insert || !(referencedObjects instanceof CollectionProxyDefaultImpl
  -                        && !((CollectionProxyDefaultImpl) referencedObjects).isLoaded()))
  +        if(insert || !(referencedObjects instanceof CollectionProxy
  +                        && !((CollectionProxy) referencedObjects).isLoaded()))
           {
               // if referenced objects are null, assign empty list
               if(referencedObjects == null)
  @@ -856,48 +859,40 @@
               if we store an object with m:n reference and no references could be
               found, we remove all entires of given object in indirection table
               */
  -            Iterator referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +            Iterator referencedObjectsIterator;
   
  -            if(!referencedObjectsIterator.hasNext())
  +            if(!onlyLink && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
               {
  -                mtoNBroker.deleteMtoNImplementor(cod, obj);
  -            }
  -            else
  -            {
  -                Collection existingMtoNKeys;
  -                // use empty list on insert (by Andy Malakov)
  -                if (insert)
  -                {
  -                    existingMtoNKeys = Collections.EMPTY_LIST;
  -                }
  -                else
  -                {
  -                    existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  -                    // remove all entries in indirection table which not be part of
  -                    // referenced objects
  -                    mtoNBroker.deleteMtoNImplementor(cod, obj, referencedObjectsIterator, existingMtoNKeys);
  -                }
  -                // we can't reuse iterator
                   referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
                   while (referencedObjectsIterator.hasNext())
                   {
  -                    Object refObj = referencedObjectsIterator.next();
  -                    // If cascade store is enabled and we don't want to link only,
  -                    // store depended upon object first to avoid FK violation
  -                    if(!onlyLink && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
  -                    {
  -                        store(refObj);
  -                        // BRJ: store could have inserted MtoNImplementors
  -                        // so we need to read them to avoid ref. integrity
  -                        // violations
  -                        existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  -                    }
  -                    // Now store indirection record
  -                    // BRJ: this could cause integrity problems because
  -                    // obj may not be stored depending on auto-update
  -                    mtoNBroker.storeMtoNImplementor(cod, obj, refObj, existingMtoNKeys);
  +                    store(referencedObjectsIterator.next());
                   }
               }
  +
  +            List existingMtoNKeys;
  +            if(!insert)
  +            {
  +                existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  +                // we can't reuse iterator
  +                referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +                // remove all entries in indirection table which not be part of referenced objects
  +                mtoNBroker.deleteMtoNImplementor(cod, obj, referencedObjectsIterator, existingMtoNKeys);
  +            }
  +            else
  +            {
  +                existingMtoNKeys = Collections.EMPTY_LIST;
  +            }
  +            // we can't reuse iterator
  +            referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +            while (referencedObjectsIterator.hasNext())
  +            {
  +                Object refObj = referencedObjectsIterator.next();
  +                // Now store indirection record
  +                // BRJ: this could cause integrity problems because
  +                // obj may not be stored depending on auto-update
  +                mtoNBroker.storeMtoNImplementor(cod, obj, refObj, existingMtoNKeys);
  +            }
           }
       }
   
  @@ -1076,12 +1071,16 @@
        * Assign FK values and store entries in indirection table
        * for all objects referenced by given object.
        *
  -     * @param obj real object with 1:n reference
  -     * @param cod {@link CollectionDescriptor} of referenced 1:n objects
  +     * @param obj real object with m:n reference
  +     * @param cod {@link CollectionDescriptor} of referenced m:n objects
        * @param insert flag signal insert operation, false signals update operation
        */
       public void linkMtoN(Object obj, CollectionDescriptor cod, boolean insert)
       {
  +        if(!cod.isMtoNRelation())
  +        {
  +            throw new PersistenceBrokerException("Given CollectionDescriptor is not a m:n relation: " + cod.toXML());
  +        }
           Object referencedObjects = cod.getPersistentField().get(obj);
           storeAndLinkMtoN(true, obj, cod, referencedObjects, insert);
       }
  @@ -1493,18 +1492,122 @@
       }
   
       /**
  +     * @see org.apache.ojb.broker.PersistenceBroker#update(Object, String[])
  +     */
  +    public void update(Object obj, String[] fields)
  +    {
  +        // check fields to update
  +        if(fields == null || fields.length == 0)
  +        {
  +            if(logger.isEnabledFor(Logger.INFO))
  +            {
  +                logger.info("Fields to update are 'null' or have length 0, nothing to update!");
  +            }
  +            return;
  +        }
  +        // check for update
  +        if(!preparedForUpdate(obj))
  +        {
  +            return;
  +        }
  +
  +        ClassDescriptor cld = getClassDescriptor(obj.getClass());
  +        // Get all FieldDescriptor for given field names
  +        List fieldList = Arrays.asList(fields);
  +        List newList = new ArrayList();
  +        Iterator it = fieldList.iterator();
  +        FieldDescriptor field;
  +        String fieldName;
  +        FieldDescriptor[] matchedFields = new FieldDescriptor[]{};
  +        while (it.hasNext())
  +        {
  +            fieldName = (String) it.next();
  +            field = cld.getFieldDescriptorByName(fieldName);
  +            if(field != null)
  +            {
  +                FieldDescriptor[] newMatchedFields = new FieldDescriptor[matchedFields.length + 1];
  +			    System.arraycopy(matchedFields, 0, newMatchedFields, 0, matchedFields.length);
  +                newMatchedFields[newMatchedFields.length - 1] = field;
  +                matchedFields = newMatchedFields;
  +            }
  +            else
  +            {
  +                newList.add(fieldName);
  +            }
  +        }
  +        fieldList = newList;
  +
  +        if(fieldList.size() > 0)
  +        {
  +            ObjectReferenceDescriptor ord = hasMultiMappedReference(cld);
  +            if (ord != null)
  +            {
  +                Object refObj = ord.getPersistentField().get(obj);
  +                String[] newFields = (String[]) fieldList.toArray(new String[fieldList.size()]);
  +                update(refObj, newFields);
  +            }
  +            else
  +            {
  +                throw new PersistenceBrokerException("Fields " + fieldList + ", do not match " + obj.getClass());
  +            }
  +        }
  +        doUpdate(obj, cld, matchedFields);
  +    }
  +
  +    /**
  +     * Updates the specified fields of the given persistent object. Note: All specified
  +     * fields have to be part of the given {@link org.apache.ojb.broker.metadata.ClassDescriptor}.
  +     * Multi mapped classes (a class mapped across several tables) have to resolved by user or use
  +     * method {@link org.apache.ojb.broker.PersistenceBroker#update(Object, String[])} which provide
  +     * multi-mapped class support.
  +     *
  +     * @param obj The object to persist
  +     * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the given object
  +     * @param fields The fields to update
  +     */
  +    public void ojbUpdate(Object obj, ClassDescriptor cld, FieldDescriptor[] fields)
  +    {
  +        if(preparedForUpdate(obj))
  +        {
  +            doUpdate(obj, cld, fields);
  +        }
  +    }
  +
  +    private void doUpdate(Object realObject, ClassDescriptor cld, FieldDescriptor[] fields)
  +    {
  +        BEFORE_UPDATE_EVENT.setTarget(realObject);
  +        fireBrokerEvent(BEFORE_UPDATE_EVENT);
  +        BEFORE_UPDATE_EVENT.setTarget(null);
  +
  +        dbAccess.executeUpdate(cld, fields, realObject);
  +        Identity oid = serviceIdentity().buildIdentity(cld, realObject);
  +        ojbLocalCache().cache(oid, realObject);
  +
  +        AFTER_UPDATE_EVENT.setTarget(realObject);
  +        fireBrokerEvent(AFTER_UPDATE_EVENT);
  +        AFTER_UPDATE_EVENT.setTarget(null);
  +    }
  +
  +    /**
        * makes object obj persistent in the underlying persistence system.
        * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
        * The ObjectModification parameter can be used to determine whether INSERT or update is to be used.
        * This functionality is typically called from transaction managers, that
  -     * track which objects have to be stored.
  +     * track which objects have to be stored. If the object is an unmaterialized
  +     * proxy the method return immediately.
        */
       public void store(Object obj, ObjectModification mod) throws PersistenceBrokerException
       {
  -        obj = ProxyHelper.getRealObject(obj);
  +        obj = ProxyHelper.getRealObjectIfMaterialized(obj);
  +        if (obj == null)    // null for unmaterialized Proxy
  +        {
  +            if(logger.isDebugEnabled())
  +                logger.debug("No materialized object could be found -> nothing to store");
  +            return;
  +        }
           ClassDescriptor cld = getClassDescriptor(obj.getClass());
           // this call ensures that all autoincremented primary key attributes are filled
  -        Identity oid = new Identity(obj, this, cld);
  +        Identity oid = serviceIdentity().buildIdentity(cld, obj);
           // select flag for insert / update selection by checking the ObjectModification
           if (mod.needsInsert())
           {
  @@ -1525,6 +1628,39 @@
           }
       }
   
  +    private ObjectReferenceDescriptor hasMultiMappedReference(ClassDescriptor cld)
  +    {
  +        List list = cld.getObjectReferenceDescriptors();
  +        for (int i = 0; i < list.size(); i++)
  +        {
  +            ObjectReferenceDescriptor ord =  (ObjectReferenceDescriptor) list.get(i);
  +            if(ord.isMultiMappedClass())
  +            {
  +                return ord;
  +            }
  +        }
  +        return null;
  +    }
  +
  +    private boolean preparedForUpdate(Object obj)
  +    {
  +        if(!isInTransaction())
  +        {
  +            throw new PersistenceBrokerException("No running tx");
  +        }
  +        obj = ProxyHelper.getRealObjectIfMaterialized(obj);
  +        if (obj == null)    // null for unmaterialized Proxy
  +        {
  +            if(logger.isEnabledFor(Logger.INFO))
  +            {
  +                logger.info("No materialized object could be found for "
  +                + ProxyHelper.getRealClass(obj) + "--> nothing to update");
  +            }
  +            return false;
  +        }
  +        return true;
  +    }
  +
       /**
        * makes object obj persistent in the underlying persistence system.
        * E.G. by INSERT INTO ... or UPDATE ...  in an RDBMS.
  @@ -1640,7 +1776,6 @@
            */
           if(cld.getSuperClass() != null)
           {
  -
               ClassDescriptor superCld = getDescriptorRepository().getDescriptorFor(cld.getSuperClass());
               storeToDb(obj, superCld, oid, insert);
               // arminw: why this?? I comment out this section
  @@ -1897,6 +2032,12 @@
       {
           nowStoring.clear();
           deletedDuringTransaction.clear();
  +        /*
  +        arminw:
  +        for better performance I don't register MtoNBroker as listner,
  +        so use this method to reset on commit/rollback
  +        */
  +        mtoNBroker.reset();
       }
   
       /**
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/core/GenericObject.java
  
  Index: GenericObject.java
  ===================================================================
  package org.apache.ojb.broker.core;
  
  import java.io.Serializable;
  
  import org.apache.ojb.broker.OJBRuntimeException;
  import org.apache.commons.lang.builder.ToStringBuilder;
  
  /* Copyright 2002-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.
   */
  
  /**
   * Object representation of a arbitrary DB table row.
   *
   * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
   * @version $Id: GenericObject.java,v 1.1 2004/09/14 16:16:35 arminw Exp $
   */
  public final class GenericObject implements Serializable
  {
      private String tablename;
      private String[] columnNames;
      private ValueContainer[] values;
  
      public GenericObject(String tablename, String[] columnNames, ValueContainer[] values)
      {
          this.tablename = tablename;
          this.columnNames = columnNames;
          this.values = values;
          if(values != null && columnNames.length != values.length)
          {
              throw new OJBRuntimeException("Column name array and value array have NOT same length");
          }
      }
  
      public boolean equals(Object obj)
      {
          if(this == obj)
          {
              return true;
          }
          boolean result = false;
          if(obj instanceof GenericObject)
          {
              GenericObject other = (GenericObject) obj;
              if(result = (tablename.equalsIgnoreCase(other.tablename)
                      && (columnNames != null)
                      && (other.columnNames != null)
                      && (columnNames.length == other.columnNames.length)))
              {
                  for (int i = 0; i < columnNames.length; i++)
                  {
                      // System.out.println("## test: " + this);
                      int otherIndex = other.indexForColumn(columnNames[i]);
                      if(otherIndex < 0)
                      {
                          result = false;
                          break;
                      }
                      result = result && values[i].equals(other.values[otherIndex]);
                      if(!result) break;
                  }
  //                if(result)
  //                {
  //                    System.out.println("## Match: " + this);
  //                }
              }
          }
          return result;
      }
  
      int indexForColumn(String name)
      {
          int result = -1;
          for (int i = 0; i < columnNames.length; i++)
          {
              if(columnNames[i].equals(name))
              {
                  result = i;
                  break;
              }
          }
          return result;
      }
  
      public int hashCode()
      {
          return super.hashCode();
      }
  
      public ValueContainer getValueFor(String columnName)
      {
          try
          {
              return values[indexForColumn(columnName)];
          }
          catch(Exception e)
          {
              throw new OJBRuntimeException("Can't find value for column " + columnName
                      + (indexForColumn(columnName) < 0 ? ". Column name was not found" : ""), e);
          }
      }
  
      public String getTablename()
      {
          return tablename;
      }
  
      public String[] getColumnNames()
      {
          return columnNames;
      }
  
      public ValueContainer[] getValues()
      {
          return values;
      }
  
      public void setValues(ValueContainer[] values)
      {
          this.values = values;
      }
  
      public String toString()
      {
          return new ToStringBuilder(this)
                  .append("tableName", tablename)
                  .append("columnNames", columnNames)
                  .append("values", values)
                  .toString();
      }
  }
  
  
  
  1.2       +2 -2      db-ojb/src/java/org/apache/ojb/broker/cache/CacheHelper.java
  
  Index: CacheHelper.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/cache/CacheHelper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CacheHelper.java	11 Aug 2004 00:42:56 -0000	1.1
  +++ CacheHelper.java	14 Sep 2004 16:16:36 -0000	1.2
  @@ -38,7 +38,7 @@
   
       public static CacheStrategy buildCacheStrategy(ObjectCacheDescriptor cacheDescriptor) throws ConfigurationException
       {
  -        Properties confProp = cacheDescriptor.getConfigurationProperties();
  +        Properties confProp = cacheDescriptor.getAttributes();
           Class cacheClass = cacheDescriptor.getObjectCache() != null
                   ? cacheDescriptor.getObjectCache() : DEFAULT_OBJECT_CACHE_CLASS;
           Class cacheStrategy = cacheDescriptor.getCacheStrategy() != null
  
  
  
  1.27      +1 -2      db-ojb/src/java/org/apache/ojb/broker/cache/ObjectCacheDefaultImpl.java
  
  Index: ObjectCacheDefaultImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/cache/ObjectCacheDefaultImpl.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- ObjectCacheDefaultImpl.java	11 Aug 2004 00:42:56 -0000	1.26
  +++ ObjectCacheDefaultImpl.java	14 Sep 2004 16:16:36 -0000	1.27
  @@ -20,7 +20,6 @@
   import java.util.HashMap;
   import java.util.Map;
   import java.util.Properties;
  -import java.util.Collections;
   
   import org.apache.commons.collections.LRUMap;
   import org.apache.commons.lang.builder.ToStringBuilder;
  
  
  
  1.15      +1 -2      db-ojb/src/java/org/apache/ojb/broker/cache/ObjectCacheEmptyImpl.java
  
  Index: ObjectCacheEmptyImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/cache/ObjectCacheEmptyImpl.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- ObjectCacheEmptyImpl.java	11 Aug 2004 00:42:56 -0000	1.14
  +++ ObjectCacheEmptyImpl.java	14 Sep 2004 16:16:36 -0000	1.15
  @@ -18,7 +18,6 @@
   import org.apache.commons.lang.builder.ToStringBuilder;
   import org.apache.commons.lang.builder.ToStringStyle;
   import org.apache.ojb.broker.Identity;
  -import org.apache.ojb.broker.PersistenceBroker;
   
   import java.util.Properties;
   
  
  
  

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


Mime
View raw message