Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/ConvertHelper.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/ConvertHelper.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/ConvertHelper.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/ConvertHelper.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,92 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2006 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 org.apache.commons.lang.BooleanUtils;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+/**
+ * Helper class to convert objects (e.g. String to Integer).
+ *
+ * @version $Id: $
+ */
+public class ConvertHelper
+{
+ private static Logger log = LoggerFactory.getLogger(ConvertHelper.class);
+
+ public static Integer toInteger(String value) throws NumberFormatException
+ {
+ try
+ {
+ return value != null ? new Integer(value) : null;
+ }
+ catch(NumberFormatException e)
+ {
+ log.error("Can't convert String '" + value + "' to Integer");
+ throw e;
+ }
+ }
+
+ public static int toIntegerPrimitiv(String value) throws NumberFormatException
+ {
+ try
+ {
+ return value != null ? Integer.parseInt(value) : 0;
+ }
+ catch(NumberFormatException e)
+ {
+ log.error("Can't convert String '" + value + "' to Integer");
+ throw e;
+ }
+ }
+
+ public static Long toLong(String value) throws NumberFormatException
+ {
+ try
+ {
+ return value != null ? new Long(value) : null;
+ }
+ catch(NumberFormatException e)
+ {
+ log.error("Can't convert String '" + value + "' to Long");
+ throw e;
+ }
+ }
+
+ public static long toLongPrimitiv(String value) throws NumberFormatException
+ {
+ try
+ {
+ return value != null ? Long.parseLong(value) : 0;
+ }
+ catch(NumberFormatException e)
+ {
+ log.error("Can't convert String '" + value + "' to Long");
+ throw e;
+ }
+ }
+
+ public static Boolean toBoolean(String value)
+ {
+ return BooleanUtils.toBooleanObject(value);
+ }
+
+ public static boolean toBooleanPrimitiv(String value)
+ {
+ return BooleanUtils.toBoolean(value);
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/IdentityHashSet.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/IdentityHashSet.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/IdentityHashSet.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/IdentityHashSet.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,94 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2006 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.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.collections.map.IdentityMap;
+
+/**
+ * This is a object identity based {@link java.util.Set} implementation.
+ *
+ * @version $Id: $
+ */
+public class IdentityHashSet extends AbstractSet implements Set
+{
+ private static final Object DUMMY = new Object();
+ private org.apache.commons.collections.map.IdentityMap map;
+
+ public IdentityHashSet()
+ {
+ this(null);
+ }
+
+ public IdentityHashSet(Collection c)
+ {
+ map = new org.apache.commons.collections.map.IdentityMap();
+ if(c != null) addAll(c);
+ }
+
+ public Iterator iterator()
+ {
+ return map.keySet().iterator();
+ }
+
+ public int size()
+ {
+ return map.size();
+ }
+
+ public boolean isEmpty()
+ {
+ return map.isEmpty();
+ }
+
+ public boolean contains(Object o)
+ {
+ return map.containsKey(o);
+ }
+
+ public boolean add(Object o)
+ {
+ return map.put(o, DUMMY) == null;
+ }
+
+ public boolean remove(Object o)
+ {
+ return map.remove(o) == DUMMY;
+ }
+
+ public void clear()
+ {
+ map.clear();
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ IdentityHashSet newSet = (IdentityHashSet) super.clone();
+ newSet.map = (IdentityMap) map.clone();
+ return newSet;
+ }
+ catch(CloneNotSupportedException e)
+ {
+ throw new RuntimeException("Unexpected error", e);
+ }
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/WeakIdentityList.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/WeakIdentityList.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/WeakIdentityList.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/WeakIdentityList.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,171 @@
+package org.apache.ojb.broker.util;
+
+/* Copyright 2002-2006 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.Object;
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.AbstractList;
+import java.util.List;
+
+/**
+ * A object identity based (use '==' instead of 'equals' to compare objects) {@link java.util.List}
+ * with <em>weak</em> object entries (internal use of {@link java.lang.ref.WeakReference}).
+ *
+ * @version $Id: $
+ */
+public class WeakIdentityList extends AbstractList
+{
+ private List list;
+
+ /**
+ * Reference queue for weak references
+ */
+ private final ReferenceQueue queue = new ReferenceQueue();
+
+ public WeakIdentityList()
+ {
+ this(null, 20);
+ }
+
+ public WeakIdentityList(int initialCapacity)
+ {
+ this(null, initialCapacity);
+ }
+
+ public WeakIdentityList(Collection c)
+ {
+ this(c, c != null ? c.size() + 20 : 20);
+ }
+
+ public WeakIdentityList(Collection c, int initialCapacity)
+ {
+ list = new ArrayList(initialCapacity);
+ if(c != null)
+ {
+ addAll(c);
+ }
+ }
+
+ public Object get(int index)
+ {
+ Entry result = (Entry) list.get(index);
+ // pollQueue() call could corrupt internal used Iterator
+ return unwrap(result);
+ }
+
+ public Iterator iterator()
+ {
+ // poll before return Iterator
+ pollQueue();
+ return super.iterator();
+ }
+
+ public int size()
+ {
+ pollQueue();
+ return list.size();
+ }
+
+ public Object set(int index, Object element)
+ {
+ Entry result = (Entry) list.set(index, wrap(element));
+ // poll queue after set of object to avoid index error
+ pollQueue();
+ return unwrap(result);
+ }
+
+ public void add(int index, Object element)
+ {
+ list.add(index, wrap(element));
+ // poll queue after add of object to avoid index error
+ pollQueue();
+ }
+
+ public Object remove(int index)
+ {
+ return list.remove(index);
+ }
+
+ /**
+ * Poll reference queue.
+ */
+ private void pollQueue()
+ {
+ Object ref;
+ while((ref = queue.poll()) != null)
+ {
+ remove(ref);
+ }
+ }
+
+ private Entry wrap(Object obj)
+ {
+ if(obj == null)
+ {
+ throw new NullPointerException("Adding 'null' entries to list is not allowed");
+ }
+ return new Entry(obj, queue);
+ }
+
+ private Object unwrap(Entry e)
+ {
+ return e != null ? e.get() : null;
+ }
+
+ static class Entry extends WeakReference
+ {
+ public Entry(Object referent)
+ {
+ super(referent);
+ }
+
+ public Entry(Object referent, ReferenceQueue q)
+ {
+ super(referent, q);
+ }
+
+ public boolean equals(Object other)
+ {
+ boolean result = false;
+ Object current = get();
+ //Object other = obj != null ? ((WeakReference) obj).get() : null;
+ if(current != null)
+ {
+ if(other != null)
+ {
+ result = current == other;
+ }
+ }
+ else
+ {
+ if(other == null)
+ {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ public String toString()
+ {
+ return get() != null ? get().toString() : null;
+ }
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/collections/RemovalAwareVector.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/collections/RemovalAwareVector.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/collections/RemovalAwareVector.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/collections/RemovalAwareVector.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,138 @@
+package org.apache.ojb.broker.util.collections;
+
+/* Copyright 2002-2006 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.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * This class
+ *
+ * @version $Id: $
+ */
+public class RemovalAwareVector extends ManageableVector implements TrackingCollection
+{
+ private Collection deletedObjects = new HashSet();
+ private Collection newObjects = new HashSet();
+
+ public Collection getDeletedObjects()
+ {
+ return deletedObjects;
+ }
+
+ public Collection getNewObjects()
+ {
+ return newObjects;
+ }
+
+ public void clearDeletedObjects()
+ {
+ deletedObjects.clear();
+ }
+
+ public void clearNewObjects()
+ {
+ newObjects.clear();
+ }
+
+
+
+ public void add(int index, Object element)
+ {
+ newObjects.add(element);
+ super.add(index, element);
+ }
+
+ public synchronized boolean add(Object o)
+ {
+ newObjects.add(o);
+ return super.add(o);
+ }
+
+ public synchronized boolean addAll(Collection c)
+ {
+ newObjects.addAll(c);
+ return super.addAll(c);
+ }
+
+ public synchronized boolean addAll(int index, Collection c)
+ {
+ newObjects.addAll(c);
+ return super.addAll(index, c);
+ }
+
+ public synchronized void addElement(Object obj)
+ {
+ newObjects.add(obj);
+ super.addElement(obj);
+ }
+
+ public synchronized Object remove(int index)
+ {
+ deletedObjects.add(get(index));
+ return super.remove(index);
+ }
+
+ public synchronized boolean removeAll(Collection c)
+ {
+ Iterator e = iterator();
+ while(e.hasNext())
+ {
+ Object o = e.next();
+ if(c.contains(o))
+ {
+ deletedObjects.add(o);
+ }
+ }
+ return super.removeAll(c);
+ }
+
+ public synchronized void removeAllElements()
+ {
+ Iterator it = iterator();
+ while(it.hasNext())
+ {
+ deletedObjects.add(it.next());
+ }
+ super.removeAllElements();
+ }
+
+ public synchronized boolean removeElement(Object obj)
+ {
+ boolean result = super.removeElement(obj);
+ if(result) deletedObjects.add(obj);
+ return result;
+ }
+
+ public synchronized void removeElementAt(int index)
+ {
+ deletedObjects.add(get(index));
+ super.removeElementAt(index);
+ }
+
+ protected void removeRange(int fromIndex, int toIndex)
+ {
+ // not supported
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ public synchronized boolean retainAll(Collection c)
+ {
+ // not supported
+ throw new UnsupportedOperationException("Not supported");
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,132 @@
+package org.apache.ojb.broker.util.sequence;
+
+/* Copyright 2002-2006 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.Map;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.accesslayer.JdbcAccess;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.metadata.FieldDescriptor;
+import org.apache.ojb.broker.metadata.SequenceDescriptor;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+/**
+ * A sequence manager implementation which handle per field sequence manager
+ * declarations.
+ *
+ * @version $Id: $
+ */
+public class PerFieldManager implements SequenceManager
+{
+ private Logger log = LoggerFactory.getLogger(this.getClass());
+
+ private Map fieldToManagerMap;
+ private SequenceManager defaultManager;
+
+ /**
+ * Constructor.
+ * @param defaultManager The default sequence manager instance used if no specific
+ * sequence manager ({@link org.apache.ojb.broker.metadata.SequenceDescriptor}) is set
+ * for the {@link org.apache.ojb.broker.metadata.FieldDescriptor}.
+ */
+ public PerFieldManager(SequenceManager defaultManager)
+ {
+ setDefaultManager(defaultManager);
+ log.info("Init per field sequence manager. Current set default manager is " + defaultManager);
+ fieldToManagerMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD);
+ }
+
+ /**
+ * Get the default manager.
+ */
+ public SequenceManager getDefaultManager()
+ {
+ return defaultManager;
+ }
+
+ /**
+ * Set the default manager instance used for all {@link org.apache.ojb.broker.metadata.FieldDescriptor}
+ * without specific {@link org.apache.ojb.broker.metadata.SequenceDescriptor}.
+ *
+ * @param defaultManager The default {@link SequenceManager} instance.
+ */
+ public void setDefaultManager(SequenceManager defaultManager)
+ {
+ if(log.isDebugEnabled()) log.debug("Set default sequence manager: " + defaultManager);
+ this.defaultManager = defaultManager;
+ }
+
+ public Object getUniqueValue(PersistenceBrokerInternal broker, FieldDescriptor field) throws SequenceManagerException
+ {
+ SequenceManager sm = lookup(broker, field);
+ return sm.getUniqueValue(broker, field);
+ }
+
+ public void afterStore(PersistenceBrokerInternal broker, JdbcAccess dbAccess, ClassDescriptor cld, Object obj) throws SequenceManagerException
+ {
+ FieldDescriptor[] pks = cld.getAutoIncrementFields();
+ FieldDescriptor result;
+ for(int i = 0; i < pks.length; i++)
+ {
+ result = pks[i];
+ SequenceManager sm = lookup(broker, result);
+ if(sm != null)
+ {
+ sm.afterStore(broker, dbAccess, cld, obj);
+ }
+ }
+ }
+
+ private SequenceManager lookup(PersistenceBrokerInternal broker, FieldDescriptor field)
+ {
+ SequenceManager sm = (SequenceManager) fieldToManagerMap.get(field);
+ if(sm == null && field.isAutoIncrement())
+ {
+ SequenceDescriptor sd = field.getSequenceDescriptor();
+ if(sd != null)
+ {
+ if(log.isDebugEnabled())
+ {
+ ClassDescriptor cld = field.getClassDescriptor();
+ log.debug("Create field specific sequence manager for field '"
+ + field.getPersistentField().getName()
+ + "' of class '"
+ + (cld != null ? cld.getClassNameOfObject() : "null")
+ + "', using sequence descriptor=" + sd);
+ }
+ sm = SequenceManagerHelper.createManager(broker.serviceConnectionManager().getSupportedPlatform(), sd);
+ }
+ else
+ {
+ if(log.isDebugEnabled())
+ {
+ ClassDescriptor cld = field.getClassDescriptor();
+ log.debug("Use default sequence manager for field '"
+ + field.getPersistentField().getName()
+ + "' of class '"
+ + (cld != null ? cld.getClassNameOfObject() : "null")
+ + "'");
+ }
+ sm = defaultManager;
+ }
+ fieldToManagerMap.put(field, sm);
+ }
+ return sm;
+ }
+}
Added: db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,225 @@
+package org.apache.ojb.broker.util.sequence;
+
+/* Copyright 2002-2006 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.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.platforms.Platform;
+import org.apache.ojb.broker.accesslayer.JdbcAccess;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.metadata.FieldDescriptor;
+import org.apache.ojb.broker.metadata.SequenceDescriptor;
+import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
+
+/**
+ * Sequence manager implementation using native database <tt>Identity columns</tt>
+ * (like MySQL, MSSQL, ...). For proper work some specific metadata settings
+ * needed:
+ * <ul>
+ * <li>field representing the identity column need attribute <code>autoincrement</code> 'true'</li>
+ * <li>field representing the identity column need attribute <code>access</code> set 'readonly'</li>
+ * <li>field representing the identity column need attribute <code>primarykey</code> set 'true'</li>
+ * <li>only possible to declare one identity field per class</li>
+ * </ul>
+ * <p/>
+ * <b>Note:</b>
+ * Make sure that the DB generated identity columns represent values > 0, because negative values
+ * intern used by this implementation and 0 could cause problems with primitive FK fields.
+ * </p>
+ * <p/>
+ * Implementation configuration properties:
+ * <table cellspacing="2" cellpadding="2" border="3" frame="box">
+ * <tr>
+ * <td><strong>Property Key</strong></td>
+ * <td><strong>Property Values</strong></td>
+ * </tr>
+ * <tr>
+ * <td>no properties to set</td>
+ * <td>
+ * <p/>
+ * </td>
+ * </tr>
+ * </table>
+ * </p>
+ * <p/>
+ * <p/>
+ * <b>Limitations:</b>
+ * <ul>
+ * <li>Native key generation is not 'extent aware'
+ * when extent classes span several tables! Please
+ * see more in shipped docs 'extents and polymorphism'
+ * or sequence manager docs.
+ * </li>
+ * <li>
+ * Only positive identity values are allowed (see above).
+ * </li>
+ * </ul>
+ * </p>
+ * <br/>
+ *
+ * @version $Id: SequenceManagerIdentityImpl.java 432648 2006-08-18 19:18:37 +0200 (Fr, 18 Aug 2006) arminw $
+ */
+public class SequenceManagerIdentityImpl extends AbstractSequenceManager
+{
+ private Log log = LogFactory.getLog(SequenceManagerIdentityImpl.class);
+
+ /*
+ TODO:
+ 1. Find a better solution (if possible) for this problem
+ We need this dummy field to return a negative long value
+ on getUniqueLong(...) call. If we return always the same
+ value, the resulting Identity object was found on cache.
+
+ 2. Problem is that generated oid (by Identity column)
+ must not begin with 0.
+
+ Use keyword 'volatile' to make decrement of a long value an
+ atomic operation
+ */
+ private static volatile long tempKey = -1;
+
+ public SequenceManagerIdentityImpl(Platform platform, SequenceDescriptor descriptor)
+ {
+ super(platform, descriptor);
+ }
+
+ public void afterStore(PersistenceBrokerInternal broker, JdbcAccess dbAccess, ClassDescriptor cld, Object obj)
+ throws SequenceManagerException
+ {
+ // if database Identity Columns are used, query the id from database
+ // thus we have to execute batch entries before
+ broker.serviceBatchManager().executeBatch();
+ FieldDescriptor identityField = extractIdentityColumnField(cld);
+ if(identityField != null)
+ {
+ ifNotReadOnlyFail(identityField);
+ long newId = getLastInsert(broker, cld, identityField);
+ setFieldValue(obj, identityField, new Long(newId));
+ }
+ }
+
+ /**
+ * Gets the identity column descriptor for the given class
+ * or return <code>null</code> if none defined.
+ *
+ * @param cld The class descriptor
+ * @return The class's identity column or <code>null</code> if it does not have one
+ */
+ private FieldDescriptor extractIdentityColumnField(ClassDescriptor cld)
+ {
+ FieldDescriptor[] pkFields = cld.getAutoIncrementFields();
+ for(int i = 0; i < pkFields.length; i++)
+ {
+ // to find the identity column we search for a autoincrement
+ // read-only field
+ if(pkFields[i].isAccessReadOnly())
+ {
+ return pkFields[i];
+ }
+ }
+ return null;
+ }
+
+ private void ifNotReadOnlyFail(FieldDescriptor field) throws SequenceManagerException
+ {
+ // is field declared as read-only?
+ if(!field.isAccessReadOnly())
+ {
+ throw new SequenceManagerException("Can't find Identity column: Identity columns/fields need to be declared as" +
+ " 'autoincrement' with 'readonly' access in field-descriptor");
+ }
+ }
+
+ private long getLastInsert(PersistenceBrokerInternal broker, ClassDescriptor cld, FieldDescriptor field) throws SequenceManagerException
+ {
+ long newId = 0;
+ Statement stmt = null;
+ if(field != null)
+ { // an autoinc column exists
+ try
+ {
+ stmt = broker.serviceConnectionManager().getConnection().createStatement();
+ ResultSet rs = stmt.executeQuery(lastInsertSelect(broker, cld.getFullTableName()));
+ if(!rs.next())
+ {
+ throw new SequenceManagerException("Could not find native identifier");
+ }
+ newId = rs.getLong(1);
+ rs.close();
+ if(log.isDebugEnabled()) log.debug("After store - newid=" + newId);
+ }
+ catch(Exception e)
+ {
+ throw new SequenceManagerException(
+ "Error while execute query: " + lastInsertSelect(broker, cld.getFullTableName()), e);
+ }
+ finally
+ {
+ try
+ {
+ if(stmt != null) stmt.close();
+ }
+ catch(SQLException e)
+ {
+ if(log.isDebugEnabled())
+ log.debug("Threw SQLException while in getLastInsert and closing stmt", e);
+ // ignore it
+ }
+ }
+ }
+ else
+ {
+ throw new SequenceManagerException("No autoincrement field declared, please check repository for " + cld);
+ }
+ return newId;
+ }
+
+ /*
+ * query for the last insert id.
+ */
+ protected String lastInsertSelect(PersistenceBrokerInternal broker, String tableName)
+ {
+ return broker.serviceConnectionManager().
+ getSupportedPlatform().getLastInsertIdentityQuery(tableName);
+ }
+
+ private void setFieldValue(Object obj, FieldDescriptor field, Long identifier) throws SequenceManagerException
+ {
+ Object result = field.getJdbcType().sequenceKeyConversion(identifier);
+ result = field.getFieldConversion().sqlToJava(result);
+ PersistentField pf = field.getPersistentField();
+ pf.set(obj, result);
+ }
+
+ /**
+ * returns a negative value
+ */
+ protected long getUniqueLong(PersistenceBrokerInternal broker, FieldDescriptor field) throws SequenceManagerException
+ {
+ /*
+ arminw:
+ workaround for locking problems of new objects
+ We need unique 'dummy keys' for new objects before storing.
+ Variable 'tempKey' is declared volatile, thus decrement should be atomic
+ */
+ return --tempKey;
+ }
+}
Added: db/ojb/trunk/src/test/org/apache/ojb/broker/BatchStrategyTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/broker/BatchStrategyTest.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/broker/BatchStrategyTest.java (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/broker/BatchStrategyTest.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,388 @@
+package org.apache.ojb.broker;
+
+/* Copyright 2002-2006 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.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ojb.junit.PBTestCase;
+import org.apache.ojb.broker.accesslayer.batch.BatchStrategy;
+import org.apache.ojb.broker.accesslayer.batch.BatchManager;
+import org.apache.ojb.broker.accesslayer.batch.Batcher;
+import org.apache.ojb.broker.accesslayer.batch.BatchListener;
+import org.apache.ojb.broker.accesslayer.batch.BatchStrategyDefaultImpl;
+import org.apache.ojb.broker.accesslayer.sql.SqlInsertStatement;
+import org.apache.ojb.broker.accesslayer.sql.SqlUpdateStatement;
+import org.apache.ojb.broker.accesslayer.sql.SqlDeleteByPkStatement;
+import org.apache.ojb.broker.core.ValueContainer;
+import org.apache.ojb.broker.util.ClassHelper;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.platforms.Platform;
+
+/**
+ * Test batch strategy implementation.
+ */
+public class BatchStrategyTest extends PBTestCase
+{
+ public static void main(String[] args)
+ {
+ String[] arr = {BatchStrategyTest.class.getName()};
+ junit.textui.TestRunner.main(arr);
+ }
+
+ public BatchStrategyTest(String testName)
+ {
+ super(testName);
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ }
+
+ public void testMultipleObject() throws Exception
+ {
+ doMultipleObject(BatchStrategyDefaultImpl.class);
+ }
+
+ public void doMultipleObject(Class strategyClass) throws Exception
+ {
+ TestBatchManager bm = new TestBatchManager();
+ BatchStrategy strategy = createStrategy(strategyClass, bm);
+ bm.setStrategy(strategy);
+ Platform pf = broker.serviceConnectionManager().getSupportedPlatform();
+ Logger log = new NoopLogger();
+
+ ValueContainer[] empty = new ValueContainer[]{};
+ ClassDescriptor cld = broker.getClassDescriptor(Person.class);
+ ClassDescriptor cldOther = broker.getClassDescriptor(Zoo.class);
+
+ String sqlInsert = (new SqlInsertStatement(pf, log, cld)).getStatement();
+ String sqlUpdate = (new SqlUpdateStatement(pf, log, cld)).getStatement();
+ String sqlDelete = (new SqlDeleteByPkStatement(pf, log, cld)).getStatement();
+
+ String sqlInsertOther = (new SqlInsertStatement(pf, log, cldOther)).getStatement();
+ String sqlUpdateOther = (new SqlUpdateStatement(pf, log, cldOther)).getStatement();
+ String sqlDeleteOther = (new SqlDeleteByPkStatement(pf, log, cldOther)).getStatement();
+
+ Batcher b_insert = new Batcher.Insert(cld, cld.getInsertProcedure(), sqlInsert);
+ Batcher b_update = new Batcher.Update(cld, cld.getUpdateProcedure(), sqlUpdate);
+ Batcher b_delete = new Batcher.Delete(cld, cld.getDeleteProcedure(), sqlDelete);
+
+ Batcher b_insertOther = new Batcher.Insert(cldOther, cldOther.getInsertProcedure(), sqlInsertOther);
+ Batcher b_updateOther = new Batcher.Update(cldOther, cldOther.getUpdateProcedure(), sqlUpdateOther);
+ Batcher b_deleteOther = new Batcher.Delete(cldOther, cldOther.getDeleteProcedure(), sqlDeleteOther);
+
+
+ bm.add(b_insertOther, empty, 1);
+ bm.add(b_updateOther, empty, 1);
+ assertEquals(2, bm.getBatchEntities().size());
+
+ bm.add(b_update, empty, 1);
+ bm.add(b_delete, empty, 1);
+ assertEquals(4, bm.getBatchEntities().size());
+
+ bm.add(b_deleteOther, empty, 1);
+ assertEquals(4, bm.getBatchEntities().size());
+
+ bm.add(b_insert, empty, 1);
+ assertEquals(2, bm.getBatchEntities().size());
+
+ bm.executeBatch();
+ }
+
+ public void testSingleObject() throws Exception
+ {
+ doSingleObject(BatchStrategyDefaultImpl.class);
+ }
+
+ public void doSingleObject(Class strategyClass) throws Exception
+ {
+ TestBatchManager bm = new TestBatchManager();
+ BatchStrategy strategy = createStrategy(strategyClass, bm);
+ bm.setStrategy(strategy);
+ Platform pf = broker.serviceConnectionManager().getSupportedPlatform();
+ Logger log = new NoopLogger();
+
+
+ ValueContainer[] empty = new ValueContainer[]{};
+ ClassDescriptor cld = broker.getClassDescriptor(Person.class);
+
+ String sqlInsert = (new SqlInsertStatement(pf, log, cld)).getStatement();
+ String sqlUpdate = (new SqlUpdateStatement(pf, log, cld)).getStatement();
+ String sqlDelete = (new SqlDeleteByPkStatement(pf, log, cld)).getStatement();
+
+ Batcher b_insert = new Batcher.Insert(cld, cld.getInsertProcedure(), sqlInsert);
+ Batcher b_update = new Batcher.Update(cld, cld.getUpdateProcedure(), sqlUpdate);
+ Batcher b_delete = new Batcher.Delete(cld, cld.getDeleteProcedure(), sqlDelete);
+
+ bm.add(b_insert, empty, 1);
+ bm.add(b_insert, empty, 1);
+ bm.add(b_insert, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+
+ bm.add(b_delete, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+ bm.add(b_update, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+
+ bm.executeBatch();
+
+ bm.add(b_delete, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+ bm.add(b_update, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+ bm.add(b_insert, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+
+ bm.executeBatch();
+
+ bm.add(b_insert, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+ bm.add(b_update, empty, 1);
+ assertEquals(2, bm.getBatchEntities().size());
+
+ bm.executeBatch();
+
+ bm.add(b_update, empty, 1);
+ assertEquals(1, bm.getBatchEntities().size());
+ bm.add(b_delete, empty, 1);
+ assertEquals(2, bm.getBatchEntities().size());
+ }
+
+ private BatchStrategy createStrategy(Class strategy, BatchManager bm) throws Exception
+ {
+ return (BatchStrategy) ClassHelper.newInstance(
+ strategy, BatchManager.class, bm);
+ }
+
+ static class TestBatchManager implements BatchManager
+ {
+ int addCount;
+ int executeBatchCount;
+ BatchStrategy strategy;
+ List batchEntities = new ArrayList();
+
+ public int getAddCount()
+ {
+ return addCount;
+ }
+
+ public int getExecuteBatchCount()
+ {
+ return executeBatchCount;
+ }
+
+ public List getBatchEntities()
+ {
+ return batchEntities;
+ }
+
+ public void add(Batcher batcher, ValueContainer[] values, int expectedResult) throws SQLException
+ {
+ //System.out.println("* add(...)");
+ ++addCount;
+ Batcher entity = checkForExistingBatcher(batcher);
+ if(entity == null)
+ {
+ entity = batcher;
+ // lookup batch strategy and ask for updated (reordered, reduced, ...)
+ // list of batch entities
+ batchEntities = strategy.prepareForBatch(batchEntities, batcher);
+ }
+ entity.add(values, expectedResult);
+ }
+
+ private Batcher checkForExistingBatcher(Batcher newBatcher)
+ {
+ for(int i = 0; i < batchEntities.size(); i++)
+ {
+ Batcher batcher = (Batcher) batchEntities.get(i);
+ if(batcher.equals(newBatcher))
+ {
+ return batcher;
+ }
+ }
+ return null;
+ }
+
+ public void executeBatch() throws PersistenceBrokerException
+ {
+ System.out.println("* executeBatch()");
+ batchEntities.clear();
+ }
+
+ public void executeBatch(Batcher batcher) throws PersistenceBrokerException
+ {
+ System.out.println("* executeBatch(batcher): " + batcher);
+ ++executeBatchCount;
+ }
+
+ public void cancelBatch()
+ {
+ }
+
+ public void addBatchListener(BatchListener listener)
+ {
+ }
+
+ public void removeBatchListener(BatchListener listener)
+ {
+ }
+
+ public void reset()
+ {
+ }
+
+ public void setBatchMode(boolean mode)
+ {
+ }
+
+ public boolean isBatchMode()
+ {
+ return false;
+ }
+
+ public void setBatchSupportOptimisticLocking(boolean batchOptimisticLocking)
+ {
+ }
+
+ public boolean getBatchSupportOptimisticLocking()
+ {
+ return false;
+ }
+
+ public void setBatchLimit(int limit)
+ {
+ }
+
+ public int getBatchLimit()
+ {
+ return 1000;
+ }
+
+ public BatchStrategy getStrategy()
+ {
+ return strategy;
+ }
+
+ public void setStrategy(BatchStrategy strategy)
+ {
+ this.strategy = strategy;
+ }
+ }
+
+ static class NoopLogger implements Logger
+ {
+ public void debug(Object pObject)
+ {
+ }
+
+ public void info(Object pObject)
+ {
+ }
+
+ public void warn(Object pObject)
+ {
+ }
+
+ public void error(Object pObject)
+ {
+ }
+
+ public void fatal(Object pObject)
+ {
+ }
+
+ public void debug(Object message, Throwable obj)
+ {
+ }
+
+ public void info(Object message, Throwable obj)
+ {
+ }
+
+ public void warn(Object message, Throwable obj)
+ {
+ }
+
+ public void error(Object message, Throwable obj)
+ {
+ }
+
+ public void fatal(Object message, Throwable obj)
+ {
+ }
+
+ public boolean isEnabledFor(int priority)
+ {
+ return false;
+ }
+
+ public boolean isDebugEnabled()
+ {
+ return false;
+ }
+
+ public String getName()
+ {
+ return null;
+ }
+
+ public void safeDebug(String message, Object obj)
+ {
+ }
+
+ public void safeDebug(String message, Object obj, Throwable t)
+ {
+ }
+
+ public void safeInfo(String message, Object obj)
+ {
+ }
+
+ public void safeInfo(String message, Object obj, Throwable t)
+ {
+ }
+
+ public void safeWarn(String message, Object obj)
+ {
+ }
+
+ public void safeWarn(String message, Object obj, Throwable t)
+ {
+ }
+
+ public void safeError(String message, Object obj)
+ {
+ }
+
+ public void safeError(String message, Object obj, Throwable t)
+ {
+ }
+
+ public void safeFatal(String message, Object obj)
+ {
+ }
+
+ public void safeFatal(String message, Object obj, Throwable t)
+ {
+ }
+ }
+}
Added: db/ojb/trunk/src/test/org/apache/ojb/broker/OneToOneWithoutFKTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/broker/OneToOneWithoutFKTest.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/broker/OneToOneWithoutFKTest.java (added)
+++ db/ojb/trunk/src/test/org/apache/ojb/broker/OneToOneWithoutFKTest.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,354 @@
+package org.apache.ojb.broker;
+
+/* Copyright 2002-2006 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 org.apache.ojb.junit.PBTestCase;
+import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
+import org.apache.ojb.broker.util.ObjectModification;
+
+/**
+ * This class show handling of bidirectional 1:1 reference without
+ * using a separate FK column (the PK of the main object is the FK too and the both objects use
+ * the same PK value).
+ * NOTE: It's not recommended to use 1:1 references without FK column.
+ *
+ * @version $Id: $
+ */
+public class OneToOneWithoutFKTest extends PBTestCase
+{
+ public static void main(String[] args)
+ {
+ String[] arr = {OneToOneWithoutFKTest.class.getName()};
+ junit.textui.TestRunner.main(arr);
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ /**
+ * Handle Person object without using a reference to Passport class.
+ */
+ public void testInsertUpdateDeletePerson()
+ {
+ ojbChangeReferenceSetting(Passport.class, "person",
+ true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_NONE, true);
+ ojbChangeReferenceSetting(Person.class, "passport",
+ true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, true);
+ String t = "_" + System.currentTimeMillis();
+ String name = "Person_testInsertUpdateDeletePerson_" + t;
+ assertTrue(broker.getClassDescriptor(Person.class).getObjectReferenceDescriptorByName("passport").isLazy());
+ assertTrue(broker.getClassDescriptor(Passport.class).getObjectReferenceDescriptorByName("person").isLazy());
+
+
+ Person pers = new Person(name);
+
+ broker.beginTransaction();
+ // store plain Person
+ broker.store(pers, ObjectModification.INSERT);
+ broker.commitTransaction();
+ // clear cache to check DB entry
+ broker.clearCache();
+ // lookup
+ Identity oid = broker.serviceIdentity().buildIdentity(Person.class, pers.getId());
+ Person pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+
+ broker.beginTransaction();
+ pers_new.setName(name + "_updated");
+ // store plain Person
+ broker.store(pers_new, ObjectModification.UPDATE);
+ broker.commitTransaction();
+ // clear cache to check DB entry
+ broker.clearCache();
+ // lookup
+ oid = broker.serviceIdentity().buildIdentity(Person.class, pers_new.getId());
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ assertEquals(name+"_updated", pers_new.getName());
+ // NOTE: You try to access the none existing Passport object
+ // always null will be returned
+ assertNull(pers_new.getPassport().getId());
+ assertNull(pers_new.getPassport().getNumber());
+ assertNull(pers_new.getPassport().getPerson());
+
+
+ broker.beginTransaction();
+ // delete plain Person
+ broker.delete(pers);
+ broker.commitTransaction();
+ // lookup
+ oid = broker.serviceIdentity().buildIdentity(Person.class, pers_new.getId());
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNull(pers_new);
+ }
+
+ /**
+ * Handle Person <---> Passport objects with enabled proxy
+ */
+ public void testInsertUpdateDelete()
+ {
+ // metadata settings
+ // the main object Person use cascade update/delete, the dependend object not.
+ // For both 1:1 references proxy object are enabled.
+ ojbChangeReferenceSetting(Passport.class, "person",
+ true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_NONE, true);
+ ojbChangeReferenceSetting(Person.class, "passport",
+ true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, true);
+ String t = "_" + System.currentTimeMillis();
+ String name = "Person_testInsertUpdateDelete_" + t;
+ String number = "Passport_testInsertUpdateDelete_" + t;
+ assertTrue(broker.getClassDescriptor(Person.class).getObjectReferenceDescriptorByName("passport").isLazy());
+ assertTrue(broker.getClassDescriptor(Passport.class).getObjectReferenceDescriptorByName("person").isLazy());
+
+ // insert
+ Person pers = new Person(name);
+ Passport pass = new Passport(number);
+ broker.beginTransaction();
+ // store plain Person to assign PK
+ broker.store(pers);
+ // set PK/FK of Passport
+ pass.setId(pers.getId());
+ // set references
+ pers.setPassport(pass);
+ pass.setPerson(pers);
+ broker.store(pers);
+ broker.commitTransaction();
+
+ // lookup
+ Identity oid = broker.serviceIdentity().buildIdentity(pers);
+ Person pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ assertNotNull(pers_new.getPassport());
+
+ // update
+ broker.beginTransaction();
+ pers_new.setName(name + "_updated");
+ pers_new.getPassport().setNumber(number + "_updated");
+ broker.store(pers_new);
+ broker.commitTransaction();
+
+ // lookup
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ assertNotNull(pers_new.getPassport());
+ assertEquals(name + "_updated", pers_new.getName());
+ assertEquals(number + "_updated", pers_new.getPassport().getNumber());
+
+ // update nullify reference, with proxy references enabled, this result
+ // in unexpected proxy placeholder intead of null reference
+ broker.beginTransaction();
+ broker.delete(pers_new.getPassport());
+ pers_new.setPassport(null);
+ broker.store(pers_new);
+ broker.commitTransaction();
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ // we alway get a proxy placeholder object
+ // assertNull(pers_new.getPassport());
+ assertNull(pers_new.getPassport().getId());
+ assertEquals(name + "_updated", pers_new.getName());
+
+ // delete
+ broker.beginTransaction();
+ // first delete the object with constraint
+ broker.delete(pers_new.getPassport());
+ // not needed, but this reduce the number of generated queries
+ pers_new.setPassport(null);
+ broker.delete(pers_new);
+ broker.commitTransaction();
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNull(pers_new);
+ }
+
+ /**
+ * Handle Person <---> Passport objects withot proxy
+ */
+ public void testInsertUpdateDelete_2()
+ {
+ // metadata settings
+ // the main object Person use cascade update/delete, the dependend object not.
+ // For both 1:1 references proxy references are disabled.
+ ojbChangeReferenceSetting(Passport.class, "person",
+ true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_NONE, false);
+ ojbChangeReferenceSetting(Person.class, "passport",
+ true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
+ String t = "_" + System.currentTimeMillis();
+ String name = "Person_testInsertUpdateDelete_2_" + t;
+ String number = "Passport_testInsertUpdateDelete_2_" + t;
+ assertFalse(broker.getClassDescriptor(Person.class).getObjectReferenceDescriptorByName("passport").isLazy());
+ assertFalse(broker.getClassDescriptor(Passport.class).getObjectReferenceDescriptorByName("person").isLazy());
+
+ // insert
+ Person pers = new Person(name);
+ Passport pass = new Passport(number);
+ broker.beginTransaction();
+ // store plain Person to assign PK
+ broker.store(pers);
+ // set PK/FK of Passport
+ pass.setId(pers.getId());
+ // set references
+ pers.setPassport(pass);
+ pass.setPerson(pers);
+ broker.store(pers);
+ broker.commitTransaction();
+
+ // lookup
+ Identity oid = broker.serviceIdentity().buildIdentity(pers);
+ Person pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ assertNotNull(pers_new.getPassport());
+ assertNotNull(pers_new.getPassport().getPerson());
+
+ // update
+ broker.beginTransaction();
+ pers_new.setName(name + "_updated");
+ pers_new.getPassport().setNumber(number + "_updated");
+ broker.store(pers_new);
+ broker.commitTransaction();
+
+ // lookup
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNotNull(pers_new);
+ assertNotNull(pers_new.getPassport());
+ assertEquals(name + "_updated", pers_new.getName());
+ assertEquals(number + "_updated", pers_new.getPassport().getNumber());
+
+ // update nullify reference, with proxy references enabled, this result
+ // in unexpected proxy placeholder intead of null reference
+ broker.beginTransaction();
+ broker.delete(pers_new.getPassport());
+ pers_new.setPassport(null);
+ broker.store(pers_new);
+ broker.commitTransaction();
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNull(pers_new.getPassport());
+ assertEquals(name + "_updated", pers_new.getName());
+
+ // delete
+ broker.beginTransaction();
+ // first delete the object with constraint
+ broker.delete(pers_new.getPassport());
+ // not needed, but this reduce the number of generated queries
+ pers_new.setPassport(null);
+ broker.delete(pers_new);
+ broker.commitTransaction();
+ pers_new = (Person) broker.getObjectByIdentity(oid);
+ assertNull(pers_new);
+ }
+
+
+
+ public static class Person implements Serializable
+ {
+ private Integer id;
+ private String name;
+ private Passport passport;
+
+ public Person()
+ {
+ }
+
+ public Person(String name)
+ {
+ this.name = name;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public Passport getPassport()
+ {
+ return passport;
+ }
+
+ public void setPassport(Passport passport)
+ {
+ this.passport = passport;
+ }
+ }
+
+ public static class Passport implements Serializable
+ {
+ private Integer id;
+ private String number;
+ private Person person;
+
+ public Passport()
+ {
+ }
+
+ public Passport(String number)
+ {
+ this.number = number;
+ }
+
+ public Integer getId()
+ {
+ return id;
+ }
+
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public String getNumber()
+ {
+ return number;
+ }
+
+ public void setNumber(String number)
+ {
+ this.number = number;
+ }
+
+ public Person getPerson()
+ {
+ return person;
+ }
+
+ public void setPerson(Person person)
+ {
+ this.person = person;
+ }
+ }
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.