Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

- FetcherEcho class

- More Task related updates
  • Loading branch information...
commit 1c07611879e89b786d26a2db69c1ec7dc8935857 1 parent d6093b8
@sushantk authored
Showing with 588 additions and 236 deletions.
  1. +1 −0  ants/.classpath
  2. +9 −0 ants/src/ants/Const.java
  3. +53 −0 ants/src/ants/FetcherEcho.java
  4. +36 −0 ants/src/ants/ModuleTask.java
  5. +30 −25 ants/src/ants/ObjectFactory.java
  6. +33 −0 ants/src/ants/ObjectStore.java
  7. +0 −23 ants/src/ants/ObjectTree.java
  8. +3 −3 ants/src/ants/ParamsDefault.java
  9. +2 −2 ants/src/ants/StringDefault.java
  10. +37 −30 ants/src/ants/TaskExecutor.java
  11. +5 −0 ants/src/ants/api/Configurable.java
  12. +6 −6 ants/src/ants/api/Data.java
  13. +7 −0 ants/src/ants/api/IFetcher.java
  14. +2 −2 ants/src/ants/api/IList.java
  15. +7 −0 ants/src/ants/api/IModule.java
  16. +11 −0 ants/src/ants/api/IObjectFactory.java
  17. +2 −2 ants/src/ants/api/IParams.java
  18. +2 −2 ants/src/ants/api/IString.java
  19. +49 −0 ants/src/ants/api/ModuleContext.java
  20. +10 −0 ants/src/ants/api/RequestContext.java
  21. +19 −0 ants/src/ants/api/SourceTask.java
  22. +61 −41 ants/src/ants/api/Task.java
  23. +21 −0 ants/src/ants/exception/EvaluateException.java
  24. +8 −0 ants/src/ants/exception/InvalidStateException.java
  25. +0 −21 ants/src/ants/exception/ObjectEvaluateException.java
  26. +0 −12 ants/src/ants/exception/ObjectParseException.java
  27. +12 −0 ants/src/ants/exception/ParseException.java
  28. +49 −0 ants/test/ants/test/FetcherEchoTest.java
  29. +20 −27 ants/test/ants/test/ObjectFactoryTest.java
  30. +29 −34 ants/test/ants/test/ParamsDefaultTest.java
  31. +0 −6 ants/test/ants/test/Util.java
  32. +12 −0 ants/test/ants/test/stub/TestExecuteContext.java
  33. +33 −0 ants/test/ants/test/stub/TestString.java
  34. +19 −0 ants/test/ants/test/stub/TestTaskExecutor.java
View
1  ants/.classpath
@@ -2,6 +2,7 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
+ <classpathentry kind="src" path="store"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="external/slf4j-api-1.7.1.jar"/>
<classpathentry kind="lib" path="external/slf4j-simple-1.7.1.jar"/>
View
9 ants/src/ants/Const.java
@@ -3,16 +3,25 @@
public final class Const {
public static class thefault {
+ public static final String ModuleClass = "ants.ModuleDefault";
public static final String StringClass = "ants.StringDefault";
public static final String ParamsClass = "ants.ParamsDefault";
}
+ public static class tag {
+ public static final String module = "module";
+ }
+
public static class attribute {
public static final String nodeId = "@id";
public static final String nodeClass = "@class";
public static final String name = "name";
}
+
+ public static class mime {
+ public static final String plain = "text/plain";
+ }
public static final String comma = ",";
View
53 ants/src/ants/FetcherEcho.java
@@ -0,0 +1,53 @@
+package ants;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ants.annotation.ConfigurableMethod;
+import ants.api.Configurable;
+import ants.api.Data;
+import ants.api.ExecuteContext;
+import ants.api.IFetcher;
+import ants.api.IString;
+import ants.api.Task;
+import ants.exception.EvaluateException;
+
+public class FetcherEcho extends Configurable
+ implements IFetcher {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(FetcherEcho.class);
+
+ private IString value;
+
+ public FetcherEcho(String tagName, String id) {
+ super(tagName, id);
+ }
+
+ @ConfigurableMethod(required=true)
+ public void setString(Configurable value) {
+ this.value = IString.class.cast(value);
+ }
+
+ /**
+ * In general fetchers will be sync_io or async_io. This is
+ * shown as an example.
+ */
+ @Override
+ public Task fetch(final ExecuteContext context) {
+ return new Task(Task.Type.SYNC_IO) {
+ protected Collection<Task> runImpl() {
+ try {
+ String str = FetcherEcho.this.value.getValue(context);
+ this.setData(new Data(str, Const.mime.plain), Task.Result.SUCCEDED);
+ } catch (EvaluateException e) {
+ logger.error(FetcherEcho.this.toContextString(context) + ": Failed to fetch data", e);
+ }
+ return Collections.emptyList();
+ }
+ };
+ }
+}
View
36 ants/src/ants/ModuleTask.java
@@ -0,0 +1,36 @@
+package ants;
+
+import java.util.LinkedHashMap;
+
+import ants.api.Context;
+import ants.api.IModule;
+import ants.api.IObjectFactory;
+import ants.api.IParams;
+import ants.api.ModuleContext;
+import ants.api.RequestContext;
+import ants.api.IParams.Type;
+import ants.api.Task;
+import ants.exception.ObjectConfigureException;
+import ants.exception.ParseException;
+
+public class ModuleTask extends Task {
+
+ ModuleContext context;
+
+ public ModuleTask(String iid, String moduleId,
+ LinkedHashMap<String, IParams.Type> params,
+ RequestContext requestContext, Context parent) {
+ super(Task.Type.CPU);
+
+ this.context = new ModuleContext(iid, moduleId, params, requestContext, parent);
+ }
+
+ @Override
+ public Iterable<Task> run() {
+ IObjectFactory factory = this.requestContext.getFactory();
+
+ IModule module = IModule.class.cast(factory.create(moduleId, Const.thefault.ModuleClass, Const.tag.module));
+ return null;
+ }
+
+}
View
55 ants/src/ants/ObjectFactory.java
@@ -19,7 +19,6 @@
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.MappingJsonFactory;
-import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,27 +26,32 @@
import ants.annotation.ConfigurableClass;
import ants.annotation.ConfigurableMethod;
import ants.api.Configurable;
+import ants.api.IObjectFactory;
import ants.exception.ObjectConfigureException;
import ants.exception.ObjectCreateException;
import ants.exception.ObjectIncompleteException;
-import ants.exception.ObjectParseException;
+import ants.exception.ParseException;
-public class ObjectFactory {
+public class ObjectFactory implements IObjectFactory {
- static final Logger logger = LoggerFactory.getLogger(ObjectFactory.class);
- static JsonFactory jsonMapper = new MappingJsonFactory();
- static JsonNodeFactory jsonFactory = JsonNodeFactory.instance;
+ private static final Logger logger = LoggerFactory.getLogger(ObjectFactory.class);
+ private static JsonFactory jsonMapper = new MappingJsonFactory();
- static int autoId = 0;
+ private static int autoId = 0;
+
+ @Override
+ public Configurable create(String id, String defaultClass, String tagName) throws ObjectConfigureException, ParseException {
+ return ObjectStore.getInstance(id, defaultClass, tagName);
+ }
/**
* parse a json string into an object tree.
*
- * @throws ObjectParseException
+ * @throws ParseException
*/
- public ObjectTree parse(String json) throws ObjectParseException {
+ public static JsonNode parse(String json) throws ParseException {
try {
- return this.parse(json,
+ return ObjectFactory.parse(json,
new ByteArrayInputStream(json.getBytes("utf-8")));
} catch (UnsupportedEncodingException ex) {
// ignored, we dont expect this with utf-8
@@ -58,20 +62,20 @@ public ObjectTree parse(String json) throws ObjectParseException {
/**
* parse a json stream into an object tree.
*
- * @throws ObjectParseException
+ * @throws ParseException
*/
- public ObjectTree parse(String identifier, InputStream json)
- throws ObjectParseException {
+ public static JsonNode parse(String identifier, InputStream json)
+ throws ParseException {
JsonNode node = null;
try {
JsonParser parser = jsonMapper.createJsonParser(json);
node = parser.readValueAsTree();
} catch (IOException ex) {
- throw new ObjectParseException("Failed to parse JSON: "
+ throw new ParseException("Failed to parse JSON: "
+ identifier, ex);
}
- return new ObjectTree(node);
+ return node;
}
/**
@@ -79,14 +83,14 @@ public ObjectTree parse(String identifier, InputStream json)
*
* @throws ObjectConfigureException
*/
- public Configurable configure(ObjectTree tree, String defaultClass,
+ public static Configurable configure(JsonNode tree, String defaultClass,
String tagName, String id, String defaultListItemClass,
String listItemTag) throws ObjectConfigureException {
Stack<String> tagStack = new Stack<String>();
Exception ex = null;
try {
- return this.configure(tree.getNode(), defaultClass, tagName,
+ return ObjectFactory.configure(tree, defaultClass, tagName,
id, defaultListItemClass, listItemTag, tagStack);
} catch (SecurityException e) {
ex = e;
@@ -117,7 +121,7 @@ public Configurable configure(ObjectTree tree, String defaultClass,
* Internal method to create and configure the object recursively with the
* given node
*/
- private Configurable configure(JsonNode node,
+ private static Configurable configure(JsonNode node,
String defaultClass, String tagName, String id,
String defaultListItemClass, String listItemTag,
Stack<String> tagStack)
@@ -137,9 +141,9 @@ private Configurable configure(JsonNode node,
Method method = klass.getMethod(Const.setValue, String.class);
method.invoke(object, node.asText());
} else if (node.isArray() || ((null != kannotation) && kannotation.expectsList())) {
- this.configureWithList(object, node, defaultListItemClass, listItemTag, tagStack);
+ ObjectFactory.configureWithList(object, node, defaultListItemClass, listItemTag, tagStack);
} else if (node.isObject()) {
- this.configureWithObjects(object, (ObjectNode) node, tagStack);
+ ObjectFactory.configureWithObjects(object, (ObjectNode) node, tagStack);
}
tagStack.pop();
@@ -150,7 +154,7 @@ private Configurable configure(JsonNode node,
* Internal method to configure the object recursively with the given node's
* children, treating them as child objects
*/
- private void configureWithObjects(Configurable object, ObjectNode node,
+ private static void configureWithObjects(Configurable object, ObjectNode node,
Stack<String> tagStack) throws ObjectCreateException,
ObjectIncompleteException, SecurityException,
IllegalArgumentException, NoSuchMethodException,
@@ -194,7 +198,7 @@ private void configureWithObjects(Configurable object, ObjectNode node,
listItemTag = mannotation.listItemTag();
}
- Configurable childObject = this.configure(childNode,
+ Configurable childObject = ObjectFactory.configure(childNode,
defaultClass, childTagName, "",
defaultListItemClass, listItemTag, tagStack);
method.invoke(object, childObject);
@@ -210,7 +214,7 @@ private void configureWithObjects(Configurable object, ObjectNode node,
* Internal method to configure the object recursively with the given node's
* children treating them as a list of child objects
*/
- private void configureWithList(Configurable object, JsonNode node,
+ private static void configureWithList(Configurable object, JsonNode node,
String defaultListItemClass, String listItemTag,
Stack<String> tagStack)
throws ObjectCreateException, ObjectIncompleteException,
@@ -235,7 +239,7 @@ private void configureWithList(Configurable object, JsonNode node,
if (node.isArray()) {
Iterator<JsonNode> it = node.getElements();
while (it.hasNext()) {
- Configurable childObject = this.configure(it.next(),
+ Configurable childObject = ObjectFactory.configure(it.next(),
defaultListItemClass, listItemTag, "", "", "", tagStack);
childList.put(childObject.getId(), childObject);
}
@@ -252,7 +256,7 @@ private void configureWithList(Configurable object, JsonNode node,
continue;
}
- Configurable childObject = this.configure(childNode,
+ Configurable childObject = ObjectFactory.configure(childNode,
defaultListItemClass, listItemTag, childId, "", "", tagStack);
childList.put(childObject.getId(), childObject);
}
@@ -329,4 +333,5 @@ private static Configurable create(JsonNode node, String defaultClass,
Object t = tc.newInstance(tagName, id);
return (Configurable) t;
}
+
}
View
33 ants/src/ants/ObjectStore.java
@@ -0,0 +1,33 @@
+package ants;
+
+import java.io.InputStream;
+
+import org.codehaus.jackson.JsonNode;
+
+import ants.api.Configurable;
+import ants.exception.ObjectConfigureException;
+import ants.exception.ParseException;
+
+public class ObjectStore {
+
+ // TODO: cache object instance
+ public static Configurable getInstance(String id, String defaultClass, String tagName) throws ObjectConfigureException, ParseException {
+ int idIndex = id.indexOf('.');
+ if(-1 == idIndex) {
+ throw new ParseException("Failed to extract object id " + " from " + id);
+ }
+
+ String jsonFile = id.substring(0, idIndex) + ".json";
+ String oid = id.substring(idIndex + 1);
+
+ InputStream is = ObjectStore.class.getResourceAsStream(jsonFile);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
+ JsonNode node = tree.get(oid);
+ if(null == node) {
+ throw new ParseException("Failed to locate " + oid + " in " + jsonFile);
+ }
+
+ return ObjectFactory.configure(node, defaultClass, tagName, oid, "", "");
+ }
+
+}
View
23 ants/src/ants/ObjectTree.java
@@ -1,23 +0,0 @@
-package ants;
-
-import org.codehaus.jackson.JsonNode;
-
-/**
- * Wrapper over jackson node class
- */
-public final class ObjectTree {
-
- private JsonNode node;
-
- public ObjectTree(JsonNode node) {
- this.node = node;
- }
-
- public JsonNode getNode() {
- return this.node;
- }
-
- public String toString() {
- return this.node.toString();
- }
-}
View
6 ants/src/ants/ParamsDefault.java
@@ -13,7 +13,7 @@
import ants.api.ExecuteContext;
import ants.api.IParams;
import ants.api.IString;
-import ants.exception.ObjectEvaluateException;
+import ants.exception.EvaluateException;
/**
*
@@ -36,7 +36,7 @@ public void setList(LinkedHashMap<String, Configurable> params) {
@Override
public LinkedHashMap<String, Type> getPairs(ExecuteContext context,
- boolean simple) throws ObjectEvaluateException {
+ boolean simple) throws EvaluateException {
LinkedHashMap<String, Type> result = new LinkedHashMap<String, Type>();
Iterator<Entry<String, Configurable>> iter = this.params.entrySet().iterator();
@@ -68,7 +68,7 @@ public void setList(LinkedHashMap<String, Configurable> params) {
result.put(name, new Complex(iparams.getPairs(context, false)));
}
else {
- throw new ObjectEvaluateException("Invalid parameter type, string, list or map expected: " + name,
+ throw new EvaluateException("Invalid parameter type, string, list or map expected: " + name,
context, this);
}
}
View
4 ants/src/ants/StringDefault.java
@@ -14,11 +14,11 @@
implements IString {
private static final Logger logger = LoggerFactory.getLogger(StringDefault.class);
+ private String value;
+
public StringDefault(String tagName, String id) {
super(tagName, id);
}
-
- private String value;
@ConfigurableMethod(required=true)
public void setValue(String value) {
View
67 ants/src/ants/TaskExecutor.java
@@ -1,5 +1,6 @@
package ants;
+import java.util.Collection;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -12,9 +13,10 @@
/**
* Provides foundation for task execution
*/
-public class TaskExecutor implements Task.AsyncMonitor {
+public class TaskExecutor implements Task.Monitor {
- private static final Logger logger = LoggerFactory.getLogger(TaskExecutor.class);
+ private static final Logger logger = LoggerFactory
+ .getLogger(TaskExecutor.class);
private static ThreadPoolExecutor cpuTaskExecutor;
private static ThreadPoolExecutor syncIOTaskExecutor;
@@ -25,7 +27,7 @@
*/
public static void configure(int cpuTaskPoolSize, int syncIOTaskPoolSize) {
// cpu tasks have a fixed size pre-started thread pool with an unbounded
- // queue. it is recommended that the pool size be a little more than the
+ // queue. it is recommended that the pool size be a little more than the
// number of available cores in the system
ThreadPoolExecutor cpuTaskExecutor = new ThreadPoolExecutor(
cpuTaskPoolSize, cpuTaskPoolSize, 0, TimeUnit.MILLISECONDS,
@@ -51,16 +53,18 @@ public TaskExecutor(boolean logging) {
this.logging = logging;
}
- public void run(final Task task) {
- final TaskExecutor self = this;
+ public void queue(final Task task) {
+ logger.debug("Queue task: {}: ", task);
+
+ task.setMonitor(this);
+ final TaskExecutor self = this;
switch (task.getType()) {
case CPU: {
TaskExecutor.cpuTaskExecutor.submit(new Runnable() {
@Override
public void run() {
- Iterable<Task> next = task.run();
- self.complete(task, next);
+ self.run(task);
}
});
}
@@ -69,48 +73,51 @@ public void run() {
TaskExecutor.syncIOTaskExecutor.submit(new Runnable() {
@Override
public void run() {
- Iterable<Task> next = task.run();
- self.complete(task, next);
+ self.run(task);
}
});
}
break;
case ASYNC_IO: {
- task.setAsyncMonitor(this);
+ // async tasks don't need a managed thread pool, they should have
+ // their own pool as required
+ self.run(task);
}
break;
}
}
/**
- * @see ants.api.Task.AsyncMonitor#onAsyncDataReady(ants.api.Task)
+ * @see ants.api.Task.Monitor#onReady(ants.api.Task, Collection<Task> next)
*/
@Override
- public void onAsyncDataReady(final Task task) {
- // thread pool is not used to run the async io task, as it is already
- // done fetching data. it is supposedly going to advice for any further
- // activity via returned tasks
- Iterable<Task> next = task.run();
- this.complete(task, next);
+ public void onDone(Task task, Collection<Task> next) {
+ logger.trace("Task done: {}, next: ", task, next);
+ this.runNext(next);
}
/**
- * finalize the task after completing its run
+ * run a task and the set of tasks collected as a result
*/
- private void complete(Task task, Iterable<Task> nextTasks) {
- // run the new set of tasks returned by the completed task
- for (Task next : nextTasks) {
- this.run(next);
+ private void run(final Task task) {
+ logger.debug("Running task: {}: ", task);
+
+ try {
+ Collection<Task> next = task.run();
+ this.runNext(next);
+ } catch(Exception e) {
+ // Catching all exceptions for error reporting
+ logger.error("Failed to run task: " + task, e);
}
+ }
- // notify the callbacks and run the new set of tasks returned
- // by the callback
- Iterable<Task.Callback> callbacks = task.getCallbacks();
- for (Task.Callback callback : callbacks) {
- Iterable<Task> cbNextTasks = callback.onComplete(task);
- for (Task next : cbNextTasks) {
- this.run(next);
- }
+ /**
+ * Run a set of tasks returned as a result of previous activities
+ */
+ private void runNext(Collection<Task> next) {
+ for (Task task : next) {
+ this.queue(task);
}
}
+
}
View
5 ants/src/ants/api/Configurable.java
@@ -36,4 +36,9 @@ public String toTagString() {
return this.getTag() + "<" + this.getClass().getName() + ", "
+ this.getId() + ">";
}
+
+ public String toContextString(Context context) {
+ return context + "/" + this.toTagString();
+ }
+
}
View
12 ants/src/ants/api/Data.java
@@ -2,19 +2,19 @@
public class Data {
- private byte[] bytes;
+ private Object dataObject;
private String mimeType;
- public Data(byte[] bytes, String mimeType) {
- this.bytes = bytes;
+ public Data(Object dataObject, String mimeType) {
+ this.dataObject = dataObject;
this.mimeType = mimeType;
}
- byte[] getBytes() {
- return this.bytes;
+ public Object getObject() {
+ return this.dataObject;
}
- String getMimeType() {
+ public String getMimeType() {
return this.mimeType;
}
}
View
7 ants/src/ants/api/IFetcher.java
@@ -0,0 +1,7 @@
+package ants.api;
+
+public interface IFetcher {
+
+ Task fetch(ExecuteContext context);
+
+}
View
4 ants/src/ants/api/IList.java
@@ -2,10 +2,10 @@
import java.util.LinkedHashMap;
-import ants.exception.ObjectEvaluateException;
+import ants.exception.EvaluateException;
public interface IList {
LinkedHashMap<String, Configurable> getItems(ExecuteContext context)
- throws ObjectEvaluateException;
+ throws EvaluateException;
}
View
7 ants/src/ants/api/IModule.java
@@ -0,0 +1,7 @@
+package ants.api;
+
+public interface IModule {
+
+ Task execute(ModuleContext context);
+
+}
View
11 ants/src/ants/api/IObjectFactory.java
@@ -0,0 +1,11 @@
+package ants.api;
+
+import ants.exception.ObjectConfigureException;
+import ants.exception.ParseException;
+
+public interface IObjectFactory {
+
+ Configurable create(String id, String defaultClass, String tagName)
+ throws ObjectConfigureException, ParseException;
+
+}
View
4 ants/src/ants/api/IParams.java
@@ -4,7 +4,7 @@
import java.util.List;
import java.util.Map;
-import ants.exception.ObjectEvaluateException;
+import ants.exception.EvaluateException;
public interface IParams {
@@ -78,5 +78,5 @@ public String toString() {
}
LinkedHashMap<String, Type> getPairs(ExecuteContext context,
- boolean simple) throws ObjectEvaluateException;
+ boolean simple) throws EvaluateException;
}
View
4 ants/src/ants/api/IString.java
@@ -1,8 +1,8 @@
package ants.api;
-import ants.exception.ObjectEvaluateException;
+import ants.exception.EvaluateException;
public interface IString {
- String getValue(ExecuteContext context) throws ObjectEvaluateException;
+ String getValue(ExecuteContext context) throws EvaluateException;
}
View
49 ants/src/ants/api/ModuleContext.java
@@ -0,0 +1,49 @@
+package ants.api;
+
+import java.util.LinkedHashMap;
+
+import ants.api.IParams.Type;
+
+public class ModuleContext extends Context {
+ private boolean logging;
+
+ private RequestContext requestContext;
+
+ private String iid;
+ private String moduleId;
+
+ public ModuleContext(String iid, String moduleId,
+ LinkedHashMap<String, Type> params,
+ RequestContext requestContext, Context parent) {
+ super(parent, params);
+
+ this.requestContext = requestContext;
+
+ this.iid = iid;
+ this.moduleId = moduleId;
+
+ //TODO: Use request context to check filters
+ this.logging = true;
+ }
+
+ public RequestContext getRequestContext() {
+ return this.requestContext;
+ }
+
+ public String getInstanceId() {
+ return this.iid;
+ }
+
+ public String getModuleId() {
+ return this.moduleId;
+ }
+
+ public boolean isLogging() {
+ return this.logging;
+ }
+
+ public String toString() {
+ // TODO: chained and request
+ return "context<" + this.moduleId + ", " + this.iid + ">";
+ }
+}
View
10 ants/src/ants/api/RequestContext.java
@@ -5,11 +5,21 @@
import ants.api.IParams.Type;
public class RequestContext extends Context {
+
+ IObjectFactory factory;
public RequestContext(LinkedHashMap<String, Type> params) {
super(null, params);
}
+ public IObjectFactory getFactory() {
+ return this.factory;
+ }
+
+ public void setFactory(IObjectFactory factory) {
+ this.factory = factory;
+ }
+
public boolean isLogging() {
// TODO: use filters
return true;
View
19 ants/src/ants/api/SourceTask.java
@@ -0,0 +1,19 @@
+package ants.api;
+
+
+public class SourceTask extends Task {
+
+ private Context context;
+
+ public SourceTask(ModuleContext context) {
+ super(Task.Type.CPU);
+
+ this.context = context;
+ }
+
+ @Override
+ public Iterable<Task> run() {
+ return null;
+ }
+
+}
View
102 ants/src/ants/api/Task.java
@@ -1,14 +1,17 @@
package ants.api;
+import java.util.Collection;
import java.util.LinkedList;
+import ants.exception.InvalidStateException;
+
/**
* The most basic unit of activity
*/
public abstract class Task {
static public enum Status {
- DONE, NOT_DONE
+ NOT_RUN, RUNNING, DONE
}
static public enum Result {
@@ -20,23 +23,35 @@
}
/**
- * Callback to send the task completion notification to one
- * or more listeners.
+ * Used by the task manager to monitor task activity and run the next set of
+ * tasks of returned by the callbacks
+ */
+ public interface Monitor {
+ /**
+ * Notify the monitor when the task has finished fetching the data
+ */
+ void onDone(Task task, Collection<Task> next);
+ }
+
+ /**
+ * Callback to send the task completion notification to one or more
+ * listeners.
*/
public interface Callback {
/**
- * The listener can return one more tasks as a result to execute
- * after the callback
+ * The listener can return one more tasks as a result to execute after
+ * the callback
*/
- Iterable<Task> onComplete(Task task);
+ Collection<Task> onDone(Task task);
}
private Type type;
- private Status status = Status.NOT_DONE;
+ private Status status = Status.NOT_RUN;
private Result result = Result.FAILED;
private Data data;
private LinkedList<Callback> callbacks = new LinkedList<Callback>();
+ private Monitor monitor;
public Task(Type type) {
this.type = type;
@@ -58,55 +73,60 @@ public Data getData() {
return this.data;
}
- synchronized public void setData(Data data, Result result) {
- this.status = Status.DONE;
+ public void addCallback(Callback callback) {
+ this.callbacks.add(callback);
+ }
+
+ public void setData(Data data, Result result) throws InvalidStateException {
+ if (Status.RUNNING != this.status) {
+ throw new InvalidStateException("Task is not run yet: " + this);
+ }
this.data = data;
this.result = result;
+ this.status = Status.DONE;
- // let the monitor know that the async task has finished fetching
- if ((Type.ASYNC_IO == this.type) && (null != this.asyncMonitor)) {
- this.asyncMonitor.onAsyncDataReady(this);
- this.asyncMonitor = null;
- }
+ this.complete();
}
- public abstract Iterable<Task> run();
-
- public Iterable<Callback> getCallbacks() {
- return this.callbacks;
+ public void setMonitor(Monitor monitor) {
+ this.monitor = monitor;
}
- public void addCallback(Callback callback) {
- this.callbacks.add(callback);
- }
+ protected abstract Collection<Task> runImpl();
- public String toString() {
- return "Task<" + this.type + ">";
- }
+ public final Collection<Task> run() {
+ if (Status.NOT_RUN != this.status) {
+ throw new InvalidStateException("Task is already run: " + this);
+ }
- /**
- * Used by the task manager to monitor async task activity
- */
- public interface AsyncMonitor {
- /**
- * Notify the monitor when the async task has finished fetching
- * the data
- */
- void onAsyncDataReady(Task task);
+ this.status = Status.RUNNING;
+ Collection<Task> next = this.runImpl();
+
+ // If it is a sync task, not done and no further tasks are returned,
+ // it must have failed
+ if((Type.ASYNC_IO != this.type) && (Status.DONE != this.status) && (next.isEmpty())) {
+ this.setData(null, Result.FAILED);
+ }
+
+ return next;
}
- private AsyncMonitor asyncMonitor;
+ public String toString() {
+ return "<" + super.toString() + ", " + this.type + ">";
+ }
/**
- * if the data has already arrived, we will notify the monitor
- * right away, else save it for future notification in setData
+ * Notify callbacks, collect tasks and finally notify the monitor with the
+ * tasks collected from the callbacks
*/
- synchronized public void setAsyncMonitor(AsyncMonitor monitor) {
- if (Status.DONE == this.status) {
- monitor.onAsyncDataReady(this);
- } else {
- this.asyncMonitor = monitor;
+ private void complete() {
+ LinkedList<Task> nextTasks = new LinkedList<Task>();
+ for (Task.Callback callback : this.callbacks) {
+ Collection<Task> cbNextTasks = callback.onDone(this);
+ nextTasks.addAll(cbNextTasks);
}
+
+ this.monitor.onDone(this, nextTasks);
}
}
View
21 ants/src/ants/exception/EvaluateException.java
@@ -0,0 +1,21 @@
+package ants.exception;
+
+import ants.api.Configurable;
+import ants.api.Context;
+
+public class EvaluateException extends Exception {
+
+ Context context;
+ Configurable object;
+
+ public EvaluateException(String s, Context context, Configurable object) {
+ super(s);
+
+ this.context = context;
+ this.object = object;
+ }
+
+ public String toString() {
+ return object.toContextString(this.context) + ": " + this.getMessage();
+ }
+}
View
8 ants/src/ants/exception/InvalidStateException.java
@@ -0,0 +1,8 @@
+package ants.exception;
+
+public class InvalidStateException extends RuntimeException {
+
+ public InvalidStateException(String s) {
+ super(s);
+ }
+}
View
21 ants/src/ants/exception/ObjectEvaluateException.java
@@ -1,21 +0,0 @@
-package ants.exception;
-
-import ants.api.Configurable;
-import ants.api.Context;
-
-public class ObjectEvaluateException extends Exception {
-
- Context context;
- Configurable object;
-
- public ObjectEvaluateException(String s, Context context, Configurable object) {
- super(s);
-
- this.context = context;
- this.object = object;
- }
-
- public String toContextString() {
- return this.context + "/" + object.toTagString() + ": " + this.getMessage();
- }
-}
View
12 ants/src/ants/exception/ObjectParseException.java
@@ -1,12 +0,0 @@
-package ants.exception;
-
-public class ObjectParseException extends Exception {
-
- public ObjectParseException(String s) {
- super(s);
- }
-
- public ObjectParseException(String s, Throwable cause) {
- super(s, cause);
- }
-}
View
12 ants/src/ants/exception/ParseException.java
@@ -0,0 +1,12 @@
+package ants.exception;
+
+public class ParseException extends Exception {
+
+ public ParseException(String s) {
+ super(s);
+ }
+
+ public ParseException(String s, Throwable cause) {
+ super(s, cause);
+ }
+}
View
49 ants/test/ants/test/FetcherEchoTest.java
@@ -0,0 +1,49 @@
+package ants.test;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import ants.Const;
+import ants.FetcherEcho;
+import ants.api.Data;
+import ants.api.ExecuteContext;
+import ants.api.Task;
+import ants.test.stub.TestExecuteContext;
+import ants.test.stub.TestString;
+import ants.test.stub.TestTaskExecutor;
+
+public class FetcherEchoTest {
+
+ @Test
+ public void testSuccess() {
+ String testStr = "Hello World";
+
+ FetcherEcho fetcher = new FetcherEcho("fetcher", "");
+ fetcher.setString(new TestString(testStr, true));
+
+ ExecuteContext context = new TestExecuteContext();
+ Task task = fetcher.fetch(context);
+ task.setMonitor(new TestTaskExecutor());
+ task.run();
+
+ assertEquals("Task is done", Task.Status.DONE, task.getStatus());
+ assertEquals("Result is success", Task.Result.SUCCEDED, task.getResult());
+ Data data = task.getData();
+ assertEquals("Data mime type is plain", Const.mime.plain, data.getMimeType());
+ assertEquals("Data is as given", testStr, data.getObject());
+ }
+
+ @Test
+ public void testFail() {
+ FetcherEcho fetcher = new FetcherEcho("fetcher", "");
+ fetcher.setString(new TestString(null, false));
+
+ ExecuteContext context = new TestExecuteContext();
+ Task task = fetcher.fetch(context);
+ task.setMonitor(new TestTaskExecutor());
+ task.run();
+
+ assertEquals("Task is done", Task.Status.DONE, task.getStatus());
+ assertEquals("Result is failed", Task.Result.FAILED, task.getResult());
+ }
+}
View
47 ants/test/ants/test/ObjectFactoryTest.java
@@ -5,12 +5,11 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
+import org.codehaus.jackson.JsonNode;
import org.junit.Test;
-
import static org.junit.Assert.*;
import ants.ObjectFactory;
-import ants.ObjectTree;
import ants.ParamsDefault;
import ants.StringDefault;
import ants.annotation.ConfigurableClass;
@@ -19,34 +18,32 @@
import ants.exception.ObjectConfigureException;
import ants.exception.ObjectCreateException;
import ants.exception.ObjectIncompleteException;
-import ants.exception.ObjectParseException;
+import ants.exception.ParseException;
public class ObjectFactoryTest {
@Test
public void testParse() {
- ObjectFactory factory = new ObjectFactory();
-
boolean parseFailure = false;
try {
- factory.parse("??");
- } catch(ObjectParseException ex) {
+ ObjectFactory.parse("??");
+ } catch(ParseException ex) {
parseFailure = true;
}
assertTrue("Invalid json parsing", parseFailure);
parseFailure = false;
try {
- factory.parse("[]");
- } catch(ObjectParseException ex) {
+ ObjectFactory.parse("[]");
+ } catch(ParseException ex) {
parseFailure = true;
}
assertFalse("Non object json parsing", parseFailure);
parseFailure = false;
try {
- factory.parse("{}");
- } catch(ObjectParseException ex) {
+ ObjectFactory.parse("{}");
+ } catch(ParseException ex) {
parseFailure = true;
}
assertFalse("object json parsing", parseFailure);
@@ -156,13 +153,12 @@ public void setChildMap(Configurable map) {
}
@Test
- public void testChildren() throws ObjectParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
+ public void testChildren() throws ParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
String jsonFile = "data/ObjectFactory/childObjectTree.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- TestClass testObject = (TestClass)factory.configure(tree, TestClass.class.getName(), "test", "t1", "", "");
+ TestClass testObject = (TestClass)ObjectFactory.configure(tree, TestClass.class.getName(), "test", "t1", "", "");
assertEquals("Tag is populated", "test", testObject.getTag());
assertEquals("Id is populated", "t1", testObject.getId());
@@ -175,13 +171,12 @@ public void testChildren() throws ObjectParseException, ObjectCreateException, O
}
@Test
- public void testMissingChildren() throws ObjectParseException, ObjectCreateException, ObjectConfigureException {
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse("{}");
+ public void testMissingChildren() throws ParseException, ObjectCreateException, ObjectConfigureException {
+ JsonNode tree = ObjectFactory.parse("{}");
boolean incomplete = false;
try {
- factory.configure(tree, TestClass.class.getName(), "test", "t1", "", "");
+ ObjectFactory.configure(tree, TestClass.class.getName(), "test", "t1", "", "");
} catch (ObjectConfigureException e) {
incomplete = true;
}
@@ -189,13 +184,12 @@ public void testMissingChildren() throws ObjectParseException, ObjectCreateExcep
}
@Test
- public void testParamsArray() throws ObjectParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
+ public void testParamsArray() throws ParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
String jsonFile = "data/ObjectFactory/paramsArrayTree.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- TestList testList = (TestList)factory.configure(tree, TestList.class.getName(), "params", "", "", "child");
+ TestList testList = (TestList)ObjectFactory.configure(tree, TestList.class.getName(), "params", "", "", "child");
LinkedHashMap<String, Configurable> children = testList.getChildren();
assertEquals("Params have a list of children", 2, children.size());
@@ -212,13 +206,12 @@ public void testParamsArray() throws ObjectParseException, ObjectCreateException
}
@Test
- public void testParamsMap() throws ObjectParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
+ public void testParamsMap() throws ParseException, ObjectCreateException, ObjectConfigureException, ObjectIncompleteException {
String jsonFile = "data/ObjectFactory/paramsMapTree.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- TestParams testParams = (TestParams)factory.configure(tree, TestParams.class.getName(), "params", "", "", "testParam");
+ TestParams testParams = (TestParams)ObjectFactory.configure(tree, TestParams.class.getName(), "params", "", "", "testParam");
LinkedHashMap<String, Configurable> children = testParams.getChildren();
assertEquals("Params have a list of children", 2, children.size());
View
63 ants/test/ants/test/ParamsDefaultTest.java
@@ -6,29 +6,28 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
+import org.codehaus.jackson.JsonNode;
import org.junit.Test;
import ants.ObjectFactory;
-import ants.ObjectTree;
import ants.ParamsDefault;
-import ants.api.Context;
import ants.api.IParams.Type;
import ants.api.ExecuteContext;
import ants.exception.ObjectConfigureException;
-import ants.exception.ObjectEvaluateException;
-import ants.exception.ObjectParseException;
+import ants.exception.EvaluateException;
+import ants.exception.ParseException;
+import ants.test.stub.TestExecuteContext;
public class ParamsDefaultTest {
@Test
- public void testSimple() throws ObjectParseException, ObjectConfigureException, ObjectEvaluateException {
+ public void testSimple() throws ParseException, ObjectConfigureException, EvaluateException {
String jsonFile = "data/ParamsDefault/simple.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
LinkedHashMap<String, Type> result = params.getPairs(context, true);
assertEquals("Simple params size", 2, result.size());
assertEquals("Simple params name value", "v1", result.get("n1").getSimple());
@@ -36,14 +35,13 @@ public void testSimple() throws ObjectParseException, ObjectConfigureException,
}
@Test
- public void testSimpleOrder() throws ObjectParseException, ObjectConfigureException, ObjectEvaluateException {
+ public void testSimpleOrder() throws ParseException, ObjectConfigureException, EvaluateException {
String jsonFile = "data/ParamsDefault/simpleArray.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
LinkedHashMap<String, Type> result = params.getPairs(context, true);
assertEquals("Simple params size", 3, result.size());
@@ -59,18 +57,17 @@ public void testSimpleOrder() throws ObjectParseException, ObjectConfigureExcept
}
@Test
- public void testComplexAsSimple() throws ObjectParseException, ObjectConfigureException {
+ public void testComplexAsSimple() throws ParseException, ObjectConfigureException {
String jsonFile = "data/ParamsDefault/complex.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
boolean failed = false;
try {
params.getPairs(context, true);
- } catch(ObjectEvaluateException e) {
+ } catch(EvaluateException e) {
failed = true;
}
@@ -78,14 +75,13 @@ public void testComplexAsSimple() throws ObjectParseException, ObjectConfigureEx
}
@Test
- public void testComplex() throws ObjectParseException, ObjectConfigureException, ObjectEvaluateException {
+ public void testComplex() throws ParseException, ObjectConfigureException, EvaluateException {
String jsonFile = "data/ParamsDefault/complex.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
LinkedHashMap<String, Type> result = params.getPairs(context, false);
System.out.println(result);
@@ -100,14 +96,14 @@ public void testComplex() throws ObjectParseException, ObjectConfigureException,
}
@Test
- public void testMultiValue() throws ObjectParseException, ObjectConfigureException, ObjectEvaluateException {
+ public void testMultiValue() throws ParseException, ObjectConfigureException, EvaluateException {
String jsonFile = "data/ParamsDefault/multivalue.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
LinkedHashMap<String, Type> result = params.getPairs(context, false);
assertEquals("Simple params size", 1, result.size());
@@ -119,14 +115,13 @@ public void testMultiValue() throws ObjectParseException, ObjectConfigureExcepti
}
@Test
- public void testMultiValueArray() throws ObjectParseException, ObjectConfigureException, ObjectEvaluateException {
+ public void testMultiValueArray() throws ParseException, ObjectConfigureException, EvaluateException {
String jsonFile = "data/ParamsDefault/multivalueArray.json";
InputStream is = this.getClass().getResourceAsStream(jsonFile);
- ObjectFactory factory = new ObjectFactory();
- ObjectTree tree = factory.parse(jsonFile, is);
+ JsonNode tree = ObjectFactory.parse(jsonFile, is);
- ExecuteContext context = Util.createExecuteContext();
- ParamsDefault params = (ParamsDefault)factory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
+ ExecuteContext context = new TestExecuteContext();
+ ParamsDefault params = (ParamsDefault)ObjectFactory.configure(tree, ParamsDefault.class.getName(), "", "", "", "");
LinkedHashMap<String, Type> result = params.getPairs(context, false);
assertEquals("Simple params size", 1, result.size());
View
6 ants/test/ants/test/Util.java
@@ -5,10 +5,4 @@
import ants.api.RequestContext;
public class Util {
- public static ExecuteContext createExecuteContext() {
- return new ExecuteContext(
- new ModuleContext("test-instance", "test-module",
- null, new RequestContext(null), null), null);
- }
-
}
View
12 ants/test/ants/test/stub/TestExecuteContext.java
@@ -0,0 +1,12 @@
+package ants.test.stub;
+
+import ants.api.ExecuteContext;
+import ants.api.ModuleContext;
+import ants.api.RequestContext;
+
+public class TestExecuteContext extends ExecuteContext {
+ public TestExecuteContext() {
+ super(new ModuleContext("test-instance", "test-module",
+ null, new RequestContext(null), null), null);
+ }
+}
View
33 ants/test/ants/test/stub/TestString.java
@@ -0,0 +1,33 @@
+package ants.test.stub;
+
+import ants.api.Configurable;
+import ants.api.ExecuteContext;
+import ants.api.IString;
+import ants.exception.EvaluateException;
+
+public class TestString extends Configurable
+ implements IString {
+
+ private String value;
+ private boolean returnSuccess;
+
+ public TestString(String value, boolean returnSuccess) {
+ super("string", "");
+
+ this.value = value;
+ this.returnSuccess = returnSuccess;
+ }
+
+ @Override
+ public String getValue(ExecuteContext context) throws EvaluateException {
+ if(this.returnSuccess) {
+ return this.value;
+ }
+
+ throw new EvaluateException(this.value, context, this);
+ }
+
+ public String toString() {
+ return this.value;
+ }
+}
View
19 ants/test/ants/test/stub/TestTaskExecutor.java
@@ -0,0 +1,19 @@
+package ants.test.stub;
+
+import java.util.Collection;
+
+import ants.api.Task;
+
+public class TestTaskExecutor implements Task.Monitor {
+
+ private Collection<Task> next;
+
+ @Override
+ public void onDone(Task task, Collection<Task> next) {
+ this.next = next;
+ }
+
+ public Collection<Task> getNext() {
+ return next;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.