package org.radargun.config;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Definition for more complex arguments:
*
* <my-stage>
* <my-property another-attribute="xxx">yyy</my-property>
* </my-stage>
*
* That should be also equivalent to:
*
* <my-stage>
* <my-property>
* <another-attribute>xxx</another-attribute>
* yyy
* </my-property>
* </my-stage>
*
* Definitions can even nest:
*
* <my-stage>
* <my-property>
* <foo bar="baz">goo</foo>
* <moo>oom</moo>
* </my-property>
* </my-stage>
*/
public class ComplexDefinition implements Definition {
private List<Entry> attributes;
private String namespace;
/**
* Definition can use multiple entries with same name - {@link ComplexConverter} should handle that.
* @return
*/
public List<Entry> getAttributes() {
return attributes == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(attributes);
}
/**
* When using {@link PropertyHelper#setPropertiesFromDefinitions(Object, java.util.Map, boolean, boolean)}
* we don't allow duplicate entry names.
* Due to the way templates are merged, we just overwrite the value in the map by the last entry.
* @return
*/
public Map<String, Definition> getAttributeMap() {
if (attributes == null) return Collections.EMPTY_MAP;
Map<String, Definition> map = new HashMap<String, Definition>();
for (Entry entry : attributes) {
map.put(entry.name, entry.definition);
}
return map;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (attributes != null) {
boolean first = true;
for (Entry entry : attributes) {
if (!first) sb.append(", ");
first = false;
sb.append(entry.name.isEmpty() ? "<value>" : entry.name).append("=");
if (entry.definition instanceof SimpleDefinition) {
sb.append(entry.definition);
} else {
sb.append('[').append(entry.definition).append(']');
}
}
}
return sb.toString();
}
public void add(String attribute, Definition definition) {
if (attributes == null) attributes = new ArrayList<Entry>();
attributes.add(new Entry(attribute, definition));
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getNamespace() {
return namespace;
}
@Override
public Definition apply(Definition other) {
if (other instanceof ComplexDefinition) {
ComplexDefinition cd = (ComplexDefinition) other;
if (!Objects.equals(namespace, cd.namespace)) {
throw new IllegalArgumentException("Namespace for overwritten definition does not match: " + namespace + " vs. " + cd.namespace);
}
ComplexDefinition nd = new ComplexDefinition();
nd.namespace = this.namespace;
nd.attributes = new ArrayList<>(this.attributes);
nd.attributes.addAll(cd.attributes);
return nd;
} else {
return other;
}
}
public static class Entry implements Serializable {
public final String name;
public final Definition definition;
public Entry(String name, Definition definition) {
this.name = name;
this.definition = definition;
}
}
}