blob: b6d39738f9c39a4238e4bce33f31ab54bf758895 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2005, 2006, 2007 Springsite BV (The Netherlands) and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Martin Taal - Initial API and implementation
*
* </copyright>
*
* $Id: PersistableEList.java,v 1.13 2007/03/08 04:25:32 mtaal Exp $
*/
package org.eclipse.emf.teneo.mapping.elist;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.DelegatingEcoreEList;
import org.eclipse.emf.teneo.util.StoreUtil;
/**
* A persistable elist which can be used by different or mappers. This persistable elist works around the idea that the
* persisted list (e.g. PersistentList in Hibernate) is the delegate for this elist.
*
* @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
* @version $Revision: 1.13 $
*/
public abstract class PersistableEList<E> extends DelegatingEcoreEList<E> implements PersistableDelegateList<E> {
/** The logger */
private static Log log = LogFactory.getLog(PersistableEList.class);
/** The actual list, must never be an elist as notifications etc. are done by this list */
protected List<E> delegate;
/** The structural feature modeled by this list */
private EStructuralFeature estructuralFeature;
/** The unique path to the efeature, used to support serializaion */
private String eFeaturePath = "";
/** Is loaded from backend */
private boolean isLoaded = false;
/** Is being loaded from backend */
private boolean isLoading = false;
/** The string used for logging */
protected final String logString;
/** Constructor */
public PersistableEList(InternalEObject owner, EStructuralFeature feature, List<E> list) {
super(owner);
estructuralFeature = feature;
if (list == null) {
delegate = new ArrayList<E>();
isLoaded = true;
} else if (list instanceof EList) {
delegate = new ArrayList<E>(list);
isLoaded = true;
} else if (list instanceof ArrayList) // already loaded lists are packaged in an elist
{
delegate = list;
isLoaded = list.size() > 0;
} else {
delegate = list;
}
logString = "EList of type: " + this.getClass().getName() + " of member " + estructuralFeature.getName()
+ " owned by " + owner.getClass().getName() + " with delegate list " + delegate.getClass().getName();
log.debug("Created persistable list " + logString);
}
/** Takes care of serializing the efeature */
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
eFeaturePath = StoreUtil.structuralFeatureToString(estructuralFeature);
estructuralFeature = null;
additionalWriteObject();
out.defaultWriteObject();
}
/** Do your subclass thing for serialization */
protected void additionalWriteObject() {
}
/** Takes care of deserializing the efeature */
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
estructuralFeature = StoreUtil.stringToStructureFeature(eFeaturePath);
}
/*
* Get the underlying efeature
*
* @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getEStructuralFeature()
*/
@Override
public EStructuralFeature getEStructuralFeature() {
return estructuralFeature;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeature()
*/
@Override
public Object getFeature() {
return estructuralFeature;
}
/** Return the isunique value of the efeature */
@Override
public boolean isUnique() {
return estructuralFeature.isUnique();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.util.DelegatingEcoreEList#getFeatureID()
*/
@Override
public int getFeatureID() {
return estructuralFeature.getFeatureID();
}
/** Return the delegate list without doing a load */
public List<E> getDelegate() {
return delegate;
}
/** Returns the underlying elist */
@Override
protected List<E> delegateList() {
load();
return delegate;
}
/** Replace the delegating list */
public void replaceDelegate(List<E> newDelegate) {
// disabled this assertion because in case of a session refresh it is possible
// that the list is replaced by a persistent list
// AssertUtil.assertTrue("This elist " + logString + " already wraps an or specific list",
// !isPersistencyWrapped());
delegate = newDelegate;
isLoaded = false;
}
/** Returns a string which can be used to log for this elist */
public String getLogString() {
return logString;
}
/** Performs the load action if not yet oaded and sends out the load notification. */
protected void load() {
if (isLoaded)
return;
// When we are loading we should not be reloaded!
// this can happen in the jpox elist impl. when detaching
if (isLoading)
return;
isLoading = true;
log.debug("Loading " + getLogString());
// prevent notifications to be sent out
boolean eDeliver = owner.eDeliver();
boolean setDeliver = false;
try {
// only set to false if it was true
if (eDeliver) {
log.debug("Owner " + owner.getClass() + " set eDeliver to false");
owner.eSetDeliver(false);
setDeliver = true;
}
} catch (UnsupportedOperationException e) {
// in this case the eSetDeliver was not overridden from the baseclass
// ignore
}
try {
doLoad();
} finally {
isLoaded = true;
isLoading = false;
if (setDeliver) {
owner.eSetDeliver(eDeliver);
}
}
// StoreUtil.dispatchEListLoadNotification(owner, this, getEStructuralFeature());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.util.EcoreEList#isNotificationRequired()
*/
protected boolean isNotificationRequired() {
if (!isLoaded() || isLoading())
return false; // not yet loaded so no notifications, prevents infinite looping
return super.isNotificationRequired();
}
/** Is loaded */
public boolean isLoaded() {
return isLoaded;
}
/** Is loaded */
public void setIsLoaded(boolean isLoaded) {
this.isLoaded = isLoaded;
}
/** Is loading */
public void setIsLoading(boolean isLoading) {
this.isLoading = isLoading;
}
/** Returns true if the load action is running and false otherwise */
public boolean isLoading() {
return isLoading;
}
/** The load method which should be overridden by the subclass to add lazyloading */
protected abstract void doLoad();
/** Returns true if the wrapped list is a persistency layer specific list */
public abstract boolean isPersistencyWrapped();
// ---------------------------- Overloaded delegate methods --------------------------
// These methods have been overridden to a load action before the backing list is
// accessed.
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(int, java.lang.Object)
*/
@Override
protected void delegateAdd(int index, E object) {
load();
super.delegateAdd(index, object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateAdd(java.lang.Object)
*/
@Override
protected void delegateAdd(E object) {
load();
super.delegateAdd(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateBasicList()
*/
@Override
protected List<E> delegateBasicList() {
load();
return super.delegateBasicList();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateClear()
*/
@Override
protected void delegateClear() {
load();
super.delegateClear();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateContains(java.lang.Object)
*/
@Override
protected boolean delegateContains(Object object) {
load();
return super.delegateContains(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateContainsAll(java.util.Collection)
*/
@Override
protected boolean delegateContainsAll(Collection<?> collection) {
load();
return super.delegateContainsAll(collection);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateEquals(java.lang.Object)
*/
@Override
protected boolean delegateEquals(Object object) {
load();
return super.delegateEquals(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateGet(int)
*/
@Override
protected E delegateGet(int index) {
load();
return super.delegateGet(index);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateHashCode()
*/
@Override
protected int delegateHashCode() {
load();
return super.delegateHashCode();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateIndexOf(java.lang.Object)
*/
@Override
protected int delegateIndexOf(Object object) {
load();
return super.delegateIndexOf(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateIsEmpty()
*/
@Override
protected boolean delegateIsEmpty() {
load();
return super.delegateIsEmpty();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateIterator()
*/
@Override
protected Iterator<E> delegateIterator() {
load();
return super.delegateIterator();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateLastIndexOf(java.lang.Object)
*/
@Override
protected int delegateLastIndexOf(Object object) {
load();
return super.delegateLastIndexOf(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateListIterator()
*/
@Override
protected ListIterator<E> delegateListIterator() {
return super.delegateListIterator();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateRemove(int)
*/
@Override
protected E delegateRemove(int index) {
load();
return super.delegateRemove(index);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateSet(int, java.lang.Object)
*/
@Override
protected E delegateSet(int index, E object) {
load();
return super.delegateSet(index, object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateSize()
*/
@Override
protected int delegateSize() {
load();
return super.delegateSize();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray()
*/
@Override
protected Object[] delegateToArray() {
load();
return super.delegateToArray();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateToArray(java.lang.Object[])
*/
@Override
protected <T> T[] delegateToArray(T[] array) {
load();
return super.delegateToArray(array);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.util.DelegatingEList#delegateToString()
*/
@Override
protected String delegateToString() {
load();
return super.delegateToString();
}
/** If not loaded then basicIterator will always return a false for hasNext */
@Override
public Iterator<E> basicIterator() {
if (!isLoaded()) {
return new NonResolvingEIterator<E>() {
/** Always returns false */
public boolean hasNext() {
return false;
}
};
}
return super.basicIterator();
}
/** If not loaded then basicIterator will always return a false for hasNext/hasPrevious */
@Override
public ListIterator<E> basicListIterator() {
if (!isLoaded()) {
return new NonResolvingEListIterator<E>() {
/** Always returns false */
public boolean hasNext() {
return false;
}
/** Always returns false */
public boolean hasPrevious() {
return false;
}
};
}
return super.basicListIterator();
}
/** If not loaded then basicIterator will always return a false for hasNext/hasPrevious */
@Override
public ListIterator<E> basicListIterator(int index) {
if (!isLoaded()) {
// note no size check on index as this would load this thing
return new NonResolvingEListIterator<E>() {
/** Always returns false */
public boolean hasNext() {
return false;
}
/** Always returns false */
public boolean hasPrevious() {
return false;
}
};
}
return super.basicListIterator(index);
}
/**
* Is overridden because it can't use delegates for equality because the delegate
* (a hibernate or jpox list) will try to be equal with this persistable elist.
*
* This method does jvm instance equality because doing a full-fledge equal would result in
* a load of the list.
*/
@Override
public boolean equals(Object object) {
return this == object;
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
//TODOMAP
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#containsKey(java.lang.Object)
// */
// public boolean containsKey(Object arg0) {
// return get(arg0) != null;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#containsValue(java.lang.Object)
// */
// public boolean containsValue(Object arg0) {
// // TODO Auto-generated method stub
// return false;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#entrySet()
// */
// public Set entrySet() {
// return new TreeSet(this);
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#get(java.lang.Object)
// */
// public Object get(Object arg0) {
// for (Iterator it = iterator(); it.hasNext();) {
// Entry entry = (Entry) it.next();
// if (arg0.equals(entry.getKey())) {
// return entry.getValue();
// }
// }
// return null;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#indexOfKey(java.lang.Object)
// */
// public int indexOfKey(Object arg0) {
// final Object entry = get(arg0);
// return indexOf(entry);
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#keySet()
// */
// public Set keySet() {
// final Set set = new TreeSet();
// for (Iterator it = iterator(); it.hasNext();) {
// Entry entry = (Entry) it.next();
// set.add(entry.getKey());
// }
// return set;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#map()
// */
// public Map map() {
// return new DelegatingMap();
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#put(java.lang.Object, java.lang.Object)
// */
// public Object put(Object key, Object value) {
// Object entry = get(key);
// if (entry != null) {
// ((Entry) entry).setValue(value);
// return entry;
// }
// entry = newEntry(key, value);
// add(entry);
// return entry;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#putAll(org.eclipse.emf.common.util.EMap)
// */
// public void putAll(EMap arg0) {
// putAll(arg0.map());
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#putAll(java.util.Map)
// */
// public void putAll(Map arg0) {
// load();
// addAll(Arrays.asList(arg0.entrySet().toArray()));
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#removeKey(java.lang.Object)
// */
// public Object removeKey(Object arg0) {
// load();
// for (Iterator it = iterator(); it.hasNext();) {
// Entry entry = (Entry) it.next();
// if (arg0.equals(entry.getKey())) {
// remove(entry);
// return entry.getValue();
// }
// }
// return null;
// }
//
// /*
// * (non-Javadoc)
// *
// * @see org.eclipse.emf.common.util.EMap#values()
// */
// public Collection values() {
// final ArrayList result = new ArrayList();
// for (Iterator it = iterator(); it.hasNext();) {
// Entry entry = (Entry) it.next();
// result.add(entry.getValue());
// }
//
// return result;
// }
//
// /** returns a new map entry */
// protected Entry newEntry(Object key, Object value) {
// final EClass entryEClass = (EClass) getEStructuralFeature().getEType();
//
// org.eclipse.emf.common.util.BasicEMap.Entry entry = (org.eclipse.emf.common.util.BasicEMap.Entry) entryEClass
// .getEPackage().getEFactoryInstance().create(entryEClass);
// entry.setHash(key == null ? 0 : key.hashCode());
// entry.setKey(key);
// entry.setValue(value);
// return entry;
// }
//
// /** Forwards all calls to its EListWrapper */
// public class DelegatingMap implements EMap.InternalMapView {
// public DelegatingMap() {
// }
//
// public EMap eMap() {
// return PersistableEList.this;
// }
//
// public int size() {
// return PersistableEList.this.size();
// }
//
// public boolean isEmpty() {
// return PersistableEList.this.isEmpty();
// }
//
// public boolean containsKey(Object key) {
// return PersistableEList.this.containsKey(key);
// }
//
// public boolean containsValue(Object value) {
// return PersistableEList.this.containsValue(value);
// }
//
// public Object get(Object key) {
// return PersistableEList.this.get(key);
// }
//
// public Object put(Object key, Object value) {
// return PersistableEList.this.put(key, value);
// }
//
// public Object remove(Object key) {
// return PersistableEList.this.removeKey(key);
// }
//
// public void putAll(Map map) {
// PersistableEList.this.putAll(map);
// }
//
// public void clear() {
// PersistableEList.this.clear();
// }
//
// public Set keySet() {
// return PersistableEList.this.keySet();
// }
//
// public Collection values() {
// return PersistableEList.this.values();
// }
//
// public Set entrySet() {
// return PersistableEList.this.entrySet();
// }
//
// public boolean equals(Object object) {
// return PersistableEList.this.equals(object);
// }
//
// public int hashCode() {
// return PersistableEList.this.hashCode();
// }
//
// public boolean isLoaded() {
// return PersistableEList.this.isLoaded();
// }
// }
}