package org.exolab.castor.persist; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.castor.core.util.EnumerationIterator; import org.castor.persist.TransactionContext; import org.exolab.castor.mapping.MappingException; import org.exolab.castor.mapping.loader.AbstractMappingLoader; import org.exolab.castor.mapping.xml.ClassMapping; import org.exolab.castor.mapping.xml.FieldMapping; import org.exolab.castor.persist.spi.Identity; /** * Utility class that provides (mostly) static methods in relation to the functions * required by a {@link ClassMolder}. * */ public final class ClassMolderHelper { /** * Logger used for logging. */ public static final Log LOG = LogFactory.getLog(ClassMolderHelper.class); private ClassMolderHelper() { // nothing to do } /** * A utility method which compare object. * @param o1 First object instance * @param o2 Second object instance * @return True if the objects compared are equal */ public static boolean isEquals(final Object o1, final Object o2) { if (o1 == o2) { return true; } if (o1 == null || o2 == null) { return false; } if (o1.equals(o2)) { return true; } // [oleg] is some special cases equals doesn't work properly if ((o1 instanceof java.math.BigDecimal) && ((java.math.BigDecimal) o1) .compareTo((java.math.BigDecimal) o2) == 0) { return true; } if ((o1 instanceof java.sql.Timestamp) && (o2 instanceof java.sql.Timestamp)) { java.sql.Timestamp t1 = (java.sql.Timestamp) o1; java.sql.Timestamp t2 = (java.sql.Timestamp) o2; return (t1.getTime() == t2.getTime() && t1.getNanos() / 1000000 == t2 .getNanos() / 1000000); } if ((o1 instanceof byte[]) && (o2 instanceof byte[])) { return Arrays.equals((byte[]) o1, (byte[]) o2); } if ((o1 instanceof char[]) && (o2 instanceof char[])) { return Arrays.equals((char[]) o1, (char[]) o2); } return false; } /** * Utility method to compare collections for equality. * * @param c1 collection one. * @param c2 collection two. * @return True if the collections are equal. */ public static boolean isEquals(final Collection c1, final Collection c2) { if (c1 == c2) { return true; } if (c1 == null || c2 == null) { return false; } if (c1.containsAll(c2) && c2.containsAll(c1)) { return true; } return false; } /** * Return all the object identity of a Collection of object of the same * type. * * @param tx the transaction context * @param molder class molder of the type of the objects * @param col a Collection or Vector containing * @return an <tt>ArrayList</tt>s which contains list of object identity */ public static List<Identity> getIdsList(final TransactionContext tx, final ClassMolder molder, final Object col) { List<Identity> idList = new ArrayList<Identity>(); if (col.getClass().isArray()) { Object[] colArr = (Object[]) col; for (int i = 0; i < colArr.length; i++) { Identity id = molder.getIdentity(tx, colArr[i]); if (id != null) { idList.add(id); } } } else if (col instanceof Enumeration) { Enumeration<Object> enumeration = (Enumeration<Object>) col; while (enumeration.hasMoreElements()) { Identity id = molder.getIdentity(tx, enumeration.nextElement()); if (id != null) { idList.add(id); } } } else { Iterator<Object> iter; if (col instanceof Iterator) { iter = (Iterator<Object>) col; } else if (col instanceof Collection) { iter = ((Collection<Object>) col).iterator(); } else if (col instanceof Map) { iter = ((Map<Object, Object>) col).values().iterator(); } else { throw new IllegalArgumentException( "A Collection or Map is expected!"); } while (iter.hasNext()) { Identity id = molder.getIdentity(tx, iter.next()); if (id != null) { idList.add(id); } } } return idList; } /** * Return the iterator on values of the specified Collection * or, return the iterator on values of the specified Map. * * @param object - a Collection instance. */ public static Iterator getIterator(final Object object) { if (object == null) { return new Iterator() { public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } }; } else if (object instanceof Collection) { return ((Collection) object).iterator(); } else if (object instanceof Enumeration) { return new EnumerationIterator((Enumeration) object); } else if (object instanceof Iterator) { return (Iterator) object; } else if (object instanceof Map) { return ((Map) object).values().iterator(); } else if (object.getClass().isArray()) { final class ArrayIterator implements java.util.Iterator { private Object[] _array; private int _i = 0; ArrayIterator(final Object[] array) { this._array = array; } public boolean hasNext() { return _i < _array.length; } public Object next() { return _array[_i++]; } public void remove() { throw new UnsupportedOperationException(); } } return new ArrayIterator((Object[]) object); } else { throw new IllegalArgumentException(); } } /** * It is assumed the returned collection will not be modified. Any modification * to the returned collection may or may not affect the original collection or map. */ public static Collection<Object> getAddedEntitiesList(final TransactionContext tx, final List<Identity> orgIds, final Object collection, final ClassMolder molder) { if (collection == null) { return new ArrayList<Object>(0); } if ((orgIds == null) || (orgIds.size() == 0)) { if (collection.getClass().isArray()) { List<Object> added = new ArrayList<Object>(); Object[] newArr = (Object[]) collection; for (int i = 0; i < newArr.length; i++) { Object newValue = newArr[i]; added.add(newValue); } return added; } else if (collection instanceof Enumeration) { List<Object> added = new ArrayList<Object>(); Enumeration<Object> newEnum = (Enumeration<Object>) collection; while (newEnum.hasMoreElements()) { Object newValue = newEnum.nextElement(); added.add(newValue); } return added; } else if (collection instanceof Iterator) { List<Object> added = new ArrayList<Object>(); Iterator<Object> newIter = (Iterator<Object>) collection; while (newIter.hasNext()) { Object newValue = newIter.next(); added.add(newValue); } return added; } else if (collection instanceof Collection) { return (Collection<Object>) collection; } else if (collection instanceof Map) { return ((Map<Object, Object>) collection).values(); } else { throw new IllegalArgumentException("Collection type " + collection.getClass().getName() + " is not supported!"); } } List<Object> added = new ArrayList<Object>(); Set<Identity> orgSet = new HashSet<Identity>(orgIds); if (collection.getClass().isArray()) { Object[] newArr = (Object[]) collection; for (int i = 0; i < newArr.length; i++) { Object newValue = newArr[i]; Identity newId = molder.getIdentity(tx, newValue); if ((newId == null) || !orgSet.contains(newId)) { added.add(newValue); } } } else if (collection instanceof Enumeration) { Enumeration<Object> newEnum = (Enumeration<Object>) collection; while (newEnum.hasMoreElements()) { Object newValue = newEnum.nextElement(); Identity newId = molder.getIdentity(tx, newValue); if ((newId == null) || !orgSet.contains(newId)) { added.add(newValue); } } } else { Iterator<Object> newIter; if (collection instanceof Iterator) { newIter = (Iterator<Object>) collection; } else if (collection instanceof Collection) { newIter = ((Collection<Object>) collection).iterator(); } else if (collection instanceof Map) { newIter = ((Map<Object, Object>) collection).values().iterator(); } else { throw new IllegalArgumentException("Collection type " + collection.getClass().getName() + " is not supported!"); } while (newIter.hasNext()) { Object newValue = newIter.next(); Identity newId = molder.getIdentity(tx, newValue); if ((newId == null) || !orgSet.contains(newId)) { added.add(newValue); } } } return added; } /** * It is assumed the returned collection will not be modified. Any modification * to the returned collection may or may not affect the original collection or map. */ public static List<Identity> getRemovedIdsList(final TransactionContext tx, final List<Identity> orgIds, final Object collection, final ClassMolder molder) { if ((orgIds == null) || (orgIds.size() == 0)) { return new ArrayList<Identity>(0); } if (collection == null) { return orgIds; } Set<Identity> newSet = new HashSet<Identity>(); if (collection.getClass().isArray()) { Object[] newArr = (Object[]) collection; for (int i = 0; i < newArr.length; i++) { Object newObject = newArr[i]; Identity newId = molder.getIdentity(tx, newObject); if (newId != null) { newSet.add(newId); } } } else if (collection instanceof Enumeration) { Enumeration<Object> newEnum = (Enumeration<Object>) collection; while (newEnum.hasMoreElements()) { Object newObject = newEnum.nextElement(); Identity newId = molder.getIdentity(tx, newObject); if (newId != null) { newSet.add(newId); } } } else { Iterator<Object> newIter; if (collection instanceof Iterator) { newIter = (Iterator<Object>) collection; } else if (collection instanceof Collection) { Collection<Object> newCol = (Collection<Object>) collection; newIter = newCol.iterator(); } else if (collection instanceof Map) { Collection<Object> newCol = ((Map<Object, Object>) collection).values(); newIter = newCol.iterator(); } else { throw new IllegalArgumentException("Collection type " + collection.getClass().getName() + " is not supported!"); } while (newIter.hasNext()) { Object newObject = newIter.next(); Identity newId = molder.getIdentity(tx, newObject); if (newId != null) { newSet.add(newId); } } } List<Identity> removedIds = new ArrayList<Identity>(); Iterator<Identity> orgIter = orgIds.iterator(); while (orgIter.hasNext()) { Identity id = orgIter.next(); if (!newSet.contains(id)) { removedIds.add(id); } } return removedIds; } }