/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.impl;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.util.DbClientCallbackEvent;
/**
* @author cgarber
*
*/
public abstract class LazyLoadedCollection<E extends DataObject> implements Collection<E> {
protected Collection<E> list;
protected LazyLoader lazyLoader;
protected String fieldName;
protected E parentObj;
protected boolean iteratorOnly;
protected boolean loaded;
protected Iterator<E> iterator;
protected StringSet mappedByUriSet;
protected abstract Collection<E> getNewCollection();
/**
* @param name
* @param mappedBy
* @param id
* @param lazyLoader2
*/
public LazyLoadedCollection(String name, E parentObj, LazyLoader lazyLoader, StringSet mappedBy) {
this.fieldName = name;
this.parentObj = parentObj;
this.lazyLoader = lazyLoader;
this.mappedByUriSet = mappedBy;
loaded = false;
iteratorOnly = true;
}
protected synchronized Collection<E> getCollection() {
if (list == null) {
list = getNewCollection();
}
if (!loaded || (loaded && iteratorOnly)) {
list.clear();
// load collection elements
lazyLoader.load(fieldName, parentObj, list, new InvalidateLazyLoadedListCb<E>(this));
loaded = true;
iteratorOnly = false;
}
return list;
}
protected synchronized Iterator<E> populateIteratorResults() {
if (list == null) {
list = getNewCollection();
}
if (loaded && !iteratorOnly) {
return list.iterator();
}
if (!loaded) {
list.clear();
iterator = lazyLoader.load(fieldName, parentObj, (Collection<E>) null, new InvalidateLazyLoadedListCb<E>(this));
if (iterator != null) {
loaded = true;
iteratorOnly = true;
}
}
return iterator;
}
public synchronized void invalidate() {
loaded = false;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#size()
*/
@Override
public int size() {
return getCollection().size();
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#isEmpty()
*/
@Override
public boolean isEmpty() {
return getCollection().isEmpty();
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#contains(java.lang.Object)
*/
@Override
public boolean contains(Object o) {
// Inappropriate "Collection" calls should not be made
// it's better to comply with Collection.contains(Object o) declare, equals method of DataObject will be invoked if o is instance of
// DataObject
return getCollection().contains(o); // NOSONAR ("squid:S2175")
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#iterator()
*/
@Override
public Iterator<E> iterator() {
return populateIteratorResults();
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#toArray()
*/
@Override
public Object[] toArray() {
return getCollection().toArray();
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#toArray(java.lang.Object[])
*/
@Override
public <T> T[] toArray(T[] a) {
return getCollection().toArray(a);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#add(java.lang.Object)
*/
@Override
public synchronized boolean add(E e) {
if (mappedByUriSet != null) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.add(e.getId().toString());
mappedByUriSet.setCallback(cb);
}
return getCollection().add(e);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#remove(java.lang.Object)
*/
@Override
public synchronized boolean remove(Object o) {
if (mappedByUriSet != null && DataObject.class.isAssignableFrom(o.getClass())) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.remove(((DataObject) o).getId().toString());
mappedByUriSet.setCallback(cb);
}
// Inappropriate "Collection" calls should not be made
// it's better to comply with Collection.contains(Object o) declare, equals method of DataObject will be invoked if o is instance of
// DataObject
return getCollection().remove(o); // NOSONAR ("squid:S2175")
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#containsAll(java.util.Collection)
*/
@Override
public boolean containsAll(Collection<?> c) {
return getCollection().containsAll(c);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#addAll(java.util.Collection)
*/
@Override
public synchronized boolean addAll(Collection<? extends E> c) {
if (mappedByUriSet != null) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.addAll(toIds(c));
mappedByUriSet.setCallback(cb);
}
return getCollection().addAll(c);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#removeAll(java.util.Collection)
*/
@Override
public synchronized boolean removeAll(Collection<?> c) {
if (mappedByUriSet != null) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.remove(toIds(c));
mappedByUriSet.setCallback(cb);
}
return getCollection().removeAll(c);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#retainAll(java.util.Collection)
*/
@Override
public synchronized boolean retainAll(Collection<?> c) {
if (mappedByUriSet != null) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.retainAll(toIds(c));
mappedByUriSet.setCallback(cb);
}
return getCollection().retainAll(c);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#clear()
*/
@Override
public synchronized void clear() {
if (mappedByUriSet != null) {
DbClientCallbackEvent cb = mappedByUriSet.getCallback();
mappedByUriSet.setCallback(null);
mappedByUriSet.clear();
mappedByUriSet.setCallback(cb);
}
getCollection().clear();
}
public static class InvalidateLazyLoadedListCb<T extends DataObject> implements DbClientCallbackEvent {
private LazyLoadedCollection<T> list;
public InvalidateLazyLoadedListCb(LazyLoadedCollection<T> lazyLoadedCollection) {
this.list = lazyLoadedCollection;
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.db.client.util.DbClientCallbackEvent#call(java.lang.Object[])
*/
@Override
public void call(Object... args) {
list.invalidate();
}
}
public boolean isLoaded() {
return loaded;
}
private Set<String> toIds(Collection<?> c) {
Set<String> ids = new HashSet<String>();
for (Object obj : c) {
if (DataObject.class.isAssignableFrom(obj.getClass())) {
ids.add(((DataObject) obj).getId().toString());
}
}
return ids;
}
}