You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2015/10/27 15:48:24 UTC
[2/8] incubator-brooklyn git commit: Introduce relationships between
brooklyn objects
Introduce relationships between brooklyn objects
adds BrooklynObject.relations() and relationships such as MANAGER_OF and IN_GROUP.
includes tests, also convering persistence.
also adds self-bounding generics to BrooklynObject, and lifts getConfig(key) to Configurable to avoid generics conflicts (not sure why `public <T> T getConfig(ConfigKey<T> key)` declared in two interfaces is incompatible but it is apparently).
however there is much still to do:
* add relations to CAMP, and to the REST API and UI
* use relations for groups and children, and for locations, policies, etc (ensuring old persistence is still supported)
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/772e707f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/772e707f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/772e707f
Branch: refs/heads/master
Commit: 772e707f81fd34e3db2eafca3067890f384cb9e1
Parents: e3553a1
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 22 23:09:15 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Oct 23 14:06:54 2015 +0100
----------------------------------------------------------------------
.../brooklyn/basic/relations/Relationship.java | 38 ++++
.../org/apache/brooklyn/api/entity/Entity.java | 2 +
.../api/mgmt/rebind/mementos/Memento.java | 5 +-
.../brooklyn/api/objs/BrooklynObject.java | 15 ++
.../apache/brooklyn/api/objs/Configurable.java | 5 +
.../apache/brooklyn/api/sensor/Enricher.java | 12 --
.../core/catalog/internal/CatalogItemDo.java | 20 +-
.../internal/CatalogItemDtoAbstract.java | 9 +-
.../core/enricher/AbstractEnricher.java | 2 +-
.../brooklyn/core/entity/AbstractEntity.java | 5 +-
.../brooklyn/core/entity/EntityInternal.java | 2 +-
.../brooklyn/core/entity/EntityRelations.java | 160 ++++++++++++++++
.../apache/brooklyn/core/feed/AbstractFeed.java | 2 +-
.../core/location/AbstractLocation.java | 4 +-
.../access/PortForwardManagerClient.java | 5 +
.../location/internal/LocationInternal.java | 2 +-
.../AbstractBrooklynObjectRebindSupport.java | 23 ++-
.../core/mgmt/rebind/dto/AbstractMemento.java | 36 ++--
.../mgmt/rebind/dto/BasicEnricherMemento.java | 1 -
.../mgmt/rebind/dto/BasicEntityMemento.java | 2 -
.../core/mgmt/rebind/dto/BasicFeedMemento.java | 1 -
.../mgmt/rebind/dto/BasicLocationMemento.java | 1 -
.../mgmt/rebind/dto/BasicPolicyMemento.java | 1 -
.../mgmt/rebind/dto/MementosGenerators.java | 12 +-
.../core/objs/AbstractBrooklynObject.java | 32 +++-
.../core/objs/AbstractEntityAdjunct.java | 9 +-
.../brooklyn/core/objs/BrooklynDynamicType.java | 4 +-
.../core/objs/BrooklynObjectInternal.java | 13 +-
.../brooklyn/core/policy/AbstractPolicy.java | 2 +-
.../relations/AbstractBasicRelationSupport.java | 55 ++++++
.../relations/ByObjectBasicRelationSupport.java | 103 ++++++++++
.../brooklyn/core/relations/Relationships.java | 188 +++++++++++++++++++
.../entity/group/AbstractGroupImpl.java | 2 +
.../effector/EffectorSayHiGroovyTest.groovy | 2 +-
.../relations/RelationsEntityBasicTest.java | 55 ++++++
.../relations/RelationsEntityRebindTest.java | 51 +++++
.../core/relations/RelationshipTest.java | 58 ++++++
.../util/core/internal/FlagUtilsTest.java | 5 +
.../brooklyn/camp/brooklyn/ObjectsYamlTest.java | 5 +
39 files changed, 876 insertions(+), 73 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/brooklyn/basic/relations/Relationship.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/basic/relations/Relationship.java b/api/src/main/java/brooklyn/basic/relations/Relationship.java
new file mode 100644
index 0000000..bc17e6a
--- /dev/null
+++ b/api/src/main/java/brooklyn/basic/relations/Relationship.java
@@ -0,0 +1,38 @@
+/*
+ * 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 brooklyn.basic.relations;
+
+import brooklyn.basic.relations.Relationship;
+
+
+public interface Relationship<SourceType,TargetType> {
+
+ public String getRelationshipTypeName();
+ public Class<SourceType> getSourceType();
+ public Class<TargetType> getTargetType();
+
+ public String getSourceName();
+ public String getSourceNamePlural();
+
+ public String getTargetName();
+ public String getTargetNamePlural();
+
+ public Relationship<TargetType,SourceType> getInverseRelationship();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
index e01d5e2..a15f4e1 100644
--- a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
@@ -314,6 +314,8 @@ public interface Entity extends BrooklynObject {
GroupSupport groups();
+ RelationSupport<Entity> relations();
+
@Beta
public interface SensorSupport {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
index 4a21117..b57780d 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java
@@ -21,9 +21,11 @@ package org.apache.brooklyn.api.mgmt.rebind.mementos;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
+import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.EntityAdjunct;
/**
@@ -77,7 +79,8 @@ public interface Memento extends Serializable {
public Collection<Object> getTags();
+ Map<String, Set<BrooklynObject>> getRelations();
+
/** Null for {@link Entity}, but important for adjuncts; see {@link EntityAdjunct#getUniqueTag()} */
public String getUniqueTag();
-
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
index f3fcad4..8648491 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java
@@ -34,6 +34,8 @@ import org.apache.brooklyn.api.sensor.SensorEventListener;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMap;
+import brooklyn.basic.relations.Relationship;
+
/**
* Super-type of entity, location, policy and enricher.
*/
@@ -70,6 +72,12 @@ public interface BrooklynObject extends Identifiable, Configurable {
*/
SubscriptionSupport subscriptions();
+ /**
+ * Relations specify a typed, directed connection between two entities.
+ * Generic type is overridden in sub-interfaces.
+ */
+ public RelationSupport<?> relations();
+
public interface TagSupport {
/**
* @return An immutable copy of the set of tags on this entity.
@@ -141,4 +149,11 @@ public interface BrooklynObject extends Identifiable, Configurable {
*/
boolean unsubscribe(SubscriptionHandle handle);
}
+
+ public interface RelationSupport<T extends BrooklynObject> {
+ public <U extends BrooklynObject> void add(Relationship<? super T,U> relationship, U target);
+ public <U extends BrooklynObject> void remove(Relationship<? super T,U> relationship, U target);
+ public Set<Relationship<? super T,? extends BrooklynObject>> getRelationships();
+ public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super T,U> relationship);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
index 513c8d7..5f1b294 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java
@@ -41,6 +41,11 @@ public interface Configurable {
@Deprecated
public <T> T setConfig(ConfigKey<T> key, T val);
+ /**
+ * Convenience method for {@code config().get(key)}
+ */
+ <T> T getConfig(ConfigKey<T> key);
+
ConfigurationSupport config();
@Beta
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/api/src/main/java/org/apache/brooklyn/api/sensor/Enricher.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/sensor/Enricher.java b/api/src/main/java/org/apache/brooklyn/api/sensor/Enricher.java
index aaaecf0..7d34e6c 100644
--- a/api/src/main/java/org/apache/brooklyn/api/sensor/Enricher.java
+++ b/api/src/main/java/org/apache/brooklyn/api/sensor/Enricher.java
@@ -24,7 +24,6 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
import org.apache.brooklyn.api.objs.Configurable;
import org.apache.brooklyn.api.objs.EntityAdjunct;
import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.config.ConfigKey;
import com.google.common.annotations.Beta;
@@ -48,17 +47,6 @@ public interface Enricher extends EntityAdjunct, Rebindable, Configurable {
EnricherType getEnricherType();
/**
- * Convenience method for {@code config().get(key)}
- */
- <T> T getConfig(ConfigKey<T> key);
-
- /**
- * @deprecated since 0.7.0; use {@link #config()}, such as {@code policy.config().setConfig(key, val)}
- */
- @Deprecated
- <T> T setConfig(ConfigKey<T> key, T val);
-
- /**
* Users are strongly discouraged from calling or overriding this method.
* It is for internal calls only, relating to persisting/rebinding entities.
* This method may change (or be removed) in a future release without notice.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
index 0545a06..7f3a54a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java
@@ -23,17 +23,16 @@ import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
-import org.apache.brooklyn.core.objs.BrooklynObjectInternal.SubscriptionSupportInternal;
import org.apache.brooklyn.api.catalog.CatalogItem;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
import com.google.common.base.Preconditions;
-public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT>, BrooklynObjectInternal {
+public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT>, BrooklynObjectInternal<CatalogItem<T,SpecT>,CatalogItemDo<T,SpecT>> {
protected final CatalogDo catalog;
protected final CatalogItemDtoAbstract<T,SpecT> itemDto;
@@ -65,6 +64,19 @@ public class CatalogItemDo<T,SpecT> implements CatalogItem<T,SpecT>, BrooklynObj
throw new UnsupportedOperationException();
}
+ /**
+ * @throws UnsupportedOperationException; relations are not supported for catalog items
+ */
+ @Override
+ public RelationSupportInternal<CatalogItem<T,SpecT>> relations() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <U> U getConfig(ConfigKey<U> key) {
+ return config().get(key);
+ }
+
@Override
public <U> U setConfig(ConfigKey<U> key, U val) {
return config().set(key, val);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
index c950b7b..078cd27 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
@@ -44,7 +44,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
-public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynObject implements CatalogItem<T, SpecT> {
+public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynObject<CatalogItem<T, SpecT>, CatalogItemDtoAbstract<T, SpecT>> implements CatalogItem<T, SpecT> {
private static Logger LOG = LoggerFactory.getLogger(CatalogItemDtoAbstract.class);
@@ -82,6 +82,11 @@ public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynO
}
@Override
+ public <U> U getConfig(ConfigKey<U> key) {
+ return config().get(key);
+ }
+
+ @Override
public <U> U setConfig(ConfigKey<U> key, U val) {
return config().set(key, val);
}
@@ -245,7 +250,7 @@ public abstract class CatalogItemDtoAbstract<T, SpecT> extends AbstractBrooklynO
}
@Override
- protected AbstractBrooklynObject configure(Map<?, ?> flags) {
+ protected CatalogItemDtoAbstract<T, SpecT> configure(Map<?, ?> flags) {
FlagUtils.setFieldsFromFlags(flags, this);
return this;
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java b/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
index 8c3f41e..2597baa 100644
--- a/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/core/enricher/AbstractEnricher.java
@@ -43,7 +43,7 @@ import com.google.common.collect.Maps;
/**
* Base {@link Enricher} implementation; all enrichers should extend this or its children
*/
-public abstract class AbstractEnricher extends AbstractEntityAdjunct implements Enricher {
+public abstract class AbstractEnricher extends AbstractEntityAdjunct<Enricher,AbstractEnricher> implements Enricher {
public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = ConfigKeys.newBooleanConfigKey("enricher.suppressDuplicates",
"Whether duplicate values published by this enricher should be suppressed");
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index 65ec72f..5b52321 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -141,7 +141,7 @@ import com.google.common.collect.Sets;
* The legacy (pre 0.5) mechanism for creating entities is for others to call the constructor directly.
* This is now deprecated.
*/
-public abstract class AbstractEntity extends AbstractBrooklynObject implements EntityLocal, EntityInternal {
+public abstract class AbstractEntity extends AbstractBrooklynObject<Entity,EntityInternal> implements EntityLocal, EntityInternal {
private static final Logger LOG = LoggerFactory.getLogger(AbstractEntity.class);
@@ -287,7 +287,7 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
entityType = new EntityDynamicType(this);
if (isLegacyConstruction()) {
- AbstractBrooklynObject checkWeGetThis = configure(flags);
+ AbstractEntity checkWeGetThis = configure(flags);
assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
boolean deferConstructionChecks = (flags.containsKey("deferConstructionChecks") && TypeCoercions.coerce(flags.get("deferConstructionChecks"), Boolean.class));
@@ -2082,4 +2082,5 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
super.onTagsChanged();
getManagementSupport().getEntityChangeListener().onTagsChanged();
}
+
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
index 27b09a4..af81c21 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInternal.java
@@ -46,7 +46,7 @@ import com.google.common.annotations.Beta;
* for the brooklyn framework only).
*/
@Beta
-public interface EntityInternal extends BrooklynObjectInternal, EntityLocal, Rebindable {
+public interface EntityInternal extends BrooklynObjectInternal<Entity,EntityInternal>, EntityLocal, Rebindable {
void addLocations(Collection<? extends Location> locations);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
new file mode 100644
index 0000000..7b20845
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityRelations.java
@@ -0,0 +1,160 @@
+/*
+ * 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.core.entity;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+import org.apache.brooklyn.core.relations.Relationships;
+import org.apache.brooklyn.util.collections.MutableMap;
+
+import com.google.common.annotations.Beta;
+
+import brooklyn.basic.relations.Relationship;
+
+/** TODO these relations are not used yet; see issue where this is introduced and email thread */
+@Beta
+public class EntityRelations<T extends BrooklynObject> {
+
+ /** {@link #MANAGER_OF} indicates that one entity is the manager of another entity,
+ * in the internal Brooklyn management hierarchy model.
+ * Apart from root {@link Application} entities, every deployed entity must have exactly one manager.
+ * The inverse relationship is {@link #MANAGED_BY}. */
+ public static final Relationship<Entity,Entity> MANAGER_OF = Relationships.newRelationshipPair(
+ "manager", "managers", Entity.class, "manager_of",
+ "managed child", "managed children", Entity.class, "managed_by");
+ /** Inverse of {@link #MANAGER_OF}. */
+ public static final Relationship<Entity,Entity> MANAGED_BY = MANAGER_OF.getInverseRelationship();
+
+ /** {@link #GROUP_CONTAINS} indicates that one entity, typically a {@link Group},
+ * has zero or more entities which are labelled as "members" of that group entity.
+ * What membership means will depend on the group entity.
+ * An entity may be a member of any number of other entities.
+ * The inverse relationship is {@link #IN_GROUP}. */
+ public static final Relationship<Entity,Entity> GROUP_CONTAINS = Relationships.newRelationshipPair(
+ "group", "groups", Entity.class, "group_contains",
+ "member", "members", Entity.class, "in_group");
+ /** Inverse of {@link #GROUP_CONTAINS}. */
+ public static final Relationship<Entity,Entity> IN_GROUP = GROUP_CONTAINS.getInverseRelationship();
+
+ /** {@link #HAS_TARGET} indicates that one entity directs to one or more other entities.
+ * What this targeting relationship means depends on the targetter.
+ * The inverse relationship is {@link #TARGETTED_BY}. */
+ public static final Relationship<Entity,Entity> HAS_TARGET = Relationships.newRelationshipPair(
+ "targetter", "targetters", Entity.class, "has_target",
+ "target", "targets", Entity.class, "targetted_by");
+ /** Inverse of {@link #HAS_TARGET}. */
+ public static final Relationship<Entity,Entity> TARGETTED_BY = HAS_TARGET.getInverseRelationship();
+
+ /** {@link #ACTIVE_PARENT_OF} indicates that one entity is should be considered as the logical parent of another,
+ * e.g. for presentation purposes to the end user.
+ * Frequently this relationship coincides with a {@link #MANAGED_BY} relationship,
+ * but sometimes some managed children are there for purposes the designers consider less important,
+ * and they can choose to suppress the {@link #ACTIVE_PARENT_OF} relationship
+ * so that the active children is a subset of the managed children.
+ * <p>
+ * One recommended consideration is whether the child should be shown in a default tree view.
+ * Whilst a user can always fina a way to see all managed children,
+ * it may be the case that only some of those are of primary interest,
+ * and it is to identify those that this relationship exists.
+ * <p>
+ * It is permitted that an entity be an {@link #ACTIVE_PARENT_OF} an entity for which it is not a manager,
+ * but in most cases a different relationship type is more appropriate where there is not also a management relationship.
+ * <p>
+ * The inverse relationship is {@link #ACTIVE_CHILD_OF},
+ * and an entity should normally be an {@link #ACTIVE_CHILD_OF} zero or one entities. */
+ public static final Relationship<Entity,Entity> ACTIVE_PARENT_OF = Relationships.newRelationshipPair(
+ "parent", "parents", Entity.class, "parent_of_active",
+ "active child", "active children", Entity.class, "active_child_of");
+ /** Inverse of {@link #ACTIVE_PARENT_OF}. */
+ public static final Relationship<Entity,Entity> ACTIVE_CHILD_OF = ACTIVE_PARENT_OF.getInverseRelationship();
+
+ /** {@link #HAS_POLICY} indicates that an entity has a policy associated to it.
+ * The inverse relationship is {@link #POLICY_FOR}. */
+ public static final Relationship<Entity,Policy> HAS_POLICY = Relationships.newRelationshipPair(
+ "entity", "entities", Entity.class, "has_policy",
+ "policy", "policies", Policy.class, "policy_for");
+ /** Inverse of {@link #HAS_POLICY}. */
+ public static final Relationship<Policy,Entity> POLICY_FOR = HAS_POLICY.getInverseRelationship();
+
+ // ----
+
+ // TODO replace by relations stored in catalog when catalog supports arbitrary types
+ private static Map<String,Relationship<? extends BrooklynObject, ? extends BrooklynObject>> KNOWN_RELATIONSHIPS = MutableMap.of();
+ private static void addRelationship(Relationship<? extends BrooklynObject, ? extends BrooklynObject> r) {
+ KNOWN_RELATIONSHIPS.put(r.getRelationshipTypeName(), r);
+ if (r.getInverseRelationship()!=null) {
+ KNOWN_RELATIONSHIPS.put(r.getInverseRelationship().getRelationshipTypeName(), r.getInverseRelationship());
+ }
+ }
+ static {
+ addRelationship(MANAGER_OF);
+ addRelationship(GROUP_CONTAINS);
+ addRelationship(HAS_TARGET);
+ addRelationship(HAS_POLICY);
+ }
+
+ /** Find the typed Relationship instance for the given relationship name, if known;
+ * behaviour is not guaranteed by the API if not known (hence the Beta marker),
+ * it may fail fast or return null or create a poor-man's relationship instance.
+ */
+ @Beta
+ public static Relationship<? extends BrooklynObject, ? extends BrooklynObject> lookup(ManagementContext mgmt, String relationshipTypeName) {
+ if (relationshipTypeName==null) return null;
+ Relationship<? extends BrooklynObject, ? extends BrooklynObject> result = KNOWN_RELATIONSHIPS.get(relationshipTypeName);
+ if (result!=null) return result;
+
+ /* TODO ultimately we'd like to support arbitrary relationships via persistence and lookup against the catalog;
+ * however for now, so that we can persist nicely (without catalog items for relationships)
+ * we are smart about the relationships defined here, and we return a poor-man's version for items elsewhere.
+ *
+ * for now, a poor-man's relationship; if not in catalog ultimately we should fail. */
+ return Relationships.newRelationshipOneway("source", "sources", BrooklynObject.class, relationshipTypeName, "target", "targets", BrooklynObject.class);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T extends BrooklynObject> Set<Relationship<? super T,? extends BrooklynObject>> getRelations(T source) {
+ return ((BrooklynObjectInternal)source).relations().getLocalBackingStore().getRelationships();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T extends BrooklynObject,U extends BrooklynObject> Set<U> getRelationships(Relationship<? super T,U> relationship, T source) {
+ return ((BrooklynObjectInternal)source).relations().getLocalBackingStore().getRelations(relationship);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T extends BrooklynObject,U extends BrooklynObject> void add(T source, Relationship<? super T,U> relationship, U target) {
+ ((BrooklynObjectInternal)source).relations().getLocalBackingStore().add(relationship, target);
+ ((BrooklynObjectInternal)target).relations().getLocalBackingStore().add(relationship.getInverseRelationship(), source);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public static <T extends BrooklynObject,U extends BrooklynObject> void remove(T source, Relationship<? super T,U> relationship, U target) {
+ ((BrooklynObjectInternal)source).relations().getLocalBackingStore().remove(relationship, target);
+ ((BrooklynObjectInternal)target).relations().getLocalBackingStore().remove(relationship.getInverseRelationship(), source);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
index a31b73e..64320cd 100644
--- a/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
+++ b/core/src/main/java/org/apache/brooklyn/core/feed/AbstractFeed.java
@@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory;
* These generally poll or subscribe to get sensor values for an entity.
* They make it easy to poll over http, jmx, etc.
*/
-public abstract class AbstractFeed extends AbstractEntityAdjunct implements Feed {
+public abstract class AbstractFeed extends AbstractEntityAdjunct<Feed,AbstractFeed> implements Feed {
private static final Logger log = LoggerFactory.getLogger(AbstractFeed.class);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java b/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java
index b5a91c7..996b1a0 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java
@@ -94,7 +94,7 @@ import com.google.common.reflect.TypeToken;
*
* Override {@link #configure(Map)} to add special initialization logic.
*/
-public abstract class AbstractLocation extends AbstractBrooklynObject implements LocationInternal, HasHostGeoInfo, Configurable {
+public abstract class AbstractLocation extends AbstractBrooklynObject<Location,LocationInternal> implements LocationInternal, HasHostGeoInfo, Configurable {
private static final long serialVersionUID = -7495805474138619830L;
@@ -175,7 +175,7 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements
locationType = new LocationDynamicType(this);
if (isLegacyConstruction()) {
- AbstractBrooklynObject checkWeGetThis = configure(properties);
+ AbstractLocation checkWeGetThis = configure(properties);
assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java
index fb27ada..d312f53 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java
@@ -394,6 +394,11 @@ public class PortForwardManagerClient implements PortForwardManager {
}
@Override
+ public RelationSupport<?> relations() {
+ return getDelegate().relations();
+ }
+
+ @Override
public <T> T setConfig(ConfigKey<T> key, T val) {
return getDelegate().config().set(key, val);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java
index 18bceef..fe9f669 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationInternal.java
@@ -35,7 +35,7 @@ import com.google.common.annotations.Beta;
/**
* Information about locations private to Brooklyn.
*/
-public interface LocationInternal extends BrooklynObjectInternal, Location {
+public interface LocationInternal extends BrooklynObjectInternal<Location,LocationInternal>, Location {
@Beta
public static final ConfigKey<String> ORIGINAL_SPEC = ConfigKeys.newStringConfigKey("spec.original", "The original spec used to instantiate a location");
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
index 326df67..74a7dca 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
@@ -18,10 +18,15 @@
*/
package org.apache.brooklyn.core.mgmt.rebind;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
+import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.core.entity.EntityRelations;
import org.apache.brooklyn.core.mgmt.rebind.dto.MementosGenerators;
import org.apache.brooklyn.core.objs.AbstractBrooklynObject;
import org.apache.brooklyn.core.objs.AbstractEntityAdjunct.AdjunctTagSupport;
@@ -29,13 +34,15 @@ import org.apache.brooklyn.util.text.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import brooklyn.basic.relations.Relationship;
+
public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> implements RebindSupport<T> {
private static final Logger LOG = LoggerFactory.getLogger(AbstractBrooklynObjectRebindSupport.class);
- private final AbstractBrooklynObject instance;
+ private final AbstractBrooklynObject<?,?> instance;
- public AbstractBrooklynObjectRebindSupport(AbstractBrooklynObject instance) {
+ public AbstractBrooklynObjectRebindSupport(AbstractBrooklynObject<?,?> instance) {
this.instance = instance;
}
@@ -55,6 +62,7 @@ public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> imp
//catalogItemId already set when creating the object
addConfig(rebindContext, memento);
addTags(rebindContext, memento);
+ addRelations(rebindContext, memento);
addCustoms(rebindContext, memento);
doReconstruct(rebindContext, memento);
@@ -66,6 +74,7 @@ public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> imp
protected abstract void addCustoms(RebindContext rebindContext, T memento);
+ @SuppressWarnings("rawtypes")
protected void addTags(RebindContext rebindContext, T memento) {
if (instance instanceof EntityAdjunct && Strings.isNonBlank(memento.getUniqueTag())) {
((AdjunctTagSupport)(instance.tags())).setUniqueTag(memento.getUniqueTag());
@@ -75,6 +84,16 @@ public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> imp
}
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected void addRelations(RebindContext rebindContext, T memento) {
+ for (Map.Entry<String,Set<BrooklynObject>> rEntry : memento.getRelations().entrySet()) {
+ Relationship<? extends BrooklynObject, ? extends BrooklynObject> r = EntityRelations.lookup(instance.getManagementContext(), rEntry.getKey());
+ if (r==null) throw new IllegalStateException("Unsupported relationship -- "+rEntry.getKey() + " -- in "+memento);
+ for (BrooklynObject item: rEntry.getValue())
+ instance.relations().add((Relationship)r, item);
+ }
+ }
+
@Override
public void addPolicies(RebindContext rebindContext, T Memento) {
throw new UnsupportedOperationException();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
index 77ebdbb..1fae585 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
@@ -25,9 +25,9 @@ import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
+import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.core.BrooklynVersion;
import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Entities;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
@@ -47,6 +47,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
protected String catalogItemId;
protected Map<String, Object> customFields = Maps.newLinkedHashMap();
protected List<Object> tags = Lists.newArrayList();
+ protected Map<String,Set<BrooklynObject>> relations = Maps.newLinkedHashMap();
// only supported for EntityAdjuncts
protected String uniqueTag;
@@ -65,29 +66,10 @@ public abstract class AbstractMemento implements Memento, Serializable {
catalogItemId = other.getCatalogItemId();
customFields.putAll(other.getCustomFields());
tags.addAll(other.getTags());
+ relations.putAll(other.getRelations());
uniqueTag = other.getUniqueTag();
return self();
}
- // this method set is incomplete; and they are not used, as the protected fields are set directly
- // kept in case we want to expose this elsewhere, but we should complete the list
-// public B brooklynVersion(String val) {
-// brooklynVersion = val; return self();
-// }
-// public B id(String val) {
-// id = val; return self();
-// }
-// public B type(String val) {
-// type = val; return self();
-// }
-// public B typeClass(Class<?> val) {
-// typeClass = val; return self();
-// }
-// public B displayName(String val) {
-// displayName = val; return self();
-// }
-// public B catalogItemId(String val) {
-// catalogItemId = val; return self();
-// }
/**
* @deprecated since 0.7.0; use config/attributes so generic persistence will work, rather than requiring "custom fields"
@@ -104,6 +86,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
private String displayName;
private String catalogItemId;
private List<Object> tags;
+ private Map<String, Set<BrooklynObject>> relations;
// for EntityAdjuncts; not used for entity
private String uniqueTag;
@@ -124,6 +107,7 @@ public abstract class AbstractMemento implements Memento, Serializable {
catalogItemId = builder.catalogItemId;
setCustomFields(builder.customFields);
tags = toPersistedList(builder.tags);
+ relations = toPersistedMap(builder.relations);
uniqueTag = builder.uniqueTag;
}
@@ -172,6 +156,11 @@ public abstract class AbstractMemento implements Memento, Serializable {
}
@Override
+ public Map<String, Set<BrooklynObject>> getRelations() {
+ return fromPersistedMap(relations);
+ }
+
+ @Override
public String getUniqueTag() {
return uniqueTag;
}
@@ -199,7 +188,10 @@ public abstract class AbstractMemento implements Memento, Serializable {
protected ToStringHelper newVerboseStringHelper() {
return Objects.toStringHelper(this).add("id", getId()).add("type", getType())
- .add("displayName", getDisplayName()).add("customFields", Sanitizer.sanitize(getCustomFields()));
+ .add("displayName", getDisplayName())
+ .add("tags", getTags())
+ .add("relations", getRelations())
+ .add("customFields", Sanitizer.sanitize(getCustomFields()));
}
protected <T> List<T> fromPersistedList(List<T> l) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
index 254b803..80c502d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
@@ -23,7 +23,6 @@ import java.util.Map;
import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Entities;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.Maps;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
index 7418813..8294562 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
@@ -90,7 +90,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
feeds.addAll(other.getFeeds());
members.addAll(other.getMembers());
effectors.addAll(other.getEffectors());
- tags.addAll(other.getTags());
return this;
}
public EntityMemento build() {
@@ -319,7 +318,6 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
.add("attributes", Sanitizer.sanitize(getAttributes()))
.add("policies", getPolicies())
.add("enrichers", getEnrichers())
- .add("tags", getTags())
.add("locations", getLocations());
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
index 2f07443..072756f 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
@@ -23,7 +23,6 @@ import java.util.Map;
import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Entities;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.Maps;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
index 16c9e92..71ddcaa 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
@@ -25,7 +25,6 @@ import java.util.Set;
import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
import org.apache.brooklyn.api.mgmt.rebind.mementos.TreeNode;
import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.util.core.config.ConfigBag;
import com.google.common.base.Objects.ToStringHelper;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
index 31ce3b2..87a0dfb 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
@@ -23,7 +23,6 @@ import java.util.Map;
import org.apache.brooklyn.api.mgmt.rebind.mementos.PolicyMemento;
import org.apache.brooklyn.core.config.Sanitizer;
-import org.apache.brooklyn.core.entity.Entities;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.Maps;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index e5d0359..6cfda79 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -44,9 +44,9 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.EntityAdjunct;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
import org.apache.brooklyn.api.sensor.Enricher;
import org.apache.brooklyn.api.sensor.Feed;
-import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.catalog.internal.CatalogItemDo;
import org.apache.brooklyn.core.enricher.AbstractEnricher;
@@ -67,6 +67,8 @@ import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
+import brooklyn.basic.relations.Relationship;
+
public class MementosGenerators {
private MementosGenerators() {}
@@ -429,6 +431,7 @@ public class MementosGenerators {
return builder.build();
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance, AbstractMemento.Builder<?> builder) {
if (Proxy.isProxyClass(instance.getClass())) {
throw new IllegalStateException("Attempt to create memento from proxy "+instance+" (would fail with wrong type)");
@@ -445,6 +448,13 @@ public class MementosGenerators {
for (Object tag : instance.tags().getTags()) {
builder.tags.add(tag);
}
+ if (!(instance instanceof CatalogItem)) {
+ // CatalogItem is a BrooklynObject so it can be persisted
+ // but it does not support relations
+ for (Relationship<?,? extends BrooklynObject> relationship: instance.relations().getRelationships()) {
+ builder.relations.put(relationship.getRelationshipTypeName(), instance.relations().getRelations((Relationship)relationship));
+ }
+ }
}
protected static Object configValueToPersistable(Object value) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java
index 385d279..a0e02c5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java
@@ -24,10 +24,12 @@ import java.util.Set;
import org.apache.brooklyn.api.internal.ApiObjectsFactory;
import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.core.entity.AbstractEntity;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
import org.apache.brooklyn.core.objs.proxy.InternalFactory;
+import org.apache.brooklyn.core.relations.ByObjectBasicRelationSupport;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.text.Identifiers;
@@ -39,7 +41,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
+public abstract class AbstractBrooklynObject<PublicSelfType extends BrooklynObject,InternalSelfType extends BrooklynObjectInternal<PublicSelfType,InternalSelfType>> implements BrooklynObjectInternal<PublicSelfType,InternalSelfType> {
private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynObject.class);
@@ -55,8 +57,18 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
@SetFromFlag(value = "tags")
private final Set<Object> tags = Sets.newLinkedHashSet();
+ private RelationSupportInternal<PublicSelfType> relations = new ByObjectBasicRelationSupport<PublicSelfType>(getPublicThis(), new RelationChangedCallback());
+
private volatile ManagementContext managementContext;
-
+
+ @SuppressWarnings("unchecked")
+ /** returns this cast to T, e.g. EntityInternal */
+ protected InternalSelfType getThis() { return (InternalSelfType)this; }
+
+ /** returns this cast to PublicT, e.g. Entity */
+ @SuppressWarnings("unchecked")
+ protected PublicSelfType getPublicThis() { return (PublicSelfType)this; }
+
public abstract void setDisplayName(String newName);
public AbstractBrooklynObject() {
@@ -86,7 +98,7 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
* @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
*/
@Deprecated
- protected AbstractBrooklynObject configure() {
+ protected InternalSelfType configure() {
return configure(Collections.emptyMap());
}
@@ -105,7 +117,7 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
* @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
*/
@Deprecated
- protected abstract AbstractBrooklynObject configure(Map<?, ?> flags);
+ protected abstract InternalSelfType configure(Map<?, ?> flags);
protected boolean isLegacyConstruction() {
return _legacyConstruction;
@@ -245,4 +257,16 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal {
}
}
+ @Override
+ public RelationSupportInternal<PublicSelfType> relations() {
+ return relations;
+ }
+
+ private class RelationChangedCallback implements Runnable {
+ @Override
+ public void run() {
+ requestPersist();
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
index 3fc2839..63745d3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
@@ -67,7 +67,7 @@ import com.google.common.collect.Maps;
/**
* Common functionality for policies and enrichers
*/
-public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable {
+public abstract class AbstractEntityAdjunct<PublicSelfType extends BrooklynObject,InternalSelfType extends AbstractEntityAdjunct<PublicSelfType,InternalSelfType>> extends AbstractBrooklynObject<PublicSelfType,InternalSelfType> implements BrooklynObjectInternal<PublicSelfType,InternalSelfType>, EntityAdjunct, Configurable {
private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
private boolean _legacyNoConstructionInit;
@@ -121,7 +121,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
_legacyNoConstructionInit = (properties != null) && Boolean.TRUE.equals(properties.get("noConstructionInit"));
if (isLegacyConstruction()) {
- AbstractBrooklynObject checkWeGetThis = configure(properties);
+ InternalSelfType checkWeGetThis = configure(properties);
assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
@@ -137,7 +137,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
@Override
@Deprecated
@SuppressWarnings({ "unchecked", "rawtypes" })
- public AbstractEntityAdjunct configure(Map flags) {
+ public InternalSelfType configure(Map flags) {
// TODO only set on first time through
boolean isFirstTime = true;
@@ -183,7 +183,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
}
}
- return this;
+ return (InternalSelfType) this;
}
/**
@@ -366,6 +366,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
}
}
+ @Override
public <T> T getConfig(ConfigKey<T> key) {
return config().get(key);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynDynamicType.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynDynamicType.java
index 3642448..d7c73dd 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynDynamicType.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynDynamicType.java
@@ -55,7 +55,7 @@ import com.google.common.collect.Lists;
* for this reason it does *not* implement BrooklynType, but
* callers can call {@link #getSnapshot()} to get a snapshot such instance.
*/
-public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT extends AbstractBrooklynObject> {
+public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT extends AbstractBrooklynObject<T,?>> {
private static final Logger LOG = LoggerFactory.getLogger(BrooklynDynamicType.class);
@@ -144,7 +144,7 @@ public abstract class BrooklynDynamicType<T extends BrooklynObject, AbstractT ex
* Prefers keys which overwrite other keys, and prefers keys which are lower in the hierarchy;
* logs warnings if there are two conflicting keys which don't have an overwriting relationship.
*/
- protected static void buildConfigKeys(Class<? extends BrooklynObject> clazz, AbstractBrooklynObject optionalInstance,
+ protected static void buildConfigKeys(Class<? extends BrooklynObject> clazz, AbstractBrooklynObject<?,?> optionalInstance,
Map<String, FieldAndValue<ConfigKey<?>>> configKeys) {
ListMultimap<String,FieldAndValue<ConfigKey<?>>> configKeysAll =
ArrayListMultimap.<String, FieldAndValue<ConfigKey<?>>>create();
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
index 6888c52..658a9da 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java
@@ -31,12 +31,12 @@ import org.apache.brooklyn.util.guava.Maybe;
import com.google.common.annotations.Beta;
-public interface BrooklynObjectInternal extends BrooklynObject, Rebindable {
+public interface BrooklynObjectInternal<PublicSelfType extends BrooklynObject, InternalSelfType extends BrooklynObjectInternal<PublicSelfType,InternalSelfType>> extends BrooklynObject, Rebindable {
void setCatalogItemId(String id);
- @SuppressWarnings("rawtypes") // subclasses typically apply stronger typing
- RebindSupport getRebindSupport();
+ // subclasses typically apply stronger typing
+ RebindSupport<?> getRebindSupport();
@Override
ConfigurationSupportInternal config();
@@ -123,4 +123,11 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable {
public interface SubscriptionSupportInternal extends BrooklynObject.SubscriptionSupport {
public void unsubscribeAll();
}
+
+ RelationSupportInternal<PublicSelfType> relations();
+
+ public interface RelationSupportInternal<T extends BrooklynObject> extends BrooklynObject.RelationSupport<T> {
+ @Beta
+ RelationSupport<T> getLocalBackingStore();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/policy/AbstractPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/AbstractPolicy.java b/core/src/main/java/org/apache/brooklyn/core/policy/AbstractPolicy.java
index 1c9bb1c..3cb39e9 100644
--- a/core/src/main/java/org/apache/brooklyn/core/policy/AbstractPolicy.java
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/AbstractPolicy.java
@@ -37,7 +37,7 @@ import com.google.common.base.Objects;
/**
* Base {@link Policy} implementation; all policies should extend this or its children
*/
-public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Policy, Configurable {
+public abstract class AbstractPolicy extends AbstractEntityAdjunct<Policy,AbstractPolicy> implements Policy, Configurable {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(AbstractPolicy.class);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java b/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
new file mode 100644
index 0000000..e87d0ea
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/AbstractBasicRelationSupport.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.relations;
+
+import java.util.Set;
+
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.core.entity.EntityRelations;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal.RelationSupportInternal;
+
+import brooklyn.basic.relations.Relationship;
+
+public abstract class AbstractBasicRelationSupport<SourceType extends BrooklynObject> implements RelationSupportInternal<SourceType> {
+
+ final SourceType source;
+
+ public AbstractBasicRelationSupport(SourceType source) { this.source = source; }
+
+ @Override
+ public Set<Relationship<? super SourceType, ? extends BrooklynObject>> getRelationships() {
+ return EntityRelations.getRelations(source);
+ }
+
+ @Override
+ public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super SourceType, U> relationship) {
+ return EntityRelations.getRelationships(relationship, source);
+ }
+
+ @Override
+ public <U extends BrooklynObject> void add(Relationship<? super SourceType, U> relationship, U target) {
+ EntityRelations.add(source, relationship, target);
+ }
+
+ @Override
+ public <U extends BrooklynObject> void remove(Relationship<? super SourceType, U> relationship, U target) {
+ EntityRelations.remove(source, relationship, target);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java b/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
new file mode 100644
index 0000000..1152e85
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/ByObjectBasicRelationSupport.java
@@ -0,0 +1,103 @@
+/*
+ * 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.core.relations;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.objs.BrooklynObject.RelationSupport;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.collections.MutableSet;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+import brooklyn.basic.relations.Relationship;
+
+public class ByObjectBasicRelationSupport<SourceType extends BrooklynObject> extends AbstractBasicRelationSupport<SourceType> {
+
+ DataForBasicRelations<SourceType> data;
+
+ public ByObjectBasicRelationSupport(SourceType source, Runnable relationChangeCallback) {
+ super(source);
+ data = new DataForBasicRelations<SourceType>(relationChangeCallback);
+ }
+
+ @Override
+ public RelationSupport<SourceType> getLocalBackingStore() {
+ return data;
+ }
+
+ public static class DataForBasicRelations<T extends BrooklynObject> implements RelationSupport<T> {
+
+ Runnable relationChangeCallback;
+
+ public DataForBasicRelations(Runnable relationChangeCallback) {
+ this.relationChangeCallback = relationChangeCallback;
+ }
+
+ // TODO for now, relationships are stored here (and persisted); ideally we'd look them up in catalog
+ private Map<String,Relationship<? super T,? extends BrooklynObject>> relationships = MutableMap.of();
+
+ private Multimap<String,BrooklynObject> relations = Multimaps.newMultimap(MutableMap.<String,Collection<BrooklynObject>>of(),
+ new Supplier<Collection<BrooklynObject>>() {
+ public Collection<BrooklynObject> get() {
+ return MutableSet.of();
+ }
+ });
+
+ public Set<Relationship<? super T,? extends BrooklynObject>> getRelationships() {
+ synchronized (relations) {
+ return MutableSet.copyOf(relationships.values());
+ }
+ }
+
+ @SuppressWarnings("unchecked") @Override
+ public <U extends BrooklynObject> Set<U> getRelations(Relationship<? super T, U> relationship) {
+ synchronized (relations) {
+ return (Set<U>)MutableSet.copyOf(relations.get(relationship.getRelationshipTypeName()));
+ }
+ }
+
+ @Override
+ public <U extends BrooklynObject> void add(Relationship<? super T,U> relationship, U target) {
+ synchronized (relations) {
+ relationships.put(relationship.getRelationshipTypeName(), relationship);
+ relations.put(relationship.getRelationshipTypeName(), target);
+ }
+ onRelationsChanged();
+ }
+
+ @Override
+ public <U extends BrooklynObject> void remove(Relationship<? super T,U> relationship, U target) {
+ synchronized (relations) {
+ relations.remove(relationship.getRelationshipTypeName(), target);
+ }
+ onRelationsChanged();
+ }
+
+ protected void onRelationsChanged() {
+ if (relationChangeCallback!=null) relationChangeCallback.run();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/core/relations/Relationships.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/relations/Relationships.java b/core/src/main/java/org/apache/brooklyn/core/relations/Relationships.java
new file mode 100644
index 0000000..8f7ad54
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/relations/Relationships.java
@@ -0,0 +1,188 @@
+/*
+ * 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.core.relations;
+
+import com.google.common.base.Objects;
+
+import brooklyn.basic.relations.Relationship;
+
+public class Relationships {
+
+ private static abstract class AbstractBasicRelationship<SourceType,TargetType> implements Relationship<SourceType,TargetType> {
+ private final String relationshipTypeName;
+ private final String sourceName;
+ private final String sourceNamePlural;
+ private final Class<TargetType> targetType;
+
+ private AbstractBasicRelationship(String relationshipTypeName, String sourceName, String sourceNamePlural, Class<TargetType> targetType) {
+ this.relationshipTypeName = relationshipTypeName;
+ this.sourceName = sourceName;
+ this.sourceNamePlural = sourceNamePlural;
+ this.targetType = targetType;
+ }
+
+ @Override
+ public String getRelationshipTypeName() {
+ return relationshipTypeName;
+ }
+
+ @Override
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ @Override
+ public String getSourceNamePlural() {
+ return sourceNamePlural;
+ }
+
+ @Override
+ public Class<TargetType> getTargetType() {
+ return targetType;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof AbstractBasicRelationship)) return false;
+
+ @SuppressWarnings("rawtypes")
+ AbstractBasicRelationship other = (AbstractBasicRelationship) obj;
+
+ // only look at type name and class; name of source and target is informational
+ if (!Objects.equal(relationshipTypeName, other.relationshipTypeName)) return false;
+ if (!Objects.equal(getSourceType(), other.getSourceType())) return false;
+ if (!Objects.equal(targetType, other.targetType)) return false;
+
+ if (getInverseRelationship() == null) {
+ // require both null or...
+ if (other.getInverseRelationship() != null)
+ return false;
+ } else {
+ // ... they have same type name
+ // (don't recurse as that sets up infinite loop)
+ if (other.getInverseRelationship() == null)
+ return false;
+ if (!Objects.equal(getInverseRelationship().getRelationshipTypeName(), other.getInverseRelationship().getRelationshipTypeName())) return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ // comments as per equals
+ return Objects.hashCode(relationshipTypeName, getSourceType(), targetType,
+ getInverseRelationship()!=null ? getInverseRelationship().getRelationshipTypeName() : null);
+ }
+
+ @Override
+ public String toString() {
+ return relationshipTypeName;
+ }
+ }
+
+ private static class BasicRelationshipWithInverse<SourceType,TargetType> extends AbstractBasicRelationship<SourceType,TargetType> {
+ private BasicRelationshipWithInverse<TargetType,SourceType> inverseRelationship;
+
+ private BasicRelationshipWithInverse(String relationshipTypeName, String sourceName, String sourceNamePlural, Class<TargetType> targetType) {
+ super(relationshipTypeName, sourceName, sourceNamePlural, targetType);
+ }
+
+ @Override
+ public Relationship<TargetType,SourceType> getInverseRelationship() {
+ return inverseRelationship;
+ }
+
+ @Override
+ public Class<SourceType> getSourceType() {
+ if (getInverseRelationship()==null) return null;
+ return getInverseRelationship().getTargetType();
+ }
+
+ @Override
+ public String getTargetName() {
+ if (getInverseRelationship()==null) return null;
+ return getInverseRelationship().getSourceName();
+ }
+
+ @Override
+ public String getTargetNamePlural() {
+ if (getInverseRelationship()==null) return null;
+ return getInverseRelationship().getSourceNamePlural();
+ }
+ }
+
+ private static class BasicRelationshipOneWay<SourceType,TargetType> extends AbstractBasicRelationship<SourceType,TargetType> {
+
+ private final String targetName;
+ private final String targetNamePlural;
+ private final Class<SourceType> sourceType;
+
+ private BasicRelationshipOneWay(String sourceName, String sourceNamePlural, Class<SourceType> sourceType, String toTargetRelationshipTypeName,
+ String targetName, String targetNamePlural, Class<TargetType> targetType) {
+ super(toTargetRelationshipTypeName, sourceName, sourceNamePlural, targetType);
+ this.targetName = targetName;
+ this.targetNamePlural = targetNamePlural;
+ this.sourceType = sourceType;
+ }
+
+ @Override
+ public Class<SourceType> getSourceType() {
+ return sourceType;
+ }
+
+ @Override
+ public String getTargetName() {
+ return targetName;
+ }
+
+ @Override
+ public String getTargetNamePlural() {
+ return targetNamePlural;
+ }
+
+ @Override
+ public Relationship<TargetType, SourceType> getInverseRelationship() {
+ return null;
+ }
+ }
+
+ public static <SourceType,TargetType> Relationship<SourceType,TargetType> newRelationshipPair(
+ String sourceName, String sourceNamePlural, Class<SourceType> sourceType, String toTargetRelationshipTypeName,
+ String targetName, String targetNamePlural, Class<TargetType> targetType, String toSourceRelationshipTypeName) {
+ BasicRelationshipWithInverse<SourceType, TargetType> r1 = new BasicRelationshipWithInverse<SourceType, TargetType>(
+ toTargetRelationshipTypeName, sourceName, sourceNamePlural, targetType);
+ BasicRelationshipWithInverse<TargetType, SourceType> r2 = new BasicRelationshipWithInverse<TargetType, SourceType>(
+ toSourceRelationshipTypeName, targetName, targetNamePlural, sourceType);
+ r1.inverseRelationship = r2;
+ r2.inverseRelationship = r1;
+ return r1;
+ }
+
+ public static <SourceType,TargetType> Relationship<SourceType,TargetType> newRelationshipOneway(
+ String sourceName, String sourceNamePlural, Class<SourceType> sourceType, String toTargetRelationshipTypeName,
+ String targetName, String targetNamePlural, Class<TargetType> targetType) {
+ return new BasicRelationshipOneWay<SourceType,TargetType>(
+ sourceName, sourceNamePlural, sourceType, toTargetRelationshipTypeName,
+ targetName, targetNamePlural, targetType);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java
index 8108c9f..d8814bd 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/AbstractGroupImpl.java
@@ -239,6 +239,8 @@ public abstract class AbstractGroupImpl extends AbstractEntity implements Abstra
@Override
public Collection<Entity> getMembers() {
+ // TODO use this instead; see issue and email thread where this comment was introduced
+// relations().getRelations(EntityRelations.GROUP_CONTAINS);
synchronized (members) {
return ImmutableSet.<Entity>copyOf(members);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
index 5dd776e..02b1076 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/EffectorSayHiGroovyTest.groovy
@@ -45,7 +45,7 @@ import org.testng.annotations.Test
/**
* Test the operation of the {@link Effector} implementations.
*
- * TODO clarify test purpose
+ * TODO delete? the groovy causes compile errors, and EffectorSayHiTest does most of what this does
*/
public class EffectorSayHiGroovyTest {
private static final Logger log = LoggerFactory.getLogger(EffectorSayHiTest.class);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityBasicTest.java b/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityBasicTest.java
new file mode 100644
index 0000000..ea4bcb3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityBasicTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.core.relations;
+
+import java.util.Collections;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.EntityRelations;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class RelationsEntityBasicTest extends BrooklynAppUnitTestSupport {
+
+ @Override
+ protected void setUpApp() {
+ super.setUpApp();
+ }
+
+ public void testCustomEntityRelation() {
+ TestEntity t1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+ TestEntity t2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ t1.relations().add(EntityRelations.HAS_TARGET, t2);
+ Assert.assertEquals(t1.relations().getRelations(EntityRelations.HAS_TARGET), Collections.singleton(t2));
+ Assert.assertEquals(t2.relations().getRelations(EntityRelations.HAS_TARGET), Collections.emptySet());
+ Assert.assertEquals(t2.relations().getRelations(EntityRelations.TARGETTED_BY), Collections.singleton(t1));
+
+ t1.relations().add(EntityRelations.HAS_TARGET, t2);
+ Assert.assertEquals(t1.relations().getRelations(EntityRelations.HAS_TARGET), Collections.singleton(t2));
+
+ t1.relations().add(EntityRelations.HAS_TARGET, t1);
+ Assert.assertEquals(t1.relations().getRelations(EntityRelations.HAS_TARGET), MutableSet.of(t1, t2));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/772e707f/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityRebindTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityRebindTest.java b/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityRebindTest.java
new file mode 100644
index 0000000..544794d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/relations/RelationsEntityRebindTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.core.relations;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.core.entity.EntityRelations;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class RelationsEntityRebindTest extends RebindTestFixtureWithApp {
+
+ public void testCustomEntityRelation() throws Exception {
+ TestEntity origT1 = origApp.createAndManageChild(EntitySpec.create(TestEntity.class));
+ TestEntity origT2 = origApp.createAndManageChild(EntitySpec.create(TestEntity.class));
+ origT1.relations().add(EntityRelations.HAS_TARGET, origT2);
+
+ TestApplication newApp = rebind();
+ Iterator<Entity> ci = newApp.getChildren().iterator();
+ Entity t1 = ci.next();
+ Entity t2 = ci.next();
+
+ Assert.assertEquals(t1.relations().getRelations(EntityRelations.HAS_TARGET), Collections.singleton(t2));
+ Assert.assertEquals(t2.relations().getRelations(EntityRelations.HAS_TARGET), Collections.emptySet());
+ Assert.assertEquals(t2.relations().getRelations(EntityRelations.TARGETTED_BY), Collections.singleton(t1));
+ }
+
+}