Skip to content

Commit

Permalink
- ParamsDefault implementation and test
Browse files Browse the repository at this point in the history
  • Loading branch information
sushantk committed Oct 6, 2012
1 parent b166bea commit 1ce77d6
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 181 deletions.
6 changes: 4 additions & 2 deletions ants/src/ants/Const.java
Expand Up @@ -8,8 +8,10 @@ public static class thefault {
}

public static class attribute {
public static final String id = "@id";
public static final String klass = "@class";
public static final String nodeId = "@id";
public static final String nodeClass = "@class";

public static final String name = "name";
}

public static final String comma = ",";
Expand Down
111 changes: 60 additions & 51 deletions ants/src/ants/ObjectFactory.java
Expand Up @@ -10,7 +10,6 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.HashSet;
import java.util.Set;
Expand All @@ -27,7 +26,7 @@

import ants.annotation.ConfigurableClass;
import ants.annotation.ConfigurableMethod;
import ants.api.IConfigurable;
import ants.api.Configurable;
import ants.exception.ObjectConfigureException;
import ants.exception.ObjectCreateException;
import ants.exception.ObjectIncompleteException;
Expand Down Expand Up @@ -80,7 +79,7 @@ public ObjectTree parse(String identifier, InputStream json)
*
* @throws ObjectConfigureException
*/
public IConfigurable configure(ObjectTree tree, String defaultClass,
public Configurable configure(ObjectTree tree, String defaultClass,
String tagName, String id, String defaultListItemClass,
String listItemTag) throws ObjectConfigureException {
Stack<String> tagStack = new Stack<String>();
Expand Down Expand Up @@ -118,7 +117,7 @@ public IConfigurable configure(ObjectTree tree, String defaultClass,
* Internal method to create and configure the object recursively with the
* given node
*/
private IConfigurable configure(JsonNode node,
private Configurable configure(JsonNode node,
String defaultClass, String tagName, String id,
String defaultListItemClass, String listItemTag,
Stack<String> tagStack)
Expand All @@ -127,9 +126,9 @@ private IConfigurable configure(JsonNode node,
IllegalAccessException, InvocationTargetException,
ClassNotFoundException, InstantiationException {

IConfigurable object = ObjectFactory.create(node, defaultClass,
Configurable object = ObjectFactory.create(node, defaultClass,
tagName, id);
tagStack.push(ObjectFactory.toString(object));
tagStack.push(object.toTagString());

logger.debug("Configuring node: {}", tagStack.peek());
Class<?> klass = object.getClass();
Expand All @@ -151,7 +150,7 @@ private IConfigurable configure(JsonNode node,
* Internal method to configure the object recursively with the given node's
* children, treating them as child objects
*/
private void configureWithObjects(IConfigurable object, ObjectNode node,
private void configureWithObjects(Configurable object, ObjectNode node,
Stack<String> tagStack) throws ObjectCreateException,
ObjectIncompleteException, SecurityException,
IllegalArgumentException, NoSuchMethodException,
Expand All @@ -160,36 +159,47 @@ private void configureWithObjects(IConfigurable object, ObjectNode node,
HashSet<String> setMethods = new HashSet<String>();

Class<?> klass = object.getClass();
ConfigurableClass kannotation = klass.getAnnotation(ConfigurableClass.class);
boolean expectsValue = (null == kannotation ? false : kannotation.expectsValue());
Iterator<Entry<String, JsonNode>> it = node.getFields();
while (it.hasNext()) {
Entry<String, JsonNode> entry = it.next();
String childTagName = entry.getKey();
JsonNode childNode = entry.getValue();

// attributes
if (childTagName.startsWith("@")) {
continue; // attributes
// TODO: set attribute on parent
object.setAttribute(childTagName.substring(1), childNode.asText());
continue;
}

String setMethodName = Const.set
+ childTagName.substring(0, 1).toUpperCase()
+ childTagName.substring(1);
Method method = klass.getMethod(setMethodName, IConfigurable.class);
ConfigurableMethod annotation = method
Method method;
if(expectsValue) {
method = klass.getMethod(setMethodName, String.class);
method.invoke(object, childNode.asText());
} else {
method = klass.getMethod(setMethodName, Configurable.class);
ConfigurableMethod mannotation = method
.getAnnotation(ConfigurableMethod.class);

String defaultClass = "";
String defaultListItemClass = "";
String listItemTag = "";
if(null != annotation) {
defaultClass = annotation.defaultClass();
defaultListItemClass = annotation.defaultListItemClass();
listItemTag = annotation.listItemTag();
String defaultClass = "";
String defaultListItemClass = "";
String listItemTag = "";
if(null != mannotation) {
defaultClass = mannotation.defaultClass();
defaultListItemClass = mannotation.defaultListItemClass();
listItemTag = mannotation.listItemTag();
}

Configurable childObject = this.configure(childNode,
defaultClass, childTagName, "",
defaultListItemClass, listItemTag, tagStack);
method.invoke(object, childObject);
}

IConfigurable childObject = this.configure(entry.getValue(),
defaultClass, childTagName, "",
defaultListItemClass, listItemTag, tagStack);
method.invoke(object, childObject);

setMethods.add(setMethodName);
}

Expand All @@ -200,7 +210,7 @@ private void configureWithObjects(IConfigurable 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(IConfigurable object, JsonNode node,
private void configureWithList(Configurable object, JsonNode node,
String defaultListItemClass, String listItemTag,
Stack<String> tagStack)
throws ObjectCreateException, ObjectIncompleteException,
Expand All @@ -209,18 +219,23 @@ private void configureWithList(IConfigurable object, JsonNode node,
ClassNotFoundException, InstantiationException {
Class<?> klass = object.getClass();
Method method = klass.getMethod(Const.setList, LinkedHashMap.class);
ConfigurableMethod annotation = method
.getAnnotation(ConfigurableMethod.class);

if(listItemTag.isEmpty()) {
listItemTag = annotation.listItemTag();
ConfigurableMethod mannotation = method
.getAnnotation(ConfigurableMethod.class);
if(null != mannotation) {
if(listItemTag.isEmpty()) {
listItemTag = mannotation.listItemTag();
}
if(defaultListItemClass.isEmpty()) {
defaultListItemClass = mannotation.defaultListItemClass();
}
}

LinkedHashMap<String, IConfigurable> childList = new LinkedHashMap<String, IConfigurable>();
LinkedHashMap<String, Configurable> childList = new LinkedHashMap<String, Configurable>();
if (node.isArray()) {
Iterator<JsonNode> it = node.getElements();
while (it.hasNext()) {
IConfigurable childObject = this.configure(it.next(),
Configurable childObject = this.configure(it.next(),
defaultListItemClass, listItemTag, "", "", "", tagStack);
childList.put(childObject.getId(), childObject);
}
Expand All @@ -229,12 +244,15 @@ private void configureWithList(IConfigurable object, JsonNode node,
while (it.hasNext()) {
Entry<String, JsonNode> entry = it.next();
String childId = entry.getKey();
JsonNode childNode = entry.getValue();

// attributes
if (childId.startsWith("@")) {
continue; // attribute of the parent object
// TODO: set it on parent
object.setAttribute(childId.substring(1), childNode.asText());
continue;
}

IConfigurable childObject = this.configure(entry.getValue(),
Configurable childObject = this.configure(childNode,
defaultListItemClass, listItemTag, childId, "", "", tagStack);
childList.put(childObject.getId(), childObject);
}
Expand All @@ -247,18 +265,18 @@ private void configureWithList(IConfigurable object, JsonNode node,
* Verifies if all required parameters are set on an object after it is
* configured
*/
private static void verify(IConfigurable object, Set<String> setMethods)
private static void verify(Configurable object, Set<String> setMethods)
throws ObjectIncompleteException {
ArrayList<String> missingParams = new ArrayList<String>();

Class<?> klass = object.getClass();
Method[] methods = klass.getMethods();
for (Method method : methods) {
ConfigurableMethod annotation = method
ConfigurableMethod mannotation = method
.getAnnotation(ConfigurableMethod.class);
if (null != annotation) {
if (null != mannotation) {
String methodName = method.getName();
boolean required = annotation.required();
boolean required = mannotation.required();
if (required && !setMethods.contains(methodName)) {
missingParams.add(methodName.substring(3).toLowerCase());
}
Expand All @@ -273,17 +291,17 @@ private static void verify(IConfigurable object, Set<String> setMethods)
}

/**
* instantiate an IConfigurable object using the class name specified in the
* instantiate an Configurable object using the class name specified in the
* JsonNode or the provided default class name.
*/
private static IConfigurable create(JsonNode node, String defaultClass,
private static Configurable create(JsonNode node, String defaultClass,
String tagName, String id) throws ObjectCreateException,
ClassNotFoundException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException {
String className = defaultClass;
if (node.isObject()) {
JsonNode classNode = node.get(Const.attribute.klass);
JsonNode classNode = node.get(Const.attribute.nodeClass);
if (null != classNode) {
className = classNode.asText();
}
Expand All @@ -297,7 +315,7 @@ private static IConfigurable create(JsonNode node, String defaultClass,
}

if (id.isEmpty()) {
JsonNode idNode = node.get(Const.attribute.id);
JsonNode idNode = node.get(Const.attribute.nodeId);
if (null != idNode) {
id = idNode.asText();
}
Expand All @@ -309,15 +327,6 @@ private static IConfigurable create(JsonNode node, String defaultClass,
Class<?> klass = Class.forName(className);
Constructor<?> tc = klass.getConstructor(String.class, String.class);
Object t = tc.newInstance(tagName, id);
return (IConfigurable) t;
}

/**
* return a string representation of an IConfigurable object for debugging
*/
private static String toString(IConfigurable object) {
return object.getTag() + "<" + object.getClass().getName() + ", "
+ object.getId() + ">";
return (Configurable) t;
}

}
82 changes: 82 additions & 0 deletions ants/src/ants/ParamsDefault.java
@@ -0,0 +1,82 @@
package ants;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ants.annotation.ConfigurableClass;
import ants.annotation.ConfigurableMethod;
import ants.api.Configurable;
import ants.api.Context;
import ants.api.IParams;
import ants.api.IString;
import ants.exception.ObjectEvaluateException;

/**
*
*/
@ConfigurableClass(expectsList=true)
public class ParamsDefault extends Configurable
implements IParams {
static final Logger logger = LoggerFactory.getLogger(ParamsDefault.class);

LinkedHashMap<String, Configurable> params;

public ParamsDefault(String tagName, String id) {
super(tagName, id);
}

@ConfigurableMethod(required=true, defaultListItemClass="ants.StringDefault", listItemTag="param")
public void setList(LinkedHashMap<String, Configurable> params) {
this.params = params;
}

@Override
public LinkedHashMap<String, SimpleOrComplex> getPairs(Context context,
boolean simple) throws ObjectEvaluateException {
LinkedHashMap<String, SimpleOrComplex> result = new LinkedHashMap<String, SimpleOrComplex>();

Iterator<Entry<String, Configurable>> iter = this.params.entrySet().iterator();
while(iter.hasNext()) {
Entry<String, Configurable> entry = iter.next();
Configurable configurable = entry.getValue();

String name = configurable.getAttribute(Const.attribute.name);
if(null == name) {
name = entry.getKey();
}

if(configurable instanceof IString) {
IString istring = (IString)configurable;
String string = istring.getValue(context);
if(simple) {
result.put(name, new Simple(string));
} else {
SimpleOrComplex value = result.get(name);
if(null == value) {
value = new Complex(new LinkedHashMap<String, SimpleOrComplex>());
result.put(name, value);
}
value.getComplex().put(configurable.getId(), new Simple(string));
}

} else if(!simple && (configurable instanceof IParams)) {
IParams iparams = (IParams)configurable;
result.put(name, new Complex(iparams.getPairs(context, false)));
}
else {
throw new ObjectEvaluateException("Invalid parameter type, string, list or map expected: " + name,
context, this);
}
}

return result;
}

public String toString() {
return this.params.toString();
}
}
6 changes: 6 additions & 0 deletions ants/src/ants/StringDefault.java
Expand Up @@ -3,11 +3,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ants.annotation.ConfigurableClass;
import ants.annotation.ConfigurableMethod;
import ants.api.Configurable;
import ants.api.Context;
import ants.api.IString;

@ConfigurableClass(expectsValue=true)
public class StringDefault extends Configurable
implements IString {
static final Logger logger = LoggerFactory.getLogger(StringDefault.class);
Expand All @@ -33,4 +35,8 @@ public static String evaluate(Context context, String text) {
if(context.isLogging()) logger.debug("{} - Evaluated {}=>{}", new Object[]{context, text, evaledText});
return evaledText;
}

public String toString() {
return this.value;
}
}
8 changes: 7 additions & 1 deletion ants/src/ants/StringLiteral.java
@@ -1,10 +1,12 @@
package ants;

import ants.annotation.ConfigurableClass;
import ants.annotation.ConfigurableMethod;
import ants.api.Configurable;
import ants.api.Context;
import ants.api.IString;

@ConfigurableClass(expectsValue=true)
public class StringLiteral extends Configurable
implements IString {

Expand All @@ -22,5 +24,9 @@ public void setValue(String value) {
@Override
public String getValue(Context context) {
return this.value;
}
}

public String toString() {
return this.value;
}
}
1 change: 1 addition & 0 deletions ants/src/ants/annotation/ConfigurableClass.java
Expand Up @@ -6,4 +6,5 @@
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigurableClass {
boolean expectsList() default false;
boolean expectsValue() default false;
}

0 comments on commit 1ce77d6

Please sign in to comment.