package org.sigmah.client.cache;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.sigmah.shared.dto.base.EntityDTO;
import com.google.gwt.user.client.rpc.AsyncCallback;
/**
* Caches a collection locally.
*
* @author tmi
* @author Denis Colliot (dcolliot@ideia.fr)
* @param <E>
* The type of the cached elements.
*/
public class LocalCachedCollection<E extends EntityDTO<?>> {
/**
* Job to get an entity.
*
* @author tmi
* @param <E>
* The type of the cached elements.
*/
private static final class EntityAsyncCallback<E> {
private final int id;
private final AsyncCallback<E> callback;
private EntityAsyncCallback(int id, AsyncCallback<E> callback) {
this.id = id;
this.callback = callback;
}
}
/**
* Job to get the whole collection.
*
* @author tmi
* @param <E>
* The type of the cached elements.
*/
private static final class EntitiesAsyncCallback<E> {
private final AsyncCallback<List<E>> callback;
private EntitiesAsyncCallback(AsyncCallback<List<E>> callback) {
this.callback = callback;
}
}
/**
* Cached collection/
*/
private final ArrayList<E> list;
/**
* Cached elements mapped to their ids.
*/
private final HashMap<Serializable, E> map;
/**
* If the cache has been set.
*/
private boolean hasBeenSet;
/**
* Waiting jobs to get a single entity instance.
*/
private final ArrayList<EntityAsyncCallback<E>> queueEntity;
/**
* Waiting jobs to get a whole collection.
*/
private final ArrayList<EntitiesAsyncCallback<E>> queueEntities;
public LocalCachedCollection() {
map = new HashMap<Serializable, E>();
list = new ArrayList<E>();
hasBeenSet = false;
queueEntity = new ArrayList<EntityAsyncCallback<E>>();
queueEntities = new ArrayList<EntitiesAsyncCallback<E>>();
}
/**
* Gets the entity with the given id. If the collection isn't available immediately, the callback will be called after
* the collection has been set by the first server call.
*
* @param id
* The entity id.
* @param callback
* The callback.
*/
public void get(int id, AsyncCallback<E> callback) {
// If the collection is available, returns the entity immediately.
if (hasBeenSet) {
callback.onSuccess(map.get(id));
}
// Else put the callback in queue to be called later.
else {
queueEntity.add(new EntityAsyncCallback<E>(id, callback));
}
}
/**
* Tries to get an entity without waiting.
*
* @param id
* The entity id.
* @return The entity if the cache has been set, <code>null</code> otherwise.
*/
public E get(int id) {
if (hasBeenSet) {
return map.get(id);
} else {
return null;
}
}
/**
* Gets the whole collection. If the collection isn't available immediately, the callback will be called after the
* collection has been set by the first server call.
*
* @param callback
* The callback.
*/
public void get(AsyncCallback<List<E>> callback) {
// If the countries list is available, returns the list immediately.
if (hasBeenSet) {
callback.onSuccess(list);
}
// Else put the callback in queue to be called later.
else {
queueEntities.add(new EntitiesAsyncCallback<E>(callback));
}
}
/**
* Tries to get the collection without waiting.
*
* @return The collection if the cache has been set, <code>null</code> otherwise.
*/
public List<E> get() {
if (hasBeenSet) {
return list;
} else {
return null;
}
}
/**
* Sets the collection and call all waiting jobs.
*
* @param entities
* The entities.
*/
protected void set(List<E> entities) {
// This method is called once.
if (hasBeenSet) {
return;
}
// Stores entities.
if (entities != null) {
list.addAll(entities);
for (final E entity : list) {
map.put(entity.getId(), entity);
}
}
// Calls the waiting jobs.
for (final EntityAsyncCallback<E> job : queueEntity) {
job.callback.onSuccess(map.get(job.id));
}
for (final EntitiesAsyncCallback<E> job : queueEntities) {
job.callback.onSuccess(list);
}
// Clears the queues.
queueEntity.clear();
queueEntities.clear();
hasBeenSet = true;
}
}