brj 2005/01/22 12:52:34
Modified: src/java/org/apache/ojb/broker/core MtoNBroker.java
src/java/org/apache/ojb/broker/accesslayer
PkEnumeration.java
Log:
small refactorings based on findbugs
Revision Changes Path
1.16 +529 -530
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.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- MtoNBroker.java 10 Dec 2004 22:40:42 -0000 1.15
+++ MtoNBroker.java 22 Jan 2005 20:52:34 -0000 1.16
@@ -1,530 +1,529 @@
-package org.apache.ojb.broker.core;
-
-/* 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.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-import java.io.Serializable;
-
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.ojb.broker.MtoNImplementor;
-import org.apache.ojb.broker.PersistenceBroker;
-import org.apache.ojb.broker.PersistenceBrokerException;
-import org.apache.ojb.broker.OJBRuntimeException;
-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;
-import org.apache.ojb.broker.metadata.FieldDescriptor;
-import org.apache.ojb.broker.metadata.JdbcType;
-import org.apache.ojb.broker.query.Query;
-import org.apache.ojb.broker.util.logging.Logger;
-import org.apache.ojb.broker.util.logging.LoggerFactory;
-
-/**
- * Manage all stuff related to non-decomposed M:N association.
- *
- * @author <a href="mailto:[EMAIL PROTECTED]">Thomas Mahler<a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Leandro Rodrigo Saad Cruz<a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Matthew Baird<a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Jakob Braeuchi</a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Armin Waibel</a>
- * @version $Id$
- */
-public class MtoNBroker
-{
- private Logger log = LoggerFactory.getLogger(MtoNBroker.class);
-
- private PersistenceBroker pb;
- /**
- * Used to store [EMAIL PROTECTED] 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)
- {
- this.pb = broker;
- }
-
- public void reset()
- {
- tempObjects.clear();
- }
-
- /**
- * Stores new values of a M:N association in a indirection table.
- *
- * @param cod The [EMAIL PROTECTED]
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 [EMAIL PROTECTED]
org.apache.ojb.broker.core.MtoNBroker.Key} matching the real object
- */
- public void storeMtoNImplementor(CollectionDescriptor cod, Object
realObject, Object otherObj, Collection mnKeys)
- {
- ClassDescriptor cld =
pb.getDescriptorRepository().getDescriptorFor(realObject.getClass());
- ValueContainer[] pkValues =
pb.serviceBrokerHelper().getKeyValues(cld, realObject);
- String[] pkColumns = cod.getFksToThisClass();
-
- 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))
- {
- return;
- }
-
- 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 List getMtoNImplementor(CollectionDescriptor cod, Object obj)
- {
- ResultSetAndStatement rs = null;
- 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()
-
.getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_SELECT, table,
fkColumns, pkColumns);
-
- ClassDescriptor itemCLD = cod.getItemClassDescriptor();
- Collection extents =
pb.getDescriptorRepository().getAllConcreteSubclassDescriptors(itemCLD);
- if(extents.size() > 0)
- {
- itemCLD = (ClassDescriptor) extents.iterator().next();
- }
- FieldDescriptor[] itemClassPKFields = itemCLD.getPkFields();
- if(itemClassPKFields.length != fkColumns.length)
- {
- 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." +
- " Declared 'fk-pointing-to-element-class' elements in
collection-descriptor are"
- + fkColumns.length);
- }
- try
- {
- 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++)
- {
- row[i] = new ValueContainer(rs.m_rs.getObject(i + 1),
itemClassPKFields[i].getJdbcType());
- }
- result.add(new MtoNBroker.Key(row));
- }
- }
- catch(Exception e)
- {
- throw new PersistenceBrokerException(e);
- }
- finally
- {
- rs.close();
- }
- return result;
- }
-
- /**
- * 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()
-
.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
- * @param mnKeys
- */
- public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj,
Iterator collectionIterator, Collection mnKeys)
- {
- if(mnKeys.isEmpty() || collectionIterator == null)
- {
- return;
- }
- List workList = new ArrayList(mnKeys);
- MtoNBroker.Key relatedObjKeys;
- ClassDescriptor relatedCld = cod.getItemClassDescriptor();
- Object relatedObj;
-
- // remove keys of relatedObject from the existing m:n rows in
workList
- while(collectionIterator.hasNext())
- {
- relatedObj = collectionIterator.next();
- relatedObjKeys = new
MtoNBroker.Key(pb.serviceBrokerHelper().getKeyValues(relatedCld, relatedObj,
true));
- workList.remove(relatedObjKeys);
- }
-
- // delete all remaining keys in workList
- 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 deleteStmt;
-
- String[] columns = mergeColumns(pkColumns, fkColumns);
- ValueContainer[] fkValues;
- Iterator iter = workList.iterator();
- while(iter.hasNext())
- {
- 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);
- }
-
-
- /**
- * @see org.apache.ojb.broker.PersistenceBroker#deleteMtoNImplementor
- */
- private void insertOrDeleteMtoNImplementor(MtoNImplementor m2nImpl,
boolean insert)
- throws PersistenceBrokerException
- {
- //look for a collection descriptor on left such as
left.element-class-ref='right'
- DescriptorRepository dr = pb.getDescriptorRepository();
-
- Object leftObject = m2nImpl.getLeftObject();
- Class leftClass = leftObject.getClass();
- 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
- ClassDescriptor leftCld = dr.getDescriptorFor(leftClass);
- ClassDescriptor rightCld = dr.getDescriptorFor(rightClass);
- Vector leftColds = leftCld.getCollectionDescriptors();
- CollectionDescriptor wanted = findCollectionDescriptor(leftClass,
rightClass, leftColds);
-
- if(leftObject == null || rightObject == null)
- {
- //TODO: to be implemented, must change MtoNImplementor
- //deleteMtoNImplementor(wanted,leftObject) ||
deleteMtoNImplementor(wanted,rightObject)
- }
- else
- {
- //delete only one row
- ValueContainer[] leftPkValues =
pb.serviceBrokerHelper().getKeyValues(leftCld, leftObject);
- 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 without an indirection table");
-
- String stmt = null;
- String[] cols = mergeColumns(pkLeftColumns, pkRightColumns);
- ValueContainer[] values = mergeContainer(leftPkValues,
rightPkValues);
- if(insert)
- {
- 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()
-
.getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_DELETE, table, null,
cols);
- pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld,
values);
- }
- }
- }
-
- private CollectionDescriptor findCollectionDescriptor(Class leftClass,
Class rightClass, Vector leftColds)
- {
- for(Iterator iter = leftColds.iterator(); iter.hasNext();)
- {
- CollectionDescriptor element = (CollectionDescriptor)
iter.next();
-
- //try super classes and interfaces too
- if(element.getItemClass().isAssignableFrom(rightClass))
- {
- //we found it !
- return element;
- }
- }
- 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;
- }
-
-
-
-// ************************************************************************
-// inner class
-// ************************************************************************
-
- /**
- * This is a helper class to model a Key of an Object
- */
- private static final class Key
- {
- final ValueContainer[] m_containers;
-
- Key(final ValueContainer[] containers)
- {
- m_containers = new ValueContainer[containers.length];
-
- for(int i = 0; i < containers.length; i++)
- {
- Object value = containers[i].getValue();
- JdbcType type = containers[i].getJdbcType();
-
- // BRJ:
- // convert all Numbers to Long to simplify equals
- // Long(100) is not equal to Integer(100)
- //
- // could lead to problems when Floats are used as key
- // converting to String could be a better alternative
- if(value instanceof Number)
- {
- value = new Long(((Number) value).longValue());
- }
-
- m_containers[i] = new ValueContainer(value, type);
- }
- }
-
- public boolean equals(Object other)
- {
- if(other == this)
- {
- return true;
- }
- if(!(other instanceof Key))
- {
- return false;
- }
-
- Key otherKey = (Key) other;
- EqualsBuilder eb = new EqualsBuilder();
-
- eb.append(m_containers, otherKey.m_containers);
- return eb.isEquals();
- }
-
- public int hashCode()
- {
- HashCodeBuilder hb = new HashCodeBuilder();
- hb.append(m_containers);
-
- return hb.toHashCode();
- }
- }
-
-
-
- //
************************************************************************
- // inner class
- //
************************************************************************
- private static final class GenericObject
- {
- 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;
- result = (tablename.equalsIgnoreCase(other.tablename)
- && (columnNames != null)
- && (other.columnNames != null)
- && (columnNames.length == other.columnNames.length));
- if(result)
- {
- 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;
- }
- }
- }
- 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();
- }
- }
-}
+package org.apache.ojb.broker.core;
+
+/* 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.ojb.broker.MtoNImplementor;
+import org.apache.ojb.broker.OJBRuntimeException;
+import org.apache.ojb.broker.PersistenceBroker;
+import org.apache.ojb.broker.PersistenceBrokerException;
+import org.apache.ojb.broker.accesslayer.ResultSetAndStatement;
+import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
+import org.apache.ojb.broker.core.proxy.ProxyHelper;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.metadata.CollectionDescriptor;
+import org.apache.ojb.broker.metadata.DescriptorRepository;
+import org.apache.ojb.broker.metadata.FieldDescriptor;
+import org.apache.ojb.broker.metadata.JdbcType;
+import org.apache.ojb.broker.query.Query;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+/**
+ * Manage all stuff related to non-decomposed M:N association.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Thomas Mahler<a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Leandro Rodrigo Saad Cruz<a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Matthew Baird<a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jakob Braeuchi</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Armin Waibel</a>
+ * @version $Id$
+ */
+public class MtoNBroker
+{
+ private Logger log = LoggerFactory.getLogger(MtoNBroker.class);
+
+ private PersistenceBroker pb;
+ /**
+ * Used to store [EMAIL PROTECTED] 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)
+ {
+ this.pb = broker;
+ }
+
+ public void reset()
+ {
+ tempObjects.clear();
+ }
+
+ /**
+ * Stores new values of a M:N association in a indirection table.
+ *
+ * @param cod The [EMAIL PROTECTED]
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 [EMAIL PROTECTED]
org.apache.ojb.broker.core.MtoNBroker.Key} matching the real object
+ */
+ public void storeMtoNImplementor(CollectionDescriptor cod, Object
realObject, Object otherObj, Collection mnKeys)
+ {
+ ClassDescriptor cld =
pb.getDescriptorRepository().getDescriptorFor(realObject.getClass());
+ ValueContainer[] pkValues =
pb.serviceBrokerHelper().getKeyValues(cld, realObject);
+ String[] pkColumns = cod.getFksToThisClass();
+
+ 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))
+ {
+ return;
+ }
+
+ 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 List getMtoNImplementor(CollectionDescriptor cod, Object obj)
+ {
+ ResultSetAndStatement rs = null;
+ 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()
+
.getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_SELECT, table,
fkColumns, pkColumns);
+
+ ClassDescriptor itemCLD = cod.getItemClassDescriptor();
+ Collection extents =
pb.getDescriptorRepository().getAllConcreteSubclassDescriptors(itemCLD);
+ if(extents.size() > 0)
+ {
+ itemCLD = (ClassDescriptor) extents.iterator().next();
+ }
+ FieldDescriptor[] itemClassPKFields = itemCLD.getPkFields();
+ if(itemClassPKFields.length != fkColumns.length)
+ {
+ 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." +
+ " Declared 'fk-pointing-to-element-class' elements in
collection-descriptor are"
+ + fkColumns.length);
+ }
+ try
+ {
+ 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++)
+ {
+ row[i] = new ValueContainer(rs.m_rs.getObject(i + 1),
itemClassPKFields[i].getJdbcType());
+ }
+ result.add(new MtoNBroker.Key(row));
+ }
+ }
+ catch(Exception e)
+ {
+ throw new PersistenceBrokerException(e);
+ }
+ finally
+ {
+ rs.close();
+ }
+ return result;
+ }
+
+ /**
+ * 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()
+
.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
+ * @param mnKeys
+ */
+ public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj,
Iterator collectionIterator, Collection mnKeys)
+ {
+ if(mnKeys.isEmpty() || collectionIterator == null)
+ {
+ return;
+ }
+ List workList = new ArrayList(mnKeys);
+ MtoNBroker.Key relatedObjKeys;
+ ClassDescriptor relatedCld = cod.getItemClassDescriptor();
+ Object relatedObj;
+
+ // remove keys of relatedObject from the existing m:n rows in
workList
+ while(collectionIterator.hasNext())
+ {
+ relatedObj = collectionIterator.next();
+ relatedObjKeys = new
MtoNBroker.Key(pb.serviceBrokerHelper().getKeyValues(relatedCld, relatedObj,
true));
+ workList.remove(relatedObjKeys);
+ }
+
+ // delete all remaining keys in workList
+ 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 deleteStmt;
+
+ String[] columns = mergeColumns(pkColumns, fkColumns);
+ ValueContainer[] fkValues;
+ Iterator iter = workList.iterator();
+ while(iter.hasNext())
+ {
+ 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);
+ }
+
+
+ /**
+ * @see org.apache.ojb.broker.PersistenceBroker#deleteMtoNImplementor
+ */
+ private void insertOrDeleteMtoNImplementor(MtoNImplementor m2nImpl,
boolean insert)
+ throws PersistenceBrokerException
+ {
+ //look for a collection descriptor on left such as
left.element-class-ref='right'
+ DescriptorRepository dr = pb.getDescriptorRepository();
+
+ Object leftObject = m2nImpl.getLeftObject();
+ Class leftClass = leftObject.getClass();
+ 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
+ ClassDescriptor leftCld = dr.getDescriptorFor(leftClass);
+ ClassDescriptor rightCld = dr.getDescriptorFor(rightClass);
+ Vector leftColds = leftCld.getCollectionDescriptors();
+ CollectionDescriptor wanted = findCollectionDescriptor(leftClass,
rightClass, leftColds);
+
+ if(leftObject == null || rightObject == null)
+ {
+ //TODO: to be implemented, must change MtoNImplementor
+ //deleteMtoNImplementor(wanted,leftObject) ||
deleteMtoNImplementor(wanted,rightObject)
+ }
+ else
+ {
+ //delete only one row
+ ValueContainer[] leftPkValues =
pb.serviceBrokerHelper().getKeyValues(leftCld, leftObject);
+ 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 without an indirection table");
+
+ String stmt = null;
+ String[] cols = mergeColumns(pkLeftColumns, pkRightColumns);
+ ValueContainer[] values = mergeContainer(leftPkValues,
rightPkValues);
+ if(insert)
+ {
+ 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()
+
.getGenericPreparedStatement(SqlGenerator.TYPE_GENERIC_DELETE, table, null,
cols);
+ pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld,
values);
+ }
+ }
+ }
+
+ private CollectionDescriptor findCollectionDescriptor(Class leftClass,
Class rightClass, Vector leftColds)
+ {
+ for(Iterator iter = leftColds.iterator(); iter.hasNext();)
+ {
+ CollectionDescriptor element = (CollectionDescriptor)
iter.next();
+
+ //try super classes and interfaces too
+ if(element.getItemClass().isAssignableFrom(rightClass))
+ {
+ //we found it !
+ return element;
+ }
+ }
+ 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;
+ }
+
+
+
+// ************************************************************************
+// inner class
+// ************************************************************************
+
+ /**
+ * This is a helper class to model a Key of an Object
+ */
+ private static final class Key
+ {
+ final ValueContainer[] m_containers;
+
+ Key(final ValueContainer[] containers)
+ {
+ m_containers = new ValueContainer[containers.length];
+
+ for(int i = 0; i < containers.length; i++)
+ {
+ Object value = containers[i].getValue();
+ JdbcType type = containers[i].getJdbcType();
+
+ // BRJ:
+ // convert all Numbers to Long to simplify equals
+ // Long(100) is not equal to Integer(100)
+ //
+ // could lead to problems when Floats are used as key
+ // converting to String could be a better alternative
+ if(value instanceof Number)
+ {
+ value = new Long(((Number) value).longValue());
+ }
+
+ m_containers[i] = new ValueContainer(value, type);
+ }
+ }
+
+ public boolean equals(Object other)
+ {
+ if(other == this)
+ {
+ return true;
+ }
+ if(!(other instanceof Key))
+ {
+ return false;
+ }
+
+ Key otherKey = (Key) other;
+ EqualsBuilder eb = new EqualsBuilder();
+
+ eb.append(m_containers, otherKey.m_containers);
+ return eb.isEquals();
+ }
+
+ public int hashCode()
+ {
+ HashCodeBuilder hb = new HashCodeBuilder();
+ hb.append(m_containers);
+
+ return hb.toHashCode();
+ }
+ }
+
+
+
+ //
************************************************************************
+ // inner class
+ //
************************************************************************
+ private static final class GenericObject
+ {
+ 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;
+ result = (tablename.equalsIgnoreCase(other.tablename)
+ && (columnNames != null)
+ && (other.columnNames != null)
+ && (columnNames.length == other.columnNames.length));
+ if(result)
+ {
+ 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;
+ }
+ }
+ }
+ 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.18 +4 -3
db-ojb/src/java/org/apache/ojb/broker/accesslayer/PkEnumeration.java
Index: PkEnumeration.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/PkEnumeration.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- PkEnumeration.java 4 Apr 2004 23:53:31 -0000 1.17
+++ PkEnumeration.java 22 Jan 2005 20:52:34 -0000 1.18
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.sql.SQLException;
import java.util.Enumeration;
@@ -38,7 +37,7 @@
* @author Thomas Mahler
* @version $Id$
*/
-public class PkEnumeration implements Enumeration, Serializable
+public class PkEnumeration implements Enumeration
{
static final long serialVersionUID = -834955711995869884L;
protected boolean hasCalledCheck = false;
@@ -177,7 +176,9 @@
try
{
if (!hasCalledCheck)
+ {
hasMoreElements();
+ }
hasCalledCheck = false;
if (hasNext)
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]