package de.ppi.fuwesta.jpa.helper; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.springframework.util.CollectionUtils; /** * A list which handles JPA-bidirectional aspects, furthermore an element can * only be once part of the list. * * @param <E> the type of elements in this list. * @param <A> the associated type */ public abstract class JPAList<E, A> implements List<E> { /** The list which holds the data. */ private final List<E> internalList; /** * The entity which holds this list. */ private final A associatedEntity; /** * Constructs an JPAList which the internalList. * * @param internalList the list which holds the data. * @param associatedEntity the entity which holds this list. */ public JPAList(List<E> internalList, A associatedEntity) { this.internalList = internalList; this.associatedEntity = associatedEntity; } /** * Constructs an empty list with an initial capacity of ten. * * @param associatedEntity the entity which holds this list. */ public JPAList(A associatedEntity) { this(new ArrayList<E>(), associatedEntity); } /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @param associatedEntity the entity which holds this list. * @throws IllegalArgumentException if the specified initial capacity is * negative */ public JPAList(int initialCapacity, A associatedEntity) { this(new ArrayList<E>(initialCapacity), associatedEntity); } /** * {@inheritDoc} */ @Override public int size() { return internalList.size(); } /** * {@inheritDoc} */ @Override public boolean isEmpty() { return internalList.isEmpty(); } /** * {@inheritDoc} */ @Override public boolean contains(Object o) { return internalList.contains(o); } /** * {@inheritDoc} */ @Override public Iterator<E> iterator() { return internalList.iterator(); } /** * {@inheritDoc} */ @Override public Object[] toArray() { return internalList.toArray(); } /** * {@inheritDoc} */ @Override public <T> T[] toArray(T[] a) { return internalList.toArray(a); } /** * {@inheritDoc} */ @Override public boolean add(E e) { if (!internalList.contains(e)) { boolean result = internalList.add(e); add(e, associatedEntity); return result; } else { return false; } } /** * {@inheritDoc} */ @Override public boolean remove(Object o) { int pos = indexOf(o); if (pos == -1) { return false; } else { remove(indexOf(o)); } return true; } /** * {@inheritDoc} */ @Override public boolean containsAll(Collection<?> c) { return internalList.containsAll(c); } /** * {@inheritDoc} */ @Override public boolean addAll(Collection<? extends E> c) { boolean allAdded = true; final ArrayList<E> newList = new ArrayList<E>(); newList.addAll(c); for (E e : newList) { allAdded = add(e) && allAdded; } return allAdded; } /** * {@inheritDoc} */ @Override public boolean addAll(int index, Collection<? extends E> c) { final int startSize = size(); int currentIndex = index; for (E e : c) { if (!internalList.contains(e)) { add(currentIndex, e); currentIndex++; } } return (startSize + c.size() == size()); } /** * {@inheritDoc} */ @Override public boolean removeAll(Collection<?> c) { boolean allRemoved = true; for (Object e : c) { allRemoved = remove(e) && allRemoved; } return allRemoved; } /** * {@inheritDoc} */ @Override public boolean retainAll(Collection<?> c) { boolean allRemoved = true; for (Object e : internalList.toArray()) { if (!c.contains(e)) { allRemoved = remove(e) && allRemoved; } } return allRemoved; } /** * {@inheritDoc} */ @Override public void clear() { for (Object e : internalList.toArray()) { remove(e); } } /** * {@inheritDoc} */ @Override public E get(int index) { return internalList.get(index); } /** * {@inheritDoc} */ @Override public E set(int index, E element) { E oldElement = remove(index); add(index, element); return oldElement; } /** * {@inheritDoc} */ @Override public void add(int index, E element) { if (!internalList.contains(element)) { internalList.add(index, element); add(element, associatedEntity); } } /** * {@inheritDoc} */ @Override public E remove(int index) { E removedElement = internalList.remove(index); if (removedElement != null) { remove(removedElement, associatedEntity); } return removedElement; } /** * {@inheritDoc} */ @Override public int indexOf(Object o) { return internalList.indexOf(o); } /** * {@inheritDoc} */ @Override public int lastIndexOf(Object o) { return internalList.lastIndexOf(o); } /** * {@inheritDoc} */ @Override public ListIterator<E> listIterator() { return internalList.listIterator(); } /** * {@inheritDoc} */ @Override public ListIterator<E> listIterator(int index) { return internalList.listIterator(index); } /** * {@inheritDoc} */ @Override public List<E> subList(int fromIndex, int toIndex) { return internalList.subList(fromIndex, toIndex); } /** * Set the list to the given list. * * @param newList the new list. */ public void set(List<E> newList) { if (internalList.isEmpty()) { if (!CollectionUtils.isEmpty(newList)) { addAll(newList); } } else { final List<E> entriesToAdd = new ArrayList<E>(); if (newList != null) { entriesToAdd.addAll(newList); } final Object[] oldEntries = internalList.toArray(); for (int i = 0; i < oldEntries.length; i++) { final Object entry = oldEntries[i]; if (entriesToAdd.contains(entry)) { entriesToAdd.remove(entry); } else { remove(entry); } } addAll(entriesToAdd); } } /** * Returns the internal list. * * @return the internalList */ public List<E> getInternalList() { return internalList; } /** * Does the addional tasks which must be done to handle the relations. * * @param entity the entity which is added. * @param associatedEntity the associated entity. */ public abstract void add(E entity, A associatedEntity); /** * Does the addional tasks which must be done to handle the relations. * * @param entity the entity which is added. * @param associatedEntity the associated entity. */ public abstract void remove(E entity, A associatedEntity); }