brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [01/16] incubator-brooklyn git commit: implement catalog multi-item in same file support
Date Tue, 21 Apr 2015 20:41:20 GMT
Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master ff31a41d4 -> c4ca5b683


implement catalog multi-item in same file support

needs tests at this point, but seems to be working, and backwards compatible


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/08cb3e75
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/08cb3e75
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/08cb3e75

Branch: refs/heads/master
Commit: 08cb3e75f7d9f6ccd87bffbf34ab149e56b7411e
Parents: 99fa0b1
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Mon Mar 30 17:21:34 2015 -0500
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Wed Apr 15 20:05:19 2015 -0500

----------------------------------------------------------------------
 .../java/brooklyn/catalog/BrooklynCatalog.java  |  18 ++
 .../catalog/internal/BasicBrooklynCatalog.java  | 168 ++++++++++++++-----
 .../catalog/internal/CatalogItemBuilder.java    |   5 +
 .../brooklyn/catalog/internal/CatalogUtils.java |   1 +
 .../catalog/internal/CatalogLoadTest.java       |   4 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |   5 +-
 6 files changed, 156 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/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 e2b39b0..ce4386f 100644
--- a/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
+++ b/api/src/main/java/brooklyn/catalog/BrooklynCatalog.java
@@ -104,6 +104,24 @@ public interface BrooklynCatalog {
     CatalogItem<?,?> addItem(String yaml, boolean forceUpdate);
     
     /**
+     * Adds items (represented in yaml) to the catalog.
+     * Fails if the same version exists in catalog.
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     */
+    Iterable<? extends CatalogItem<?,?>> addItems(String yaml);
+    
+    /**
+     * Adds items (represented in yaml) to the catalog.
+     * 
+     * @param forceUpdate If true allows catalog update even when an
+     * item exists with the same symbolicName and version
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     */
+    Iterable<? extends CatalogItem<?,?>> addItems(String yaml, boolean forceUpdate);
+    
+    /**
      * adds an item to the 'manual' catalog;
      * this does not update the classpath or have a record to the java Class
      *

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/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 96760aa..8a562d0 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -28,7 +28,7 @@ import io.brooklyn.camp.spi.pdp.Service;
 
 import java.io.FileNotFoundException;
 import java.util.Collection;
-import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
@@ -37,6 +37,7 @@ import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.yaml.snakeyaml.Yaml;
 
 import brooklyn.basic.AbstractBrooklynObjectSpec;
 import brooklyn.basic.BrooklynObjectInternal.ConfigurationSupportInternal;
@@ -57,9 +58,11 @@ import brooklyn.management.internal.EntityManagementUtils;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
+import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.AggregateClassLoader;
 import brooklyn.util.javalang.LoadedClassLoader;
@@ -491,44 +494,112 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
         if (item instanceof CatalogItemDtoAbstract) return (CatalogItemDtoAbstract<T,SpecT>)
item;
         throw new IllegalStateException("Cannot unwrap catalog item '"+item+"' (type "+item.getClass()+")
to restore DTO");
     }
+    
+    @SuppressWarnings("unchecked")
+    private <T> Maybe<T> getFirstAs(Map<?,?> map, Class<T> type,
String firstKey, String ...otherKeys) {
+        if (map==null) return Maybe.absent("No map available");
+        String foundKey = null;
+        Object value = null;
+        if (map.containsKey(firstKey)) foundKey = firstKey;
+        else for (String key: otherKeys) {
+            if (map.containsKey(key)) {
+                foundKey = key;
+                break;
+            }
+        }
+        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());
+        return Maybe.of((T)value);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private Maybe<Map<?,?>> getFirstAsMap(Map<?,?> map, String firstKey,
String ...otherKeys) {
+        return (Maybe<Map<?,?>>)(Maybe) getFirstAs(map, Map.class, firstKey,
otherKeys);
+    }
 
-    private CatalogItemDtoAbstract<?,?> getAbstractCatalogItem(String yaml) {
-        DeploymentPlan plan = makePlanFromYaml(yaml);
+    private List<CatalogItemDtoAbstract<?,?>> getAbstractCatalogItems(String
yaml) {
+        Map<?,?> itemDef = Yamls.getAs(Yamls.parseAll(yaml), Map.class);
+        Map<?,?> catalogMetadata = getFirstAsMap(itemDef, "brooklyn.catalog", "catalog").orNull();
+        if (catalogMetadata==null)
+            log.warn("No `brooklyn.catalog` supplied in catalog request; using legacy mode
for "+itemDef);
+        catalogMetadata = MutableMap.copyOf(catalogMetadata);
 
-        @SuppressWarnings("rawtypes")
-        Maybe<Map> possibleCatalog = plan.getCustomAttribute("brooklyn.catalog", Map.class,
true);
-        MutableMap<String, Object> catalog = MutableMap.of();
-        if (possibleCatalog.isPresent()) {
-            @SuppressWarnings("unchecked")
-            Map<String, Object> catalog2 = (Map<String, Object>) possibleCatalog.get();
-            catalog.putAll(catalog2);
+        List<CatalogItemDtoAbstract<?, ?>> result = MutableList.of();
+        
+        addAbstractCatalogItems(catalogMetadata, result, null);
+        
+        itemDef.remove("brooklyn.catalog");
+        catalogMetadata.remove("item");
+        catalogMetadata.remove("items");
+        if (!itemDef.isEmpty()) {
+            log.debug("Reading brooklyn.catalog peer keys as item");
+            Map<String,?> rootItem = MutableMap.of("item", itemDef);
+            addAbstractCatalogItems(rootItem, result, catalogMetadata);
         }
+        
+        return result;
+    }
 
-        Collection<CatalogBundle> libraries = Collections.emptyList();
-        Maybe<Object> possibleLibraries = catalog.getMaybe("libraries");
-        if (possibleLibraries.isAbsent()) possibleLibraries = catalog.getMaybe("brooklyn.libraries");
-        if (possibleLibraries.isPresentAndNonNull()) {
-            if (!(possibleLibraries.get() instanceof Collection))
-                throw new IllegalArgumentException("Libraries should be a list, not "+possibleLibraries.get());
-            libraries = CatalogItemDtoAbstract.parseLibraries((Collection<?>) possibleLibraries.get());
-        }
+    enum CatalogItemTypes { ENTITY, TEMPLATE, POLICY, LOCATION }
+    
+    @SuppressWarnings("unchecked")
+    private void addAbstractCatalogItems(Map<?,?> itemMetadata, List<CatalogItemDtoAbstract<?,
?>> result, Map<?,?> parentMetadata) {
 
-        final String id = (String) catalog.getMaybe("id").orNull();
-        final String version = Strings.toString(catalog.getMaybe("version").orNull());
-        final String symbolicName = (String) catalog.getMaybe("symbolicName").orNull();
-        final String name = (String) catalog.getMaybe("name").orNull();
-        final String displayName = (String) catalog.getMaybe("displayName").orNull();
-        final String description = (String) catalog.getMaybe("description").orNull();
-        final String iconUrl = (String) catalog.getMaybe("iconUrl").orNull();
-        final String iconUrlUnderscore = (String) catalog.getMaybe("icon_url").orNull();
-        final String deprecated = (String) catalog.getMaybe("deprecated").orNull();
+        // TODO:
+//        get yaml
+//        (tests)
+//        docs used as test casts -- (doc assertions that these match -- or import -- known
test casesyamls)
+//        multiple versions in catalog page
+
+        Map<Object,Object> catalogMetadata = MutableMap.builder().putAll(parentMetadata).putAll(itemMetadata).build();
+        
+        // libraries we treat specially, to append the list, with the child's list preferred
in classloading order
+        List<?> librariesL = MutableList.copyOf(getFirstAs(itemMetadata, List.class,
"brooklyn.libraries", "libraries").orNull())
+            .appendAll(getFirstAs(parentMetadata, List.class, "brooklyn.libraries", "libraries").orNull());
+        if (!librariesL.isEmpty())
+            catalogMetadata.put("brooklyn.libraries", librariesL);
+        Collection<CatalogBundle> libraries = CatalogItemDtoAbstract.parseLibraries(librariesL);
+
+        Object items = catalogMetadata.remove("items");
+        Object item = catalogMetadata.remove("item");
+
+        if (items!=null) {
+            for (Map<?,?> i: ((List<Map<?,?>>)items)) {
+                addAbstractCatalogItems(i, result, catalogMetadata);
+            }
+        }
+        
+        if (item==null) return;
+        
+        //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);
+        
+        String id = getFirstAs(catalogMetadata, String.class, "id").orNull();
+        String version = getFirstAs(catalogMetadata, String.class, "version").orNull();
+        String symbolicName = getFirstAs(catalogMetadata, String.class, "symbolicName").orNull();
+        String displayName = getFirstAs(catalogMetadata, String.class, "displayName").orNull();
+        String name = getFirstAs(catalogMetadata, String.class, "name").orNull();
 
         if ((Strings.isNonBlank(id) || Strings.isNonBlank(symbolicName)) && 
                 Strings.isNonBlank(displayName) &&
                 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);
+        } 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);
+        }
+        
         final String catalogSymbolicName;
         if (Strings.isNonBlank(symbolicName)) {
             catalogSymbolicName = symbolicName;
@@ -540,9 +611,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             }
         } else if (Strings.isNonBlank(name)) {
             catalogSymbolicName = name;
-        } else if (Strings.isNonBlank(plan.getName())) {
+        } else if (plan!=null && Strings.isNonBlank(plan.getName())) {
             catalogSymbolicName = plan.getName();
-        } else if (plan.getServices().size()==1) {
+        } else if (plan!=null && plan.getServices().size()==1) {
             Service svc = Iterables.getOnlyElement(plan.getServices());
             if (Strings.isBlank(svc.getServiceType())) {
                 throw new IllegalStateException("CAMP service type not expected to be missing
for " + svc);
@@ -577,6 +648,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             catalogDisplayName = null;
         }
 
+        final String description = getFirstAs(catalogMetadata, String.class, "description").orNull();
         final String catalogDescription;
         if (Strings.isNonBlank(description)) {
             catalogDescription = description;
@@ -586,33 +658,30 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
             catalogDescription = null;
         }
 
-        final String catalogIconUrl;
-        if (Strings.isNonBlank(iconUrl)) {
-            catalogIconUrl = iconUrl;
-        } else if (Strings.isNonBlank(iconUrlUnderscore)) {
-            catalogIconUrl = iconUrlUnderscore;
-        } else {
-            catalogIconUrl = null;
-        }
+        final String catalogIconUrl = getFirstAs(catalogMetadata, String.class, "icon.url",
"iconUrl", "icon_url").orNull();
 
+        final String deprecated = getFirstAs(catalogMetadata, String.class, "deprecated").orNull();
         final Boolean catalogDeprecated = Boolean.valueOf(deprecated);
 
         CatalogUtils.installLibraries(mgmt, libraries);
 
-        String versionedId = CatalogUtils.getVersionedId(catalogSymbolicName, catalogVersion);
+        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);
 
         CatalogItemDtoAbstract<?, ?> dto = createItemBuilder(spec, catalogSymbolicName,
catalogVersion)
             .libraries(libraries)
             .displayName(catalogDisplayName)
             .description(catalogDescription)
+            .deprecated(catalogDeprecated)
             .iconUrl(catalogIconUrl)
             .plan(yaml)
             .build();
 
         dto.setManagementContext((ManagementContextInternal) mgmt);
-        return dto;
+        result.add(dto);
     }
 
     private AbstractBrooklynObjectSpec<?,?> createSpec(String symbolicName, DeploymentPlan
plan, BrooklynClassLoadingContext loader) {
@@ -664,10 +733,27 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     }
 
     @Override
+    public List<? extends CatalogItem<?,?>> addItems(String yaml) {
+        return addItems(yaml, false);
+    }
+
+    @Override
     public CatalogItem<?,?> addItem(String yaml, boolean forceUpdate) {
+        return Iterables.getOnlyElement(addItems(yaml, forceUpdate));
+    }
+    
+    @Override
+    public List<? extends CatalogItem<?,?>> addItems(String yaml, boolean forceUpdate)
{
         log.debug("Adding manual catalog item to "+mgmt+": "+yaml);
         checkNotNull(yaml, "yaml");
-        CatalogItemDtoAbstract<?,?> itemDto = getAbstractCatalogItem(yaml);
+        List<CatalogItemDtoAbstract<?, ?>> result = getAbstractCatalogItems(yaml);
+        for (CatalogItemDtoAbstract<?, ?> item: result) {
+            addItemDto(item, forceUpdate);
+        }
+        return result;
+    }
+    
+    private CatalogItem<?,?> addItemDto(CatalogItemDtoAbstract<?, ?> itemDto,
boolean forceUpdate) {
         checkItemNotExists(itemDto, forceUpdate);
 
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java b/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java
index 2b16cc6..fb7a735 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogItemBuilder.java
@@ -94,6 +94,11 @@ public class CatalogItemBuilder<CatalogItemType extends CatalogItemDtoAbstract<?
         return this;
     }
 
+    public CatalogItemBuilder<CatalogItemType> deprecated(boolean deprecated) {
+        dto.setDeprecated(deprecated);
+        return this;
+    }
+
     public CatalogItemBuilder<CatalogItemType> libraries(Collection<CatalogBundle>
libraries) {
         dto.setLibraries(libraries);
         return this;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/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 ed4d06d..50ef436 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java
@@ -200,6 +200,7 @@ public class CatalogUtils {
     }
 
     public static String getVersionedId(String id, String version) {
+        // TODO null checks
         return id + VERSION_DELIMITER + version;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
index f36d4c9..3ff89f4 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java
@@ -44,8 +44,10 @@ public class CatalogLoadTest {
         return ResourceUtils.create(this).getResourceAsString(file);
     }
 
+    // CAMP YAML parsing not available in core, so YAML catalog tests are in camp, e.g. CatalogYamlEntitiesTest

+    
     @Test
-    public void testLoadCatalog() {
+    public void testLoadXmlCatalog() {
         CatalogDto catalog = (CatalogDto) serializer.fromString(
                 loadFile("classpath://brooklyn/catalog/internal/osgi-catalog.xml"));
         assertNotNull(catalog);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/08cb3e75/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 048a75f..5b79982 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
@@ -21,12 +21,9 @@ package io.brooklyn.camp.brooklyn.catalog;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
-import brooklyn.test.TestResourceUnavailableException;
-import brooklyn.util.ResourceUtils;
 import io.brooklyn.camp.brooklyn.AbstractYamlTest;
 
 import java.io.InputStream;
-import java.net.URL;
 import java.util.Collection;
 
 import org.testng.Assert;
@@ -39,6 +36,8 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.management.osgi.OsgiStandaloneTest;
 import brooklyn.management.osgi.OsgiTestResources;
+import brooklyn.test.TestResourceUnavailableException;
+import brooklyn.util.ResourceUtils;
 
 import com.google.common.collect.Iterables;
 


Mime
View raw message