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 <[email protected]> Authored: Mon Jun 22 23:09:15 2015 -0700 Committer: Alex Heneveld <[email protected]> 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)); + } + +}
