Listing 1: ListInvocationHandler.java
package orders.demandlist;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.*;
public class ListInvocationHandler implements
InvocationHandler,PersistentOperations
{
private List backingList;
private DataStore dataStore;
private boolean dataLoaded = false;
private List deletedItems = new LinkedList();
private Set originalSet = new HashSet();
public ListInvocationHandler( List
list,
DataStore dataStore )
{
this.backingList = list;
this.dataStore = dataStore;
}
public Object invoke(Object proxy,
Method method, Object[]
args) throws Throwable
{
// persistent operations
interface
if (method.getDeclaringClass().equals(
orders.demandlist.PersistentOperations.class
))
return method.invoke( this, args );
else
{
// list interface
if (!dataLoaded)
{
dataStore.load( this );
dataLoaded = true;
}
processDeletedItems(
method, args );
Object obj
= method.invoke( backingList,
args );
if (obj instanceof Iterator)
{
return DemandListIteratorFactory.
getDemandListIterator( (Iterator)obj,
this );
}
else if (obj instanceof List)
{
return Collections.unmodifiableList(
(List)obj);
}
else
return obj;
}
}
// PersistentOperations implementation
public void loadFromStore()
{
dataStore.load( this );
}
public void saveToStore()
{
if (dataLoaded)
{
dataStore.persist(
this );
originalSet.addAll(
backingList );
}
}
public List getDeletedObjects()
{
return Collections.unmodifiableList(
deletedItems
);
}
public Set getOriginalSet()
{
return Collections.unmodifiableSet(
originalSet
);
}
public List getCurrentList()
{
return Collections.unmodifiableList(
backingList
);
}
public void addFromStore( Object obj
)
{
backingList.add( obj );
originalSet.add( obj );
}
// package protected iterator support
void notifyObjectRemoved( Object obj
)
{
deletedItems.add( obj
);
}
// implementation
private void processDeletedItems(Method
method,
Object[] args)
{
String methodName = method.getName();
if (methodName.equals("clear"))
{
deletedItems.addAll(
backingList );
}
else if (methodName.equals("removeAll"))
{
deletedItems.addAll(
(Collection)args[0] );
}
else if (methodName.equals("retainAll"))
{
List tempList
= new LinkedList();
tempList.addAll(
backingList );
tempList.removeAll(
(Collection)args[0] );
deletedItems.addAll(
tempList );
}
else if (methodName.equals("remove"))
{
Class[] paramTypes
=
method.getParameterTypes();
if (paramTypes[0].equals(
Integer.TYPE ))
{
Object obj = backingList.get(
((Integer)args[0]).intValue() );
deletedItems.add( obj );
}
else
{
deletedItems.add( args[0] );
}
}
}
}
Listing 2: DemandListIteratorFactory.java
package orders.demandlist;
import java.util.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
public class DemandListIteratorFactory
{
public static Iterator getDemandListIterator(
final Iterator iterator,
final ListInvocationHandler
invocationHandler)
{
InvocationHandler handler
=
new InvocationHandler()
{
private Object
cacheLastRetrieval = null;
public Object
invoke(Object proxy,
Method method, Object[] args)
throws Throwable
{
String methodName = method.getName();
if (methodName.equals("next") ||
methodName.equals("previous") )
{
Object obj = method.invoke(
iterator, args );
cacheLastRetrieval = obj;
return obj;
}
else if (methodName.equals("remove"))
{
Object obj = method.invoke(
iterator, args );
invocationHandler.notifyObjectRemoved(
cacheLastRetrieval );
return obj;
}
return method.invoke( iterator, args );
}
};
Class clazz = null;
if (iterator instanceof
ListIterator)
clazz = java.util.ListIterator.class;
else
clazz = java.util.Iterator.class;
return (Iterator) Proxy.newProxyInstance(
java.util.List.class.getClassLoader(),
new Class[]
{ clazz }, handler);
}
}
Listing 3: PersistentOperations.java
package orders.demandlist;
import java.util.*;
public interface PersistentOperations
{
public void loadFromStore();
public void saveToStore();
public void addFromStore( Object obj
);
public List getDeletedObjects();
public Set getOriginalSet();
public List getCurrentList();
}
Listing 4: DataStore.java
package orders.demandlist;
import java.util.*;
public interface DataStore
{
public void load(
PersistentOperations persistOp
);
public void persist(
PersistentOperations persistOp
);
}
Listing 5: DemandList Factory.java
package orders.demandlist;
import java.util.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DemandListFactory
{
public static List getDemandList(
final List
list, final DataStore
dataStore )
{
InvocationHandler handler
=
new ListInvocationHandler(list,
dataStore);
return (List) Proxy.newProxyInstance(
PersistentOperations.class.getClassLoader(),
new Class[]
{ List.class,
PersistentOperations.class
}, handler);
}
}