ResourcePredicates.urlExists() Adds a predicate that is true if a resource is available via a configurable context object. ConfigConstraints looks for instances of the Brooklyn-object-aware predicate and calls apply(T, BrooklynObject) if possible.
Requires non-deployment management contexts to return useful entitlement and OSGi managers. Rework contextual predicates Context must be passed to apply, not set as a field on the predicate. Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/60d85fa4 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/60d85fa4 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/60d85fa4 Branch: refs/heads/master Commit: 60d85fa41f566785663c45948d7a01612d3e92d5 Parents: 7a728b4 Author: Sam Corbett <[email protected]> Authored: Fri Sep 11 17:14:17 2015 +0100 Committer: Sam Corbett <[email protected]> Committed: Thu Oct 8 17:54:39 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/core/config/ConfigConstraints.java | 17 ++++-- .../NonDeploymentManagementContext.java | 18 +++--- .../core/objs/BrooklynObjectPredicate.java | 33 +++++++++++ .../brooklyn/util/core/ResourcePredicates.java | 61 ++++++++++++++++++++ .../core/config/ConfigKeyConstraintTest.java | 55 +++++++++++++++--- .../util/guava/PredicateWithContext.java | 33 +++++++++++ 6 files changed, 197 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java index 24142a5..6c6445f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java @@ -27,6 +27,7 @@ import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.objs.AbstractEntityAdjunct; +import org.apache.brooklyn.core.objs.BrooklynObjectPredicate; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,8 +45,8 @@ public abstract class ConfigConstraints<T extends BrooklynObject> { /** * Checks all constraints of all config keys available to an entity. * <p> - * If a constraint is a {@link BrooklynObjectAwarePredicate} then it will be - * informed of the entity before the predicate is tested. + * If a constraint is a {@link BrooklynObjectPredicate} then + * {@link BrooklynObjectPredicate#apply(Object, BrooklynObject)} will be used. */ public static void assertValid(Entity entity) { Iterable<ConfigKey<?>> violations = new EntityConfigConstraints(entity).getViolations(); @@ -57,8 +58,8 @@ public abstract class ConfigConstraints<T extends BrooklynObject> { /** * Checks all constraints of all config keys available to an entity adjunct. * <p> - * If a constraint is a {@link BrooklynObjectAwarePredicate} then it will be - * informed of the adjunct before the predicate is tested. + * If a constraint is a {@link BrooklynObjectPredicate} then + * {@link BrooklynObjectPredicate#apply(Object, BrooklynObject)} will be used. */ public static void assertValid(EntityAdjunct adjunct) { Iterable<ConfigKey<?>> violations = new EntityAdjunctConstraints(adjunct).getViolations(); @@ -114,7 +115,13 @@ public abstract class ConfigConstraints<T extends BrooklynObject> { // keep its type to Predicte<? super T>, where T is ConfigKey<T>. try { Predicate<Object> po = (Predicate<Object>) configKey.getConstraint(); - if (!po.apply(value)) { + boolean isValid; + if (po instanceof BrooklynObjectPredicate) { + isValid = BrooklynObjectPredicate.class.cast(po).apply(value, brooklynObject); + } else { + isValid = po.apply(value); + } + if (!isValid) { violating.add(configKey); } } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java index 1f62add..5223cf8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java @@ -102,7 +102,6 @@ public class NonDeploymentManagementContext implements ManagementContextInternal private NonDeploymentLocationManager locationManager; private NonDeploymentAccessManager accessManager; private NonDeploymentUsageManager usageManager; - private EntitlementManager entitlementManager;; public NonDeploymentManagementContext(AbstractEntity entity, NonDeploymentManagementContextMode mode) { this.entity = checkNotNull(entity, "entity"); @@ -113,10 +112,6 @@ public class NonDeploymentManagementContext implements ManagementContextInternal locationManager = new NonDeploymentLocationManager(null); accessManager = new NonDeploymentAccessManager(null); usageManager = new NonDeploymentUsageManager(null); - - // TODO might need to be some kind of "system" which can see that the system is running at this point - // though quite possibly we are entirely behind the auth-wall at this point - entitlementManager = Entitlements.minimal(); } @Override @@ -213,7 +208,15 @@ public class NonDeploymentManagementContext implements ManagementContextInternal @Override public Maybe<OsgiManager> getOsgiManager() { - return Maybe.absent(); + switch (mode) { + case PRE_MANAGEMENT: + case MANAGEMENT_STARTING: + case MANAGEMENT_STARTED: + checkInitialManagementContextReal(); + return initialManagementContext.getOsgiManager(); + default: + return Maybe.absent("Entity " + entity + " is no longer managed; OSGi context no longer available"); + } } @Override @@ -335,7 +338,8 @@ public class NonDeploymentManagementContext implements ManagementContextInternal @Override public EntitlementManager getEntitlementManager() { - return entitlementManager; + checkInitialManagementContextReal(); + return initialManagementContext.getEntitlementManager(); } @Override http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectPredicate.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectPredicate.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectPredicate.java new file mode 100644 index 0000000..422e9f8 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectPredicate.java @@ -0,0 +1,33 @@ +/* + * 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.objs; + +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.util.guava.PredicateWithContext; + +/** + * A marker interface for predicates that can use a {@link BrooklynObject} in their {@link #apply} method. + */ +public interface BrooklynObjectPredicate<P> extends PredicateWithContext<P, BrooklynObject> { + + @Override + boolean apply(P input, BrooklynObject context); + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java new file mode 100644 index 0000000..8bf0309 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java @@ -0,0 +1,61 @@ +/* + * 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.util.core; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.core.objs.BrooklynObjectPredicate; +import org.apache.brooklyn.util.text.Strings; + +import com.google.common.base.Predicate; + +public class ResourcePredicates { + + private ResourcePredicates() {} + + /** + * @return A predicate that tests whether its input is a resource readable by Brooklyn. + * @see ResourceUtils#doesUrlExist(String) + */ + public static Predicate<String> urlExists() { + return new ResourceExistsPredicate(); + } + + private static class ResourceExistsPredicate implements BrooklynObjectPredicate<String> { + + @Override + public boolean apply(@Nullable String resource) { + return apply(resource, null); + } + + @Override + public boolean apply(@Nullable String resource, @Nullable BrooklynObject context) { + return !Strings.isBlank(resource) && new ResourceUtils(context).doesUrlExist(resource); + } + + @Override + public String toString() { + return "ResourcePredicates.exists()"; + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java index 6cf42ab..05e0814 100644 --- a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java @@ -25,12 +25,14 @@ import static org.testng.Assert.fail; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.entity.ImplementedBy; +import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.objs.BrooklynObjectPredicate; import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.core.test.entity.TestEntity; @@ -48,6 +50,8 @@ import com.google.common.collect.Range; public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { + // ----------- Setup ----------------------------------------------------------------------------------------------- + @ImplementedBy(EntityWithNonNullConstraintImpl.class) public static interface EntityWithNonNullConstraint extends TestEntity { ConfigKey<Object> NON_NULL_CONFIG = ConfigKeys.builder(Object.class) @@ -56,6 +60,8 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { .constraint(Predicates.notNull()) .build(); } + public static class EntityWithNonNullConstraintImpl extends TestEntityImpl implements EntityWithNonNullConstraint { + } @ImplementedBy(EntityWithNonNullConstraintWithNonNullDefaultImpl.class) public static interface EntityWithNonNullConstraintWithNonNullDefault extends TestEntity { @@ -66,6 +72,8 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { .constraint(Predicates.notNull()) .build(); } + public static class EntityWithNonNullConstraintWithNonNullDefaultImpl extends TestEntityImpl implements EntityWithNonNullConstraintWithNonNullDefault { + } @ImplementedBy(EntityRequiringConfigKeyInRangeImpl.class) public static interface EntityRequiringConfigKeyInRange extends TestEntity { @@ -76,22 +84,25 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { .constraint(Range.closed(0, 9)) .build(); } + public static class EntityRequiringConfigKeyInRangeImpl extends TestEntityImpl implements EntityRequiringConfigKeyInRange { + } @ImplementedBy(EntityProvidingDefaultValueForConfigKeyInRangeImpl.class) public static interface EntityProvidingDefaultValueForConfigKeyInRange extends EntityRequiringConfigKeyInRange { ConfigKey<Integer> REVISED_RANGE = ConfigKeys.newConfigKeyWithDefault(RANGE, -1); } - - public static class EntityWithNonNullConstraintImpl extends TestEntityImpl implements EntityWithNonNullConstraint { - } - - public static class EntityWithNonNullConstraintWithNonNullDefaultImpl extends TestEntityImpl implements EntityWithNonNullConstraintWithNonNullDefault { + public static class EntityProvidingDefaultValueForConfigKeyInRangeImpl extends TestEntityImpl implements EntityProvidingDefaultValueForConfigKeyInRange { } - public static class EntityRequiringConfigKeyInRangeImpl extends TestEntityImpl implements EntityRequiringConfigKeyInRange { + @ImplementedBy(EntityWithContextAwareConstraintImpl.class) + public static interface EntityWithContextAwareConstraint extends TestEntity { + ConfigKey<String> MUST_BE_DISPLAY_NAME = ConfigKeys.builder(String.class) + .name("must-be-display-name") + .description("Configuration key that must not be null") + .constraint(new MatchesEntityDisplayNamePredicate()) + .build(); } - - public static class EntityProvidingDefaultValueForConfigKeyInRangeImpl extends TestEntityImpl implements EntityProvidingDefaultValueForConfigKeyInRange { + public static class EntityWithContextAwareConstraintImpl extends TestEntityImpl implements EntityWithContextAwareConstraint { } public static class PolicyWithConfigConstraint extends AbstractPolicy { @@ -110,6 +121,20 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { .build(); } + private static class MatchesEntityDisplayNamePredicate implements BrooklynObjectPredicate<String> { + @Override + public boolean apply(String input) { + return false; + } + + @Override + public boolean apply(String input, BrooklynObject context) { + return context != null && context.getDisplayName().equals(input); + } + } + + // ----------- Tests ----------------------------------------------------------------------------------------------- + @Test public void testExceptionWhenEntityHasNullConfig() { try { @@ -240,7 +265,21 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { } }) .build(); + // i.e. no exception. assertFalse(key.isValueValid("abc")); } + @Test + public void testContextAwarePredicateInformedOfEntity() { + try { + app.createAndManageChild(EntitySpec.create(EntityWithContextAwareConstraint.class) + .displayName("Mr. Big") + .configure("must-be-display-name", "Mr. Bag")); + fail("Expected exception when managing entity with incorrect config"); + } catch (Exception e) { + Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); + assertNotNull(t); + } + } + } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60d85fa4/utils/common/src/main/java/org/apache/brooklyn/util/guava/PredicateWithContext.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/PredicateWithContext.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/PredicateWithContext.java new file mode 100644 index 0000000..9e8eb5e --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/PredicateWithContext.java @@ -0,0 +1,33 @@ +/* + * 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.util.guava; + +import com.google.common.base.Predicate; + +/** + * A marker interface for predicates that may take a context object into account. + * <p> + * Such predicates should handle absent contexts sensibly. + */ +public interface PredicateWithContext<P, T> extends Predicate<P> { + + boolean apply(P input, T context); + +}
