You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/12/23 12:06:41 UTC
[18/71] [abbrv] incubator-brooklyn git commit: Merge commit 'e430723'
into reorg2
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
----------------------------------------------------------------------
diff --cc brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
index 0000000,291a06a..47925e5
mode 000000,100644..100644
--- a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
@@@ -1,0 -1,252 +1,252 @@@
+ /*
+ * 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.camp.brooklyn.catalog;
+
+ import static org.testng.Assert.assertEquals;
+ import static org.testng.Assert.assertNull;
+
+ import java.util.Collection;
+ import java.util.List;
+
+ import org.apache.brooklyn.api.entity.Entity;
+ import org.apache.brooklyn.api.location.Location;
+ import org.apache.brooklyn.api.location.LocationDefinition;
+ import org.apache.brooklyn.api.location.LocationSpec;
+ import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
+ import org.apache.brooklyn.api.typereg.RegisteredType;
+ import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+ import org.apache.brooklyn.core.config.BasicConfigKey;
+ import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
+ import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+ import org.apache.brooklyn.core.typereg.RegisteredTypes;
+ import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+ import org.apache.brooklyn.test.support.TestResourceUnavailableException;
+ import org.apache.brooklyn.util.text.StringFunctions;
+ import org.testng.Assert;
+ import org.testng.annotations.AfterMethod;
+ import org.testng.annotations.Test;
+
+ import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.Iterables;
+ import com.google.common.collect.Lists;
+
+ public class CatalogYamlLocationTest extends AbstractYamlTest {
+ private static final String LOCALHOST_LOCATION_SPEC = "localhost";
+ private static final String LOCALHOST_LOCATION_TYPE = LocalhostMachineProvisioningLocation.class.getName();
+ private static final String SIMPLE_LOCATION_TYPE = "org.apache.brooklyn.test.osgi.entities.SimpleLocation";
+
+ @AfterMethod
+ public void tearDown() {
- for (RegisteredType ci : mgmt().getTypeRegistry().getAll(RegisteredTypePredicates.IS_LOCATION)) {
++ for (RegisteredType ci : mgmt().getTypeRegistry().getMatching(RegisteredTypePredicates.IS_LOCATION)) {
+ mgmt().getCatalog().deleteCatalogItem(ci.getSymbolicName(), ci.getVersion());
+ }
+ }
+
+ @Test
+ public void testAddCatalogItem() throws Exception {
+ assertEquals(countCatalogLocations(), 0);
+
+ String symbolicName = "my.catalog.location.id.load";
+ addCatalogLocation(symbolicName, LOCALHOST_LOCATION_TYPE, null);
+ assertAdded(symbolicName, LOCALHOST_LOCATION_TYPE);
+ removeAndAssert(symbolicName);
+ }
+
+ @Test
+ public void testAddCatalogItemOsgi() throws Exception {
+ assertEquals(countCatalogLocations(), 0);
+
+ String symbolicName = "my.catalog.location.id.load";
+ addCatalogLocation(symbolicName, SIMPLE_LOCATION_TYPE, getOsgiLibraries());
+ assertAdded(symbolicName, SIMPLE_LOCATION_TYPE);
+ assertOsgi(symbolicName);
+ removeAndAssert(symbolicName);
+ }
+
+ @Test
+ public void testAddCatalogItemTopLevelItemSyntax() throws Exception {
+ assertEquals(countCatalogLocations(), 0);
+
+ String symbolicName = "my.catalog.location.id.load";
+ addCatalogLocationTopLevelItemSyntax(symbolicName, LOCALHOST_LOCATION_TYPE, null);
+ assertAdded(symbolicName, LOCALHOST_LOCATION_TYPE);
+ removeAndAssert(symbolicName);
+ }
+
+ @Test
+ public void testAddCatalogItemOsgiTopLevelItemSyntax() throws Exception {
+ assertEquals(countCatalogLocations(), 0);
+
+ String symbolicName = "my.catalog.location.id.load";
+ addCatalogLocationTopLevelItemSyntax(symbolicName, SIMPLE_LOCATION_TYPE, getOsgiLibraries());
+ assertAdded(symbolicName, SIMPLE_LOCATION_TYPE);
+ assertOsgi(symbolicName);
+ removeAndAssert(symbolicName);
+ }
+
+ private void assertOsgi(String symbolicName) {
+ RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, TEST_VERSION);
+ Collection<OsgiBundleWithUrl> libs = item.getLibraries();
+ assertEquals(libs.size(), 1);
+ assertEquals(Iterables.getOnlyElement(libs).getUrl(), Iterables.getOnlyElement(getOsgiLibraries()));
+ }
+
+ @SuppressWarnings({ "rawtypes" })
+ private void assertAdded(String symbolicName, String expectedJavaType) {
+ RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, TEST_VERSION);
+ assertEquals(item.getSymbolicName(), symbolicName);
+ Assert.assertTrue(RegisteredTypes.isSubtypeOf(item, Location.class), "Expected Location, not "+item.getSuperTypes());
+ assertEquals(countCatalogLocations(), 1);
+
+ // Item added to catalog should automatically be available in location registry
+ LocationDefinition def = mgmt().getLocationRegistry().getDefinedLocationByName(symbolicName);
+ assertEquals(def.getId(), symbolicName);
+ assertEquals(def.getName(), symbolicName);
+
+ LocationSpec spec = (LocationSpec) mgmt().getTypeRegistry().createSpec(item, null, LocationSpec.class);
+ assertEquals(spec.getType().getName(), expectedJavaType);
+ }
+
+ private void removeAndAssert(String symbolicName) {
+ // Deleting item: should be gone from catalog, and from location registry
+ deleteCatalogEntity(symbolicName);
+
+ assertEquals(countCatalogLocations(), 0);
+ assertNull(mgmt().getLocationRegistry().getDefinedLocationByName(symbolicName));
+ }
+
+ @Test
+ public void testLaunchApplicationReferencingLocationClass() throws Exception {
+ String symbolicName = "my.catalog.location.id.launch";
+ addCatalogLocation(symbolicName, LOCALHOST_LOCATION_TYPE, null);
+ runLaunchApplicationReferencingLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
+ public void testLaunchApplicationReferencingLocationSpec() throws Exception {
+ String symbolicName = "my.catalog.location.id.launch";
+ addCatalogLocation(symbolicName, LOCALHOST_LOCATION_SPEC, null);
+ runLaunchApplicationReferencingLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
+ public void testLaunchApplicationReferencingLocationClassTopLevelItemSyntax() throws Exception {
+ String symbolicName = "my.catalog.location.id.launch";
+ addCatalogLocationTopLevelItemSyntax(symbolicName, LOCALHOST_LOCATION_TYPE, null);
+ runLaunchApplicationReferencingLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
+ public void testLaunchApplicationReferencingLocationSpecTopLevelSyntax() throws Exception {
+ String symbolicName = "my.catalog.location.id.launch";
+ addCatalogLocationTopLevelItemSyntax(symbolicName, LOCALHOST_LOCATION_SPEC, null);
+ runLaunchApplicationReferencingLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
+ public void testLaunchApplicationReferencingOsgiLocation() throws Exception {
+ String symbolicName = "my.catalog.location.id.launch";
+ addCatalogLocation(symbolicName, SIMPLE_LOCATION_TYPE, getOsgiLibraries());
+ runLaunchApplicationReferencingLocation(symbolicName, SIMPLE_LOCATION_TYPE);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ protected void runLaunchApplicationReferencingLocation(String locTypeInYaml, String locType) throws Exception {
+ Entity app = createAndStartApplication(
+ "name: simple-app-yaml",
+ "location: ",
+ " "+locTypeInYaml+":",
+ " config2: config2 override",
+ " config3: config3",
+ "services: ",
+ " - type: org.apache.brooklyn.entity.stock.BasicStartable");
+
+ Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
+ Location location = Iterables.getOnlyElement(simpleEntity.getLocations());
+ assertEquals(location.getClass().getName(), locType);
+ assertEquals(location.getConfig(new BasicConfigKey<String>(String.class, "config1")), "config1");
+ assertEquals(location.getConfig(new BasicConfigKey<String>(String.class, "config2")), "config2 override");
+ assertEquals(location.getConfig(new BasicConfigKey<String>(String.class, "config3")), "config3");
+ }
+
+ private List<String> getOsgiLibraries() {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+ return ImmutableList.of(OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL);
+ }
+
+ private void addCatalogLocation(String symbolicName, String locationType, List<String> libraries) {
+ ImmutableList.Builder<String> yaml = ImmutableList.<String>builder().add(
+ "brooklyn.catalog:",
+ " id: " + symbolicName,
+ " name: My Catalog Location",
+ " description: My description",
+ " version: " + TEST_VERSION);
+ if (libraries!=null && libraries.size() > 0) {
+ yaml.add(" libraries:")
+ .addAll(Lists.transform(libraries, StringFunctions.prepend(" - url: ")));
+ }
+ yaml.add(
+ " item.type: location",
+ " item:",
+ " type: " + locationType,
+ " brooklyn.config:",
+ " config1: config1",
+ " config2: config2");
+
+
+ addCatalogItems(yaml.build());
+ }
+
+ private void addCatalogLocationTopLevelItemSyntax(String symbolicName, String locationType, List<String> libraries) {
+ ImmutableList.Builder<String> yaml = ImmutableList.<String>builder().add(
+ "brooklyn.catalog:",
+ " id: " + symbolicName,
+ " name: My Catalog Location",
+ " description: My description",
+ " version: " + TEST_VERSION);
+ if (libraries!=null && libraries.size() > 0) {
+ yaml.add(" libraries:")
+ .addAll(Lists.transform(libraries, StringFunctions.prepend(" - url: ")));
+ }
+ yaml.add(
+ "",
+ "brooklyn.locations:",
+ "- type: " + locationType,
+ " brooklyn.config:",
+ " config1: config1",
+ " config2: config2");
+
+
+ addCatalogItems(yaml.build());
+ }
+
+ private int countCatalogLocations() {
- return Iterables.size(mgmt().getTypeRegistry().getAll(RegisteredTypePredicates.IS_LOCATION));
++ return Iterables.size(mgmt().getTypeRegistry().getMatching(RegisteredTypePredicates.IS_LOCATION));
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlVersioningTest.java
----------------------------------------------------------------------
diff --cc brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlVersioningTest.java
index 0000000,f92f3a4..440c114
mode 000000,100644..100644
--- a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlVersioningTest.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlVersioningTest.java
@@@ -1,0 -1,269 +1,269 @@@
+ /*
+ * 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.camp.brooklyn.catalog;
+
+ import static org.testng.Assert.assertEquals;
+ import static org.testng.Assert.assertFalse;
+ import static org.testng.Assert.assertTrue;
+ import static org.testng.Assert.fail;
+
+ import org.apache.brooklyn.api.entity.Entity;
+ import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+ import org.apache.brooklyn.api.typereg.RegisteredType;
+ import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
+ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
+ import org.apache.brooklyn.core.config.ConfigKeys;
+ import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+ import org.apache.brooklyn.core.typereg.RegisteredTypes;
+ import org.apache.brooklyn.entity.stock.BasicApplication;
+ import org.apache.brooklyn.entity.stock.BasicEntity;
+ import org.testng.Assert;
+ import org.testng.annotations.BeforeMethod;
+ import org.testng.annotations.Test;
+
+ import com.google.common.base.Predicates;
+ import com.google.common.collect.Iterables;
+
+ public class CatalogYamlVersioningTest extends AbstractYamlTest {
+
+ private BrooklynTypeRegistry types;
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUp() {
+ super.setUp();
+ types = mgmt().getTypeRegistry();
+ }
+
+ @Test
+ public void testAddItem() {
+ String symbolicName = "sampleId";
+ String version = "0.1.0";
+ addCatalogEntity(symbolicName, version);
+ assertSingleCatalogItem(symbolicName, version);
+ }
+
+ @Test
+ public void testAddUnversionedItem() {
+ String symbolicName = "sampleId";
+ addCatalogEntity(symbolicName, null);
+ assertSingleCatalogItem(symbolicName, BasicBrooklynCatalog.NO_VERSION);
+ }
+
+ @Test
+ public void testAddSameVersionFailsWhenIconIsDifferent() {
+ String symbolicName = "sampleId";
+ String version = "0.1.0";
+ addCatalogEntity(symbolicName, version);
+ addCatalogEntity(symbolicName, version);
+ try {
+ addCatalogEntity(symbolicName, version, BasicEntity.class.getName(), "classpath:/another/icon.png");
+ fail("Expected to fail");
+ } catch (IllegalStateException e) {
+ assertEquals(e.getMessage(), "Updating existing catalog entries is forbidden: " + symbolicName + ":" + version + ". Use forceUpdate argument to override.");
+ }
+ }
+
+ @Test
+ public void testAddSameVersionForce() {
+ String symbolicName = "sampleId";
+ String version = "0.1.0";
+ addCatalogEntity(symbolicName, version);
+ forceCatalogUpdate();
+ String expectedType = "org.apache.brooklyn.entity.stock.BasicApplication";
+ addCatalogEntity(symbolicName, version, expectedType);
+ RegisteredType item = types.get(symbolicName, version);
+ String yaml = RegisteredTypes.getImplementationDataStringForSpec(item);
+ assertTrue(yaml.contains(expectedType), "Version not updated:\n"+yaml);
+ }
+
+ @Test
+ public void testGetLatest() {
+ String symbolicName = "sampleId";
+ String v1 = "0.1.0";
+ String v2 = "0.2.0";
+ addCatalogEntity(symbolicName, v1);
+ addCatalogEntity(symbolicName, v2);
+ RegisteredType item = types.get(symbolicName, BasicBrooklynCatalog.DEFAULT_VERSION);
+ assertEquals(item.getVersion(), v2);
+ }
+
+ @Test
+ public void testGetLatestStable() {
+ String symbolicName = "sampleId";
+ String v1 = "0.1.0";
+ String v2 = "0.2.0-SNAPSHOT";
+ addCatalogEntity(symbolicName, v1);
+ addCatalogEntity(symbolicName, v2);
+ RegisteredType item = types.get(symbolicName, BasicBrooklynCatalog.DEFAULT_VERSION);
+ assertEquals(item.getVersion(), v1);
+ }
+
+ @Test
+ public void testDelete() {
+ String symbolicName = "sampleId";
+ String version = "0.1.0";
+ addCatalogEntity(symbolicName, version);
+
+ Iterable<RegisteredType> matches;
- matches = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ matches = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ assertTrue(matches.iterator().hasNext());
+
+ mgmt().getCatalog().deleteCatalogItem(symbolicName, version);
- matches = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ matches = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ assertFalse(matches.iterator().hasNext());
+ }
+
+ @Test
+ public void testDeleteDefault() {
+ String symbolicName = "sampleId";
+ addCatalogEntity(symbolicName, null);
+
+ Iterable<RegisteredType> matches;
- matches = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ matches = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ assertTrue(matches.iterator().hasNext());
+
+ mgmt().getCatalog().deleteCatalogItem(symbolicName, BasicBrooklynCatalog.NO_VERSION);
- matches = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ matches = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ assertFalse(matches.iterator().hasNext());
+ }
+
+ @Test
+ public void testList() {
+ String symbolicName = "sampleId";
+ String v1 = "0.1.0";
+ String v2 = "0.2.0-SNAPSHOT";
+ addCatalogEntity(symbolicName, v1);
+ addCatalogEntity(symbolicName, v2);
- Iterable<RegisteredType> items = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ Iterable<RegisteredType> items = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ assertEquals(Iterables.size(items), 2);
+ }
+
+ @Test
+ public void testVersionedReference() throws Exception {
+ String symbolicName = "sampleId";
+ String parentName = "parentId";
+ String v1 = "0.1.0";
+ String v2 = "0.2.0";
+ String expectedType = BasicApplication.class.getName();
+
+ addCatalogEntity(symbolicName, v1, expectedType);
+ addCatalogEntity(symbolicName, v2);
+ addCatalogEntity(parentName, v1, symbolicName + ":" + v1);
+
+ Entity app = createAndStartApplication(
+ "services:",
+ "- type: " + parentName + ":" + v1);
+
+ assertEquals(app.getEntityType().getName(), expectedType);
+ }
+
+ @Test
+ public void testUnversionedReference() throws Exception {
+ String symbolicName = "sampleId";
+ String parentName = "parentId";
+ String v1 = "0.1.0";
+ String v2 = "0.2.0";
+ String expectedType = BasicApplication.class.getName();
+
+ addCatalogEntity(symbolicName, v1);
+ addCatalogEntity(symbolicName, v2, expectedType);
+ addCatalogEntity(parentName, v1, symbolicName);
+
+ Entity app = createAndStartApplication(
+ "services:",
+ "- type: " + parentName + ":" + v1);
+
+ assertEquals(app.getEntityType().getName(), expectedType);
+ }
+
+ private void doTestVersionedReferenceJustAdded(boolean isVersionImplicitSyntax) throws Exception {
+ addCatalogItems( "brooklyn.catalog:",
+ " version: 0.9",
+ " items:",
+ " - id: referrent",
+ " item:",
+ " type: "+BasicEntity.class.getName(),
+ " - id: referrent",
+ " version: 1.1",
+ " item:",
+ " type: "+BasicEntity.class.getName(),
+ " brooklyn.config: { foo: bar }",
+ " - id: referrer",
+ " version: 1.0",
+ " item:",
+ (isVersionImplicitSyntax ?
+ " type: referrent:1.1" :
+ " type: referrent\n" +
+ " version: 1.1"));
+
- Iterable<RegisteredType> items = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo("referrer")));
++ Iterable<RegisteredType> items = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo("referrer")));
+ Assert.assertEquals(Iterables.size(items), 1, "Wrong number of: "+items);
+ RegisteredType item = Iterables.getOnlyElement(items);
+ Assert.assertEquals(item.getVersion(), "1.0");
+
+ Entity app = createAndStartApplication(
+ "services:",
+ (isVersionImplicitSyntax ?
+ "- type: referrer:1.0" :
+ "- type: referrer\n" +
+ " version: 1.0") );
+ Entity child = Iterables.getOnlyElement(app.getChildren());
+ Assert.assertTrue(child instanceof BasicEntity, "Wrong child: "+child);
+ Assert.assertEquals(child.getConfig(ConfigKeys.newStringConfigKey("foo")), "bar");
+ }
+
+ @Test
+ public void testVersionedReferenceJustAddedExplicitVersion() throws Exception {
+ doTestVersionedReferenceJustAdded(false);
+ }
+
+ @Test
+ public void testVersionedReferenceJustAddedImplicitVersionSyntax() throws Exception {
+ doTestVersionedReferenceJustAdded(true);
+ }
+
+ private void assertSingleCatalogItem(String symbolicName, String version) {
- Iterable<RegisteredType> items = types.getAll(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
++ Iterable<RegisteredType> items = types.getMatching(RegisteredTypePredicates.symbolicName(Predicates.equalTo(symbolicName)));
+ RegisteredType item = Iterables.getOnlyElement(items);
+ assertEquals(item.getSymbolicName(), symbolicName);
+ assertEquals(item.getVersion(), version);
+ }
+
+ private void addCatalogEntity(String symbolicName, String version) {
+ addCatalogEntity(symbolicName, version, BasicEntity.class.getName());
+ }
+
+ private void addCatalogEntity(String symbolicName, String version, String type) {
+ addCatalogEntity(symbolicName, version, type, "classpath://path/to/myicon.jpg");
+ }
+
+ private void addCatalogEntity(String symbolicName, String version, String type, String iconUrl) {
+ addCatalogItems(
+ "brooklyn.catalog:",
+ " id: " + symbolicName,
+ " name: My Catalog App",
+ " description: My description",
+ " icon_url: "+iconUrl,
+ (version != null ? " version: " + version : ""),
+ "",
+ "services:",
+ "- type: " + type);
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
----------------------------------------------------------------------
diff --cc brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
index 0000000,d8e4b1d..9cd6bc5
mode 000000,100644..100644
--- a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
@@@ -1,0 -1,259 +1,261 @@@
+ /*
+ * 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.camp.brooklyn.test.lite;
+
+ import static org.testng.Assert.assertEquals;
+ import static org.testng.Assert.assertNotNull;
+
+ import java.io.IOException;
+ import java.io.InputStreamReader;
+ import java.io.Reader;
+ import java.util.Collection;
+ import java.util.List;
+ import java.util.Map;
+
+ import org.apache.brooklyn.api.catalog.CatalogItem;
+ import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
+ import org.apache.brooklyn.api.entity.Entity;
+ import org.apache.brooklyn.api.entity.EntitySpec;
+ import org.apache.brooklyn.api.mgmt.Task;
+ import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
+ import org.apache.brooklyn.api.typereg.RegisteredType;
+ import org.apache.brooklyn.camp.spi.Assembly;
+ import org.apache.brooklyn.camp.spi.AssemblyTemplate;
+ import org.apache.brooklyn.camp.spi.pdp.PdpYamlTest;
+ import org.apache.brooklyn.camp.test.mock.web.MockWebPlatform;
+ import org.apache.brooklyn.core.catalog.CatalogPredicates;
+ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
+ import org.apache.brooklyn.core.catalog.internal.CatalogDto;
+ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+ import org.apache.brooklyn.core.config.ConfigKeys;
+ import org.apache.brooklyn.core.effector.AddChildrenEffector;
+ import org.apache.brooklyn.core.effector.Effectors;
+ import org.apache.brooklyn.core.entity.Entities;
+ import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+ import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
+ import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+ import org.apache.brooklyn.core.test.entity.TestApplication;
+ import org.apache.brooklyn.core.test.entity.TestEntity;
+ import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
+ import org.apache.brooklyn.core.typereg.RegisteredTypes;
+ import org.apache.brooklyn.test.support.TestResourceUnavailableException;
+ import org.apache.brooklyn.util.collections.MutableMap;
+ import org.apache.brooklyn.util.core.ResourceUtils;
+ import org.apache.brooklyn.util.core.config.ConfigBag;
+ import org.apache.brooklyn.util.stream.Streams;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.testng.Assert;
+ import org.testng.annotations.AfterMethod;
+ import org.testng.annotations.BeforeMethod;
+ import org.testng.annotations.Test;
+
+ import com.google.common.base.Joiner;
+ import com.google.common.base.Predicates;
+ import com.google.common.collect.Iterables;
+
+ /** Tests of lightweight CAMP integration. Since the "real" integration is in brooklyn-camp project,
+ * but some aspects of CAMP we want to be able to test here. */
+ public class CampYamlLiteTest {
+ private static final String TEST_VERSION = "0.1.2";
+
+ private static final Logger log = LoggerFactory.getLogger(CampYamlLiteTest.class);
+
+ protected LocalManagementContext mgmt;
+ protected CampPlatformWithJustBrooklynMgmt platform;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() {
+ mgmt = LocalManagementContextForTests.newInstanceWithOsgi();
+ platform = new CampPlatformWithJustBrooklynMgmt(mgmt);
+ MockWebPlatform.populate(platform, TestAppAssemblyInstantiator.class);
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() {
+ if (mgmt!=null) mgmt.terminate();
+ }
+
+ /** based on {@link PdpYamlTest} for parsing,
+ * then creating a {@link TestAppAssembly} */
+ @Test
+ public void testYamlServiceMatchAndBrooklynInstantiate() throws Exception {
+ Reader input = new InputStreamReader(getClass().getResourceAsStream("test-app-service-blueprint.yaml"));
+ AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input);
+ log.info("AT is:\n"+at.toString());
+ Assert.assertEquals(at.getName(), "sample");
+ Assert.assertEquals(at.getPlatformComponentTemplates().links().size(), 1);
+
+ // now use brooklyn to instantiate - note it won't be faithful, but it will set some config keys
+ Assembly assembly = at.getInstantiator().newInstance().instantiate(at, platform);
+
+ TestApplication app = ((TestAppAssembly)assembly).getBrooklynApp();
+ Assert.assertEquals( app.getConfig(TestEntity.CONF_NAME), "sample" );
+ Map<String, String> map = app.getConfig(TestEntity.CONF_MAP_THING);
+ Assert.assertEquals( map.get("desc"), "Tomcat sample JSP and servlet application." );
+
+ Assert.assertEquals( app.getChildren().size(), 1 );
+ Entity svc = Iterables.getOnlyElement(app.getChildren());
+ Assert.assertEquals( svc.getConfig(TestEntity.CONF_NAME), "Hello WAR" );
+ map = svc.getConfig(TestEntity.CONF_MAP_THING);
+ Assert.assertEquals( map.get("type"), MockWebPlatform.APPSERVER.getType() );
+ // desc ensures we got the information from the matcher, as this value is NOT in the yaml
+ Assert.assertEquals( map.get("desc"), MockWebPlatform.APPSERVER.getDescription() );
+ }
+
+ /** based on {@link PdpYamlTest} for parsing,
+ * then creating a {@link TestAppAssembly} */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
+ public void testAddChildrenEffector() throws Exception {
+ String childYaml = Streams.readFullyString(getClass().getResourceAsStream("test-app-service-blueprint.yaml"));
+ AddChildrenEffector newEff = new AddChildrenEffector(ConfigBag.newInstance()
+ .configure(AddChildrenEffector.EFFECTOR_NAME, "add_tomcat")
+ .configure(AddChildrenEffector.BLUEPRINT_YAML, childYaml)
+ .configure(AddChildrenEffector.EFFECTOR_PARAMETER_DEFS, MutableMap.of("war", (Object)MutableMap.of(
+ "defaultValue", "foo.war"))) ) ;
+ TestApplication app = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class).addInitializer(newEff));
+
+ // test adding, with a parameter
+ Task<List> task = app.invoke(Effectors.effector(List.class, "add_tomcat").buildAbstract(), MutableMap.of("war", "foo.bar"));
+ List result = task.get();
+
+ Entity newChild = Iterables.getOnlyElement(app.getChildren());
+ Assert.assertEquals(newChild.getConfig(ConfigKeys.newStringConfigKey("war")), "foo.bar");
+
+ Assert.assertEquals(Iterables.getOnlyElement(result), newChild.getId());
+ Entities.unmanage(newChild);
+
+ // and test default value
+ task = app.invoke(Effectors.effector(List.class, "add_tomcat").buildAbstract(), MutableMap.<String,Object>of());
+ result = task.get();
+
+ newChild = Iterables.getOnlyElement(app.getChildren());
+ Assert.assertEquals(newChild.getConfig(ConfigKeys.newStringConfigKey("war")), "foo.war");
+
+ Assert.assertEquals(Iterables.getOnlyElement(result), newChild.getId());
+ Entities.unmanage(newChild);
+ }
+
+ @Test
+ public void testYamlServiceForCatalog() {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ CatalogItem<?, ?> realItem = Iterables.getOnlyElement(mgmt.getCatalog().addItems(Streams.readFullyString(getClass().getResourceAsStream("test-app-service-blueprint.yaml"))));
+ Iterable<CatalogItem<Object, Object>> retrievedItems = mgmt.getCatalog()
+ .getCatalogItems(CatalogPredicates.symbolicName(Predicates.equalTo("catalog-name")));
+
+ Assert.assertEquals(Iterables.size(retrievedItems), 1, "Wrong retrieved items: "+retrievedItems);
+ CatalogItem<Object, Object> retrievedItem = Iterables.getOnlyElement(retrievedItems);
+ Assert.assertEquals(retrievedItem, realItem);
+
+ Collection<CatalogBundle> bundles = retrievedItem.getLibraries();
+ Assert.assertEquals(bundles.size(), 1);
+ CatalogBundle bundle = Iterables.getOnlyElement(bundles);
+ Assert.assertEquals(bundle.getUrl(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL);
+ Assert.assertEquals(bundle.getVersion(), "0.1.0");
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ EntitySpec<?> spec1 = (EntitySpec<?>) mgmt.getCatalog().createSpec((CatalogItem)retrievedItem);
+ assertNotNull(spec1);
+ Assert.assertEquals(spec1.getConfig().get(TestEntity.CONF_NAME), "sample");
+
+ // TODO other assertions, about children
+ }
+
+ @Test
+ public void testRegisterCustomEntityWithBundleWhereEntityIsFromCoreAndIconFromBundle() throws IOException {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ String symbolicName = "my.catalog.app.id";
+ String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
+ String yaml = getSampleMyCatalogAppYaml(symbolicName, bundleUrl);
+
+ mgmt.getCatalog().addItems(yaml);
+
+ assertMgmtHasSampleMyCatalogApp(symbolicName, bundleUrl);
+ }
+
+ @Test
+ public void testResetXmlWithCustomEntity() throws IOException {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ String symbolicName = "my.catalog.app.id";
+ String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
+ String yaml = getSampleMyCatalogAppYaml(symbolicName, bundleUrl);
+
+ LocalManagementContext mgmt2 = LocalManagementContextForTests.newInstanceWithOsgi();
+ try {
+ CampPlatformWithJustBrooklynMgmt platform2 = new CampPlatformWithJustBrooklynMgmt(mgmt2);
+ MockWebPlatform.populate(platform2, TestAppAssemblyInstantiator.class);
+
+ mgmt2.getCatalog().addItems(yaml);
+ String xml = ((BasicBrooklynCatalog) mgmt2.getCatalog()).toXmlString();
+ ((BasicBrooklynCatalog) mgmt.getCatalog()).reset(CatalogDto.newDtoFromXmlContents(xml, "copy of temporary catalog"));
+ } finally {
+ mgmt2.terminate();
+ }
+
+ assertMgmtHasSampleMyCatalogApp(symbolicName, bundleUrl);
+ }
+
+ private String getSampleMyCatalogAppYaml(String symbolicName, String bundleUrl) {
+ return "brooklyn.catalog:\n" +
+ " id: " + symbolicName + "\n" +
+ " name: My Catalog App\n" +
+ " description: My description\n" +
+ " icon_url: classpath:/org/apache/brooklyn/test/osgi/entities/icon.gif\n" +
+ " version: " + TEST_VERSION + "\n" +
+ " libraries:\n" +
+ " - url: " + bundleUrl + "\n" +
+ "\n" +
+ "services:\n" +
+ "- type: io.camp.mock:AppServer\n";
+ }
+
+ private void assertMgmtHasSampleMyCatalogApp(String symbolicName, String bundleUrl) {
- RegisteredType item = RegisteredTypes.validate(mgmt.getTypeRegistry().get(symbolicName), RegisteredTypeLoadingContexts.spec(Entity.class));
++ RegisteredType item = mgmt.getTypeRegistry().get(symbolicName);
+ assertNotNull(item, "failed to load item with id=" + symbolicName + " from catalog. Entries were: " +
+ Joiner.on(",").join(mgmt.getTypeRegistry().getAll()));
+ assertEquals(item.getSymbolicName(), symbolicName);
+
++ RegisteredTypes.tryValidate(item, RegisteredTypeLoadingContexts.spec(Entity.class)).get();
++
+ // stored as yaml, not java
+ String planYaml = RegisteredTypes.getImplementationDataStringForSpec(item);
+ assertNotNull(planYaml);
+ Assert.assertTrue(planYaml.contains("io.camp.mock:AppServer"));
+
+ // and let's check we have libraries
+ Collection<OsgiBundleWithUrl> libs = item.getLibraries();
+ assertEquals(libs.size(), 1);
+ OsgiBundleWithUrl bundle = Iterables.getOnlyElement(libs);
+ assertEquals(bundle.getUrl(), bundleUrl);
+
+ // now let's check other things on the item
+ assertEquals(item.getDisplayName(), "My Catalog App");
+ assertEquals(item.getDescription(), "My description");
+ assertEquals(item.getIconUrl(), "classpath:/org/apache/brooklyn/test/osgi/entities/icon.gif");
+
+ // and confirm we can resolve ICON
+ byte[] iconData = Streams.readFully(ResourceUtils.create(CatalogUtils.newClassLoadingContext(mgmt, item)).getResourceFromUrl(item.getIconUrl()));
+ assertEquals(iconData.length, 43);
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemComparator.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemComparator.java
index 0000000,dc41457..abd4d08
mode 000000,100644..100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemComparator.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemComparator.java
@@@ -1,0 -1,142 +1,52 @@@
+ /*
+ * 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.catalog.internal;
+
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
++import java.util.Collections;
+ import java.util.Comparator;
+
+ import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.util.text.NaturalOrderComparator;
++import org.apache.brooklyn.util.text.VersionComparator;
+
+ /**
+ * Largest version first order.
+ *
+ * When using the comparator to sort - first using symbolicName
+ * and if equal puts larger versions first, snapshots at the back.
+ */
+ public class CatalogItemComparator<T,SpecT> implements Comparator<CatalogItem<T, SpecT>> {
- private static final String SNAPSHOT = "SNAPSHOT";
+
+ public static final CatalogItemComparator<?, ?> INSTANCE = new CatalogItemComparator<Object, Object>();
+
+ @SuppressWarnings("unchecked")
+ public static <T,SpecT> CatalogItemComparator<T,SpecT> getInstance() {
+ return (CatalogItemComparator<T, SpecT>) INSTANCE;
+ }
+
+ @Override
+ public int compare(CatalogItem<T, SpecT> o1, CatalogItem<T, SpecT> o2) {
+ int symbolicNameComparison = o1.getSymbolicName().compareTo(o2.getSymbolicName());
+ if (symbolicNameComparison != 0) {
+ return symbolicNameComparison;
+ } else {
- String v1 = o1.getVersion();
- String v2 = o2.getVersion();
-
- boolean isV1Snapshot = v1.toUpperCase().contains(SNAPSHOT);
- boolean isV2Snapshot = v2.toUpperCase().contains(SNAPSHOT);
- if (isV1Snapshot == isV2Snapshot) {
- String[] v1Parts = split(v1);
- String[] v2Parts = split(v2);
- return -compare(v1Parts, v2Parts);
- } else if (isV1Snapshot) {
- return 1;
- } else {
- return -1;
- }
- }
- }
-
- private String[] split(String v) {
- Collection<String> parts = new ArrayList<String>();
- int startPos = 0;
- int delimPos;
- while ((delimPos = v.indexOf('.', startPos)) != -1) {
- String part = v.substring(startPos, delimPos);
- if (parse(part) != -1) {
- parts.add(part);
- } else {
- break;
- }
- startPos = delimPos+1;
- }
- String remaining = v.substring(startPos);
- parts.addAll(Arrays.asList(remaining.split("[^\\d]", 2)));
- return parts.toArray(new String[parts.size()]);
- }
-
- private int compare(String[] v1Parts, String[] v2Parts) {
- int len = Math.max(v1Parts.length, v2Parts.length);
- for (int i = 0; i < len; i++) {
- if (i == v1Parts.length) {
- return isNumber(v2Parts[i]) ? -1 : 1;
- }
- if (i == v2Parts.length) {
- return isNumber(v1Parts[i]) ? 1 : -1;
- }
-
- String p1 = v1Parts[i];
- String p2 = v2Parts[i];
- int n1 = parse(p1);
- int n2 = parse(p2);
- if (n1 != -1 && n2 != -1) {
- if (n1 != n2) {
- return compare(n1, n2);
- }
- } else if (n1 == -1 && n2 != -1) {
- return -1;
- } else if (n1 != -1 && n2 == -1) {
- return 1;
- } else {
- int cmp = NaturalOrderComparator.INSTANCE.compare(p1, p2);
- if (cmp < 0) {
- return -1;
- } else if (cmp > 0) {
- return 1;
- }
- }
++ return Collections.reverseOrder(VersionComparator.INSTANCE).compare(o1.getVersion(), o2.getVersion());
+ }
- return 0;
+ }
+
- private boolean isNumber(String v) {
- return parse(v) != -1;
- }
-
- //Replace with Integer.compare in J7
- private int compare(int n1, int n2) {
- if (n1 == n2) {
- return 0;
- } else if (n1 < n2) {
- return -1;
- } else {
- return 1;
- }
- }
-
- private int parse(String p) {
- try {
- return Integer.parseInt(p);
- } catch (NumberFormatException e) {
- return -1;
- }
- }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
index 0000000,ef455c6..dce5493
mode 000000,100644..100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
@@@ -1,0 -1,319 +1,321 @@@
+ /*
+ * 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.catalog.internal;
+
+ import java.util.Collection;
+
+ import javax.annotation.Nullable;
+
+ import org.apache.brooklyn.api.catalog.BrooklynCatalog;
+ import org.apache.brooklyn.api.catalog.CatalogItem;
+ import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
+ import org.apache.brooklyn.api.entity.Entity;
+ import org.apache.brooklyn.api.mgmt.ManagementContext;
+ import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
+ import org.apache.brooklyn.api.objs.BrooklynObject;
+ import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+ import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
+ import org.apache.brooklyn.api.typereg.RegisteredType;
+ import org.apache.brooklyn.core.BrooklynLogging;
+ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+ import org.apache.brooklyn.core.entity.EntityInternal;
+ import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
+ import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
+ import org.apache.brooklyn.core.mgmt.classloading.OsgiBrooklynClassLoadingContext;
+ import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
+ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+ import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl.RebindTracker;
+ import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+ import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
++import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
+ import org.apache.brooklyn.core.typereg.RegisteredTypes;
+ import org.apache.brooklyn.util.guava.Maybe;
+ import org.apache.brooklyn.util.text.Strings;
+ import org.apache.brooklyn.util.time.Time;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
-import com.google.api.client.util.Preconditions;
+ import com.google.common.annotations.Beta;
+ import com.google.common.base.Joiner;
++import com.google.common.base.Preconditions;
+ import com.google.common.base.Stopwatch;
+
+ public class CatalogUtils {
+ private static final Logger log = LoggerFactory.getLogger(CatalogUtils.class);
+
+ public static final char VERSION_DELIMITER = ':';
+
+ public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, CatalogItem<?, ?> item) {
+ // TODO getLibraries() should never be null but sometimes it is still
+ // e.g. run CatalogResourceTest without the above check
+ if (item.getLibraries() == null) {
+ log.debug("CatalogItemDtoAbstract.getLibraries() is null.", new Exception("Trace for null CatalogItemDtoAbstract.getLibraries()"));
+ }
+ return newClassLoadingContext(mgmt, item.getId(), item.getLibraries());
+ }
+
+ public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item) {
+ return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), null);
+ }
+
+ /** made @Beta in 0.9.0 because we're not sure to what extent to support stacking loaders;
+ * only a couple places currently rely on such stacking, in general the item and the bundles *are* the context,
+ * and life gets hard if we support complex stacking! */
+ @Beta
+ public static BrooklynClassLoadingContext newClassLoadingContext(ManagementContext mgmt, RegisteredType item, BrooklynClassLoadingContext loader) {
+ return newClassLoadingContext(mgmt, item.getId(), item.getLibraries(), loader);
+ }
+
+ public static BrooklynClassLoadingContext getClassLoadingContext(Entity entity) {
+ ManagementContext mgmt = ((EntityInternal)entity).getManagementContext();
+ String catId = entity.getCatalogItemId();
+ if (Strings.isBlank(catId)) return JavaBrooklynClassLoadingContext.create(mgmt);
- RegisteredType cat = RegisteredTypes.validate(mgmt.getTypeRegistry().get(catId), RegisteredTypeLoadingContexts.spec(Entity.class));
- if (cat==null) {
++ Maybe<RegisteredType> cat = RegisteredTypes.tryValidate(mgmt.getTypeRegistry().get(catId), RegisteredTypeLoadingContexts.spec(Entity.class));
++ if (cat.isNull()) {
+ log.warn("Cannot load "+catId+" to get classloader for "+entity+"; will try with standard loader, but might fail subsequently");
+ return JavaBrooklynClassLoadingContext.create(mgmt);
+ }
- return newClassLoadingContext(mgmt, cat);
++ return newClassLoadingContext(mgmt, cat.get());
+ }
+
+ public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries) {
+ return newClassLoadingContext(mgmt, catalogItemId, libraries, null);
+ }
+
+ @Deprecated /** @deprecated since 0.9.0; becoming private because we should now always have a registered type callers can pass instead of the catalog item id */
+ public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<? extends OsgiBundleWithUrl> libraries, BrooklynClassLoadingContext loader) {
+ BrooklynClassLoadingContextSequential result = new BrooklynClassLoadingContextSequential(mgmt);
+
+ if (libraries!=null && !libraries.isEmpty()) {
+ result.add(new OsgiBrooklynClassLoadingContext(mgmt, catalogItemId, libraries));
+ }
+
+ if (loader !=null) {
+ // TODO determine whether to support stacking
+ result.add(loader);
+ }
+ BrooklynClassLoadingContext threadLocalLoader = BrooklynLoaderTracker.getLoader();
+ if (threadLocalLoader != null) {
+ // TODO and determine if this is needed/wanted
+ result.add(threadLocalLoader);
+ }
+
+ result.addSecondary(JavaBrooklynClassLoadingContext.create(mgmt));
+ return result;
+ }
+
+ /**
+ * @deprecated since 0.7.0 only for legacy catalog items which provide a non-osgi loader; see {@link #newDefault(ManagementContext)}
+ */ @Deprecated
+ public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable ManagementContext mgmt, String catalogItemId, Collection<CatalogBundle> libraries, ClassLoader customClassLoader) {
+ BrooklynClassLoadingContextSequential result = new BrooklynClassLoadingContextSequential(mgmt);
+
+ if (libraries!=null && !libraries.isEmpty()) {
+ result.add(new OsgiBrooklynClassLoadingContext(mgmt, catalogItemId, libraries));
+ }
+
+ BrooklynClassLoadingContext loader = BrooklynLoaderTracker.getLoader();
+ if (loader != null) {
+ result.add(loader);
+ }
+
+ result.addSecondary(JavaBrooklynClassLoadingContext.create(mgmt, customClassLoader));
+ return result;
+ }
+
+ /**
+ * Registers all bundles with the management context's OSGi framework.
+ */
+ public static void installLibraries(ManagementContext managementContext, @Nullable Collection<CatalogBundle> libraries) {
+ if (libraries == null) return;
+
+ ManagementContextInternal mgmt = (ManagementContextInternal) managementContext;
+ if (!libraries.isEmpty()) {
+ Maybe<OsgiManager> osgi = mgmt.getOsgiManager();
+ if (osgi.isAbsent()) {
+ throw new IllegalStateException("Unable to load bundles "+libraries+" because OSGi is not running.");
+ }
+ if (log.isDebugEnabled())
+ logDebugOrTraceIfRebinding(log,
+ "Loading bundles in {}: {}",
+ new Object[] {managementContext, Joiner.on(", ").join(libraries)});
+ Stopwatch timer = Stopwatch.createStarted();
+ for (CatalogBundle bundleUrl : libraries) {
+ osgi.get().registerBundle(bundleUrl);
+ }
+ if (log.isDebugEnabled())
+ logDebugOrTraceIfRebinding(log,
+ "Registered {} bundles in {}",
+ new Object[]{libraries.size(), Time.makeTimeStringRounded(timer)});
+ }
+ }
+
+ /** Scans the given {@link BrooklynClassLoadingContext} to detect what catalog item id is in effect. */
+ public static String getCatalogItemIdFromLoader(BrooklynClassLoadingContext loader) {
+ if (loader instanceof OsgiBrooklynClassLoadingContext) {
+ return ((OsgiBrooklynClassLoadingContext)loader).getCatalogItemId();
+ } else {
+ return null;
+ }
+ }
+
+ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject itemBeingAdded) {
+ if (entity.getCatalogItemId()!=null) {
+ if (itemBeingAdded.getCatalogItemId()==null) {
+ if (log.isDebugEnabled())
+ BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+ "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded);
+ ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemId(entity.getCatalogItemId());
+ } else {
+ if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) {
+ // not a problem, but something to watch out for
+ log.debug("Cross-catalog item detected: "+entity+" from "+entity.getCatalogItemId()+" has "+itemBeingAdded+" from "+itemBeingAdded.getCatalogItemId());
+ }
+ }
+ } else if (itemBeingAdded.getCatalogItemId()!=null) {
+ if (log.isDebugEnabled())
+ BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity),
+ "Catalog item addition: "+entity+" without catalog item ID has "+itemBeingAdded+" from "+itemBeingAdded.getCatalogItemId());
+ }
+ }
+
+ @Beta
+ public static void logDebugOrTraceIfRebinding(Logger log, String message, Object ...args) {
+ if (RebindTracker.isRebinding())
+ log.trace(message, args);
+ else
+ log.debug(message, args);
+ }
+
+ public static boolean looksLikeVersionedId(String versionedId) {
+ if (versionedId==null) return false;
+ int fi = versionedId.indexOf(VERSION_DELIMITER);
+ if (fi<0) return false;
+ int li = versionedId.lastIndexOf(VERSION_DELIMITER);
+ if (li!=fi) {
+ // if multiple colons, we say it isn't a versioned reference; the prefix in that case must understand any embedded versioning scheme
+ // this fixes the case of: http://localhost:8080
+ return false;
+ }
+ String candidateVersion = versionedId.substring(li+1);
+ if (!candidateVersion.matches("[0-9]+(|(\\.|_).*)")) {
+ // version must start with a number, followed if by anything with full stop or underscore before any other characters
+ // e.g. foo:1 or foo:1.1 or foo:1_SNAPSHOT all supported, but not e.g. foo:bar (or chef:cookbook or docker:my/image)
+ return false;
+ }
+ return true;
+ }
+
+ /** @deprecated since 0.9.0 use {@link #getSymbolicNameFromVersionedId(String)} */
+ // all uses removed
+ @Deprecated
+ public static String getIdFromVersionedId(String versionedId) {
+ return getSymbolicNameFromVersionedId(versionedId);
+ }
+
+ public static String getSymbolicNameFromVersionedId(String versionedId) {
+ if (versionedId == null) return null;
+ int versionDelimiterPos = versionedId.lastIndexOf(VERSION_DELIMITER);
+ if (versionDelimiterPos != -1) {
+ return versionedId.substring(0, versionDelimiterPos);
+ } else {
+ return null;
+ }
+ }
+
+ public static String getVersionFromVersionedId(String versionedId) {
+ if (versionedId == null) return null;
+ int versionDelimiterPos = versionedId.lastIndexOf(VERSION_DELIMITER);
+ if (versionDelimiterPos != -1) {
+ return versionedId.substring(versionDelimiterPos+1);
+ } else {
+ return null;
+ }
+ }
+
+ public static String getVersionedId(String id, String version) {
+ // TODO null checks
+ return id + VERSION_DELIMITER + version;
+ }
+
+ /** @deprecated since 0.9.0 use {@link BrooklynTypeRegistry#get(String, org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind, Class)} */
+ // only a handful of items remaining, and those require a CatalogItem
+ public static CatalogItem<?, ?> getCatalogItemOptionalVersion(ManagementContext mgmt, String versionedId) {
+ if (versionedId == null) return null;
+ if (looksLikeVersionedId(versionedId)) {
+ String id = getSymbolicNameFromVersionedId(versionedId);
+ String version = getVersionFromVersionedId(versionedId);
+ return mgmt.getCatalog().getCatalogItem(id, version);
+ } else {
+ return mgmt.getCatalog().getCatalogItem(versionedId, BrooklynCatalog.DEFAULT_VERSION);
+ }
+ }
+
+ public static boolean isBestVersion(ManagementContext mgmt, CatalogItem<?,?> item) {
- RegisteredType bestVersion = mgmt.getTypeRegistry().get(item.getSymbolicName(), BrooklynCatalog.DEFAULT_VERSION);
- if (bestVersion==null) return false;
- return (bestVersion.getVersion().equals(item.getVersion()));
++ RegisteredType best = RegisteredTypes.getBestVersion(mgmt.getTypeRegistry().getMatching(
++ RegisteredTypePredicates.symbolicName(item.getSymbolicName())));
++ if (best==null) return false;
++ return (best.getVersion().equals(item.getVersion()));
+ }
+
+ /** @deprecated since 0.9.0 use {@link BrooklynTypeRegistry#get(String, org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind, Class)} */
+ // only a handful of items remaining, and those require a CatalogItem
+ public static <T,SpecT> CatalogItem<T, SpecT> getCatalogItemOptionalVersion(ManagementContext mgmt, Class<T> type, String versionedId) {
+ if (looksLikeVersionedId(versionedId)) {
+ String id = getSymbolicNameFromVersionedId(versionedId);
+ String version = getVersionFromVersionedId(versionedId);
+ return mgmt.getCatalog().getCatalogItem(type, id, version);
+ } else {
+ return mgmt.getCatalog().getCatalogItem(type, versionedId, BrooklynCatalog.DEFAULT_VERSION);
+ }
+ }
+
+ /** @deprecated since it was introduced in 0.9.0; TBD where this should live */
+ public static void setDeprecated(ManagementContext mgmt, String symbolicNameAndOptionalVersion, boolean newValue) {
+ RegisteredType item = mgmt.getTypeRegistry().get(symbolicNameAndOptionalVersion);
- Preconditions.checkNotNull(item, "No such item: "+symbolicNameAndOptionalVersion);
++ Preconditions.checkNotNull(item, "No such item: " + symbolicNameAndOptionalVersion);
+ setDeprecated(mgmt, item.getSymbolicName(), item.getVersion(), newValue);
+ }
+
+ /** @deprecated since it was introduced in 0.9.0; TBD where this should live */
+ public static void setDisabled(ManagementContext mgmt, String symbolicNameAndOptionalVersion, boolean newValue) {
+ RegisteredType item = mgmt.getTypeRegistry().get(symbolicNameAndOptionalVersion);
+ Preconditions.checkNotNull(item, "No such item: "+symbolicNameAndOptionalVersion);
+ setDisabled(mgmt, item.getSymbolicName(), item.getVersion(), newValue);
+ }
+
+ /** @deprecated since it was introduced in 0.9.0; TBD where this should live */
+ @Deprecated
+ public static void setDeprecated(ManagementContext mgmt, String symbolicName, String version, boolean newValue) {
+ CatalogItem<?, ?> item = mgmt.getCatalog().getCatalogItem(symbolicName, version);
+ Preconditions.checkNotNull(item, "No such item: "+symbolicName+" v "+version);
+ item.setDeprecated(newValue);
+ mgmt.getCatalog().persist(item);
+ }
+
+ /** @deprecated since it was introduced in 0.9.0; TBD where this should live */
+ @Deprecated
+ public static void setDisabled(ManagementContext mgmt, String symbolicName, String version, boolean newValue) {
+ CatalogItem<?, ?> item = mgmt.getCatalog().getCatalogItem(symbolicName, version);
+ Preconditions.checkNotNull(item, "No such item: "+symbolicName+" v "+version);
+ item.setDisabled(newValue);
+ mgmt.getCatalog().persist(item);
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
index 0000000,fe5e064..2e59185
mode 000000,100644..100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigKey.java
@@@ -1,0 -1,316 +1,321 @@@
+ /*
+ * 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.config;
+
+ import static com.google.common.base.Preconditions.checkNotNull;
+
+ import java.io.Serializable;
+ import java.util.Collection;
+ import java.util.Map;
+ import java.util.concurrent.ExecutionException;
+
+ import javax.annotation.Nonnull;
+ import javax.annotation.Nullable;
+
+ import org.apache.brooklyn.api.mgmt.ExecutionContext;
+ import org.apache.brooklyn.config.ConfigInheritance;
+ import org.apache.brooklyn.config.ConfigKey;
+ import org.apache.brooklyn.util.core.internal.ConfigKeySelfExtracting;
+ import org.apache.brooklyn.util.core.task.Tasks;
+ import org.apache.brooklyn.util.exceptions.Exceptions;
+ import org.apache.brooklyn.util.guava.TypeTokens;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import com.google.common.annotations.Beta;
+ import com.google.common.base.Objects;
+ import com.google.common.base.Preconditions;
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+ import com.google.common.base.Splitter;
+ import com.google.common.collect.Lists;
+ import com.google.common.reflect.TypeToken;
+
+ public class BasicConfigKey<T> implements ConfigKeySelfExtracting<T>, Serializable {
+
+ @SuppressWarnings("unused")
+ private static final Logger log = LoggerFactory.getLogger(BasicConfigKey.class);
+ private static final long serialVersionUID = -1762014059150215376L;
+
+ private static final Splitter dots = Splitter.on('.');
+
+ public static <T> Builder<T> builder(TypeToken<T> type) {
+ return new Builder<T>().type(type);
+ }
+
+ public static <T> Builder<T> builder(Class<T> type) {
+ return new Builder<T>().type(type);
+ }
+
+ public static <T> Builder<T> builder(TypeToken<T> type, String name) {
+ return new Builder<T>().type(type).name(name);
+ }
+
+ public static <T> Builder<T> builder(Class<T> type, String name) {
+ return new Builder<T>().type(type).name(name);
+ }
+
+ public static <T> Builder<T> builder(ConfigKey<T> key) {
+ return new Builder<T>()
+ .name(checkNotNull(key.getName(), "name"))
+ .type(checkNotNull(key.getTypeToken(), "type"))
+ .description(key.getDescription())
+ .defaultValue(key.getDefaultValue())
+ .reconfigurable(key.isReconfigurable())
+ .inheritance(key.getInheritance())
+ .constraint(key.getConstraint());
+ }
+
+ public static class Builder<T> {
+ private String name;
+ private TypeToken<T> type;
+ private String description;
+ private T defaultValue;
+ private boolean reconfigurable;
+ private Predicate<? super T> constraint = Predicates.alwaysTrue();
+ private ConfigInheritance inheritance;
+
+ public Builder<T> name(String val) {
+ this.name = val; return this;
+ }
+ public Builder<T> type(Class<T> val) {
+ this.type = TypeToken.of(val); return this;
+ }
+ public Builder<T> type(TypeToken<T> val) {
+ this.type = val; return this;
+ }
+ public Builder<T> description(String val) {
+ this.description = val; return this;
+ }
+ public Builder<T> defaultValue(T val) {
+ this.defaultValue = val; return this;
+ }
+ public Builder<T> reconfigurable(boolean val) {
+ this.reconfigurable = val; return this;
+ }
+ public Builder<T> inheritance(ConfigInheritance val) {
+ this.inheritance = val; return this;
+ }
+ @Beta
+ public Builder<T> constraint(Predicate<? super T> constraint) {
+ this.constraint = checkNotNull(constraint, "constraint"); return this;
+ }
+ public BasicConfigKey<T> build() {
+ return new BasicConfigKey<T>(this);
+ }
+ }
+
+ private String name;
+ private TypeToken<T> typeToken;
+ private Class<? super T> type;
+ private String description;
+ private T defaultValue;
+ private boolean reconfigurable;
+ private ConfigInheritance inheritance;
+ private Predicate<? super T> constraint;
+
+ // FIXME In groovy, fields were `public final` with a default constructor; do we need the gson?
+ public BasicConfigKey() { /* for gson */ }
+
+ public BasicConfigKey(Class<T> type, String name) {
+ this(TypeToken.of(type), name);
+ }
+
+ public BasicConfigKey(Class<T> type, String name, String description) {
+ this(TypeToken.of(type), name, description);
+ }
+
+ public BasicConfigKey(Class<T> type, String name, String description, T defaultValue) {
+ this(TypeToken.of(type), name, description, defaultValue);
+ }
+
+ public BasicConfigKey(TypeToken<T> type, String name) {
+ this(type, name, name, null);
+ }
+
+ public BasicConfigKey(TypeToken<T> type, String name, String description) {
+ this(type, name, description, null);
+ }
+
+ public BasicConfigKey(TypeToken<T> type, String name, String description, T defaultValue) {
+ this.description = description;
+ this.name = checkNotNull(name, "name");
+
+ this.type = TypeTokens.getRawTypeIfRaw(checkNotNull(type, "type"));
+ this.typeToken = TypeTokens.getTypeTokenIfNotRaw(type);
+
+ this.defaultValue = defaultValue;
+ this.reconfigurable = false;
+ this.constraint = Predicates.alwaysTrue();
+ }
+
+ protected BasicConfigKey(Builder<T> builder) {
+ this.name = checkNotNull(builder.name, "name");
+ this.type = TypeTokens.getRawTypeIfRaw(checkNotNull(builder.type, "type"));
+ this.typeToken = TypeTokens.getTypeTokenIfNotRaw(builder.type);
+ this.description = builder.description;
+ this.defaultValue = builder.defaultValue;
+ this.reconfigurable = builder.reconfigurable;
+ this.inheritance = builder.inheritance;
+ // Note: it's intentionally possible to have default values that are not valid
+ // per the configured constraint. If validity were checked here any class that
+ // contained a weirdly-defined config key would fail to initialise.
+ this.constraint = checkNotNull(builder.constraint, "constraint");
+ }
+
+ /** @see ConfigKey#getName() */
+ @Override public String getName() { return name; }
+
+ /** @see ConfigKey#getTypeName() */
+ @Override public String getTypeName() { return getType().getName(); }
+
+ /** @see ConfigKey#getType() */
+ @Override public Class<? super T> getType() { return TypeTokens.getRawType(typeToken, type); }
+
+ /** @see ConfigKey#getTypeToken() */
+ @Override public TypeToken<T> getTypeToken() { return TypeTokens.getTypeToken(typeToken, type); }
+
+ /** @see ConfigKey#getDescription() */
+ @Override public String getDescription() { return description; }
+
+ /** @see ConfigKey#getDefaultValue() */
+ @Override public T getDefaultValue() { return defaultValue; }
+
+ /** @see ConfigKey#hasDefaultValue() */
+ @Override public boolean hasDefaultValue() {
+ return defaultValue != null;
+ }
+
+ /** @see ConfigKey#isReconfigurable() */
+ @Override
+ public boolean isReconfigurable() {
+ return reconfigurable;
+ }
+
+ /** @see ConfigKey#getInheritance() */
+ @Override @Nullable
+ public ConfigInheritance getInheritance() {
+ return inheritance;
+ }
+
+ /** @see ConfigKey#getConstraint() */
+ @Override @Nonnull
+ public Predicate<? super T> getConstraint() {
- return constraint;
++ // Could be null after rebinding
++ if (constraint != null) {
++ return constraint;
++ } else {
++ return Predicates.alwaysTrue();
++ }
+ }
+
+ /** @see ConfigKey#isValueValid(T) */
+ @Override
+ public boolean isValueValid(T value) {
+ // The likeliest source of an exception is a constraint from Guava that expects a non-null input.
+ try {
+ return getConstraint().apply(value);
+ } catch (Exception e) {
+ log.debug("Suppressing exception when testing validity of " + this, e);
+ return false;
+ }
+ }
+
+ /** @see ConfigKey#getNameParts() */
+ @Override public Collection<String> getNameParts() {
+ return Lists.newArrayList(dots.split(name));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) return true;
+ if (!(obj instanceof BasicConfigKey)) return false;
+ BasicConfigKey<?> o = (BasicConfigKey<?>) obj;
+
+ return Objects.equal(name, o.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s[ConfigKey:%s]", name, getTypeName());
+ }
+
+ /**
+ * Retrieves the value corresponding to this config key from the given map.
+ * Could be overridden by more sophisticated config keys, such as MapConfigKey etc.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T extractValue(Map<?,?> vals, ExecutionContext exec) {
+ Object v = vals.get(this);
+ try {
+ return (T) resolveValue(v, exec);
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ @Override
+ public boolean isSet(Map<?,?> vals) {
+ return vals.containsKey(this);
+ }
+
+ protected Object resolveValue(Object v, ExecutionContext exec) throws ExecutionException, InterruptedException {
+ if (v instanceof Collection || v instanceof Map) {
+ return Tasks.resolveDeepValue(v, Object.class, exec, "config "+name);
+ } else {
+ return Tasks.resolveValue(v, getType(), exec, "config "+name);
+ }
+ }
+
+ /** used to record a key which overwrites another; only needed at disambiguation time
+ * if a class declares a key and an equivalent one (often inherited) which overwrites it.
+ * See org.apache.brooklyn.core.entity.ConfigEntityInheritanceTest, and uses of this class, for more explanation.
+ */
+ public static class BasicConfigKeyOverwriting<T> extends BasicConfigKey<T> {
+ private static final long serialVersionUID = -3458116971918128018L;
+
+ private final ConfigKey<T> parentKey;
+
+ /** builder here should be based on the same key passed in as parent */
+ @Beta
+ public BasicConfigKeyOverwriting(Builder<T> builder, ConfigKey<T> parent) {
+ super(builder);
+ parentKey = parent;
+ Preconditions.checkArgument(Objects.equal(builder.name, parent.getName()), "Builder must use key of the same name.");
+ }
+
+ public BasicConfigKeyOverwriting(ConfigKey<T> key, T defaultValue) {
+ this(builder(key).defaultValue(defaultValue), key);
+ }
+
+ public BasicConfigKeyOverwriting(ConfigKey<T> key, String newDescription, T defaultValue) {
+ this(builder(key).description(newDescription).defaultValue(defaultValue), key);
+ }
+
+ public ConfigKey<T> getParentKey() {
+ return parentKey;
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/Sanitizer.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/Sanitizer.java
index 0000000,f9b5de5..59ca6af
mode 000000,100644..100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/Sanitizer.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/Sanitizer.java
@@@ -1,0 -1,172 +1,172 @@@
+ /*
+ * 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.config;
+
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+
+ import org.apache.brooklyn.util.core.config.ConfigBag;
+
-import com.google.api.client.util.Lists;
+ import com.google.common.base.Predicate;
+ import com.google.common.collect.ImmutableList;
++import com.google.common.collect.Lists;
+ import com.google.common.collect.Maps;
+ import com.google.common.collect.Sets;
+
+ public final class Sanitizer {
+
+ /**
+ * Names that, if they appear anywhere in an attribute/config/field
+ * indicates that it may be private, so should not be logged etc.
+ */
+ public static final List<String> SECRET_NAMES = ImmutableList.of(
+ "password",
+ "passwd",
+ "credential",
+ "secret",
+ "private",
+ "access.cert",
+ "access.key");
+
+ public static final Predicate<Object> IS_SECRET_PREDICATE = new IsSecretPredicate();
+
+ private static class IsSecretPredicate implements Predicate<Object> {
+ @Override
+ public boolean apply(Object name) {
+ String lowerName = name.toString().toLowerCase();
+ for (String secretName : SECRET_NAMES) {
+ if (lowerName.contains(secretName))
+ return true;
+ }
+ return false;
+ }
+ };
+
+ /**
+ * Kept only in case this anonymous inner class has made it into any persisted state.
+ *
+ * @deprecated since 0.7.0
+ */
+ @Deprecated
+ @SuppressWarnings("unused")
+ private static final Predicate<Object> IS_SECRET_PREDICATE_DEPRECATED = new Predicate<Object>() {
+ @Override
+ public boolean apply(Object name) {
+ String lowerName = name.toString().toLowerCase();
+ for (String secretName : SECRET_NAMES) {
+ if (lowerName.contains(secretName))
+ return true;
+ }
+ return false;
+ }
+ };
+
+ public static Sanitizer newInstance(Predicate<Object> sanitizingNeededCheck) {
+ return new Sanitizer(sanitizingNeededCheck);
+ }
+
+ public static Sanitizer newInstance(){
+ return newInstance(IS_SECRET_PREDICATE);
+ }
+
+ public static Map<String, Object> sanitize(ConfigBag input) {
+ return sanitize(input.getAllConfig());
+ }
+
+ public static <K> Map<K, Object> sanitize(Map<K, ?> input) {
+ return sanitize(input, Sets.newHashSet());
+ }
+
+ static <K> Map<K, Object> sanitize(Map<K, ?> input, Set<Object> visited) {
+ return newInstance().apply(input, visited);
+ }
+
+ private Predicate<Object> predicate;
+
+ private Sanitizer(Predicate<Object> sanitizingNeededCheck) {
+ predicate = sanitizingNeededCheck;
+ }
+
+ public <K> Map<K, Object> apply(Map<K, ?> input) {
+ return apply(input, Sets.newHashSet());
+ }
+
+ private <K> Map<K, Object> apply(Map<K, ?> input, Set<Object> visited) {
+ Map<K, Object> result = Maps.newLinkedHashMap();
+ for (Map.Entry<K, ?> e : input.entrySet()) {
+ if (predicate.apply(e.getKey())){
+ result.put(e.getKey(), "xxxxxxxx");
+ continue;
+ }
+
+ // need to compare object reference, not equality since we may miss some.
+ // not a perfect identifier, but very low probability of collision.
+ if (visited.contains(System.identityHashCode(e.getValue()))) {
+ result.put(e.getKey(), e.getValue());
+ continue;
+ }
+
+ visited.add(System.identityHashCode(e.getValue()));
+ if (e.getValue() instanceof Map) {
+ result.put(e.getKey(), apply((Map<?, ?>) e.getValue(), visited));
+ } else if (e.getValue() instanceof List) {
+ result.put(e.getKey(), applyList((List<?>) e.getValue(), visited));
+ } else if (e.getValue() instanceof Set) {
+ result.put(e.getKey(), applySet((Set<?>) e.getValue(), visited));
+ } else {
+ result.put(e.getKey(), e.getValue());
+ }
+ }
+ return result;
+ }
+
+ private List<Object> applyIterable(Iterable<?> input, Set<Object> visited){
+ List<Object> result = Lists.newArrayList();
+ for(Object o : input){
+ if(visited.contains(System.identityHashCode(o))){
+ result.add(o);
+ continue;
+ }
+
+ visited.add(System.identityHashCode(o));
+ if (o instanceof Map) {
+ result.add(apply((Map<?, ?>) o, visited));
+ } else if (o instanceof List) {
+ result.add(applyList((List<?>) o, visited));
+ } else if (o instanceof Set) {
+ result.add(applySet((Set<?>) o, visited));
+ } else {
+ result.add(o);
+ }
+
+ }
+ return result;
+ }
+
+ private List<Object> applyList(List<?> input, Set<Object> visited) {
+ return applyIterable(input, visited);
+ }
+
+ private Set<Object> applySet(Set<?> input, Set<Object> visited) {
+ Set<Object> result = Sets.newLinkedHashSet();
+ result.addAll(applyIterable(input, visited));
+ return result;
+ }
+ }