brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [3/3] brooklyn-server git commit: tidy for item lister after #17
Date Sun, 21 Feb 2016 16:56:17 GMT
tidy for item lister after #17

* support `yaml` as a list, like `jars`; and allow a user to supply both; and if just yaml is supplies, it does not scan classes; if neither supplied, as before, it looks at `INITIAL_CLASSPATH`
* share more code between yaml and java block
* use `filename.toLowerCase().endsWith(".yaml")` rather than case-sensitive `contains`
* fix assumptions on fields and paths in html
* including missing brooklyn.gif and fix paths for html generation
* remove incubator refs
* generate yaml item descriptors better (using ID, in ItemDescriptors)
* explain arguments better


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/57c6e1cf
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/57c6e1cf
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/57c6e1cf

Branch: refs/heads/master
Commit: 57c6e1cfd39ef9c14cf74821836f87b9fb44aae8
Parents: 96cef22
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Sun Feb 21 07:47:35 2016 -0800
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Sun Feb 21 08:55:56 2016 -0800

----------------------------------------------------------------------
 .../util/core/javalang/ReflectionScanner.java   |  14 +-
 .../org/apache/brooklyn/cli/ItemLister.java     | 401 +++++++++----------
 .../brooklyn/cli/lister/ItemDescriptors.java    |  74 +++-
 server-cli/src/main/license/files/DISCLAIMER    |   8 -
 .../statics/brooklyn-object-list.html           |   2 +-
 .../brooklyn/item-lister/statics/common.js      |   2 +-
 .../item-lister/statics/images/brooklyn.gif     | Bin 0 -> 4873 bytes
 .../item-lister/templates/enricher.html         |   2 +-
 .../brooklyn/item-lister/templates/entity.html  |   6 +-
 .../item-lister/templates/location.html         |   4 +-
 .../brooklyn/item-lister/templates/policy.html  |   2 +-
 server-cli/src/test/license/files/DISCLAIMER    |   8 -
 12 files changed, 276 insertions(+), 247 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/core/src/main/java/org/apache/brooklyn/util/core/javalang/ReflectionScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/javalang/ReflectionScanner.java b/core/src/main/java/org/apache/brooklyn/util/core/javalang/ReflectionScanner.java
index 3ae423b..bb46376 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/javalang/ReflectionScanner.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/javalang/ReflectionScanner.java
@@ -51,6 +51,16 @@ public class ReflectionScanner {
     protected final ClassLoader[] classLoaders;
     protected final Reflections reflections;
 
+    /** as {@link #ReflectionScanner(Iterable, String, Predicate, ClassLoader...)} using the prefix as the base for the filter */
+    public ReflectionScanner(
+            final Iterable<URL> urlsToScan, 
+            final String optionalPrefix,
+            final ClassLoader ...classLoaders) {
+        this(urlsToScan, optionalPrefix, 
+            Strings.isNonEmpty(optionalPrefix) ? new FilterBuilder.Include(FilterBuilder.prefix(optionalPrefix)) : null,
+            classLoaders);
+    }
+    
     /** scanner which will look in the given urls 
      * (or if those are null attempt to infer from the first entry in the classloaders,
      * although currently that seems to only pick up directories, not JAR's),
@@ -60,12 +70,10 @@ public class ReflectionScanner {
     public ReflectionScanner(
             final Iterable<URL> urlsToScan, 
             final String optionalPrefix,
+            final Predicate<String> filter,
             final ClassLoader ...classLoaders) {
         reflections = new Reflections(new ConfigurationBuilder() {
             {
-                final Predicate<String> filter = 
-                        Strings.isNonEmpty(optionalPrefix) ? new FilterBuilder.Include(FilterBuilder.prefix(optionalPrefix)) : null;
-
                 if (urlsToScan!=null)
                     setUrls(ImmutableSet.copyOf(urlsToScan));
                 else if (classLoaders.length>0 && classLoaders[0]!=null)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
----------------------------------------------------------------------
diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java b/server-cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
index b45d8d0..2772796 100644
--- a/server-cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
+++ b/server-cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
@@ -24,31 +24,17 @@ import io.airlift.command.Option;
 import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URL;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
+import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
-import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
-import org.apache.brooklyn.api.objs.SpecParameter;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
-import org.apache.brooklyn.camp.spi.PlatformRootSummary;
-import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.rest.domain.EntityConfigSummary;
-import org.apache.brooklyn.rest.transform.EntityTransformer;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.stream.Streams;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
@@ -56,14 +42,26 @@ import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
+import org.apache.brooklyn.camp.spi.PlatformRootSummary;
 import org.apache.brooklyn.cli.lister.ClassFinder;
 import org.apache.brooklyn.cli.lister.ItemDescriptors;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.core.javalang.ReflectionScanner;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
+import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
 import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.JsonInclude;
@@ -90,211 +88,180 @@ public class ItemLister {
     @Command(name = "list-objects", description = "List Brooklyn objects (Entities, Policies, Enrichers and Locations)")
     public static class ListAllCommand extends AbstractMain.BrooklynCommandCollectingArgs {
 
-        @Option(name = { "--jars" }, title = "Jars", description = "Jars to scan. If a file (not a url) pointing at a directory, will include all files in that directory")
-        public List<String> jars = Lists.newLinkedList();
+        @Option(name = { "--jar" }, title = "JAR to scan", description = "A JAR file to scan. If a file (not a url) pointing at a directory, will include all JAR files in that directory. "
+            + "Argument can be supplied multiple times to scan multiple JARs. If not supplied and no YAML, this attempts to use the initial classpath")
+        public List<String> jarsToScan = Lists.newLinkedList();
+        
+        @Option(name = { "--jars" }, title = "JAR to scan", description = "DEPRECATED: synonym for --jar")
+        public List<String> jarsToScanOld = Lists.newLinkedList();
 
-        @Option(name = { "--yaml" }, title = "Yaml", description = "Yaml file to parse. If a file is pointing at a directory, will include all files in that directory.")
-        public String yaml = "";
+        @Option(name = { "--yaml" }, title = "YAML blueprint file", description = "A YAML blueprint file to parse. If a file is pointing at a directory, will include all YAML and BOM files in that directory")
+        public List<String> yamlToScan = Lists.newLinkedList();
 
-        @Option(name = { "--type-regex" }, title = "Regex for types to list")
+        @Option(name = { "--type-regex" }, title = "Regex to restrict the Java types loaded")
         public String typeRegex;
 
-        @Option(name = { "--catalog-only" }, title = "Whether to only list items annotated with @Catalog")
+        @Option(name = { "--catalog-only" }, title = "When scanning JAR files, whether to include only items annotated with @Catalog (default true)")
         public boolean catalogOnly = true;
 
-        @Option(name = { "--ignore-impls" }, title = "Ignore Entity implementations, where there is an Entity interface with @ImplementedBy")
-        public boolean ignoreImpls = false;
+        @Option(name = { "--ignore-impls" }, title = "Ignore Entity class implementation where there is an Entity interface with @ImplementedBy (default true)")
+        public boolean ignoreImpls = true;
 
         @Option(name = { "--headings-only" }, title = "Whether to only show name/type, and not config keys etc")
         public boolean headingsOnly = false;
         
-        @Option(name = { "--output-folder" }, title = "Folder to save output")
+        @Option(name = { "--output-folder" }, title = "If supplied, generate HTML pages in the given folder; otherwise only generates JSON")
         public String outputFolder;
 
-        /**
-         * Used for multiple result when documentation is generated for more than one catalog at time
-         */
-        private String outputSubFolder;
-
         @SuppressWarnings("unchecked")
         @Override
         public Void call() throws Exception {
-            List<URL> urls = getUrls();
-            LOG.info("Retrieving objects from "+urls);
-
             Map<String, Object> result = MutableMap.of();
-            List<String> jsonList = new ArrayList<>();
 
-            if (!jars.isEmpty()) {
+            result = populateDescriptors();
+            String json = toJson(result);
+            
+            if (outputFolder == null) {
+                System.out.println(json);
+
+            } else {
+                LOG.info("Outputting item list (size "+itemCount+") to " + outputFolder);
+                String outputPath = Os.mergePaths(outputFolder, "index.html");
+                String parentDir = (new File(outputPath).getParentFile()).getAbsolutePath();
+                mkdir(parentDir, "entities");
+                mkdir(parentDir, "policies");
+                mkdir(parentDir, "enrichers");
+                mkdir(parentDir, "locations");
+                mkdir(parentDir, "locationResolvers"); //TODO nothing written here yet...
+
+                mkdir(parentDir, "style");
+                mkdir(Os.mergePaths(parentDir, "style"), "js");
+                mkdir(Os.mergePaths(parentDir, "style", "js"), "catalog");
+                mkdir(parentDir, "images");
+
+                // create both a JS and a JSON object
+                Files.write("var items = " + json, new File(Os.mergePaths(outputFolder, "items.js")), Charsets.UTF_8);
+                Files.write(json, new File(Os.mergePaths(outputFolder, "items.json")), Charsets.UTF_8);
+                ResourceUtils resourceUtils = ResourceUtils.create(this);
+
+                // root - just loads the above JSON
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "brooklyn-object-list.html", "index.html");
+
+                // statics - structure mirrors docs (not for any real reason however... the json is usually enough for our docs)
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "common.js");
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "items.css");
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "images/brooklyn.gif");
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/underscore-min.js");
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/underscore-min.map");
+                copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/catalog/typeahead.js");
+
+                // now make pages for each item
+
+                List<Map<String, Object>> entities = (List<Map<String, Object>>) result.get("entities");
+                String entityTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "entity.html"));
+                for (Map<String, Object> entity : entities) {
+                    String type = (String) entity.get("type");
+                    String name = (String) entity.get("name");
+                    String entityHtml = TemplateProcessor.processTemplateContents(entityTemplateHtml, ImmutableMap.of("type", type, "name", name));
+                    Files.write(entityHtml, new File(Os.mergePaths(outputFolder, "entities", type + ".html")), Charsets.UTF_8);
+                }
+
+                List<Map<String, Object>> policies = (List<Map<String, Object>>) result.get("policies");
+                String policyTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "policy.html"));
+                for (Map<String, Object> policy : policies) {
+                    String type = (String) policy.get("type");
+                    String name = (String) policy.get("name");
+                    String policyHtml = TemplateProcessor.processTemplateContents(policyTemplateHtml, ImmutableMap.of("type", type, "name", name));
+                    Files.write(policyHtml, new File(Os.mergePaths(outputFolder, "policies", type + ".html")), Charsets.UTF_8);
+                }
+
+                List<Map<String, Object>> enrichers = (List<Map<String, Object>>) result.get("enrichers");
+                String enricherTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "enricher.html"));
+                for (Map<String, Object> enricher : enrichers) {
+                    String type = (String) enricher.get("type");
+                    String name = (String) enricher.get("name");
+                    String enricherHtml = TemplateProcessor.processTemplateContents(enricherTemplateHtml, ImmutableMap.of("type", type, "name", name));
+                    Files.write(enricherHtml, new File(Os.mergePaths(outputFolder, "enrichers", type + ".html")), Charsets.UTF_8);
+                }
+
+                List<Map<String, Object>> locations = (List<Map<String, Object>>) result.get("locations");
+                String locationTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "location.html"));
+                for (Map<String, Object> location : locations) {
+                    String type = (String) location.get("type");
+                    String locationHtml = TemplateProcessor.processTemplateContents(locationTemplateHtml, ImmutableMap.of("type", type));
+                    Files.write(locationHtml, new File(Os.mergePaths(outputFolder, "locations", type + ".html")), Charsets.UTF_8);
+                }
+                LOG.info("Finished outputting item list to " + outputFolder);
+            }
+            return null;
+        }
+
+        protected List<String> getJars() {
+            return MutableList.<String>builder().addAll(jarsToScan).addAll(jarsToScanOld).build();
+        }
+        
+        protected Map<String, Object> populateDescriptors() throws MalformedURLException, IOException {
+            Map<String, Object> result;
+            List<Map<?,?>> entities = new ArrayList<>();
+            List<Map<?,?>> policies = new ArrayList<>();
+            List<Map<?,?>> enrichers = new ArrayList<>();
+            List<Map<?,?>> locations = new ArrayList<>();
+            List<Object> locationResolvers = new ArrayList<>();
+
+            if (!getJars().isEmpty() || yamlToScan.isEmpty()) {
+                List<URL> urls = getJarUrls();
+                LOG.info("Retrieving classes from "+urls);
+                
                 // TODO Remove duplication from separate ListPolicyCommand etc
-                List<Class<? extends Entity>> entityTypes = getTypes(urls, Entity.class);
-                List<Class<? extends Policy>> policyTypes = getTypes(urls, Policy.class);
-                List<Class<? extends Enricher>> enricherTypes = getTypes(urls, Enricher.class);
-                List<Class<? extends Location>> locationTypes = getTypes(urls, Location.class, Boolean.FALSE);
-
-                result = ImmutableMap.<String, Object>builder()
-                        .put("entities", ItemDescriptors.toItemDescriptors(entityTypes, headingsOnly, "name"))
-                        .put("policies", ItemDescriptors.toItemDescriptors(policyTypes, headingsOnly, "name"))
-                        .put("enrichers", ItemDescriptors.toItemDescriptors(enricherTypes, headingsOnly, "name"))
-                        .put("locations", ItemDescriptors.toItemDescriptors(locationTypes, headingsOnly, "type"))
-                        .put("locationResolvers", ItemDescriptors.toItemDescriptors(ImmutableList.copyOf(ServiceLoader.load(LocationResolver.class)), true))
-                        .build();
-                jsonList.add(toJson(result));
-            } else if (!yaml.isEmpty()) {
+                entities.addAll(ItemDescriptors.toItemDescriptors(getTypes(urls, Entity.class), headingsOnly, "name"));
+                policies.addAll(ItemDescriptors.toItemDescriptors(getTypes(urls, Policy.class), headingsOnly, "name"));
+                enrichers.addAll(ItemDescriptors.toItemDescriptors(getTypes(urls, Enricher.class), headingsOnly, "name"));
+                locations.addAll(ItemDescriptors.toItemDescriptors(getTypes(urls, Location.class, false), headingsOnly, "type"));
+                locationResolvers.addAll(ItemDescriptors.toItemDescriptors(ImmutableList.copyOf(ServiceLoader.load(LocationResolver.class)), true));
+            }
+            if (!yamlToScan.isEmpty()) {
+                List<URL> urls = getYamlUrls();
+                LOG.info("Retrieving items from "+urls);
+                
                 LocalManagementContext lmgmt = new LocalManagementContext(BrooklynProperties.Factory.newEmpty());
+                @SuppressWarnings("unused")
                 BrooklynCampPlatform platform = new BrooklynCampPlatform(
                         PlatformRootSummary.builder().name("Brooklyn CAMP Platform").build(),lmgmt)
                         .setConfigKeyAtManagmentContext();
                 BrooklynCatalog catalog = lmgmt.getCatalog();
 
                 for (URL url: urls) {
-                    List<Map<?,?>> entities = new ArrayList<>();
-                    List<Map<?,?>> policies = new ArrayList<>();
-                    List<Map<?,?>> enrichers = new ArrayList<>();
-                    List<Map<?,?>> locations = new ArrayList<>();
-                    List<Map<?,?>> locationResolvers = new ArrayList<>();
-
                     String yamlContent = Streams.readFullyString(url.openStream());
 
-                    catalog.addItems(yamlContent);
-                    for (CatalogItem item: catalog.getCatalogItems()) {
-                        AbstractBrooklynObjectSpec<?,?> spec = catalog.createSpec(item);
-                        Map<String,Object> itemDescriptor = ItemDescriptors.toItemDescriptor((Class<? extends BrooklynObject>) spec.getType(), false);
-                        List<EntityConfigSummary> config = new ArrayList<>();
-
-                        if (item.getDisplayName() != null) {
-                            itemDescriptor.put("name", item.getDisplayName());
-                        } else if (!itemDescriptor.containsKey("name") || itemDescriptor.containsKey("name") && itemDescriptor.get("name") == null) {
-                            itemDescriptor.put("name", "");
-                        }
-                        if (!itemDescriptor.containsKey("type") || itemDescriptor.containsKey("type") && itemDescriptor.get("type") == null) {
-                            itemDescriptor.put("type", "");
-                        }
-                        if (item.getDescription() != null) {
-                            itemDescriptor.put("description", item.getDescription());
-                        }
-                        if (item.getIconUrl() != null) {
-                            itemDescriptor.put("iconUrl", item.getIconUrl());
-                        }
-
-                        double priorityCounter = 0.0d;
-                        for (SpecParameter<?> param: spec.getParameters()) {
-                            Double priority;
-                            if (param.isPinned()) {
-                                priority = priorityCounter;
-                                priorityCounter++;
-                            } else {
-                                priority = null;
-                            }
-
-                            EntityConfigSummary entityConfigSummary = EntityTransformer.entityConfigSummary(param.getConfigKey(),
-                                    param.getLabel(), priority, MutableMap.<String,URI>of());
-                            config.add(entityConfigSummary);
-                        }
-                        itemDescriptor.put("config", config);
+                    Iterable<? extends CatalogItem<?, ?>> items = catalog.addItems(yamlContent);
+                    for (CatalogItem<?,?> item: items) {
+                        Map<String,Object> itemDescriptor = ItemDescriptors.toItemDescriptor(catalog, item, headingsOnly);
 
+                        itemCount++;
                         if (item.getCatalogItemType() == CatalogItem.CatalogItemType.ENTITY || item.getCatalogItemType() == CatalogItem.CatalogItemType.TEMPLATE) {
                             entities.add(itemDescriptor);
                         } else if (item.getCatalogItemType() == CatalogItem.CatalogItemType.POLICY) {
                             policies.add(itemDescriptor);
                         } else if (item.getCatalogItemType() == CatalogItem.CatalogItemType.LOCATION) {
                             locations.add(itemDescriptor);
+                        } else {
+                            LOG.warn("Skipping unknown catalog item type "+item.getCatalogItemType()+": "+item);
+                            itemCount--;
                         }
                     }
-                    for (CatalogItem item: catalog.getCatalogItems()){
-                        catalog.deleteCatalogItem(item.getSymbolicName(), item.getVersion());
-                    }
-                    result = ImmutableMap.<String, Object>builder()
-                            .put("entities", entities)
-                            .put("policies", policies)
-                            .put("enrichers", enrichers)
-                            .put("locations", locations)
-                            .put("locationResolvers", locationResolvers)
-                            .build();
-
-                    jsonList.add(toJson(result));
+                    
                 }
+                Entities.destroyAll(lmgmt);
             }
-
-            int catalogCounter = 0;
-            for (String json: jsonList) {
-
-                if (outputFolder == null) {
-                    System.out.println(json);
-                } else {
-                    outputSubFolder = outputFolder;
-                    if (jsonList.size() > 1) {
-                        catalogCounter++;
-                        String subfolder = "catalog"+catalogCounter;
-                        outputSubFolder += "/" + subfolder;
-                    }
-                    LOG.info("Outputting item list (size "+itemCount+") to " + outputSubFolder);
-                    String outputPath = Os.mergePaths(outputSubFolder, "index.html");
-                    String parentDir = (new File(outputPath).getParentFile()).getAbsolutePath();
-                    mkdir(parentDir, "entities");
-                    mkdir(parentDir, "policies");
-                    mkdir(parentDir, "enrichers");
-                    mkdir(parentDir, "locations");
-                    mkdir(parentDir, "locationResolvers"); //TODO nothing written here yet...
-
-                    mkdir(parentDir, "style");
-                    mkdir(Os.mergePaths(parentDir, "style"), "js");
-                    mkdir(Os.mergePaths(parentDir, "style", "js"), "catalog");
-
-                    Files.write("var items = " + json, new File(Os.mergePaths(outputSubFolder, "items.js")), Charsets.UTF_8);
-                    Files.write(json, new File(Os.mergePaths(outputSubFolder, "items.json")), Charsets.UTF_8);
-                    ResourceUtils resourceUtils = ResourceUtils.create(this);
-
-                    // root - just loads the above JSON
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "brooklyn-object-list.html", "index.html");
-
-                    // statics - structure mirrors docs (not for any real reason however... the json is usually enough for our docs)
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "common.js");
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "items.css");
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/underscore-min.js");
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/underscore-min.map");
-                    copyFromItemListerClasspathBaseStaticsToOutputDir(resourceUtils, "style/js/catalog/typeahead.js");
-
-                    // now make pages for each item
-
-                    List<Map<String, Object>> entities = (List<Map<String, Object>>) result.get("entities");
-                    String entityTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "entity.html"));
-                    for (Map<String, Object> entity : entities) {
-                        String type = (String) entity.get("type");
-                        String name = (String) entity.get("name");
-                        String entityHtml = TemplateProcessor.processTemplateContents(entityTemplateHtml, ImmutableMap.of("type", type, "name", name));
-                        Files.write(entityHtml, new File(Os.mergePaths(outputSubFolder, "entities", type + ".html")), Charsets.UTF_8);
-                    }
-
-                    List<Map<String, Object>> policies = (List<Map<String, Object>>) result.get("policies");
-                    String policyTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "policy.html"));
-                    for (Map<String, Object> policy : policies) {
-                        String type = (String) policy.get("type");
-                        String name = (String) policy.get("name");
-                        String policyHtml = TemplateProcessor.processTemplateContents(policyTemplateHtml, ImmutableMap.of("type", type, "name", name));
-                        Files.write(policyHtml, new File(Os.mergePaths(outputSubFolder, "policies", type + ".html")), Charsets.UTF_8);
-                    }
-
-                    List<Map<String, Object>> enrichers = (List<Map<String, Object>>) result.get("enrichers");
-                    String enricherTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "enricher.html"));
-                    for (Map<String, Object> enricher : enrichers) {
-                        String type = (String) enricher.get("type");
-                        String name = (String) enricher.get("name");
-                        String enricherHtml = TemplateProcessor.processTemplateContents(enricherTemplateHtml, ImmutableMap.of("type", type, "name", name));
-                        Files.write(enricherHtml, new File(Os.mergePaths(outputSubFolder, "enrichers", type + ".html")), Charsets.UTF_8);
-                    }
-
-                    List<Map<String, Object>> locations = (List<Map<String, Object>>) result.get("locations");
-                    String locationTemplateHtml = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_TEMPLATES, "location.html"));
-                    for (Map<String, Object> location : locations) {
-                        String type = (String) location.get("type");
-                        String locationHtml = TemplateProcessor.processTemplateContents(locationTemplateHtml, ImmutableMap.of("type", type));
-                        Files.write(locationHtml, new File(Os.mergePaths(outputSubFolder, "locations", type + ".html")), Charsets.UTF_8);
-                    }
-                    LOG.info("Finished outputting item list to " + outputSubFolder);
-                }
-            }
-            return null;
+            
+            result = ImmutableMap.<String, Object>builder()
+                    .put("entities", entities)
+                    .put("policies", policies)
+                    .put("enrichers", enrichers)
+                    .put("locations", locations)
+                    .put("locationResolvers", locationResolvers)
+                    .build();
+            return result;
         }
 
         private void copyFromItemListerClasspathBaseStaticsToOutputDir(ResourceUtils resourceUtils, String item) throws IOException {
@@ -302,49 +269,54 @@ public class ItemLister {
         }
         private void copyFromItemListerClasspathBaseStaticsToOutputDir(ResourceUtils resourceUtils, String item, String dest) throws IOException {
             String js = resourceUtils.getResourceAsString(Urls.mergePaths(BASE_STATICS, item));
-            Files.write(js, new File(Os.mergePaths(outputSubFolder, dest)), Charsets.UTF_8);
+            Files.write(js, new File(Os.mergePaths(outputFolder, dest)), Charsets.UTF_8);
         }
 
         private void mkdir(String rootDir, String dirName) {
             (new File(Os.mergePaths(rootDir, dirName))).mkdirs();
         }
 
-        protected List<URL> getUrls() throws MalformedURLException, IOException {
+        protected List<URL> getJarUrls() throws MalformedURLException, IOException {
             List<URL> urls = Lists.newArrayList();
-            if (jars.isEmpty()) {
-                if (!yaml.isEmpty()) {
-                    File yamlFolder = new File(yaml);
+            if (!getJars().isEmpty()) {
+                for (String jar : getJars()) {
+                    List<URL> expanded = ClassFinder.toJarUrls(jar);
+                    if (expanded.isEmpty())
+                        LOG.warn("No jars found at: "+jar);
+                    urls.addAll(expanded);
+                }
+            } else if (yamlToScan.isEmpty()) {
+                String classpath = System.getenv("INITIAL_CLASSPATH");
+                if (Strings.isNonBlank(classpath)) {
+                    List<String> entries = Splitter.on(":").omitEmptyStrings().trimResults().splitToList(classpath);
+                    for (String entry : entries) {
+                        if (entry.endsWith(".jar") || entry.endsWith("/*")) {
+                            urls.addAll(ClassFinder.toJarUrls(entry.replace("/*", "")));
+                        }
+                    }
+                } else {
+                    throw new FatalConfigurationRuntimeException("No JARs to process and could not infer from INITIAL_CLASSPATH env var.");
+                }
+            }
+            return urls;
+        }
+        protected List<URL> getYamlUrls() throws MalformedURLException, IOException {
+            List<URL> urls = Lists.newArrayList();
+            if (!yamlToScan.isEmpty()) {
+                for (String y: yamlToScan) {
+                    File yamlFolder = new File(y);
                     if (yamlFolder.isDirectory()) {
                         File[] fileList = yamlFolder.listFiles();
 
                         for (File file : fileList) {
-                            if (file.isFile() && (file.getName().contains(".yaml") || file.getName().contains(".bom"))) {
+                            if (file.isFile() && (file.getName().toLowerCase().endsWith(".yaml") || file.getName().toLowerCase().endsWith(".bom"))) {
                                 urls.add(file.toURI().toURL());
                             }
                         }
                     } else {
-                        urls.add(new File(yaml).toURI().toURL());
-                    }
-                } else {
-                    String classpath = System.getenv("INITIAL_CLASSPATH");
-                    if (Strings.isNonBlank(classpath)) {
-                        List<String> entries = Splitter.on(":").omitEmptyStrings().trimResults().splitToList(classpath);
-                        for (String entry : entries) {
-                            if (entry.endsWith(".jar") || entry.endsWith("/*")) {
-                                urls.addAll(ClassFinder.toJarUrls(entry.replace("/*", "")));
-                            }
-                        }
-                    } else {
-                        throw new IllegalArgumentException("No Jars to process");
+                        urls.add(new File(y).toURI().toURL());
                     }
                 }
-            } else {
-                for (String jar : jars) {
-                    List<URL> expanded = ClassFinder.toJarUrls(jar);
-                    if (expanded.isEmpty())
-                        LOG.warn("No jars found at: "+jar);
-                    urls.addAll(expanded);
-                }
             }
             return urls;
         }
@@ -356,10 +328,19 @@ public class ItemLister {
         int itemCount = 0;
         
         private <T extends BrooklynObject> List<Class<? extends T>> getTypes(List<URL> urls, Class<T> type, Boolean catalogOnlyOverride) {
-            FluentIterable<Class<? extends T>> fluent = FluentIterable.from(ClassFinder.findClasses(urls, type));
+            // temp hack to fix urls
+            ReflectionScanner rs = new ReflectionScanner(null, null, 
+//                Strings.isNonBlank(typeRegex) ? StringPredicates.<String>matchesRegex(typeRegex) : null, 
+                getClass().getClassLoader());
+            Set<Class<? extends T>> r1 = rs.getSubTypesOf(type);
+            
+            FluentIterable<Class<? extends T>> fluent;
+            if (!r1.isEmpty()) fluent = FluentIterable.from(r1);
+            else fluent = FluentIterable.from(ClassFinder.findClasses(urls, type));
             if (typeRegex != null) {
                 fluent = fluent.filter(ClassFinder.withClassNameMatching(typeRegex));
             }
+            catalogOnly = false;
             if (catalogOnlyOverride == null ? catalogOnly : catalogOnlyOverride) {
                 fluent = fluent.filter(ClassFinder.withAnnotation(Catalog.class));
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
----------------------------------------------------------------------
diff --git a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
index 3c1272e..3f9009c 100644
--- a/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
+++ b/server-cli/src/main/java/org/apache/brooklyn/cli/lister/ItemDescriptors.java
@@ -18,25 +18,29 @@
  */
 package org.apache.brooklyn.cli.lister;
 
+import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
-import org.apache.brooklyn.core.objs.BrooklynDynamicType;
-import org.apache.brooklyn.core.objs.BrooklynTypes;
+import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.EntityType;
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynType;
+import org.apache.brooklyn.api.objs.SpecParameter;
 import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.objs.BrooklynDynamicType;
+import org.apache.brooklyn.core.objs.BrooklynTypes;
 import org.apache.brooklyn.rest.domain.EffectorSummary;
 import org.apache.brooklyn.rest.domain.EntityConfigSummary;
 import org.apache.brooklyn.rest.domain.SensorSummary;
@@ -44,9 +48,12 @@ import org.apache.brooklyn.rest.domain.SummaryComparators;
 import org.apache.brooklyn.rest.transform.EffectorTransformer;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.SensorTransformer;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -76,7 +83,7 @@ public class ItemDescriptors {
             }
         }
         
-        if (!Strings.isNullOrEmpty(sortField)) {
+        if (Strings.isNonBlank(sortField)) {
             Collections.sort(itemDescriptors, new Comparator<Map<String, Object>>() {
                 @Override public int compare(Map<String, Object> id1, Map<String, Object> id2) {
                     Object o1 = id1.get(sortField);
@@ -112,6 +119,10 @@ public class ItemDescriptors {
             result.put("name", catalogAnnotation.name());
             result.put("description", catalogAnnotation.description());
             result.put("iconUrl", catalogAnnotation.iconUrl());
+        } else {
+            // these are required in the templates
+            result.put("name", clazz.getName());
+            result.put("description", "");
         }
         
         Deprecated deprecatedAnnotation = clazz.getAnnotation(Deprecated.class);
@@ -147,7 +158,7 @@ public class ItemDescriptors {
         return toItemDescriptors(resolvers, false);
     }
     
-    public static Object toItemDescriptors(List<LocationResolver> resolvers, Boolean sort) {
+    public static List<Object> toItemDescriptors(List<LocationResolver> resolvers, Boolean sort) {
         List<Object> result = Lists.newArrayList();
         for (LocationResolver resolver : resolvers) {
             result.add(toItemDescriptor(resolver));
@@ -169,4 +180,49 @@ public class ItemDescriptors {
         // on com.sun.javadoc.*
         return resolver.getPrefix();
     }
+    
+    @SuppressWarnings({ "rawtypes", "unchecked" }) 
+    public static Map<String, Object> toItemDescriptor(BrooklynCatalog catalog, CatalogItem item, boolean headingsOnly) {
+        Map<String,Object> itemDescriptor = MutableMap.of();
+        AbstractBrooklynObjectSpec<?,?> spec = catalog.createSpec(item);
+        List<EntityConfigSummary> config = new ArrayList<>();
+
+        if (item.getDisplayName() != null) {
+            itemDescriptor.put("name", item.getDisplayName());
+        } else if (Strings.isNonBlank((String)itemDescriptor.get("name"))) {
+            itemDescriptor.put("name", blankIfNull(itemDescriptor.get("name")));
+        } else {
+            itemDescriptor.put("name", item.getSymbolicName());
+        }
+        
+        itemDescriptor.put("type", item.getCatalogItemId());
+        itemDescriptor.put("description", blankIfNull(item.getDescription()));
+        itemDescriptor.put("iconUrl", blankIfNull(item.getIconUrl()));
+
+        if (!headingsOnly) {
+            double priorityCounter = 0.0d;
+            for (SpecParameter<?> param: spec.getParameters()) {
+                Double priority;
+                if (param.isPinned()) {
+                    priority = priorityCounter;
+                    priorityCounter++;
+                } else {
+                    priority = null;
+                }
+
+                EntityConfigSummary entityConfigSummary = EntityTransformer.entityConfigSummary(param.getConfigKey(),
+                    param.getLabel(), priority, MutableMap.<String,URI>of());
+                config.add(entityConfigSummary);
+            }
+            itemDescriptor.put("config", config);
+        }
+        
+        return itemDescriptor;
+    }
+
+    private static Object blankIfNull(Object object) {
+        if (object==null) return "";
+        return object;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/license/files/DISCLAIMER
----------------------------------------------------------------------
diff --git a/server-cli/src/main/license/files/DISCLAIMER b/server-cli/src/main/license/files/DISCLAIMER
deleted file mode 100644
index 9e6119b..0000000
--- a/server-cli/src/main/license/files/DISCLAIMER
+++ /dev/null
@@ -1,8 +0,0 @@
-
-Apache Brooklyn is an effort undergoing incubation at The Apache Software Foundation (ASF), 
-sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until 
-a further review indicates that the infrastructure, communications, and decision making process 
-have stabilized in a manner consistent with other successful ASF projects. While incubation 
-status is not necessarily a reflection of the completeness or stability of the code, it does 
-indicate that the project has yet to be fully endorsed by the ASF.
-

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/statics/brooklyn-object-list.html
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/statics/brooklyn-object-list.html b/server-cli/src/main/resources/brooklyn/item-lister/statics/brooklyn-object-list.html
index d45955d..d073df2 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/statics/brooklyn-object-list.html
+++ b/server-cli/src/main/resources/brooklyn/item-lister/statics/brooklyn-object-list.html
@@ -31,7 +31,7 @@ under the License.
     <div id="container">
       <div id="header">
         <div id="identity">
-          <a href="https://brooklyn.incubator.apache.org/" rel="home">Brooklyn</a>
+          <a href="https://brooklyn.apache.org/" rel="home">Brooklyn</a>
         </div>
       </div>
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/statics/common.js
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/statics/common.js b/server-cli/src/main/resources/brooklyn/item-lister/statics/common.js
index 8e8a45f..0ed422b 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/statics/common.js
+++ b/server-cli/src/main/resources/brooklyn/item-lister/statics/common.js
@@ -67,7 +67,7 @@ var brooklyn = (function ($, _) {
             "<dl>" +
             "<dt>description</dt><dd><%=(description||'&nbsp;')%></dd>" +
             "<dt>value type</dt><dd class='java'><%=(type||'&nbsp;')%></dd>" +
-            "<dt>default value</dt><dd><%=(defaultValue||'&nbsp;')%></dd>" +
+            "<dt>default value</dt><dd><%=(data['defaultValue']||'&nbsp;')%></dd>" +
             "</dl>" +
             "</div>"
         ),

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/statics/images/brooklyn.gif
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/statics/images/brooklyn.gif b/server-cli/src/main/resources/brooklyn/item-lister/statics/images/brooklyn.gif
new file mode 100644
index 0000000..ece44c5
Binary files /dev/null and b/server-cli/src/main/resources/brooklyn/item-lister/statics/images/brooklyn.gif differ

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/templates/enricher.html
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/templates/enricher.html b/server-cli/src/main/resources/brooklyn/item-lister/templates/enricher.html
index 0d4558a..0a5d6dd 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/templates/enricher.html
+++ b/server-cli/src/main/resources/brooklyn/item-lister/templates/enricher.html
@@ -27,7 +27,7 @@ under the License.
     <div id="container">
       <div id="header">
         <div id="identity">
-          <a href="https://brooklyn.incubator.apache.org/" rel="home">Brooklyn</a>
+          <a href="https://brooklyn.apache.org/" rel="home">Brooklyn</a>
         </div>
       </div>
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/templates/entity.html
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/templates/entity.html b/server-cli/src/main/resources/brooklyn/item-lister/templates/entity.html
index 397f857..a816566 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/templates/entity.html
+++ b/server-cli/src/main/resources/brooklyn/item-lister/templates/entity.html
@@ -27,7 +27,7 @@ under the License.
     <div id="container">
       <div id="header">
         <div id="identity">
-          <a href="https://brooklyn.incubator.apache.org/" rel="home">Brooklyn</a>
+          <a href="https://brooklyn.apache.org/" rel="home">Brooklyn</a>
         </div>
       </div>
 
@@ -46,7 +46,7 @@ under the License.
       </div>
     </div>
 
-    <script src="../../../style/js/underscore-min.js" type="text/javascript"></script>
+    <script src="../style/js/underscore-min.js" type="text/javascript"></script>
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
     <script src="../common.js" type="text/javascript"></script>
@@ -55,7 +55,7 @@ under the License.
         $(document).ready(function () {
             var item = brooklyn.findItemOfType(items.entities, "${type}");
             $("#summary").html(brooklyn.typeSummary(item));
-            item.config.forEach(function (element) { $("#configKeys").append(brooklyn.configKeyCard(element)); });
+            item.config.forEach(function (element) { $("#configKeys").append(brooklyn.configKeyCard(_.extend({data:element},element))); });
             item.sensors.forEach(function (element) { $("#sensors").append(brooklyn.sensorCard(element)); });
             if (item.effectors != undefined) {
                 item.effectors.forEach(function (element) { $("#effectors").append(brooklyn.effectorCard(element)); });

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/templates/location.html
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/templates/location.html b/server-cli/src/main/resources/brooklyn/item-lister/templates/location.html
index 74eb49b..1a86fbc 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/templates/location.html
+++ b/server-cli/src/main/resources/brooklyn/item-lister/templates/location.html
@@ -26,7 +26,7 @@ under the License.
 <div id="container">
     <div id="header">
         <div id="identity">
-            <a href="https://brooklyn.incubator.apache.org/" rel="home">Brooklyn</a>
+            <a href="https://brooklyn.apache.org/" rel="home">Brooklyn</a>
         </div>
     </div>
     <div id="content" class="objectContent">
@@ -59,4 +59,4 @@ under the License.
     });
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/main/resources/brooklyn/item-lister/templates/policy.html
----------------------------------------------------------------------
diff --git a/server-cli/src/main/resources/brooklyn/item-lister/templates/policy.html b/server-cli/src/main/resources/brooklyn/item-lister/templates/policy.html
index 481adb2..490f114 100644
--- a/server-cli/src/main/resources/brooklyn/item-lister/templates/policy.html
+++ b/server-cli/src/main/resources/brooklyn/item-lister/templates/policy.html
@@ -27,7 +27,7 @@ under the License.
     <div id="container">
       <div id="header">
         <div id="identity">
-          <a href="https://brooklyn.incubator.apache.org/" rel="home">Brooklyn</a>
+          <a href="https://brooklyn.apache.org/" rel="home">Brooklyn</a>
         </div>
       </div>
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/57c6e1cf/server-cli/src/test/license/files/DISCLAIMER
----------------------------------------------------------------------
diff --git a/server-cli/src/test/license/files/DISCLAIMER b/server-cli/src/test/license/files/DISCLAIMER
deleted file mode 100644
index 9e6119b..0000000
--- a/server-cli/src/test/license/files/DISCLAIMER
+++ /dev/null
@@ -1,8 +0,0 @@
-
-Apache Brooklyn is an effort undergoing incubation at The Apache Software Foundation (ASF), 
-sponsored by the Apache Incubator. Incubation is required of all newly accepted projects until 
-a further review indicates that the infrastructure, communications, and decision making process 
-have stabilized in a manner consistent with other successful ASF projects. While incubation 
-status is not necessarily a reflection of the completeness or stability of the code, it does 
-indicate that the project has yet to be fully endorsed by the ASF.
-


Mime
View raw message