modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java | 247 +++++++++- modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java | 237 +++++++++ 2 files changed, 481 insertions(+), 3 deletions(-)
New commits: commit 46ae96d60f17d0215185c0f79b8e004bdbc9c1ee Author: Lukas Krejci lkrejci@redhat.com Date: Thu May 23 11:03:31 2013 +0200
Trivial: javadoc clean up.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java index 13b1e32..4dae88a 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java @@ -850,10 +850,9 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM * * @return a clone of this configuration * - * @throws CloneNotSupportedException - * * @see #deepCopy() */ + @SuppressWarnings("override") //@Override //GWT trips over this, WTH! public Configuration clone() { return deepCopy(); @@ -1002,7 +1001,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM /** * Getter for the properties reference. * - * @return Map<String, Property> + * @return {@code Map<String, Property>} */ public Map<String, Property> getAllProperties() { return this.properties;
commit b415c386059131057d91060a3bebef41699fcb3d Author: Lukas Krejci lkrejci@redhat.com Date: Thu May 23 10:46:16 2013 +0200
Added missing generic type decls.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java index b006425..13b1e32 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java @@ -271,7 +271,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM } }
- public static class MapInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> { + public static class MapInList<Parent extends AbstractPropertyListBuilder<?>> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> { private Parent parent;
public MapInList(Parent parent, String name) { @@ -307,7 +307,7 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM } }
- public static class ListInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyListBuilder<ListInList<Parent>> { + public static class ListInList<Parent extends AbstractPropertyListBuilder<?>> extends AbstractPropertyListBuilder<ListInList<Parent>> { private Parent parent;
private ListInList(Parent parent, String name, String memberName) {
commit abbbf13986af10b65cf812ce9b0a2a49c297934a Author: Lukas Krejci lkrejci@redhat.com Date: Wed May 22 19:24:00 2013 +0200
A configuration instance builder. This should greatly simplify the process of creating complex configuration objects.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java index b1e6e22..b006425 100644 --- a/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/configuration/Configuration.java @@ -143,6 +143,244 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM public static final String QUERY_DELETE_RAW_CONFIGURATIONS_CONFIGURATION_IDS = "Configuration.deleteRawByConfigurationIds"; public static final String QUERY_DELETE_CONFIGURATIONS_BY_CONFIGURATION_IDs = "Configuration.deleteByConfigurationIdS";
+ private static abstract class AbstractPropertyMapBuilder<T extends AbstractPropertyMap, This extends AbstractPropertyMapBuilder<T, This>> { + private T map; + + protected AbstractPropertyMapBuilder(T map) { + this.map = map; + } + + /** + * Adds a simple property. + * @param name the name of the simple property + * @param value the value of the simple property + * @return continue with the definition + */ + public This addSimple(String name, Object value) { + getMap().put(new PropertySimple(name, value)); + return castThis(); + } + + /** + * Starts defining a new sub list. + * @param name the name of the sub list + * @param memberName the names of the member properties of the sub list + * @return the builder of the list + */ + public Builder.ListInMap<This> openList(String name, String memberName) { + return new Builder.ListInMap<This>(castThis(), name, memberName); + } + + /** + * Starts defining a new sub map. + * @param name the name of the sub map + * @return the builder of the map + */ + public Builder.MapInMap<This> openMap(String name) { + return new Builder.MapInMap<This>(castThis(), name); + } + + protected T getMap() { + return map; + } + + @SuppressWarnings("unchecked") + private This castThis() { + return (This) this; + } + } + + private static abstract class AbstractPropertyListBuilder<This extends AbstractPropertyListBuilder<This>> { + private PropertyList list; + + private AbstractPropertyListBuilder(String name, String memberName) { + this.list = new PropertyList(name); + this.list.memberPropertyName = memberName; + } + + /** + * Adds a simple property. The name of the property is the member name defined by this list. + * @param value the value of the simple property + * @return continue with the definition + */ + public This addSimple(Object value) { + list.add(new PropertySimple(list.memberPropertyName, value)); + return castThis(); + } + + /** + * Adds a number of simple properties. The names of the properties are the member name defined by this list. + * @param values the values of the simple properties + * @return continue with the definition + */ + public This addSimples(Object... values) { + for(Object v : values) { + list.add(new PropertySimple(list.memberPropertyName, v)); + } + + return castThis(); + } + + /** + * Starts defining a new sub map. + * @return the builder of the map + */ + public Builder.MapInList<This> openMap() { + return new Builder.MapInList<This>(castThis(), list.memberPropertyName); + } + + /** + * Starts defining a new sub list. + * @param memberName the names of the member properties of the sub list + * @return the builder of the list + */ + public Builder.ListInList<This> openList(String memberName) { + return new Builder.ListInList<This>(castThis(), list.memberPropertyName, memberName); + } + + protected PropertyList getList() { + return list; + } + + @SuppressWarnings("unchecked") + private This castThis() { + return (This) this; + } + } + + /** + * A builder to easily build Configuration instances using a fluent API. + */ + public static class Builder extends AbstractPropertyMapBuilder<Configuration, Builder> { + + public static class MapInMap<Parent extends AbstractPropertyMapBuilder<?, ?>> extends AbstractPropertyMapBuilder<PropertyMap, MapInMap<Parent>> { + private Parent parent; + + private MapInMap(Parent parent, String name) { + super(new PropertyMap(name)); + this.parent = parent; + } + + /** + * Closes the definition of the current map and returns to the parent context. + * @return the parent context + */ + public Parent closeMap() { + parent.getMap().put(getMap()); + return parent; + } + } + + public static class MapInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyMapBuilder<PropertyMap, MapInList<Parent>> { + private Parent parent; + + public MapInList(Parent parent, String name) { + super(new PropertyMap(name)); + this.parent = parent; + } + + /** + * Closes the definition of the current map and returns to the parent context. + * @return the parent context + */ + public Parent closeMap() { + parent.getList().add(getMap()); + return parent; + } + } + + public static class ListInMap<Parent extends AbstractPropertyMapBuilder<?, ?>> extends AbstractPropertyListBuilder<ListInMap<Parent>> { + private Parent parent; + + private ListInMap(Parent parent, String name, String memberName) { + super(name, memberName); + this.parent = parent; + } + + /** + * Closes the definition of the current list and returns to the parent context. + * @return the parent context + */ + public Parent closeList() { + parent.getMap().put(getList()); + return parent; + } + } + + public static class ListInList<Parent extends AbstractPropertyListBuilder> extends AbstractPropertyListBuilder<ListInList<Parent>> { + private Parent parent; + + private ListInList(Parent parent, String name, String memberName) { + super(name, memberName); + this.parent = parent; + } + + /** + * Closes the definition of the current list and returns to the parent context. + * @return the parent context + */ + public Parent closeList() { + parent.getList().add(getList()); + return parent; + } + } + + public class RawConfigurationBuilder { + + private RawConfiguration rawConfig; + + public RawConfigurationBuilder() { + rawConfig = new RawConfiguration(); + rawConfig.setConfiguration(getMap()); + } + + public RawConfigurationBuilder withPath(String path) { + rawConfig.setPath(path); + return this; + } + + public RawConfigurationBuilder withContents(String content, String sha256) { + rawConfig.setContents(content, sha256); + return this; + } + + /** + * Closes the definition of the current raw configuration and returns to the parent context. + * @return the parent context + */ + public Builder closeRawConfiguration() { + getMap().getRawConfigurations().add(rawConfig); + return Builder.this; + } + } + + public Builder() { + super(new Configuration()); + } + + public Builder withNotes(String notes) { + getMap().setNotes(notes); + return this; + } + + public Builder withVersion(long version) { + getMap().setVersion(version); + return this; + } + + /** + * Starts defining a new raw configuration that will become part of this configuration. + * @return the builder of the raw configuration + */ + public RawConfigurationBuilder openRawConfiguration() { + return new RawConfigurationBuilder(); + } + + public Configuration build() { + return getMap(); + } + } + @GeneratedValue(generator = "RHQ_CONFIG_ID_SEQ", strategy = GenerationType.AUTO) @Id private int id; @@ -283,6 +521,10 @@ public class Configuration implements Serializable, Cloneable, AbstractPropertyM @Column(name = "MTIME") private long mtime = System.currentTimeMillis();
+ public static Builder builder() { + return new Builder(); + } + public Configuration() { }
diff --git a/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java b/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java new file mode 100644 index 0000000..ad071ee --- /dev/null +++ b/modules/core/domain/src/test/java/org/rhq/core/domain/configuration/ConfigurationBuilderTest.java @@ -0,0 +1,237 @@ +package org.rhq.core.domain.configuration; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; + +/** + * @author Lukas Krejci + */ +@Test +public class ConfigurationBuilderTest { + + public void testConfigurationProperties() { + Configuration config = Configuration.builder().withNotes("notes").withVersion(2).build(); + assert "notes".equals(config.getNotes()) : "Unexpected notes"; + assert 2 == config.getVersion() : "Unexpected version"; + } + + public void testSimples() { + Configuration config = Configuration.builder().addSimple("1", 1).addSimple("2", 2).build(); + + assert config.getSimpleValue("1").equals("1") : "1 != 1"; + assert config.getSimpleValue("2").equals("2") : "2 != 2"; + + assert config.getSimple("1").getConfiguration() == config : "Configuration not set on property"; + } + + public void testListOfSimples() { + Configuration config = Configuration.builder().openList("l1", "m").addSimple(1).addSimple(2).closeList() + .openList("l2", "m").addSimples(1, 2).closeList().build(); + + PropertyList l1 = config.getList("l1"); + PropertyList l2 = config.getList("l2"); + + assert l1 != null : "Could not find l1"; + assert l2 != null : "Could not find l2"; + + assert l1.getConfiguration() == config : "Configuration on l1 not set"; + assert l2.getConfiguration() == config : "Configuration on l2 not set"; + + assert l1.getList().size() == 2 : "Unexpected number of props in the list 1"; + assert l2.getList().size() == 2 : "Unexpected number of props in the list 2"; + + testSimple((PropertySimple) l1.getList().get(0), null, l1, "1"); + testSimple((PropertySimple) l1.getList().get(1), null, l1, "2"); + testSimple((PropertySimple) l2.getList().get(0), null, l2, "1"); + testSimple((PropertySimple) l2.getList().get(1), null, l2, "2"); + } + + public void testMapOfSimples() { + Configuration config = Configuration.builder().openMap("m").addSimple("1", 1).addSimple("2", 2).closeMap() + .build(); + + PropertyMap m = config.getMap("m"); + + assert m != null : "Cound not find map"; + + assert m.getConfiguration() == config : "Configuration on the map not set"; + + testSimple(m.getSimple("1"), m, null, "1"); + testSimple(m.getSimple("2"), m, null, "2"); + } + + public void testListOfLists() { + Configuration config = new Configuration.Builder().openList("l", "m").openList("ml1").addSimples(1, 2) + .closeList().openList("ml2").addSimple(1).addSimple(2).closeList().closeList().build(); + + PropertyList l = config.getList("l"); + + assert l != null : "Could not find top-level list"; + + assert l.getList().size() == 2 : "Unexpected number of props in the top level list"; + + PropertyList m1 = (PropertyList) l.getList().get(0); + PropertyList m2 = (PropertyList) l.getList().get(1); + + assert m1.getParentList() == l : "Parent list on m1 not set"; + assert m1.getParentMap() == null : "Unexpected parent map on m1"; + assert m2.getParentList() == l : "Parent list on m2 not set"; + assert m1.getParentMap() == null : "Unexpected parent map on m2"; + + assert m1.getList().size() == 2 : "Unexpected number of props in the list 1"; + assert m2.getList().size() == 2 : "Unexpected number of props in the list 2"; + + testSimple((PropertySimple) m1.getList().get(0), null, m1, "1"); + testSimple((PropertySimple) m1.getList().get(1), null, m1, "2"); + testSimple((PropertySimple) m2.getList().get(0), null, m2, "1"); + testSimple((PropertySimple) m2.getList().get(1), null, m2, "2"); + } + + public void testListOfMaps() { + Configuration config = Configuration.builder().openList("l", "m").openMap().addSimple("c1", 1) + .addSimple("c2", 2).closeMap() + .openMap().addSimple("c1", 3).addSimple("c2", 4).closeMap().closeList().build(); + + PropertyList l = config.getList("l"); + + assert l != null : "Could not find top-level list"; + + assert l.getList().size() == 2 : "Unexpected number of props in the top level list"; + + PropertyMap m1 = (PropertyMap) l.getList().get(0); + PropertyMap m2 = (PropertyMap) l.getList().get(1); + + assert m1.getParentList() == l : "Parent list on m1 not set"; + assert m1.getParentMap() == null : "Unexpected parent map on m1"; + assert m2.getParentList() == l : "Parent list on m2 not set"; + assert m1.getParentMap() == null : "Unexpected parent map on m2"; + + assert m1.getMap().size() == 2 : "Unexpected number of props in the list 1"; + assert m2.getMap().size() == 2 : "Unexpected number of props in the list 2"; + + testSimple(m1.getSimple("c1"), m1, null, "1"); + testSimple(m1.getSimple("c2"), m1, null, "2"); + testSimple(m2.getSimple("c1"), m2, null, "3"); + testSimple(m2.getSimple("c2"), m2, null, "4"); + } + + public void testMapOfMaps() { + Configuration config = Configuration.builder().openMap("m").openMap("im1").addSimple("c1", 1).addSimple("c2", 2) + .closeMap().openMap("im2").addSimple("c1", 3).addSimple("c2", 4).closeMap().closeMap().build(); + + PropertyMap m = config.getMap("m"); + + assert m != null : "Could not find the top level map"; + + assert m.getMap().size() == 2 : "Unexpected number of props in the top level map"; + + PropertyMap m1 = m.getMap("im1"); + PropertyMap m2 = m.getMap("im2"); + + assert m1 != null : "Could not find im1"; + assert m2 != null : "Could not find im2"; + + assert m1.getParentList() == null : "Unexpected parent list on m1"; + assert m1.getParentMap() == m : "Unexpected parent map on m1"; + assert m2.getParentList() == null : "Unexpected parent list on m2"; + assert m1.getParentMap() == m : "Unexpected parent map on m2"; + + testSimple(m1.getSimple("c1"), m1, null, "1"); + testSimple(m1.getSimple("c2"), m1, null, "2"); + testSimple(m2.getSimple("c1"), m2, null, "3"); + testSimple(m2.getSimple("c2"), m2, null, "4"); + } + + public void testMapOfLists() { + Configuration config = Configuration.builder().openMap("m").openList("il1", "m").addSimples(1, 2) + .closeList().openList("il2", "m").addSimples(3, 4).closeList().closeMap().build(); + + PropertyMap m = config.getMap("m"); + + assert m != null : "Could not find the top level map"; + + assert m.getMap().size() == 2 : "Unexpected number of props in the top level map"; + + PropertyList l1 = m.getList("il1"); + PropertyList l2 = m.getList("il2"); + + assert l1 != null : "Could not find il1"; + assert l2 != null : "Could not find il2"; + + assert l1.getParentList() == null : "Unexpected parent list on l1"; + assert l1.getParentMap() == m : "Unexpected parent map on l1"; + assert l2.getParentList() == null : "Unexpected parent list on l2"; + assert l2.getParentMap() == m : "Unexpected parent map on l2"; + + testSimple((PropertySimple) l1.getList().get(0), null, l1, "1"); + testSimple((PropertySimple) l1.getList().get(1), null, l1, "2"); + testSimple((PropertySimple) l2.getList().get(0), null, l2, "3"); + testSimple((PropertySimple) l2.getList().get(1), null, l2, "4"); + } + + public void testUtterMess() { + Configuration config = Configuration.builder() + .openList("l", "m") // + /**/.openMap() // + /**//**/.openMap("innerMap") // + /**//**//**/.addSimple("c1", 1) // + /**//**//**/.openList("c2", "m") // + /**//**//**/.closeList() // + /**//**/.closeMap() // + /**//**/.addSimple("simple", 2) // + /**//**/.openList("innerList", "m") // + /**//**/.closeList() // + /**/.closeMap() // + /**/.addSimple(3) // + /**/.openList("im") // + /**//**/.openList("iim") // + /**//**/.closeList() // + /**//**/.openMap() // + /**//**/.closeMap() // + /**/.closeList() // + .closeList().build(); + + PropertyList l = config.getList("l"); + PropertyMap lm = (PropertyMap) l.getList().get(0); + PropertyMap innerMap = lm.getMap("innerMap"); + PropertySimple c1 = innerMap.getSimple("c1"); + PropertyList c2 = innerMap.getList("c2"); + PropertySimple simple = lm.getSimple("simple"); + PropertyList innerList = lm.getList("innerList"); + PropertySimple ls = (PropertySimple) l.getList().get(1); + PropertyList ll = (PropertyList) l.getList().get(2); + PropertyList lll = (PropertyList) ll.getList().get(0); + PropertyMap llm = (PropertyMap) ll.getList().get(1); + + //all the aspects of the above mess have been tested in the previous tests + //this just really is here to prove the point of how messy our configs can be + + assert c1 != null; + assert c2 != null; + assert simple != null; + assert innerList != null; + assert ls != null; + assert lll != null; + assert llm != null; + } + + public void testRawConfigs() { + Configuration config = Configuration.builder().openRawConfiguration().withPath("a/b") + .withContents("asdf", "123").closeRawConfiguration().build(); + + RawConfiguration r = config.getRawConfigurations().iterator().next(); + assert r.getPath().equals("a/b") : "Unexpected path"; + assert r.getContents().equals("asdf") : "Unexpected contents"; + assert r.getSha256().equals("123") : "Unexpected sha256"; + assert r.getConfiguration() == config : "Unexpected raw config owning configuration"; + } + + private void testSimple(PropertySimple p, PropertyMap expectedParentMap, PropertyList expectedParentList, + String expectedValue) { + assertSame(p.getParentMap(), expectedParentMap, "Unexpected parent map"); + assertSame(p.getParentList(), expectedParentList, "Unexpected parent list"); + assertEquals(p.getStringValue(), expectedValue, "Unexpected value"); + } +}
rhq-commits@lists.fedorahosted.org