/* * Copyright 2005 Werner Guttmann * * 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. * * $Id$ */ package org.castor.persist.proxy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.castor.jdo.util.ClassLoadingUtils; import org.exolab.castor.persist.FieldMolder; import org.exolab.castor.persist.spi.Identity; /** * This class is a proxy for different types of Collection and Maps. */ public abstract class CollectionProxy { private static final Log LOG = LogFactory.getLog(CollectionProxy.class); public abstract Object getCollection(); public abstract void add(Identity key, Object value); public abstract void close(); public static CollectionProxy create(final FieldMolder fieldMolder, final Object object, final ClassLoader classLoader) { Class cls = fieldMolder.getCollectionType(); if (cls == Vector.class) { return new ColProxy(fieldMolder, object, classLoader, new Vector()); } else if (cls == ArrayList.class) { return new ColProxy(fieldMolder, object, classLoader, new ArrayList()); } else if (cls == Collection.class) { return new ColProxy(fieldMolder, object, classLoader, new ArrayList()); } else if (cls == Set.class) { return new ColProxy(fieldMolder, object, classLoader, new HashSet()); } else if (cls == HashSet.class) { return new ColProxy(fieldMolder, object, classLoader, new HashSet()); } else if (cls == Hashtable.class) { return new MapProxy(fieldMolder, object, classLoader, new Hashtable()); } else if (cls == HashMap.class) { return new MapProxy(fieldMolder, object, classLoader, new HashMap()); } else if (cls == Iterator.class) { return new IteratorProxy(fieldMolder, object, classLoader, new ArrayList()); } else if (cls == Enumeration.class) { return new EnumerationProxy(fieldMolder, object, classLoader, new ArrayList()); } else if (cls == Map.class) { return new MapProxy(fieldMolder, object, classLoader, new HashMap()); } else if (cls == SortedSet.class) { String comparatorClassName = fieldMolder.getComparator(); if (comparatorClassName != null) { Comparator comparator = loadComparator(classLoader, comparatorClassName); return new ColProxy(fieldMolder, object, classLoader, new TreeSet(comparator)); } return new ColProxy(fieldMolder, object, classLoader, new TreeSet()); } else { throw new IllegalArgumentException( "Collection Proxy doesn't exist for this type : " + cls); } } /** * Instantiates the specified java.util.Comparator implementation. * @param classLoader The class loader to use for instantiation. * @param comparatorClassName The name of the java.util.Comparator implementation. * @return An instance of the specified java.util.Comparator implementation. */ private static Comparator loadComparator(final ClassLoader classLoader, final String comparatorClassName) { Comparator comparator; String message = "Problem instantiating instance of " + comparatorClassName; try { Class comparatorClass = ClassLoadingUtils.loadClass(classLoader, comparatorClassName); comparator = (Comparator) comparatorClass.newInstance(); } catch (InstantiationException e) { LOG.error (message); throw new IllegalArgumentException(message); } catch (IllegalAccessException e) { message = "Problem accessing constructor of " + comparatorClassName; LOG.error (message); throw new IllegalArgumentException(message); } catch (ClassNotFoundException e) { LOG.error ("Problem loading class for " + comparatorClassName); throw new IllegalArgumentException(message); } return comparator; } private static final class ColProxy extends CollectionProxy { private Collection _col; private FieldMolder _fm; private Object _object; private ClassLoader _cl; private ColProxy(final FieldMolder fm, final Object object, final ClassLoader cl, final Collection col) { _cl = cl; _fm = fm; _col = col; _object = object; } public Object getCollection() { return _col; } public void add(final Identity key, final Object value) { if (!_fm.isAddable()) { // [TODO] Find a better way to express this scenario where no // setter is specified either. _col.add(value); } else { _fm.addValue(_object, value, _cl); } } public void close() { if (!_fm.isAddable()) { _fm.setValue(_object, _col, _cl); } } } private static final class EnumerationProxy extends CollectionProxy { private Collection _collection; private FieldMolder _fm; private Object _object; private ClassLoader _cl; private EnumerationProxy(final FieldMolder fm, final Object object, final ClassLoader cl, final Collection collection) { _cl = cl; _fm = fm; _collection = collection; _object = object; } public Object getCollection() { return Collections.enumeration(_collection); } public void add(final Identity key, final Object value) { if (!_fm.isAddable()) { // [TODO] Find a better way to express this scenario where no // setter is specified either. _collection.add(value); } else { _fm.addValue(_object, value, _cl); } } public void close() { if (!_fm.isAddable()) { _fm.setValue(_object, Collections.enumeration(_collection), _cl); } } } private static final class IteratorProxy extends CollectionProxy { private Collection _collection; private FieldMolder _fieldMolder; private Object _object; private ClassLoader _cl; private IteratorProxy(final FieldMolder fm, final Object object, final ClassLoader cl, final Collection col) { _cl = cl; _fieldMolder = fm; _collection = col; _object = object; } public Object getCollection() { return _collection.iterator(); } public void add(final Identity key, final Object value) { if (!_fieldMolder.isAddable()) { // [TODO] Find a better way to express this scenario where no // setter is specified either. _collection.add(value); } else { _fieldMolder.addValue(_object, value, _cl); } } public void close() { if (!_fieldMolder.isAddable()) { _fieldMolder.setValue(_object, _collection.iterator(), _cl); } } } private static final class MapProxy extends CollectionProxy { private Map _map; private FieldMolder _fm; private Object _object; private ClassLoader _cl; private MapProxy(final FieldMolder fm, final Object object, final ClassLoader cl, final Map map) { _cl = cl; _map = map; _fm = fm; _object = object; } public Object getCollection() { return _map; } public void add(final Identity key, final Object value) { if (key.size() == 1) { _map.put(key.get(0), value); } else { _map.put(key, value); } } public void close() { if (!_fm.isAddable()) { _fm.setValue(_object, _map, _cl); } } } }