You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by dr...@apache.org on 2017/04/11 14:13:10 UTC
[3/8] brooklyn-server git commit: A group that sets a sequence of
values as sensors on members
A group that sets a sequence of values as sensors on members
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/2728745b
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/2728745b
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/2728745b
Branch: refs/heads/master
Commit: 2728745be0f1222d84b0230bb5c5576b54765bdb
Parents: f2bd653
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Authored: Tue Jan 31 10:27:27 2017 +0000
Committer: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Committed: Tue Apr 11 14:34:26 2017 +0100
----------------------------------------------------------------------
.../brooklyn/entity/group/SequenceGroup.java | 104 ++++++++++++++++
.../entity/group/SequenceGroupImpl.java | 85 +++++++++++++
.../entity/group/SequenceGroupTest.java | 118 +++++++++++++++++++
3 files changed, 307 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2728745b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroup.java b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroup.java
new file mode 100644
index 0000000..a6dee56
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroup.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.annotation.Effector;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.MethodEffector;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.entity.stock.SequenceEntity;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.text.StringPredicates;
+
+import com.google.common.base.Predicates;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * A group that sets a sequence of values as sensors on its member entities
+ * <p>
+ * Usage:
+ * <pre>{@code
+ * - type: org.apache.brooklyn.entity.stock.SequenceGroup
+ * id: entity-sequence
+ * brooklyn.config:
+ * entityFilter:
+ * $brooklyn:object:
+ * type: org.apache.brooklyn.core.entity.EntityPredicates
+ * factoryMethod.name: "applicationIdEqualTo"
+ * factoryMethod.args:
+ * - $brooklyn:attributeWhenReady("application.id")
+ * sequenceStart: 0
+ * sequenceIncrement: 1
+ * sequenceFormat: "entity%04x"
+ * }</pre>
+ */
+@ImplementedBy(SequenceGroupImpl.class)
+public interface SequenceGroup extends DynamicGroup {
+
+ @SetFromFlag("sequenceStart")
+ ConfigKey<Integer> SEQUENCE_START = ConfigKeys.builder(Integer.class)
+ .name("sequence.start")
+ .description("The starting point of the sequence")
+ .defaultValue(1)
+ .constraint(Predicates.<Integer>notNull())
+ .build();
+
+ @SetFromFlag("sequenceIncrement")
+ ConfigKey<Integer> SEQUENCE_INCREMENT = ConfigKeys.builder(Integer.class)
+ .name("sequence.increment")
+ .description("The sequence increment for the next value")
+ .defaultValue(1)
+ .constraint(Predicates.<Integer>notNull())
+ .build();
+
+ @SetFromFlag("sequenceFormat")
+ ConfigKey<String> SEQUENCE_FORMAT = ConfigKeys.builder(String.class)
+ .name("sequence.format")
+ .description("A format used to generate a string representation of the sequence")
+ .defaultValue("%d")
+ .constraint(StringPredicates.containsRegex("%[-#+ 0,(]*[0-9]*[doxX]"))
+ .build();
+
+ AttributeSensor<Integer> SEQUENCE_NEXT = Sensors.builder(Integer.class, "sequence.next")
+ .description("The next value of the sequence")
+ .build();
+
+ AttributeSensor<Map<String, Integer>> SEQUENCE_CACHE = Sensors.builder(new TypeToken<Map<String, Integer>>() { }, "sequence.cache")
+ .description("The current cache of entity ids to sequence numbers")
+ .build();
+
+ MethodEffector<Void> RESET = new MethodEffector<Void>(SequenceEntity.class, "reset");
+
+ @Effector(description = "Reset the sequence to initial value")
+ Void reset();
+
+ AttributeSensor<Integer> SEQUENCE_VALUE = Sensors.builder(Integer.class, "sequence.value")
+ .description("The current value of the sequence")
+ .build();
+
+ AttributeSensor<String> SEQUENCE_STRING = Sensors.builder(String.class, "sequence.string")
+ .description("The current value of the sequence formatted as a string")
+ .build();
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2728745b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroupImpl.java
new file mode 100644
index 0000000..f9fc04e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/SequenceGroupImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+
+public class SequenceGroupImpl extends DynamicGroupImpl implements SequenceGroup {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SequenceGroupImpl.class);
+
+ public SequenceGroupImpl() { }
+
+ @Override
+ public Void reset() {
+ synchronized (memberChangeMutex) {
+ sensors().set(SEQUENCE_CACHE, Maps.<String, Integer>newConcurrentMap());
+ Integer initial = config().get(SEQUENCE_START);
+ sensors().set(SEQUENCE_NEXT, initial);
+ return null;
+ }
+ }
+
+ @Override
+ public void rescanEntities() {
+ synchronized (memberChangeMutex) {
+ reset();
+ super.rescanEntities();
+ }
+ }
+
+ @Override
+ public boolean addMember(Entity member) {
+ synchronized (memberChangeMutex) {
+ boolean changed = super.addMember(member);
+ if (changed) {
+ Map<String, Integer> cache = sensors().get(SEQUENCE_CACHE);
+ if (!cache.containsKey(member.getId())) {
+ Integer value = sequence(member);
+ cache.put(member.getId(), value);
+ }
+ }
+ return changed;
+ }
+ }
+
+ private Integer sequence(Entity entity) {
+ String format = config().get(SEQUENCE_FORMAT);
+ Integer current = sensors().get(SEQUENCE_NEXT);
+ String string = String.format(format, current);
+
+ entity.sensors().set(SEQUENCE_VALUE, current);
+ entity.sensors().set(SEQUENCE_STRING,string);
+
+ Integer increment = config().get(SEQUENCE_INCREMENT);
+ Integer next = current + increment;
+ LOG.debug("Sequence for {} incremented to {}", this, next);
+
+ sensors().set(SEQUENCE_NEXT, next);
+
+ return current;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2728745b/core/src/test/java/org/apache/brooklyn/entity/group/SequenceGroupTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/SequenceGroupTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/SequenceGroupTest.java
new file mode 100644
index 0000000..afb5425
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/entity/group/SequenceGroupTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import static org.apache.brooklyn.test.Asserts.assertEqualsIgnoringOrder;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+public class SequenceGroupTest extends BrooklynAppUnitTestSupport {
+
+ private TestApplication app;
+ private SequenceGroup group;
+ private TestEntity e1;
+ private TestEntity e2;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ group = app.createAndManageChild(EntitySpec.create(SequenceGroup.class));
+ e1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+ e2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+ }
+
+ @AfterMethod(alwaysRun=true)
+ @Override
+ public void tearDown() throws Exception {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+
+ super.tearDown();
+ }
+
+ @Test
+ public void testGroupWithMatchingFilterReturnsOnlyMatchingMembers() throws Exception {
+ group.setEntityFilter(EntityPredicates.idEqualTo(e1.getId()));
+
+ assertEqualsIgnoringOrder(group.getMembers(), ImmutableList.of(e1));
+ EntityAsserts.assertAttributeEquals(e1, SequenceGroup.SEQUENCE_VALUE, 1);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_NEXT, 2);
+ }
+
+ @Test
+ public void testGroupWithMatchingFilterReturnsEverythingThatMatches() throws Exception {
+ group.setEntityFilter(Predicates.alwaysTrue());
+
+ assertEqualsIgnoringOrder(group.getMembers(), ImmutableSet.of(e1, e2, app, group));
+ EntityAsserts.assertAttributeEquals(app, SequenceGroup.SEQUENCE_VALUE, 1);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_VALUE, 2);
+ EntityAsserts.assertAttributeEquals(e1, SequenceGroup.SEQUENCE_VALUE, 3);
+ EntityAsserts.assertAttributeEquals(e2, SequenceGroup.SEQUENCE_VALUE, 4);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_NEXT, 5);
+ }
+
+ @Test
+ public void testGroupDetectsNewlyManagedMatchingMember() throws Exception {
+ group.setEntityFilter(EntityPredicates.displayNameEqualTo("myname"));
+ final Entity e3 = app.addChild(EntitySpec.create(TestEntity.class).displayName("myname"));
+
+ Asserts.succeedsEventually(new Runnable() {
+ public void run() {
+ assertEqualsIgnoringOrder(group.getMembers(), ImmutableSet.of(e3));
+ EntityAsserts.assertAttributeEquals(e3, SequenceGroup.SEQUENCE_VALUE, 1);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_NEXT, 2);
+ }});
+ }
+
+ @Test
+ public void testGroupUsesNewFilter() throws Exception {
+ group.setEntityFilter(EntityPredicates.hasInterfaceMatching(".*TestEntity"));
+
+ assertEqualsIgnoringOrder(group.getMembers(), ImmutableSet.of(e1, e2));
+ EntityAsserts.assertAttributeEquals(e1, SequenceGroup.SEQUENCE_VALUE, 1);
+ EntityAsserts.assertAttributeEquals(e2, SequenceGroup.SEQUENCE_VALUE, 2);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_NEXT, 3);
+
+ final Entity e3 = app.addChild(EntitySpec.create(TestEntity.class));
+
+ Asserts.succeedsEventually(new Runnable() {
+ public void run() {
+ assertEqualsIgnoringOrder(group.getMembers(), ImmutableSet.of(e1, e2, e3));
+ EntityAsserts.assertAttributeEquals(e3, SequenceGroup.SEQUENCE_VALUE, 3);
+ EntityAsserts.assertAttributeEquals(group, SequenceGroup.SEQUENCE_NEXT, 4);
+ }});
+ }
+}