
de.tsl2.nano.service.util.batch.CachingBatchloader Maven / Gradle / Ivy
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Thomas Schneider, Thomas Schneider
* created on: Oct 10, 2012
*
* Copyright: (c) Thomas Schneider 2012, all rights reserved
*/
package de.tsl2.nano.service.util.batch;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.service.util.IGenericService;
import de.tsl2.nano.service.util.finder.AbstractFinder;
import de.tsl2.nano.serviceaccess.ServiceFactory;
/**
* Batch loader that is optionally able to cache loaded data. Useable to optimize performance on loading several data
* using a single communication line.
*
*
*
* Features:
* - load data through several queries on a single request
* - cache base data for application access
*
*
* @author Thomas Schneider, Thomas Schneider
* @version $Revision$
*/
public class CachingBatchloader {
private static CachingBatchloader self;
/** genService */
IGenericService genService;
/** cache, holding all {@link Part}s where {@link Part#cache} is true */
Map> cache;
/** the next batch {@link Part}s to load through {@link #execute()} */
Collection> nextBatchParts;
/** mode on getting cached data through {@link #get(Class, String)} */
boolean autoExecute = true;
private CachingBatchloader() {
this(ServiceFactory.getGenService());
}
private CachingBatchloader(IGenericService genService) {
this.genService = genService;
nextBatchParts = new LinkedList>();
cache = new HashMap>();
}
public static CachingBatchloader init(IGenericService genService, boolean autoExecute) {
self = new CachingBatchloader(genService);
self.autoExecute = autoExecute;
return self;
}
/**
* instance
*
* @return singelton
*/
public static final CachingBatchloader instance() {
if (self == null) {
self = new CachingBatchloader();
}
return self;
}
public static void reset() {
self = null;
}
/**
* adds the given part to the batch loading list - to be executed later
*
* @param id part id
* @param cache whether to cache the result in memory
* @param finders for getting the data
* @return this instance itself
*/
public CachingBatchloader add(String id, boolean cache, AbstractFinder... finders) {
Class resultType = (Class) finders[0].getResultType();
Part part = new Part(id, resultType, cache);
part.setFinders(finders);
return add(part);
}
/**
* adds the given part to the batch loading list - to be executed later
*
* @param batchPart batch loading part
* @return this instance itself
*/
public CachingBatchloader add(Part> batchPart) {
nextBatchParts.add(batchPart);
return this;
}
/**
* executes all batch parts. nothing will be returned to optimize performance. to access the data, use
* {@link #get(Class, String)} and {@link #getSingle(Class, String)}.
*/
public void execute() {
try {
Part[] loadedParts = genService.findBatch(nextBatchParts.toArray(new Part[0]));
for (int i = 0; i < loadedParts.length; i++) {
if (loadedParts[i].isCache()) {
cache.put(loadedParts[i].getId(), loadedParts[i]);
}
}
} finally {
nextBatchParts.clear();
}
}
/**
* get cached result list
*
* @param result type
* @param type result type
* @param partId part id, identifying the data
* @return data or null
*/
public Collection get(Class type, String partId) {
Part> part = cache.get(partId);
if (part == null && nextBatchParts.contains(new Part(partId))) {
if (autoExecute) {
execute();
part = cache.get(partId);
} else {
throw ManagedException.implementationError("the batch-loading wasn't started yet! you have to call 'execute' before getting the data",
partId);
}
}
return (Collection) (part != null ? part.getResult() : null);
}
/**
* get cached result as single object. use {@link #get(Class, String)} to obtain a list of elements.
*
* @param result type
* @param type result type
* @param partId part id, identifying the data
* @return data or null
*/
public T getSingle(Class type, String partId) {
Collection result = get(type, partId);
if (result != null) {
if (result.size() == 1) {
return result.iterator().next();
} else {
throw ManagedException.implementationError("the cache for " + type
+ "|"
+ partId
+ " is not a single result. the cache contains"
+ result.size()
+ " elements for that!", "getSingle()", "get()");
}
}
return null;
}
/**
* reloads all cache data
*/
public void reloadCache() {
genService = ServiceFactory.getGenService();
nextBatchParts.addAll(cache.values());
execute();
}
/**
* resets the cached data
*
* @param partIds parts to reset - if no parts are given, all parts will be reset.
*/
public void reset(String... partIds) {
nextBatchParts.clear();
if (partIds.length == 0) {
partIds = (String[]) cache.keySet().toArray();
}
for (int i = 0; i < partIds.length; i++) {
if (cache.remove(partIds[i]) == null) {
throw ManagedException.implementationError("cache item couldn't be removed!",
partIds[i],
cache.keySet());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy