play.data.binding.ParamNode Maven / Gradle / Ivy
package play.data.binding;
import play.utils.Utils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ParamNode {
private final String name;
private final Map _children = new HashMap(8);
private String[] values = null;
private String originalKey;
// splits a string on one-ore-more instances of .[]
// this works so that all the following strings (param naming syntaxes)
// is resolved into the same structural hierarchy:
// a.b.c=12
// a[b].c=12
// a[b][c]=12
// a.b[c]=12
private final static String keyPartDelimiterRegexpString = "[\\.\\[\\]]+";
public ParamNode(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String[] getValues() {
return values;
}
public String getFirstValue(Class> type) {
if (values == null) {
return null;
}
if (values.length>1 && String.class.equals(type)) {
// special handling for string - when multiple values, concatenate them with comma..
return Utils.join(values, ", ");
} else {
return values[0];
}
}
public void addChild( ParamNode child) {
_children.put(child.name, child);
}
public ParamNode getChild(String name) {
return getChild( name, false);
}
public ParamNode getChild(String name, boolean returnEmptyChildIfNotFound) {
ParamNode child = getChild( name.split(keyPartDelimiterRegexpString));
if (child == null && returnEmptyChildIfNotFound) {
child = new ParamNode(name);
}
return child;
}
public static class RemovedNode {
public final ParamNode removedFrom;
public final ParamNode removedNode;
public RemovedNode(ParamNode removedFrom, ParamNode removedNode) {
this.removedFrom = removedFrom;
this.removedNode = removedNode;
}
}
/**
* Removes a child from this node, but stores what is removed to list.
* The we can later call which will add it back again.
* This is a "hack" related to #1195 which makes it possible to reuse the RootParamsNode-structure
* if you want to perform the bind-operation multiple times.
*
* @param name the name of the child-node in this paramNode which should be removed.
* @param removedNodesList a list where info about what is removed where is stored.
* @return true if anything was removed.
*/
public boolean removeChild(String name, List removedNodesList) {
ParamNode removedNode = _children.remove(name);
if ( removedNode != null) {
removedNodesList.add( new RemovedNode(this, removedNode));
return true;
} else {
return false;
}
}
public static void restoreRemovedChildren( List removedNodesList ) {
for ( RemovedNode rn : removedNodesList) {
rn.removedFrom._children.put( rn.removedNode.name, rn.removedNode);
}
}
private ParamNode getChild(String[] nestedNames) {
ParamNode currentChildNode = this;
for (int i=0; i getAllChildren() {
return _children.values();
}
public Set getAllChildrenKeys() {
return _children.keySet();
}
public void setValue(String[] value, String originalKey) {
this.values = value;
this.originalKey = originalKey;
}
public String getOriginalKey() {
if (originalKey==null) {
return name;
}
return originalKey;
}
public static RootParamNode convert(Map params) {
RootParamNode root = new RootParamNode( params);
for (Map.Entry e : params.entrySet()) {
String key = e.getKey();
String[] values = e.getValue();
if (values != null && values.length == 0) {
values = null;
}
ParamNode currentParent = root;
for ( String name : key.split(keyPartDelimiterRegexpString)) {
ParamNode paramNode = currentParent.getChild( name );
if (paramNode ==null) {
// first time we see this node - create it and add it to parent
paramNode = new ParamNode(name);
currentParent.addChild(paramNode);
}
currentParent = paramNode;
}
// currentParent is now the last node where we should place the values
currentParent.setValue( values, key);
}
return root;
}
}