package org.Webgatherer.WorkflowExample.DataHolders;
import org.Webgatherer.WorkflowExample.Status.StatusIndicator;
import org.ardverk.collection.PatriciaTrie;
import org.ardverk.collection.StringKeyAnalyzer;
import org.ardverk.collection.Trie;
import java.util.*;
/**
* @author Rick Dane
*/
public class DataHolderImpl implements DataHolder {
private Map<String, ContainerBase> containerHolder = new HashMap<String, ContainerBase>();
private Trie<String, String> internalFinishedKeyTracker = new PatriciaTrie<String, String>(StringKeyAnalyzer.INSTANCE);
private Queue<String> finishedContainerKeys = new LinkedList<String>();
private Map<String, Integer> contentTypesMap = new HashMap<String, Integer>();
public boolean isFinishedContainerQueueEmpty() {
return finishedContainerKeys.isEmpty();
}
public ContainerBase pullFromFinishedContainerQueue() {
String finishedContainerKey = null;
if (!finishedContainerKeys.isEmpty()) {
finishedContainerKey = finishedContainerKeys.remove();
}
if (finishedContainerKey != null) {
return containerHolder.get(finishedContainerKey);
}
return null;
}
/**
* meant to be called before getContainerByIdentifier so calling code knows if it should even bother trying to retrieve object
*
* @param identifier
* @return
*/
public StatusIndicator checkIfContainerAvailable(String identifier) {
ContainerBase cb = containerHolder.get(identifier);
if (cb == null) {
return StatusIndicator.DOESNOTEXIST;
}
if (cb.isUnLocked()) {
return StatusIndicator.NOTAVAILABLE;
}
return StatusIndicator.AVAILABLE;
}
/**
* returns the instance of Container that matches the key, if none exists or the instance is locked, it returns null
*
* @param identifier
* @return
*/
public ContainerBase getContainerByIdentifier(String identifier) {
ContainerBase cb = containerHolder.get(identifier);
if (cb == null || cb.isUnLocked()) {
return null;
}
return cb;
}
public StatusIndicator createContainer(String identifier, int maxEntries, int maxAttempts) {
if (containerHolder.containsKey(identifier)) {
return StatusIndicator.ALREADYEXISTS;
}
//TODO, convert this to DI
ContainerBase cb = new ContainerBase(identifier, maxEntries, maxAttempts);
containerHolder.put(identifier, cb);
return StatusIndicator.SUCCESS;
}
public StatusIndicator addEntryToContainer(String identifier, String entry) {
ContainerBase cb = containerHolder.get(identifier);
if (cb == null) {
return StatusIndicator.DOESNOTEXIST;
}
if (cb.isUnLocked()) {
return StatusIndicator.NOTAVAILABLE;
}
StatusIndicator status = cb.addContent(entry);
if (status == StatusIndicator.JUSTUNLOCKED) {
finishedContainerKeys.add(identifier);
internalFinishedKeyTracker.put(identifier, null);
}
return StatusIndicator.SUCCESS;
}
public void incrementContainerAllowedAttempts(String identifier) {
ContainerBase cb = containerHolder.get(identifier);
StatusIndicator status = cb.incrementAttempts();
if (status == StatusIndicator.JUSTUNLOCKED) {
finishedContainerKeys.add(identifier);
internalFinishedKeyTracker.put(identifier, null);
}
}
/**
* This should only be called when the thread is ready to be destroyed (all pages have been visited), generally its good practice
* to make sure there has been a delay of at least a few seconds without any new pages coming into the workflow queue before calling this,
* it gives the remaining data to the workflow that never reached its max number of attempts
*
* @return
*/
public void destroyRetrieveFinalData() {
for (Map.Entry<String, ContainerBase> curEntry : containerHolder.entrySet()) {
String id = curEntry.getKey();
ContainerBase cb = curEntry.getValue();
if (!internalFinishedKeyTracker.containsKey(id)) {
cb.forceUnlock();
finishedContainerKeys.add(id);
internalFinishedKeyTracker.put(id, null);
}
}
}
}