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/04/21 22:41:27 UTC
[08/16] incubator-brooklyn git commit: support for multi-item catalog
yaml
support for multi-item catalog yaml
adds many tests, and the rest of the features - template and policy and location; and source yaml.
also a few significant REST API changes:
* /v1/catalog/create API change returns a map (breaking)
* catalog items include more information for entity and policies
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/eaaca787
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/eaaca787
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/eaaca787
Branch: refs/heads/master
Commit: eaaca7874bc092acc5abac848eba30648836fd53
Parents: 08cb3e7
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Apr 3 13:29:28 2015 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Apr 16 01:25:39 2015 -0500
----------------------------------------------------------------------
.../java/brooklyn/catalog/BrooklynCatalog.java | 4 +
.../java/brooklyn/location/LocationSpec.java | 9 +-
.../brooklyn/catalog/CatalogPredicates.java | 12 +-
.../catalog/internal/BasicBrooklynCatalog.java | 214 +++++++++++++++----
.../brooklyn/catalog/internal/CatalogUtils.java | 6 +
.../location/basic/BasicLocationRegistry.java | 2 +-
.../location/basic/CatalogLocationResolver.java | 3 +-
.../brooklyn/camp/lite/CampYamlLiteTest.java | 6 +-
.../entity/rebind/RebindCatalogItemTest.java | 10 +-
docs/guide/misc/release-notes.md | 4 +
.../camp/brooklyn/AbstractYamlTest.java | 2 +-
.../CatalogOsgiVersionMoreEntityTest.java | 11 +-
.../brooklyn/catalog/CatalogYamlEntityTest.java | 103 ++++++++-
.../catalog/CatalogYamlLocationTest.java | 124 +++++++++--
.../brooklyn/catalog/CatalogYamlPolicyTest.java | 70 +++++-
.../catalog/CatalogYamlTemplateTest.java | 77 +++++++
.../src/main/webapp/assets/js/view/catalog.js | 57 +++--
.../assets/tpl/catalog/add-catalog-entry.html | 4 +-
.../webapp/assets/tpl/catalog/add-entity.html | 30 ---
.../webapp/assets/tpl/catalog/add-yaml.html | 30 +++
.../main/java/brooklyn/rest/api/CatalogApi.java | 19 +-
.../java/brooklyn/rest/api/LocationApi.java | 5 +-
.../rest/domain/CatalogEntitySummary.java | 6 +
.../rest/domain/CatalogItemSummary.java | 3 +
.../rest/domain/CatalogPolicySummary.java | 3 +
.../rest/resources/CatalogResource.java | 66 +++---
.../rest/resources/LocationResource.java | 4 +-
.../rest/transform/CatalogTransformer.java | 44 +++-
.../rest/resources/CatalogResourceTest.java | 67 +++---
.../src/main/java/brooklyn/util/yaml/Yamls.java | 12 ++
30 files changed, 786 insertions(+), 221 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
index ce4386f..5b11cc6 100644
--- a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
+++ b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
@@ -90,7 +90,9 @@ public interface BrooklynCatalog {
* Fails if the same version exists in catalog.
*
* @throws IllegalArgumentException if the yaml was invalid
+ * @deprecated since 0.7.0 use {@link #addItems(String, boolean)}
*/
+ @Deprecated
CatalogItem<?,?> addItem(String yaml);
/**
@@ -100,7 +102,9 @@ public interface BrooklynCatalog {
* item exists with the same symbolicName and version
*
* @throws IllegalArgumentException if the yaml was invalid
+ * @deprecated since 0.7.0 use {@link #addItems(String, boolean)}
*/
+ @Deprecated
CatalogItem<?,?> addItem(String yaml, boolean forceUpdate);
/**
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/api/src/main/java/brooklyn/location/LocationSpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/location/LocationSpec.java b/api/src/main/java/brooklyn/location/LocationSpec.java
index 7e3c4f9..10a6d7e 100644
--- a/api/src/main/java/brooklyn/location/LocationSpec.java
+++ b/api/src/main/java/brooklyn/location/LocationSpec.java
@@ -78,8 +78,11 @@ public class LocationSpec<T extends Location> extends AbstractBrooklynObjectSpec
* original entity spec.
*/
public static <T extends Location> LocationSpec<T> create(LocationSpec<T> spec) {
- // FIXME Why can I not use LocationSpec<T>?
- LocationSpec<?> result = create(spec.getType())
+ // need this to get LocationSpec<T> rather than LocationSpec<? extends T>
+ @SuppressWarnings("unchecked")
+ Class<T> exactType = (Class<T>)spec.getType();
+
+ LocationSpec<T> result = create(exactType)
.displayName(spec.getDisplayName())
.tags(spec.getTags())
.configure(spec.getConfig())
@@ -176,7 +179,7 @@ public class LocationSpec<T extends Location> extends AbstractBrooklynObjectSpec
return this;
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public <E> LocationSpec<T> extensions(Map<Class<?>, ?> extensions) {
for (Map.Entry<Class<?>, ?> entry : extensions.entrySet()) {
extension((Class)entry.getKey(), entry.getValue());
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/CatalogPredicates.java b/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
index 4331a1a..2ffebdf 100644
--- a/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
+++ b/core/src/main/java/brooklyn/catalog/CatalogPredicates.java
@@ -21,6 +21,7 @@ package brooklyn.catalog;
import javax.annotation.Nullable;
import brooklyn.catalog.CatalogItem.CatalogItemType;
+import brooklyn.catalog.internal.CatalogUtils;
import brooklyn.entity.Application;
import brooklyn.entity.Entity;
import brooklyn.entity.proxying.EntitySpec;
@@ -126,5 +127,14 @@ public class CatalogPredicates {
}
};
}
-
+
+ public static <T,SpecT> Predicate<CatalogItem<T,SpecT>> isBestVersion(final ManagementContext mgmt) {
+ return new Predicate<CatalogItem<T,SpecT>>() {
+ @Override
+ public boolean apply(@Nullable CatalogItem<T,SpecT> item) {
+ return CatalogUtils.isBestVersion(mgmt, item);
+ }
+ };
+ }
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
index 8a562d0..09ef02f 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -72,6 +72,7 @@ import brooklyn.util.text.Strings;
import brooklyn.util.time.Duration;
import brooklyn.util.time.Time;
import brooklyn.util.yaml.Yamls;
+import brooklyn.util.yaml.Yamls.YamlExtract;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@@ -322,6 +323,11 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
String yaml = loadedItem.getPlanYaml();
if (yaml!=null) {
+ // preferred way is to parse the yaml, to resolve references late;
+ // the parsing on load is to populate some fields, but it is optional.
+ // TODO messy for location and policy that we need brooklyn.{locations,policies} root of the yaml, but it works;
+ // see related comment when the yaml is set, in addAbstractCatalogItems
+ // (not sure if anywhere else relies on that syntax; if not, it should be easy to fix!)
DeploymentPlan plan = makePlanFromYaml(yaml);
BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item);
SpecT spec;
@@ -384,7 +390,6 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
}
- @SuppressWarnings("unchecked")
private <T, SpecT> SpecT createPolicySpec(DeploymentPlan plan, BrooklynClassLoadingContext loader) {
//Would ideally re-use io.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityDecorationResolver.PolicySpecResolver
//but it is CAMP specific and there is no easy way to get hold of it.
@@ -395,6 +400,11 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
Object policy = Iterables.getOnlyElement((Iterable<?>)policies);
+ return createPolicySpec(loader, policy);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T, SpecT> SpecT createPolicySpec(BrooklynClassLoadingContext loader, Object policy) {
Map<String, Object> config;
if (policy instanceof String) {
config = ImmutableMap.<String, Object>of("type", policy);
@@ -413,7 +423,6 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
return (SpecT) spec;
}
- @SuppressWarnings("unchecked")
private <T, SpecT> SpecT createLocationSpec(DeploymentPlan plan, BrooklynClassLoadingContext loader) {
// See #createPolicySpec; this impl is modeled on that.
// spec.catalogItemId is set by caller
@@ -424,6 +433,11 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
Object location = Iterables.getOnlyElement((Iterable<?>)locations);
+ return createLocationSpec(loader, location);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T, SpecT> SpecT createLocationSpec(BrooklynClassLoadingContext loader, Object location) {
Map<String, Object> config;
if (location instanceof String) {
config = ImmutableMap.<String, Object>of("type", location);
@@ -457,7 +471,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
} else {
throw new IllegalStateException("No class or resolver found for location type "+type);
}
- }
+ }
}
@SuppressWarnings("unchecked")
@@ -509,7 +523,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
if (foundKey==null) return Maybe.absent("Missing entry '"+firstKey+"'");
value = map.get(foundKey);
- if (!type.isInstance(value)) return Maybe.absent("Entry for '"+firstKey+"' should be of type "+type+", not "+value.getClass());
+ if (type.equals(String.class) && Number.class.isInstance(value)) value = value.toString();
+ if (!type.isInstance(value))
+ throw new IllegalArgumentException("Entry for '"+firstKey+"' should be of type "+type+", not "+value.getClass());
return Maybe.of((T)value);
}
@@ -518,7 +534,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
return (Maybe<Map<?,?>>)(Maybe) getFirstAs(map, Map.class, firstKey, otherKeys);
}
- private List<CatalogItemDtoAbstract<?,?>> getAbstractCatalogItems(String yaml) {
+ private List<CatalogItemDtoAbstract<?,?>> addAbstractCatalogItems(String yaml, Boolean whenAddingAsDtoShouldWeForce) {
Map<?,?> itemDef = Yamls.getAs(Yamls.parseAll(yaml), Map.class);
Map<?,?> catalogMetadata = getFirstAsMap(itemDef, "brooklyn.catalog", "catalog").orNull();
if (catalogMetadata==null)
@@ -527,30 +543,36 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
List<CatalogItemDtoAbstract<?, ?>> result = MutableList.of();
- addAbstractCatalogItems(catalogMetadata, result, null);
+ addAbstractCatalogItems(Yamls.getTextOfYamlAtPath(yaml, "brooklyn.catalog").getMatchedYamlTextOrWarn(),
+ catalogMetadata, result, null, whenAddingAsDtoShouldWeForce);
itemDef.remove("brooklyn.catalog");
catalogMetadata.remove("item");
catalogMetadata.remove("items");
if (!itemDef.isEmpty()) {
- log.debug("Reading brooklyn.catalog peer keys as item");
+ log.debug("Reading brooklyn.catalog peer keys as item ('top-level syntax')");
Map<String,?> rootItem = MutableMap.of("item", itemDef);
- addAbstractCatalogItems(rootItem, result, catalogMetadata);
+ String rootItemYaml = yaml;
+ YamlExtract yamlExtract = Yamls.getTextOfYamlAtPath(rootItemYaml, "brooklyn.catalog");
+ String match = yamlExtract.withOriginalIndentation(true).withKeyIncluded(true).getMatchedYamlTextOrWarn();
+ if (match!=null) {
+ if (rootItemYaml.startsWith(match)) rootItemYaml = Strings.removeFromStart(rootItemYaml, match);
+ else rootItemYaml = Strings.replaceAllNonRegex(rootItemYaml, "\n"+match, "");
+ }
+ addAbstractCatalogItems("item:\n"+makeAsIndentedObject(rootItemYaml), rootItem, result, catalogMetadata, whenAddingAsDtoShouldWeForce);
}
return result;
}
- enum CatalogItemTypes { ENTITY, TEMPLATE, POLICY, LOCATION }
-
@SuppressWarnings("unchecked")
- private void addAbstractCatalogItems(Map<?,?> itemMetadata, List<CatalogItemDtoAbstract<?, ?>> result, Map<?,?> parentMetadata) {
+ private void addAbstractCatalogItems(String sourceYaml, Map<?,?> itemMetadata, List<CatalogItemDtoAbstract<?, ?>> result, Map<?,?> parentMetadata, Boolean whenAddingAsDtoShouldWeForce) {
+
+ if (sourceYaml==null) sourceYaml = new Yaml().dump(itemMetadata);
// TODO:
-// get yaml
-// (tests)
-// docs used as test casts -- (doc assertions that these match -- or import -- known test casesyamls)
-// multiple versions in catalog page
+// docs used as test cases -- (doc assertions that these match -- or import -- known test cases yamls)
+// multiple versions in web app root
Map<Object,Object> catalogMetadata = MutableMap.builder().putAll(parentMetadata).putAll(itemMetadata).build();
@@ -565,16 +587,22 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
Object item = catalogMetadata.remove("item");
if (items!=null) {
+ int count = 0;
for (Map<?,?> i: ((List<Map<?,?>>)items)) {
- addAbstractCatalogItems(i, result, catalogMetadata);
+ addAbstractCatalogItems(Yamls.getTextOfYamlAtPath(sourceYaml, "items", count).getMatchedYamlTextOrWarn(),
+ i, result, catalogMetadata, whenAddingAsDtoShouldWeForce);
+ count++;
}
}
if (item==null) return;
+
+ // now look at the actual item, first correcting the sourceYaml and interpreting the catalog metadata
+ String itemYaml = Yamls.getTextOfYamlAtPath(sourceYaml, "item").getMatchedYamlTextOrWarn();
+ if (itemYaml!=null) sourceYaml = itemYaml;
+ else sourceYaml = new Yaml().dump(item);
- //now parse the metadata and apply to item
-
- CatalogItemTypes itemType = TypeCoercions.coerce(getFirstAs(catalogMetadata, String.class, "item.type", "itemType", "item_type").or(CatalogItemTypes.ENTITY.toString()), CatalogItemTypes.class);
+ CatalogItemType itemType = TypeCoercions.coerce(getFirstAs(catalogMetadata, Object.class, "item.type", "itemType", "item_type").orNull(), CatalogItemType.class);
String id = getFirstAs(catalogMetadata, String.class, "id").orNull();
String version = getFirstAs(catalogMetadata, String.class, "version").orNull();
@@ -587,19 +615,25 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
Strings.isNonBlank(name) && !name.equals(displayName)) {
log.warn("Name property will be ignored due to the existence of displayName and at least one of id, symbolicName");
}
-
- // TODO use src yaml if avail
- String yaml = new Yaml().dump(item);
-
+
DeploymentPlan plan = null;
try {
- plan = makePlanFromYaml(yaml);
+ plan = makePlanFromYaml(sourceYaml);
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
- if (itemType==CatalogItemTypes.ENTITY || itemType==CatalogItemTypes.TEMPLATE)
- log.warn("Could not parse item YAML for "+itemType+" (registering anyway): "+e+"\n"+yaml);
+ if (itemType==CatalogItemType.ENTITY || itemType==CatalogItemType.TEMPLATE)
+ log.warn("Could not parse item YAML for "+itemType+" (registering anyway): "+e+"\n"+sourceYaml);
}
+ if (Strings.isBlank(id)) {
+ // let ID be inferred, especially from name, to support style where only "name" is specified, with inline version
+ if (Strings.isNonBlank(symbolicName) && Strings.isNonBlank(version)) {
+ id = symbolicName + ":" + version;
+ } else if (Strings.isNonBlank(name)) {
+ id = name;
+ }
+ }
+
final String catalogSymbolicName;
if (Strings.isNonBlank(symbolicName)) {
catalogSymbolicName = symbolicName;
@@ -609,8 +643,6 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
} else {
catalogSymbolicName = id;
}
- } else if (Strings.isNonBlank(name)) {
- catalogSymbolicName = name;
} else if (plan!=null && Strings.isNonBlank(plan.getName())) {
catalogSymbolicName = plan.getName();
} else if (plan!=null && plan.getServices().size()==1) {
@@ -620,8 +652,8 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
catalogSymbolicName = svc.getServiceType();
} else {
- log.error("Can't infer catalog item symbolicName from the following plan:\n" + yaml);
- throw new IllegalStateException("Can't infer catalog item symbolicName from catalog item description");
+ log.error("Can't infer catalog item symbolicName from the following plan:\n" + sourceYaml);
+ throw new IllegalStateException("Can't infer catalog item symbolicName from catalog item metadata");
}
final String catalogVersion;
@@ -668,23 +700,103 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
String versionedId = CatalogUtils.getVersionedId(catalogSymbolicName, catalogVersion!=null ? catalogVersion : NO_VERSION);
BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, versionedId, libraries);
- // TODO for entities, we parse. for templates we don't. (?)
- AbstractBrooklynObjectSpec<?, ?> spec = createSpec(catalogSymbolicName, plan, loader);
+ CatalogItemType inferredItemType = inferType(plan);
+ boolean usePlan;
+ if (inferredItemType!=null) {
+ if (itemType!=null) {
+ if (itemType==CatalogItemType.TEMPLATE && inferredItemType==CatalogItemType.ENTITY) {
+ // template - we use the plan, but coupled with the type to make a catalog template item
+ usePlan = true;
+ } else if (itemType==inferredItemType) {
+ // if the plan showed the type, it is either a parsed entity or a legacy spec type
+ usePlan = true;
+ if (itemType==CatalogItemType.TEMPLATE || itemType==CatalogItemType.ENTITY) {
+ // normal
+ } else {
+ log.warn("Legacy syntax used for "+itemType+" "+catalogSymbolicName+": should declare item.type and specify type");
+ }
+ } else {
+ throw new IllegalStateException("Explicit type "+itemType+" "+catalogSymbolicName+" does not match blueprint inferred type "+inferredItemType);
+ }
+ } else {
+ // no type was declared, use the inferred type from the plan
+ itemType = inferredItemType;
+ usePlan = true;
+ }
+ } else if (itemType!=null) {
+ if (itemType==CatalogItemType.TEMPLATE || itemType==CatalogItemType.ENTITY) {
+ log.warn("Incomplete plan detected for "+itemType+" "+catalogSymbolicName+"; will likely fail subsequently");
+ usePlan = true;
+ } else {
+ usePlan = false;
+ }
+ } else {
+ throw new IllegalStateException("Unable to detect type for "+catalogSymbolicName+"; error in catalog metadata or blueprint");
+ }
+
+ AbstractBrooklynObjectSpec<?, ?> spec;
+ if (usePlan) {
+ spec = createSpecFromPlan(catalogSymbolicName, plan, loader);
+ } else {
+ String key;
+ switch (itemType) {
+ // we don't actually need the spec here, since the yaml is what is used at load time,
+ // but it isn't a bad idea to confirm that it resolves
+ case POLICY:
+ spec = createPolicySpec(loader, item);
+ key = POLICIES_KEY;
+ break;
+ case LOCATION:
+ spec = createLocationSpec(loader, item);
+ key = LOCATIONS_KEY;
+ break;
+ default: throw new IllegalStateException("Cannot create "+itemType+" "+catalogSymbolicName+"; invalid metadata or blueprint");
+ }
+ // TODO currently we then convert yaml to legacy brooklyn.{location,policy} syntax for subsequent usage;
+ // would be better to (in the other path) convert to {type: ..., brooklyn.config: ... } format and expect that elsewhere
+ sourceYaml = key + ":\n" + makeAsIndentedList(sourceYaml);
+ }
- CatalogItemDtoAbstract<?, ?> dto = createItemBuilder(spec, catalogSymbolicName, catalogVersion)
+ CatalogItemDtoAbstract<?, ?> dto = createItemBuilder(itemType, spec, catalogSymbolicName, catalogVersion)
.libraries(libraries)
.displayName(catalogDisplayName)
.description(catalogDescription)
.deprecated(catalogDeprecated)
.iconUrl(catalogIconUrl)
- .plan(yaml)
+ .plan(sourceYaml)
.build();
dto.setManagementContext((ManagementContextInternal) mgmt);
+ if (whenAddingAsDtoShouldWeForce!=null) {
+ addItemDto(dto, whenAddingAsDtoShouldWeForce);
+ }
result.add(dto);
}
- private AbstractBrooklynObjectSpec<?,?> createSpec(String symbolicName, DeploymentPlan plan, BrooklynClassLoadingContext loader) {
+ private String makeAsIndentedList(String yaml) {
+ String[] lines = yaml.split("\n");
+ lines[0] = "- "+lines[0];
+ for (int i=1; i<lines.length; i++)
+ lines[i] = " " + lines[i];
+ return Strings.join(lines, "\n");
+ }
+
+ private String makeAsIndentedObject(String yaml) {
+ String[] lines = yaml.split("\n");
+ for (int i=0; i<lines.length; i++)
+ lines[i] = " " + lines[i];
+ return Strings.join(lines, "\n");
+ }
+
+ private CatalogItemType inferType(DeploymentPlan plan) {
+ if (plan==null) return null;
+ if (isEntityPlan(plan)) return CatalogItemType.ENTITY;
+ if (isPolicyPlan(plan)) return CatalogItemType.POLICY;
+ if (isLocationPlan(plan)) return CatalogItemType.LOCATION;
+ return null;
+ }
+
+ private AbstractBrooklynObjectSpec<?,?> createSpecFromPlan(String symbolicName, DeploymentPlan plan, BrooklynClassLoadingContext loader) {
if (isPolicyPlan(plan)) {
return createPolicySpec(plan, loader);
} else if (isLocationPlan(plan)) {
@@ -694,7 +806,20 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
}
- private CatalogItemBuilder<?> createItemBuilder(AbstractBrooklynObjectSpec<?, ?> spec, String itemId, String version) {
+ private CatalogItemBuilder<?> createItemBuilder(CatalogItemType itemType, AbstractBrooklynObjectSpec<?, ?> spec, String itemId, String version) {
+ if (itemType!=null) {
+ switch (itemType) {
+ case ENTITY: return CatalogItemBuilder.newEntity(itemId, version);
+ case TEMPLATE: return CatalogItemBuilder.newTemplate(itemId, version);
+ case POLICY: return CatalogItemBuilder.newPolicy(itemId, version);
+ case LOCATION: return CatalogItemBuilder.newLocation(itemId, version);
+ }
+ log.warn("Legacy syntax for "+itemId+"; unexpected item.type "+itemType);
+ } else {
+ log.warn("Legacy syntax for "+itemId+"; no item.type declared or inferred");
+ }
+
+ // @deprecated - should not come here
if (spec instanceof EntitySpec) {
if (isApplicationSpec((EntitySpec<?>)spec)) {
return CatalogItemBuilder.newTemplate(itemId, version);
@@ -714,12 +839,16 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
return !Boolean.TRUE.equals(spec.getConfig().get(EntityManagementUtils.WRAPPER_APP_MARKER));
}
+ private boolean isEntityPlan(DeploymentPlan plan) {
+ return plan!=null && !plan.getServices().isEmpty() || !plan.getArtifacts().isEmpty();
+ }
+
private boolean isPolicyPlan(DeploymentPlan plan) {
- return plan.getCustomAttributes().containsKey(POLICIES_KEY);
+ return !isEntityPlan(plan) && plan.getCustomAttributes().containsKey(POLICIES_KEY);
}
private boolean isLocationPlan(DeploymentPlan plan) {
- return plan.getCustomAttributes().containsKey(LOCATIONS_KEY);
+ return !isEntityPlan(plan) && plan.getCustomAttributes().containsKey(LOCATIONS_KEY);
}
private DeploymentPlan makePlanFromYaml(String yaml) {
@@ -746,10 +875,11 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
public List<? extends CatalogItem<?,?>> addItems(String yaml, boolean forceUpdate) {
log.debug("Adding manual catalog item to "+mgmt+": "+yaml);
checkNotNull(yaml, "yaml");
- List<CatalogItemDtoAbstract<?, ?>> result = getAbstractCatalogItems(yaml);
- for (CatalogItemDtoAbstract<?, ?> item: result) {
- addItemDto(item, forceUpdate);
- }
+ List<CatalogItemDtoAbstract<?, ?>> result = addAbstractCatalogItems(yaml, forceUpdate);
+ // previously we did this here, but now we do it on each item, in case #2 refers to #1
+// for (CatalogItemDtoAbstract<?, ?> item: result) {
+// addItemDto(item, forceUpdate);
+// }
return result;
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
index 50ef436..c72fc9b 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
@@ -218,6 +218,12 @@ public class CatalogUtils {
}
}
+ public static boolean isBestVersion(ManagementContext mgmt, CatalogItem<?,?> item) {
+ CatalogItem<?, ?> bestVersion = getCatalogItemOptionalVersion(mgmt, item.getSymbolicName());
+ if (bestVersion==null) return false;
+ return (bestVersion.getVersion().equals(item.getVersion()));
+ }
+
public static <T,SpecT> CatalogItem<T, SpecT> getCatalogItemOptionalVersion(ManagementContext mgmt, Class<T> type, String versionedId) {
if (looksLikeVersionedId(versionedId)) {
String id = getIdFromVersionedId(versionedId);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/main/java/brooklyn/location/basic/BasicLocationRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/BasicLocationRegistry.java b/core/src/main/java/brooklyn/location/basic/BasicLocationRegistry.java
index f0b466e..c59298b 100644
--- a/core/src/main/java/brooklyn/location/basic/BasicLocationRegistry.java
+++ b/core/src/main/java/brooklyn/location/basic/BasicLocationRegistry.java
@@ -84,7 +84,7 @@ import com.google.common.collect.Sets;
* it goes through the following steps:
*
* <ol>
- * <li>Call {@link BrooklynCatalog#addItem(String)}
+ * <li>Call {@link BrooklynCatalog#addItems(String)}
* <ol>
* <li>This automatically calls {@link #updateDefinedLocation(CatalogItem)}
* <li>A LocationDefinition is creating, using as its id the {@link CatalogItem#getSymbolicName()}.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/main/java/brooklyn/location/basic/CatalogLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/location/basic/CatalogLocationResolver.java b/core/src/main/java/brooklyn/location/basic/CatalogLocationResolver.java
index 4823b05..591873d 100644
--- a/core/src/main/java/brooklyn/location/basic/CatalogLocationResolver.java
+++ b/core/src/main/java/brooklyn/location/basic/CatalogLocationResolver.java
@@ -39,6 +39,7 @@ import brooklyn.management.ManagementContext;
*/
public class CatalogLocationResolver implements LocationResolver {
+ @SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(CatalogLocationResolver.class);
public static final String NAME = "brooklyn.catalog";
@@ -51,7 +52,7 @@ public class CatalogLocationResolver implements LocationResolver {
}
@Override
- @SuppressWarnings({ "rawtypes" })
+ @SuppressWarnings({ "rawtypes", "unchecked" })
public Location newLocationFromString(Map locationFlags, String spec, brooklyn.location.LocationRegistry registry) {
String id = spec.substring(NAME.length()+1);
CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(managementContext, id);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
index b9b4bca..2739c79 100644
--- a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
+++ b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
@@ -156,7 +156,7 @@ public class CampYamlLiteTest {
public void testYamlServiceForCatalog() {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
- CatalogItem<?, ?> realItem = mgmt.getCatalog().addItem(Streams.readFullyString(getClass().getResourceAsStream("test-app-service-blueprint.yaml")));
+ 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")));
@@ -185,7 +185,7 @@ public class CampYamlLiteTest {
String bundleUrl = OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL;
String yaml = getSampleMyCatalogAppYaml(symbolicName, bundleUrl);
- mgmt.getCatalog().addItem(yaml);
+ mgmt.getCatalog().addItems(yaml);
assertMgmtHasSampleMyCatalogApp(symbolicName, bundleUrl);
}
@@ -203,7 +203,7 @@ public class CampYamlLiteTest {
CampPlatformWithJustBrooklynMgmt platform2 = new CampPlatformWithJustBrooklynMgmt(mgmt2);
MockWebPlatform.populate(platform2, TestAppAssemblyInstantiator.class);
- mgmt2.getCatalog().addItem(yaml);
+ mgmt2.getCatalog().addItems(yaml);
String xml = ((BasicBrooklynCatalog) mgmt2.getCatalog()).toXmlString();
((BasicBrooklynCatalog) mgmt.getCatalog()).reset(CatalogDto.newDtoFromXmlContents(xml, "copy of temporary catalog"));
} finally {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
index 4036dc5..e0260c3 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
@@ -212,8 +212,9 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
" version: " + TEST_VERSION + "\n" +
"services:\n" +
"- type: io.camp.mock:AppServer";
+ addItem(origManagementContext, yaml);
+
BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) origManagementContext.getCatalog();
- catalog.addItem(yaml);
String catalogXml = catalog.toXmlString();
catalog.reset(CatalogDto.newDtoFromXmlContents(catalogXml, "Test reset"));
rebindAndAssertCatalogsAreEqual();
@@ -227,9 +228,10 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
" version: " + TEST_VERSION + "\n" +
"services:\n" +
"- type: io.camp.mock:AppServer";
- BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) origManagementContext.getCatalog();
- CatalogItem<?, ?> catalogItem = catalog.addItem(yaml);
+ CatalogItem<?, ?> catalogItem = addItem(origManagementContext, yaml);
assertNotNull(catalogItem, "catalogItem");
+ BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) origManagementContext.getCatalog();
+
catalogItem.setDeprecated(true);
catalog.persist(catalogItem);
rebindAndAssertCatalogsAreEqual();
@@ -238,7 +240,7 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
}
protected CatalogItem<?, ?> addItem(ManagementContext mgmt, String yaml) {
- CatalogItem<?, ?> added = mgmt.getCatalog().addItem(yaml);
+ CatalogItem<?, ?> added = Iterables.getOnlyElement(mgmt.getCatalog().addItems(yaml));
LOG.info("Added item to catalog: {}, id={}", added, added.getId());
assertCatalogContains(mgmt.getCatalog(), added);
return added;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/docs/guide/misc/release-notes.md
----------------------------------------------------------------------
diff --git a/docs/guide/misc/release-notes.md b/docs/guide/misc/release-notes.md
index 2b6dadf..1a324d6 100644
--- a/docs/guide/misc/release-notes.md
+++ b/docs/guide/misc/release-notes.md
@@ -47,6 +47,10 @@ For more information, please visit [brooklyn.io](http://brooklyn.io).
* If `brooklyn.webconsole.security.https.required=true` is specified with no explicit port,
it now defaults to 8443; previously it would default to 8081 even in the case of `https`.
+* The /v1/catalog/create method now returns a map of ID to item map, instead of an item map,
+ as the call supports multiple items defined in the YAML.
+
+
### Community Activity
Brooklyn has moved into the Apache Software Foundation.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
index dd7ad58..b1e6817 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -153,7 +153,7 @@ public abstract class AbstractYamlTest {
}
protected void addCatalogItem(String catalogYaml) {
- mgmt().getCatalog().addItem(catalogYaml, forceUpdate);
+ mgmt().getCatalog().addItems(catalogYaml, forceUpdate);
}
protected void deleteCatalogEntity(String catalogItem) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
index 3527a5d..19c9ef8 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
@@ -18,16 +18,19 @@
*/
package io.brooklyn.camp.brooklyn.catalog;
-import brooklyn.test.TestResourceUnavailableException;
import io.brooklyn.camp.brooklyn.AbstractYamlTest;
import io.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityMatcher;
import org.testng.Assert;
import org.testng.annotations.Test;
+import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.CatalogItem.CatalogItemType;
+import brooklyn.catalog.internal.CatalogUtils;
import brooklyn.entity.Entity;
import brooklyn.management.osgi.OsgiVersionMoreEntityTest;
import brooklyn.policy.Policy;
+import brooklyn.test.TestResourceUnavailableException;
import brooklyn.util.ResourceUtils;
import com.google.common.collect.Iterables;
@@ -45,6 +48,12 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar");
addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml"));
+ CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt(), "more-entity");
+ Assert.assertNotNull(item);
+ Assert.assertEquals(item.getVersion(), "1.0");
+ Assert.assertEquals(item.getCatalogItemType(), CatalogItemType.ENTITY);
+ Assert.assertEquals(item.getLibraries().size(), 1);
+
Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]");
Entity moreEntity = Iterables.getOnlyElement(app.getChildren());
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index 5b79982..1737718 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -25,6 +25,7 @@ import io.brooklyn.camp.brooklyn.AbstractYamlTest;
import java.io.InputStream;
import java.util.Collection;
+import java.util.List;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -38,6 +39,7 @@ import brooklyn.management.osgi.OsgiStandaloneTest;
import brooklyn.management.osgi.OsgiTestResources;
import brooklyn.test.TestResourceUnavailableException;
import brooklyn.util.ResourceUtils;
+import brooklyn.util.collections.MutableList;
import com.google.common.collect.Iterables;
@@ -59,6 +61,30 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
}
@Test
+ public void testAddCatalogItemAsSiblingOfCatalogMetadata() throws Exception {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ String symbolicName = "my.catalog.app.id.load";
+ addCatalogItem(
+ "brooklyn.catalog:",
+ " id: " + symbolicName,
+ " name: My Catalog App",
+ " description: My description",
+ " icon_url: classpath://path/to/myicon.jpg",
+ " version: " + TEST_VERSION,
+ " libraries:",
+ " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
+ "",
+ "services:",
+ "- type: " + SIMPLE_ENTITY_TYPE);
+
+ CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(symbolicName, TEST_VERSION);
+ assertEquals(item.getSymbolicName(), symbolicName);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
public void testAddCatalogItemWithoutVersion() throws Exception {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
@@ -76,6 +102,23 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
}
@Test
+ public void testAddCatalogItemWithInlinedVersion() throws Exception {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ String id = "inline_version.app";
+ addCatalogItem(
+ "brooklyn.catalog:",
+ " name: " + id+":"+TEST_VERSION,
+ " libraries:",
+ " - " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
+ "services:",
+ "- type: " + SIMPLE_ENTITY_TYPE);
+ CatalogItem<?, ?> catalogItem = mgmt().getCatalog().getCatalogItem(id, TEST_VERSION);
+ assertEquals(catalogItem.getVersion(), TEST_VERSION);
+ mgmt().getCatalog().deleteCatalogItem(id, TEST_VERSION);
+ }
+
+ @Test
public void testLaunchApplicationReferencingCatalog() throws Exception {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
@@ -84,7 +127,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
}
@Test
- public void testLaunchApplicationUnverionedCatalogReference() throws Exception {
+ public void testLaunchApplicationUnversionedCatalogReference() throws Exception {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
String symbolicName = "my.catalog.app.id.fail";
@@ -106,6 +149,27 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
String referencedSymbolicName = "my.catalog.app.id.referenced";
String referrerSymbolicName = "my.catalog.app.id.referring";
+ addCatalogOSGiEntities(referencedSymbolicName, SIMPLE_ENTITY_TYPE, referrerSymbolicName, ver(referencedSymbolicName));
+
+ String yaml = "name: simple-app-yaml\n" +
+ "location: localhost\n" +
+ "services: \n" +
+ " - serviceType: " + ver(referrerSymbolicName);
+ Entity app = createAndStartApplication(yaml);
+
+ Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
+ assertEquals(simpleEntity.getEntityType().getName(), SIMPLE_ENTITY_TYPE);
+
+ deleteCatalogEntity(referencedSymbolicName);
+ deleteCatalogEntity(referrerSymbolicName);
+ }
+
+ @Test
+ public void testLaunchApplicationWithCatalogReferencingOtherCatalogInTwoSteps() throws Exception {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ String referencedSymbolicName = "my.catalog.app.id.referenced";
+ String referrerSymbolicName = "my.catalog.app.id.referring";
addCatalogOSGiEntity(referencedSymbolicName, SIMPLE_ENTITY_TYPE);
addCatalogOSGiEntity(referrerSymbolicName, ver(referencedSymbolicName));
@@ -465,11 +529,32 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
" version: " + TEST_VERSION,
" libraries:",
" - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
- "",
- "services:",
- "- type: " + serviceType);
+ " item:",
+ " services:",
+ " - type: " + serviceType);
}
+ private void addCatalogOSGiEntities(String ...namesAndTypes) {
+ List<String> lines = MutableList.of(
+ "brooklyn.catalog:",
+ " name: My Catalog App",
+ " description: My description",
+ " icon_url: classpath://path/to/myicon.jpg",
+ " version: " + TEST_VERSION,
+ " libraries:",
+ " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
+ " items:");
+
+ for (int i=0; i<namesAndTypes.length; i+=2) {
+ lines.addAll(MutableList.of(
+ " - id: " + namesAndTypes[i],
+ " item:",
+ " services:",
+ " - type: " + namesAndTypes[i+1]));
+ }
+
+ addCatalogItem(lines);
+ }
private void addCatalogChildOSGiEntity(String symbolicName, String serviceType) {
addCatalogItem(
"brooklyn.catalog:",
@@ -480,11 +565,11 @@ public class CatalogYamlEntityTest extends AbstractYamlTest {
" version: " + TEST_VERSION,
" libraries:",
" - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
- "",
- "services:",
- "- type: " + BasicEntity.class.getName(),
- " brooklyn.children:",
- " - type: " + serviceType);
+ " item:",
+ " services:",
+ " - type: " + BasicEntity.class.getName(),
+ " brooklyn.children:",
+ " - type: " + serviceType);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
index ef5aa0f..c0d41d2 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java
@@ -22,16 +22,20 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import io.brooklyn.camp.brooklyn.AbstractYamlTest;
+import java.util.Collection;
import java.util.List;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.CatalogItem.CatalogBundle;
import brooklyn.catalog.CatalogPredicates;
import brooklyn.entity.Entity;
import brooklyn.event.basic.BasicConfigKey;
import brooklyn.location.Location;
import brooklyn.location.LocationDefinition;
+import brooklyn.location.LocationSpec;
import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
import brooklyn.management.osgi.OsgiStandaloneTest;
import brooklyn.test.TestResourceUnavailableException;
@@ -46,13 +50,63 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
private static final String LOCALHOST_LOCATION_TYPE = LocalhostMachineProvisioningLocation.class.getName();
private static final String SIMPLE_LOCATION_TYPE = "brooklyn.osgi.tests.SimpleLocation";
+ @AfterMethod
+ public void tearDown() {
+ for (CatalogItem<Location, LocationSpec<?>> ci : mgmt().getCatalog().getCatalogItems(CatalogPredicates.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";
- addCatalogOSGiLocation(symbolicName, SIMPLE_LOCATION_TYPE);
+ 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) {
+ CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(symbolicName, TEST_VERSION);
+ Collection<CatalogBundle> libs = item.getLibraries();
+ assertEquals(libs.size(), 1);
+ assertEquals(Iterables.getOnlyElement(libs).getUrl(), Iterables.getOnlyElement(getOsgiLibraries()));
+ }
+
+ private void assertAdded(String symbolicName, String expectedJavaType) {
CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(symbolicName, TEST_VERSION);
assertEquals(item.getSymbolicName(), symbolicName);
assertEquals(countCatalogLocations(), 1);
@@ -61,7 +115,12 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
LocationDefinition def = mgmt().getLocationRegistry().getDefinedLocationByName(symbolicName);
assertEquals(def.getId(), symbolicName);
assertEquals(def.getName(), symbolicName);
-
+
+ LocationSpec<?> spec = (LocationSpec<?>)mgmt().getCatalog().createSpec(item);
+ assertEquals(spec.getType().getName(), expectedJavaType);
+ }
+
+ private void removeAndAssert(String symbolicName) {
// Deleting item: should be gone from catalog, and from location registry
deleteCatalogEntity(symbolicName);
@@ -72,7 +131,7 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
@Test
public void testLaunchApplicationReferencingLocationClass() throws Exception {
String symbolicName = "my.catalog.location.id.launch";
- addCatalogLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
+ addCatalogLocation(symbolicName, LOCALHOST_LOCATION_TYPE, null);
runLaunchApplicationReferencingLocation(symbolicName, LOCALHOST_LOCATION_TYPE);
deleteCatalogEntity(symbolicName);
@@ -81,7 +140,25 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
@Test
public void testLaunchApplicationReferencingLocationSpec() throws Exception {
String symbolicName = "my.catalog.location.id.launch";
- addCatalogLocation(symbolicName, LOCALHOST_LOCATION_SPEC);
+ 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);
@@ -90,7 +167,7 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
@Test
public void testLaunchApplicationReferencingOsgiLocation() throws Exception {
String symbolicName = "my.catalog.location.id.launch";
- addCatalogOSGiLocation(symbolicName, SIMPLE_LOCATION_TYPE);
+ addCatalogLocation(symbolicName, SIMPLE_LOCATION_TYPE, getOsgiLibraries());
runLaunchApplicationReferencingLocation(symbolicName, SIMPLE_LOCATION_TYPE);
deleteCatalogEntity(symbolicName);
@@ -114,30 +191,49 @@ public class CatalogYamlLocationTest extends AbstractYamlTest {
assertEquals(location.getConfig(new BasicConfigKey<String>(String.class, "config3")), "config3");
}
- private void addCatalogLocation(String symbolicName, String serviceType) {
- addCatalogLocation(symbolicName, serviceType, ImmutableList.<String>of());
- }
-
- private void addCatalogOSGiLocation(String symbolicName, String serviceType) {
+ private List<String> getOsgiLibraries() {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
- addCatalogLocation(symbolicName, serviceType, ImmutableList.of(OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL));
+ return ImmutableList.of(OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL);
}
- private void addCatalogLocation(String symbolicName, String serviceType, List<String> libraries) {
+ 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");
+
+
+ addCatalogItem(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.size() > 0) {
+ if (libraries!=null && libraries.size() > 0) {
yaml.add(" libraries:")
.addAll(Lists.transform(libraries, StringFunctions.prepend(" - url: ")));
}
yaml.add(
"",
"brooklyn.locations:",
- "- type: " + serviceType,
+ "- type: " + locationType,
" brooklyn.config:",
" config1: config1",
" config2: config2");
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java
index d83c11a..b7370be 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java
@@ -19,8 +19,6 @@
package io.brooklyn.camp.brooklyn.catalog;
import static org.testng.Assert.assertEquals;
-
-import brooklyn.test.TestResourceUnavailableException;
import io.brooklyn.camp.brooklyn.AbstractYamlTest;
import org.testng.annotations.Test;
@@ -31,6 +29,7 @@ import brooklyn.entity.Entity;
import brooklyn.event.basic.BasicConfigKey;
import brooklyn.management.osgi.OsgiStandaloneTest;
import brooklyn.policy.Policy;
+import brooklyn.test.TestResourceUnavailableException;
import com.google.common.collect.Iterables;
@@ -43,7 +42,21 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest {
assertEquals(countCatalogPolicies(), 0);
String symbolicName = "my.catalog.policy.id.load";
- addCatalogOSGiPolicy(symbolicName, SIMPLE_POLICY_TYPE);
+ addCatalogOsgiPolicy(symbolicName, SIMPLE_POLICY_TYPE);
+
+ CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(symbolicName, TEST_VERSION);
+ assertEquals(item.getSymbolicName(), symbolicName);
+ assertEquals(countCatalogPolicies(), 1);
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
+ public void testAddCatalogItemTopLevelSyntax() throws Exception {
+ assertEquals(countCatalogPolicies(), 0);
+
+ String symbolicName = "my.catalog.policy.id.load";
+ addCatalogOsgiPolicyTopLevelSyntax(symbolicName, SIMPLE_POLICY_TYPE);
CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(symbolicName, TEST_VERSION);
assertEquals(item.getSymbolicName(), symbolicName);
@@ -55,7 +68,7 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest {
@Test
public void testLaunchApplicationReferencingPolicy() throws Exception {
String symbolicName = "my.catalog.policy.id.launch";
- addCatalogOSGiPolicy(symbolicName, SIMPLE_POLICY_TYPE);
+ addCatalogOsgiPolicy(symbolicName, SIMPLE_POLICY_TYPE);
Entity app = createAndStartApplication(
"name: simple-app-yaml",
"location: localhost",
@@ -78,10 +91,35 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest {
}
@Test
+ public void testLaunchApplicationReferencingPolicyTopLevelSyntax() throws Exception {
+ String symbolicName = "my.catalog.policy.id.launch";
+ addCatalogOsgiPolicyTopLevelSyntax(symbolicName, SIMPLE_POLICY_TYPE);
+ Entity app = createAndStartApplication(
+ "name: simple-app-yaml",
+ "location: localhost",
+ "services: ",
+ " - type: brooklyn.entity.basic.BasicEntity\n" +
+ " brooklyn.policies:\n" +
+ " - type: " + ver(symbolicName),
+ " brooklyn.config:",
+ " config2: config2 override",
+ " config3: config3");
+
+ Entity simpleEntity = Iterables.getOnlyElement(app.getChildren());
+ Policy policy = Iterables.getOnlyElement(simpleEntity.getPolicies());
+ assertEquals(policy.getPolicyType().getName(), SIMPLE_POLICY_TYPE);
+ assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config1")), "config1");
+ assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config2")), "config2 override");
+ assertEquals(policy.getConfig(new BasicConfigKey<String>(String.class, "config3")), "config3");
+
+ deleteCatalogEntity(symbolicName);
+ }
+
+ @Test
public void testLaunchApplicationWithCatalogReferencingOtherCatalog() throws Exception {
String referencedSymbolicName = "my.catalog.policy.id.referenced";
String referrerSymbolicName = "my.catalog.policy.id.referring";
- addCatalogOSGiPolicy(referencedSymbolicName, SIMPLE_POLICY_TYPE);
+ addCatalogOsgiPolicy(referencedSymbolicName, SIMPLE_POLICY_TYPE);
addCatalogItem(
"brooklyn.catalog:",
@@ -112,7 +150,27 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest {
deleteCatalogEntity(referencedSymbolicName);
}
- private void addCatalogOSGiPolicy(String symbolicName, String serviceType) {
+ private void addCatalogOsgiPolicy(String symbolicName, String serviceType) {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ addCatalogItem(
+ "brooklyn.catalog:",
+ " id: " + symbolicName,
+ " name: My Catalog Policy",
+ " description: My description",
+ " icon_url: classpath://path/to/myicon.jpg",
+ " version: " + TEST_VERSION,
+ " libraries:",
+ " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
+ " item_type: policy",
+ " item:",
+ " type: " + serviceType,
+ " brooklyn.config:",
+ " config1: config1",
+ " config2: config2");
+ }
+
+ private void addCatalogOsgiPolicyTopLevelSyntax(String symbolicName, String serviceType) {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
addCatalogItem(
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
new file mode 100644
index 0000000..e473d2d
--- /dev/null
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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 io.brooklyn.camp.brooklyn.catalog;
+
+import static org.testng.Assert.assertEquals;
+import io.brooklyn.camp.brooklyn.AbstractYamlTest;
+
+import org.testng.Assert;
+import org.testng.TestListenerAdapter;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+
+import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.CatalogItem.CatalogItemType;
+import brooklyn.management.osgi.OsgiStandaloneTest;
+import brooklyn.management.osgi.OsgiTestResources;
+import brooklyn.test.TestResourceUnavailableException;
+
+
+public class CatalogYamlTemplateTest extends AbstractYamlTest {
+
+ private static final String SIMPLE_ENTITY_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY;
+
+ @Test
+ public void testAddCatalogItem() throws Exception {
+ TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
+
+ addCatalogItem(
+ "brooklyn.catalog:",
+ " id: t1",
+ " item_type: template",
+ " name: My Catalog App",
+ " description: My description",
+ " icon_url: classpath://path/to/myicon.jpg",
+ " version: " + TEST_VERSION,
+ " libraries:",
+ " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL,
+ " item:",
+ " services:",
+ " # this sample comment should be included",
+ " - type: " + SIMPLE_ENTITY_TYPE);
+
+ CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("t1", TEST_VERSION);
+ assertEquals(item.getCatalogItemType(), CatalogItemType.TEMPLATE);
+ Assert.assertTrue(item.getPlanYaml().indexOf("sample comment")>=0,
+ "YAML did not include original comments; it was:\n"+item.getPlanYaml());
+ Assert.assertFalse(item.getPlanYaml().indexOf("description")>=0,
+ "YAML included metadata which should have been excluded; it was:\n"+item.getPlanYaml());
+
+ deleteCatalogEntity("t1");
+ }
+
+ // convenience for running in eclipse when the TestNG plugin drags in old version of snake yaml
+ public static void main(String[] args) {
+ TestListenerAdapter tla = new TestListenerAdapter();
+ TestNG testng = new TestNG();
+ testng.setTestClasses(new Class[] { CatalogYamlTemplateTest.class });
+ testng.addListener(tla);
+ testng.run();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
index 6f75136..68b3c6f 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
@@ -24,7 +24,7 @@ define([
"text!tpl/catalog/details-generic.html",
"text!tpl/catalog/details-location.html",
"text!tpl/catalog/add-catalog-entry.html",
- "text!tpl/catalog/add-entity.html",
+ "text!tpl/catalog/add-yaml.html",
"text!tpl/catalog/add-location.html",
"text!tpl/catalog/nav-entry.html",
@@ -32,7 +32,7 @@ define([
], function(_, $, Backbone, Brooklyn,
Location, Entity,
CatalogPageHtml, DetailsEntityHtml, DetailsGenericHtml, LocationDetailsHtml,
- AddCatalogEntryHtml, AddEntityHtml, AddLocationHtml, EntryHtml) {
+ AddCatalogEntryHtml, AddYamlHtml, AddLocationHtml, EntryHtml) {
// Holds the currently active details type, e.g. applications, policies. Bit of a workaround
// to share the active view with all instances of AccordionItemView, so clicking the 'reload
@@ -130,15 +130,21 @@ define([
render: function (initialView) {
this.$el.html(this.template());
if (initialView) {
+ if (initialView == "entity") initialView = "yaml";
+
this.$("[data-context='"+initialView+"']").addClass("active");
this.showFormForType(initialView)
}
return this;
},
+ clearWithHtml: function(template) {
+ if (this.contextView) this.contextView.close();
+ this.context = undefined;
+ this.$(".btn").removeClass("active");
+ this.$("#catalog-add-form").html(template);
+ },
beforeClose: function () {
- if (this.contextView) {
- this.contextView.close();
- }
+ if (this.contextView) this.contextView.close();
},
showContext: function(event) {
var $event = $(event.currentTarget);
@@ -152,13 +158,13 @@ define([
},
showFormForType: function (type) {
this.context = type;
- if (type == "entity") {
- this.contextView = newEntityForm(this.options.parent);
+ if (type == "yaml" || type == "entity") {
+ this.contextView = newYamlForm(this, this.options.parent);
} else if (type == "location") {
- this.contextView = newLocationForm(this.options.parent);
+ this.contextView = newLocationForm(this, this.options.parent);
} else if (type !== undefined) {
console.log("unknown catalog type " + type);
- this.showFormForType("entity");
+ this.showFormForType("yaml");
return;
}
Backbone.history.navigate("/v1/catalog/new/" + type);
@@ -166,11 +172,10 @@ define([
}
});
- function newEntityForm(parent) {
+ function newYamlForm(addView, addViewParent) {
return new Brooklyn.view.Form({
- template: _.template(AddEntityHtml),
+ template: _.template(AddYamlHtml),
onSubmit: function (model) {
- console.log("Submit entity", model.get("yaml"));
var submitButton = this.$(".catalog-submit-button");
// "loading" is an indicator to Bootstrap, not a string to display
submitButton.button("loading");
@@ -185,9 +190,13 @@ define([
.done(function (data, status, xhr) {
// Can extract location of new item with:
//model.url = Brooklyn.util.pathOf(xhr.getResponseHeader("Location"));
- self.close(); // one of the calls below should draw a different view
- parent.loadAccordionItem("entities", data.id);
- parent.loadAccordionItem("applications", data.id);
+ if (_.size(data)==0) {
+ addView.clearWithHtml( "No items supplied." );
+ } else {
+ addView.clearWithHtml( "Added: "+_.escape(_.keys(data).join(", "))
+ + (_.size(data)==1 ? ". Loading..." : "") );
+ addViewParent.loadAnyAccordionItem(_.size(data)==1 ? _.keys(data)[0] : undefined);
+ }
})
.fail(function (xhr, status, error) {
submitButton.button("reset");
@@ -201,7 +210,7 @@ define([
}
// Could adapt to edit existing locations too.
- function newLocationForm(parent) {
+ function newLocationForm(addView, addViewParent) {
// Renders with config key list
var body = new (Backbone.View.extend({
beforeClose: function() {
@@ -235,10 +244,9 @@ define([
submitButton.button("loading");
location.set("config", configKeys);
location.save()
- .done(function (newModel) {
- newModel = new Location.Model(newModel);
- self.close(); // the call below should draw a different view
- parent.loadAccordionItem("locations", newModel.id);
+ .done(function (data) {
+ addView.clearWithHtml( "Added: "+data.id+". Loading..." );
+ addViewParent.loadAccordionItem("locations", data.id);
})
.fail(function (response) {
submitButton.button("reset");
@@ -264,7 +272,7 @@ define([
this.model = model;
},
url: function() {
- return "/v1/catalog/" + this.name;
+ return "/v1/catalog/" + this.name+"?allVersions=true";
}
});
@@ -509,6 +517,13 @@ define([
this.setDetailsView(newView);
},
+ loadAnyAccordionItem: function (id) {
+ this.loadAccordionItem("entities", id);
+ this.loadAccordionItem("applications", id);
+ this.loadAccordionItem("policies", id);
+ this.loadAccordionItem("locations", id);
+ },
+
loadAccordionItem: function (kind, id) {
if (!this.accordion[kind]) {
console.error("No accordion for: " + kind);
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
index 6bd8c00..238dd77 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
@@ -18,11 +18,11 @@ under the License.
-->
<div class="catalog-details">
- <h2>Add a new...</h2>
+ <h2>Add to Catalog</h2>
<br/>
<div data-toggle="buttons-radio">
- <button class="btn btn-large show-context" data-context="entity">Entity</button>
+ <button class="btn btn-large show-context" data-context="yaml">YAML</button>
<button class="btn btn-large show-context" data-context="location">Location</button>
</div>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-entity.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-entity.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-entity.html
deleted file mode 100644
index 9c64e90..0000000
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-entity.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-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.
--->
-<form>
- <label for="new-blueprint">Enter blueprint:</label>
- <textarea id='new-blueprint' name='yaml' rows='5' cols='15'></textarea>
-
- <button class='catalog-submit-button btn' data-loading-text='Saving...'>Submit</button>
- <p class="catalog-save-error hide">
- <span class="alert-error">
- <strong>Error:</strong><br/>
- <span class="catalog-error-message"></span>
- </span>
- </p>
-</form>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-yaml.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-yaml.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-yaml.html
new file mode 100644
index 0000000..9c64e90
--- /dev/null
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-yaml.html
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<form>
+ <label for="new-blueprint">Enter blueprint:</label>
+ <textarea id='new-blueprint' name='yaml' rows='5' cols='15'></textarea>
+
+ <button class='catalog-submit-button btn' data-loading-text='Saving...'>Submit</button>
+ <p class="catalog-save-error hide">
+ <span class="alert-error">
+ <strong>Error:</strong><br/>
+ <span class="catalog-error-message"></span>
+ </span>
+ </p>
+</form>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
index bf097e2..49549fd 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
@@ -64,7 +64,8 @@ public interface CatalogApi {
@Consumes
@POST
- @ApiOperation(value = "Add a catalog item (e.g. new type of entity, policy or location) by uploading YAML descriptor", responseClass = "String")
+ @ApiOperation(value = "Add a catalog item (e.g. new type of entity, policy or location) by uploading YAML descriptor "
+ + "Return value is map of ID to CatalogItemSummary, with code 201 CREATED.", responseClass = "Response")
public Response create(
@ApiParam(name = "yaml", value = "YAML descriptor of catalog item", required = true)
@Valid String yaml);
@@ -135,7 +136,9 @@ public interface CatalogApi {
@ApiParam(name = "regex", value = "Regular expression to search for")
@QueryParam("regex") @DefaultValue("") String regex,
@ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
- @QueryParam("fragment") @DefaultValue("") String fragment);
+ @QueryParam("fragment") @DefaultValue("") String fragment,
+ @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)")
+ @QueryParam("allVersions") @DefaultValue("false") boolean includeAllVersions);
@GET
@Path("/applications")
@@ -144,7 +147,9 @@ public interface CatalogApi {
@ApiParam(name = "regex", value = "Regular expression to search for")
@QueryParam("regex") @DefaultValue("") String regex,
@ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
- @QueryParam("fragment") @DefaultValue("") String fragment);
+ @QueryParam("fragment") @DefaultValue("") String fragment,
+ @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)")
+ @QueryParam("allVersions") @DefaultValue("false") boolean includeAllVersions);
/** @deprecated since 0.7.0 use {@link #getEntity(String, String)} */
@Deprecated
@@ -203,7 +208,9 @@ public interface CatalogApi {
@ApiParam(name = "regex", value = "Regular expression to search for")
@QueryParam("regex") @DefaultValue("") String regex,
@ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
- @QueryParam("fragment") @DefaultValue("") String fragment);
+ @QueryParam("fragment") @DefaultValue("") String fragment,
+ @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)")
+ @QueryParam("allVersions") @DefaultValue("false") boolean includeAllVersions);
/** @deprecated since 0.7.0 use {@link #getPolicy(String, String)} */
@Deprecated
@@ -236,7 +243,9 @@ public interface CatalogApi {
@ApiParam(name = "regex", value = "Regular expression to search for")
@QueryParam("regex") @DefaultValue("") String regex,
@ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
- @QueryParam("fragment") @DefaultValue("") String fragment);
+ @QueryParam("fragment") @DefaultValue("") String fragment,
+ @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)")
+ @QueryParam("allVersions") @DefaultValue("false") boolean includeAllVersions);
/** @deprecated since 0.7.0 use {@link #getLocation(String, String)} */
@Deprecated
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
index a5c5207..5035c19 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
@@ -41,6 +41,7 @@ import brooklyn.rest.domain.LocationSummary;
import com.wordnik.swagger.core.ApiOperation;
import com.wordnik.swagger.core.ApiParam;
+@SuppressWarnings("deprecation")
@Path("/v1/locations")
@Apidoc("Locations")
@Produces(MediaType.APPLICATION_JSON)
@@ -79,9 +80,7 @@ public interface LocationApi {
@DefaultValue("false")
@QueryParam("full") String fullConfig);
- /**
- * @deprecated since 0.7.0; use {@link CatalogApi#create(String)}
- */
+ /** @deprecated since 0.7.0 use {@link CatalogApi#create(String)} with a location definition */
@POST
@ApiOperation(value = "Create a new location definition", responseClass = "String")
@Deprecated
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogEntitySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogEntitySummary.java b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogEntitySummary.java
index c08e82a..268437a 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogEntitySummary.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogEntitySummary.java
@@ -23,13 +23,19 @@ import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
public class CatalogEntitySummary extends CatalogItemSummary {
private static final long serialVersionUID = 1063908984191424539L;
+ @JsonSerialize(include=Inclusion.NON_EMPTY)
private final Set<EntityConfigSummary> config;
+
+ @JsonSerialize(include=Inclusion.NON_EMPTY)
private final Set<SensorSummary> sensors;
+ @JsonSerialize(include=Inclusion.NON_EMPTY)
private final Set<EffectorSummary> effectors;
public CatalogEntitySummary(
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogItemSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogItemSummary.java b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogItemSummary.java
index db979e2..79b1d27 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogItemSummary.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogItemSummary.java
@@ -23,6 +23,7 @@ import java.net.URI;
import java.util.Map;
import org.apache.commons.lang.builder.EqualsBuilder;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
@@ -32,6 +33,8 @@ import com.google.common.collect.ImmutableMap;
/** variant of Catalog*ItemDto objects for JS/JSON serialization;
* see also, subclasses */
+@JsonIgnoreProperties(ignoreUnknown = true)
+// ignore unknown, ie properties from subclasses (entity)
public class CatalogItemSummary implements HasId, HasName, Serializable {
private static final long serialVersionUID = -823483595879417681L;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eaaca787/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogPolicySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogPolicySummary.java b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogPolicySummary.java
index f30006a..75cc6ae 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogPolicySummary.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogPolicySummary.java
@@ -23,6 +23,8 @@ import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import com.google.common.collect.ImmutableSet;
@@ -30,6 +32,7 @@ public class CatalogPolicySummary extends CatalogItemSummary {
private static final long serialVersionUID = -588856488327394445L;
+ @JsonSerialize(include=Inclusion.NON_EMPTY)
private final Set<PolicyConfigSummary> config;
public CatalogPolicySummary(