tidy CLI options, renaming startup-ignore-error flags; and other tidy

breaks backwards compatibility in CLI: previously we had `ignoreXxxOnStartup` 
fields, but now many of these default to true, and airlift offers no way to 
make them false, so they are called `--startupFailOn...` or 
`--startupContinueOn...`.

changes the nascent CatalogInitialization so that callbacks get it, and can 
query settings such as whether to throw on errors.


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

Branch: refs/heads/master
Commit: 21707da8e476f4ee530e02f93bfdefd981a9e1e1
Parents: 127150e
Author: Alex Heneveld <[email protected]>
Authored: Thu Apr 30 11:07:00 2015 +0100
Committer: Alex Heneveld <[email protected]>
Committed: Fri May 8 18:22:22 2015 +0100

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  | 12 ++-
 .../catalog/internal/CatalogInitialization.java | 96 ++++++++++++++------
 .../brooklyn/entity/rebind/RebindIteration.java |  5 +-
 .../internal/AbstractManagementContext.java     |  3 +-
 .../entity/rebind/RebindCatalogEntityTest.java  |  7 +-
 usage/cli/src/main/java/brooklyn/cli/Main.java  | 94 ++++++++++---------
 .../brooklyn/launcher/BrooklynLauncher.java     | 21 ++++-
 .../brooklyn/launcher/BrooklynLauncherTest.java |  4 +-
 8 files changed, 157 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/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 f1d5a3c..375b29e 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -25,6 +25,7 @@ import io.brooklyn.camp.spi.AssemblyTemplate;
 import io.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
 import io.brooklyn.camp.spi.pdp.DeploymentPlan;
 
+import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -346,14 +347,21 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
 
         // revert to legacy mechanism
         SpecT spec = null;
+        Method method;
+        try {
+            method = Reflections.findMethod(specType, "create", Class.class);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            throw new IllegalStateException("Unsupported creation of spec type 
"+specType+"; it must have a public static create(Class) method", e);           
 
+        }
         try {
             if (loadedItem.getJavaType()!=null) {
-                SpecT specT = (SpecT) Reflections.findMethod(specType, 
"create", Class.class).invoke(null, loadedItem.loadJavaClass(mgmt));
+                SpecT specT = (SpecT) method.invoke(null, 
loadedItem.loadJavaClass(mgmt));
                 spec = specT;
             }
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Unsupported creation of spec type 
"+specType+"; it must have a public static create(Class) method", e);
+            throw new IllegalStateException("Error creating "+specType+" 
"+loadedItem.getJavaType()+": "+e, e);
         }
 
         if (spec==null) 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java 
b/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java
index 15d5d76..69dc877 100644
--- a/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java
+++ b/core/src/main/java/brooklyn/catalog/internal/CatalogInitialization.java
@@ -30,10 +30,13 @@ import brooklyn.catalog.BrooklynCatalog;
 import brooklyn.catalog.CatalogItem;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.management.ManagementContext;
+import brooklyn.management.ManagementContextInjectable;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.FatalRuntimeException;
+import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.Urls;
@@ -41,10 +44,11 @@ import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 
 @Beta
-public class CatalogInitialization {
+public class CatalogInitialization implements ManagementContextInjectable {
 
     /*
 
@@ -74,9 +78,13 @@ public class CatalogInitialization {
     boolean force;
 
     boolean disallowLocal = false;
-    List<Function<ManagementContext, Void>> callbacks = MutableList.of();
+    List<Function<CatalogInitialization, Void>> callbacks = MutableList.of();
     AtomicInteger runCount = new AtomicInteger();
     
+    ManagementContext managementContext;
+    boolean isStartingUp = false;
+    boolean failOnStartupErrors = false;
+    
     public CatalogInitialization(String initialUri, boolean reset, String 
additionUri, boolean force) {
         this.initialUri = initialUri;
         this.reset = reset;
@@ -88,7 +96,17 @@ public class CatalogInitialization {
         this(null, false, null, false);
     }
 
-    public CatalogInitialization 
addPopulationCallback(Function<ManagementContext, Void> callback) {
+    public void injectManagementContext(ManagementContext managementContext) {
+        if (this.managementContext!=null && managementContext!=null && 
!this.managementContext.equals(managementContext))
+            throw new IllegalStateException("Cannot switch management context 
of "+this+"; from "+this.managementContext+" to "+managementContext);
+        this.managementContext = managementContext;
+    }
+    
+    public ManagementContext getManagementContext() {
+        return Preconditions.checkNotNull(managementContext, "management 
context has not been injected into "+this);
+    }
+
+    public CatalogInitialization 
addPopulationCallback(Function<CatalogInitialization, Void> callback) {
         callbacks.add(callback);
         return this;
     }
@@ -106,51 +124,51 @@ public class CatalogInitialization {
     }
 
     /** makes or updates the mgmt catalog, based on the settings in this class 
*/
-    public void populateCatalog(ManagementContext managementContext, boolean 
needsInitial, Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) {
+    public void populateCatalog(boolean needsInitial, 
Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) {
         try {
             BasicBrooklynCatalog catalog;
             Maybe<BrooklynCatalog> cm = 
((ManagementContextInternal)managementContext).getCatalogIfSet();
             if (cm.isAbsent()) {
                 if (hasRun()) {
-                    log.warn("Odd: catalog initialization has run but 
management context has no catalog; re-creating");
+                    log.warn("Catalog initialization has already run but 
management context has no catalog; re-creating");
                 }
                 catalog = new BasicBrooklynCatalog(managementContext);
                 setCatalog(managementContext, catalog, "Replacing catalog with 
newly populated catalog", true);
             } else {
                 if (!hasRun()) {
-                    log.warn("Odd: catalog initialization has not run but 
management context has a catalog; re-populating");
+                    log.warn("Catalog initialization has not properly run but 
management context has a catalog; re-populating, possibly overwriting items 
installed during earlier access (it may have been an early web request)");
                 }
                 catalog = (BasicBrooklynCatalog) cm.get();
             }
 
-            populateCatalog(managementContext, catalog, needsInitial, true, 
optionalItemsForResettingCatalog);
+            populateCatalog(catalog, needsInitial, true, 
optionalItemsForResettingCatalog);
             
         } finally {
             runCount.incrementAndGet();
         }
     }
 
-    private void populateCatalog(ManagementContext managementContext, 
BasicBrooklynCatalog catalog, boolean needsInitial, boolean runCallbacks, 
Collection<CatalogItem<?, ?>> optionalItemsForResettingCatalog) {
-        applyCatalogLoadMode(managementContext);
+    private void populateCatalog(BasicBrooklynCatalog catalog, boolean 
needsInitial, boolean runCallbacks, Collection<CatalogItem<?, ?>> 
optionalItemsForResettingCatalog) {
+        applyCatalogLoadMode();
         
         if (optionalItemsForResettingCatalog!=null) {
             catalog.reset(optionalItemsForResettingCatalog);
         }
         
         if (needsInitial) {
-            populateInitial(catalog, managementContext);
+            populateInitial(catalog);
         }
         
-        populateAdditions(catalog, managementContext);
+        populateAdditions(catalog);
 
         if (runCallbacks) {
-            populateViaCallbacks(catalog, managementContext);
+            populateViaCallbacks(catalog);
         }
     }
 
     private enum PopulateMode { YAML, XML, AUTODETECT }
     
-    protected void populateInitial(BasicBrooklynCatalog catalog, 
ManagementContext managementContext) {
+    protected void populateInitial(BasicBrooklynCatalog catalog) {
         if (disallowLocal) {
             if (!hasRun()) {
                 log.debug("CLI initial catalog not being read with 
disallow-local mode set.");
@@ -166,25 +184,25 @@ public class CatalogInitialization {
 //        B6) go to C1
 
         if (initialUri!=null) {
-            populateInitialFromUri(catalog, managementContext, initialUri, 
PopulateMode.AUTODETECT);
+            populateInitialFromUri(catalog, initialUri, 
PopulateMode.AUTODETECT);
             return;
         }
         
         String catalogUrl = 
managementContext.getConfig().getConfig(BrooklynServerConfig.BROOKLYN_CATALOG_URL);
         if (Strings.isNonBlank(catalogUrl)) {
-            populateInitialFromUri(catalog, managementContext, catalogUrl, 
PopulateMode.AUTODETECT);
+            populateInitialFromUri(catalog, catalogUrl, 
PopulateMode.AUTODETECT);
             return;
         }
         
         catalogUrl = Urls.mergePaths(BrooklynServerConfig.getMgmtBaseDir( 
managementContext.getConfig() ), "catalog.bom");
         if (new File(catalogUrl).exists()) {
-            populateInitialFromUri(catalog, managementContext, 
"file:"+catalogUrl, PopulateMode.YAML);
+            populateInitialFromUri(catalog, "file:"+catalogUrl, 
PopulateMode.YAML);
             return;
         }
         
         catalogUrl = Urls.mergePaths(BrooklynServerConfig.getMgmtBaseDir( 
managementContext.getConfig() ), "catalog.xml");
         if (new File(catalogUrl).exists()) {
-            populateInitialFromUri(catalog, managementContext, 
"file:"+catalogUrl, PopulateMode.XML);
+            populateInitialFromUri(catalog, "file:"+catalogUrl, 
PopulateMode.XML);
             return;
         }
 
@@ -195,7 +213,7 @@ public class CatalogInitialization {
         
         catalogUrl = "classpath:/brooklyn/default.catalog.bom";
         if (new ResourceUtils(this).doesUrlExist(catalogUrl)) {
-            populateInitialFromUri(catalog, managementContext, catalogUrl, 
PopulateMode.YAML);
+            populateInitialFromUri(catalog, catalogUrl, PopulateMode.YAML);
             return;
         }
         
@@ -203,7 +221,7 @@ public class CatalogInitialization {
         return;
     }
     
-    private void populateInitialFromUri(BasicBrooklynCatalog catalog, 
ManagementContext managementContext, String catalogUrl, PopulateMode mode) {
+    private void populateInitialFromUri(BasicBrooklynCatalog catalog, String 
catalogUrl, PopulateMode mode) {
         log.debug("Loading initial catalog from {}", catalogUrl);
 
         Exception problem = null;
@@ -260,7 +278,7 @@ public class CatalogInitialization {
         return problem;
     }
 
-    protected void populateAdditions(BasicBrooklynCatalog catalog, 
ManagementContext mgmt) {
+    protected void populateAdditions(BasicBrooklynCatalog catalog) {
         if (Strings.isNonBlank(additionsUri)) {
             if (disallowLocal) {
                 if (!hasRun()) {
@@ -281,17 +299,18 @@ public class CatalogInitialization {
         }
     }
 
-    protected void populateViaCallbacks(BasicBrooklynCatalog catalog, 
ManagementContext managementContext) {
-        for (Function<ManagementContext, Void> callback: callbacks)
-            callback.apply(managementContext);
+    protected void populateViaCallbacks(BasicBrooklynCatalog catalog) {
+        for (Function<CatalogInitialization, Void> callback: callbacks)
+            callback.apply(this);
     }
 
     private boolean setFromCatalogLoadMode = false;
+
     /** @deprecated since introduced in 0.7.0, only for legacy compatibility 
with 
      * {@link CatalogLoadMode} {@link BrooklynServerConfig#CATALOG_LOAD_MODE},
      * allowing control of catalog loading from a brooklyn property */
     @Deprecated
-    public void applyCatalogLoadMode(ManagementContext managementContext) {
+    public void applyCatalogLoadMode() {
         if (setFromCatalogLoadMode) return;
         setFromCatalogLoadMode = true;
         Maybe<Object> clmm = 
((ManagementContextInternal)managementContext).getConfig().getConfigRaw(BrooklynServerConfig.CATALOG_LOAD_MODE,
 false);
@@ -314,7 +333,7 @@ public class CatalogInitialization {
     /** makes the catalog, warning if persistence is on and hasn't run yet 
      * (as the catalog will be subsequently replaced) */
     @Beta
-    public BrooklynCatalog getCatalogPopulatingBestEffort(ManagementContext 
managementContext) {
+    public BrooklynCatalog getCatalogPopulatingBestEffort() {
         Maybe<BrooklynCatalog> cm = 
((ManagementContextInternal)managementContext).getCatalogIfSet();
         if (cm.isPresent()) return cm.get();
 
@@ -323,7 +342,7 @@ public class CatalogInitialization {
         if (oldC==null) {
             // our catalog was added, so run population
             // NB: we need the catalog to be saved already so that we can run 
callbacks
-            populateCatalog(managementContext, (BasicBrooklynCatalog) 
managementContext.getCatalog(), true, true, null);
+            populateCatalog((BasicBrooklynCatalog) 
managementContext.getCatalog(), true, true, null);
         }
         
         return managementContext.getCatalog();
@@ -351,5 +370,30 @@ public class CatalogInitialization {
         }
         return cm.get();
     }
+
+    public void setStartingUp(boolean isStartingUp) {
+        this.isStartingUp = isStartingUp;
+    }
+
+    public void setFailOnStartupErrors(boolean startupFailOnCatalogErrors) {
+        this.failOnStartupErrors = startupFailOnCatalogErrors;
+    }
+
+    public void handleException(Throwable throwable, Object details) {
+        if (throwable instanceof InterruptedException)
+            throw new RuntimeInterruptedException((InterruptedException) 
throwable);
+        if (throwable instanceof RuntimeInterruptedException)
+            throw (RuntimeInterruptedException) throwable;
+
+        log.error("Error loading catalog item '"+details+"': "+throwable);
+        log.debug("Trace for error loading catalog item '"+details+"': 
"+throwable, throwable);
+
+        // TODO give more detail when adding
+        
((ManagementContextInternal)getManagementContext()).errors().add(throwable);
+        
+        if (isStartingUp && failOnStartupErrors) {
+            throw new FatalRuntimeException("Unable to load catalog item 
'"+details+"': "+throwable, throwable);
+        }
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java 
b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index b5af10c..13d02e8 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -345,7 +345,8 @@ public abstract class RebindIteration {
         
         Collection<CatalogItem<?, ?>> catalogItems = 
rebindContext.getCatalogItems();
         CatalogInitialization catInit = 
((ManagementContextInternal)managementContext).getCatalogInitialization();
-        catInit.applyCatalogLoadMode(managementContext);
+        catInit.injectManagementContext(managementContext);
+        catInit.applyCatalogLoadMode();
         Collection<CatalogItem<?,?>> itemsForResettingCatalog = null;
         boolean needsInitialCatalog;
         if (rebindManager.persistCatalogItemsEnabled) {
@@ -390,7 +391,7 @@ public abstract class RebindIteration {
         }
 
         // TODO in read-only mode, perhaps do this less frequently than 
entities etc ?
-        catInit.populateCatalog(managementContext, needsInitialCatalog, 
itemsForResettingCatalog);
+        catInit.populateCatalog(needsInitialCatalog, itemsForResettingCatalog);
     }
 
     protected void instantiateLocationsAndEntities() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
 
b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
index de3460b..8ff6dfc 100644
--- 
a/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
+++ 
b/core/src/main/java/brooklyn/management/internal/AbstractManagementContext.java
@@ -380,7 +380,7 @@ public abstract class AbstractManagementContext implements 
ManagementContextInte
         // catalog init is needed; normally this will be done from start 
sequence,
         // but if accessed early -- and in tests -- we will load it here
         // TODO log if in launcher mode
-        return getCatalogInitialization().getCatalogPopulatingBestEffort(this);
+        return getCatalogInitialization().getCatalogPopulatingBestEffort();
     }
 
     /**
@@ -460,6 +460,7 @@ public abstract class AbstractManagementContext implements 
ManagementContextInte
     
     @Override
     public synchronized void setCatalogInitialization(CatalogInitialization 
catalogInitialization) {
+        if (catalogInitialization!=null) 
catalogInitialization.injectManagementContext(this);
         this.catalogInitialization = catalogInitialization;
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java 
b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
index 9c94697..212212f 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import brooklyn.catalog.internal.CatalogInitialization;
 import brooklyn.entity.Application;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.ApplicationBuilder;
@@ -133,10 +134,10 @@ public class RebindCatalogEntityTest extends 
RebindTestFixture<StartableApplicat
         // ucl.close is only introduced in java 1.7
         if (ucl instanceof Closeable) ((Closeable)ucl).close();
 
-        
newManagementContext.getCatalogInitialization().addPopulationCallback(new 
Function<ManagementContext, Void>() {
+        
newManagementContext.getCatalogInitialization().addPopulationCallback(new 
Function<CatalogInitialization, Void>() {
             @Override
-            public Void apply(ManagementContext input) {
-                input.getCatalog().addItem(appClazz);
+            public Void apply(CatalogInitialization input) {
+                input.getManagementContext().getCatalog().addItem(appClazz);
                 return null;
             }
         });

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/usage/cli/src/main/java/brooklyn/cli/Main.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/brooklyn/cli/Main.java 
b/usage/cli/src/main/java/brooklyn/cli/Main.java
index 7dab5aa..ad6aeb1 100644
--- a/usage/cli/src/main/java/brooklyn/cli/Main.java
+++ b/usage/cli/src/main/java/brooklyn/cli/Main.java
@@ -75,7 +75,6 @@ import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
 import brooklyn.util.exceptions.FatalRuntimeException;
-import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.exceptions.UserFacingException;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Enums;
@@ -192,11 +191,11 @@ public class Main extends AbstractMain {
     public static class LaunchCommand extends BrooklynCommandCollectingArgs {
 
         @Option(name = { "--localBrooklynProperties" }, title = "local 
brooklyn.properties file",
-                description = "local brooklyn.properties file, specific to 
this launch (appending to and overriding global properties)")
+                description = "Load the given properties file, specific to 
this launch (appending to and overriding global properties)")
         public String localBrooklynProperties;
 
         @Option(name = { "--noGlobalBrooklynProperties" }, title = "do not use 
any global brooklyn.properties file found",
-            description = "do not use the default global brooklyn.properties 
file found")
+            description = "Do not use the default global brooklyn.properties 
file found")
         public boolean noGlobalBrooklynProperties = false;
 
         @Option(name = { "-a", "--app" }, title = "application class or file",
@@ -223,7 +222,7 @@ public class Main extends AbstractMain {
                 + "if nothing is yet persisted in the catalog (or if it is 
reset)")
         public String catalogInitial;
 
-        @Option(name = { "--catalogReset" }, title = "clear catalog",
+        @Option(name = { "--catalogReset" }, 
             description = "Specifies that any catalog items which have been 
persisted should be cleared")
         public boolean catalogReset;
 
@@ -231,22 +230,22 @@ public class Main extends AbstractMain {
             description = "Specifies a catalog.bom to be added to the catalog")
         public String catalogAdd;
 
-        @Option(name = { "--catalogForce" }, title = "force catalog addition",
+        @Option(name = { "--catalogForce" }, 
             description = "Specifies that catalog items added via the CLI 
should be forcibly added, "
                 + "replacing any identical versions already registered (use 
with care!)")
         public boolean catalogForce;
 
         @Option(name = { "-p", "--port" }, title = "port number",
-                description = "Specifies the port to be used by the Brooklyn 
Management Console; "
+                description = "Use this port for the brooklyn management web 
console and REST API; "
                     + "default is 8081+ for http, 8443+ for https.")
         public String port;
 
         @Option(name = { "--https" },
-            description = "Specifies that the server should start on https.")
+            description = "Launch the web console on https")
         public boolean useHttps = false;
         
         @Option(name = { "-nc", "--noConsole" },
-                description = "Whether to start the web console")
+                description = "Do not start the web console or REST API")
         public boolean noConsole = false;
 
         @Option(name = { "-b", "--bindAddress" },
@@ -258,26 +257,32 @@ public class Main extends AbstractMain {
         public String publicAddress = null;
 
         @Option(name = { "--noConsoleSecurity" },
-                description = "Whether to disable security for the web console 
with no security (i.e. no authentication required)")
+                description = "Whether to disable authentication and security 
filters for the web console (for use when debugging on a secure network or 
bound to localhost)")
         public Boolean noConsoleSecurity = false;
 
-        @Option(name = { "--ignoreWebStartupErrors" },
-            description = "Ignore web subsystem failures on startup (default 
is to abort if the web API fails to start, as management is not possible)")
-        public boolean ignoreWebErrors = false;
+        @Option(name = { "--startupContinueOnWebErrors" },
+            description = "Continue on web subsystem failures during startup "
+                + "(default is to abort if the web API fails to start, as 
management access is not normally possible)")
+        public boolean startupContinueOnWebErrors = false;
+
+        @Option(name = { "--startupFailOnPersistenceErrors" },
+            description = "Fail on persistence/HA subsystem failures during 
startup "
+                + "(default is to continue, so errors can be viewed via the 
API)")
+        public boolean startupFailOnPersistenceErrors = false;
 
-        @Option(name = { "--ignorePersistenceStartupErrors" },
-            description = "Ignore persistence/HA subsystem failures on startup 
"
-                + "(default is true, so errors can be viewed via the API)")
-        public boolean ignorePersistenceErrors = true;
+        @Option(name = { "--startupFailOnCatalogErrors" },
+            description = "Fail on catalog subsystem failures during startup "
+                + "(default is to continue, so errors can be viewed via the 
API)")
+        public boolean startupFailOnCatalogErrors = false;
 
-        @Option(name = { "--ignoreManagedAppsStartupErrors" },
-            description = "Ignore failures starting managed applications 
passed on the command line on startup "
-                + "(default is true, so errors can be viewed via the API)")
-        public boolean ignoreAppErrors = true;
+        @Option(name = { "--startupFailOnManagedAppsErrors" },
+            description = "Fail startup on errors deploying of managed apps 
specified via the command line "
+                + "(default is to continue, so errors can be viewed via the 
API)")
+        public boolean startupFailOnManagedAppsErrors = false;
 
         @Beta
         @Option(name = { "--startBrooklynNode" },
-                description = "Whether to start a BrooklynNode entity 
representing this Brooklyn instance (default false)")
+                description = "Start a BrooklynNode entity representing this 
Brooklyn instance")
         public boolean startBrooklynNode = false;
 
         // Note in some cases, you can get 
java.util.concurrent.RejectedExecutionException
@@ -285,7 +290,7 @@ public class Main extends AbstractMain {
         // looks like: {@linktourl 
https://gist.github.com/47066f72d6f6f79b953e}
         @Beta
         @Option(name = { "-sk", "--stopOnKeyPress" },
-                description = "After startup, shutdown on user text entry 
(default false)")
+                description = "Shutdown immediately on user text entry after 
startup (useful for debugging and demos)")
         public boolean stopOnKeyPress = false;
 
         final static String STOP_WHICH_APPS_ON_SHUTDOWN = "--stopOnShutdown";
@@ -406,13 +411,21 @@ public class Main extends AbstractMain {
                 launcher = createLauncher();
 
                 CatalogInitialization catInit = new 
CatalogInitialization(catalogInitial, catalogReset, catalogAdd, catalogForce);
-                catInit.addPopulationCallback(new 
Function<ManagementContext,Void>() {
+                catInit.addPopulationCallback(new 
Function<CatalogInitialization,Void>() {
                     @Override
-                    public Void apply(ManagementContext mgmt) {
-                        populateCatalog(mgmt.getCatalog());
+                    public Void apply(CatalogInitialization catInit) {
+                        try {
+                            
populateCatalog(catInit.getManagementContext().getCatalog());
+                        } catch (Throwable e) {
+                            catInit.handleException(e, "overridden main class 
populate catalog");
+                        }
+                        
+                        // Force load of catalog (so web console is up to date)
+                        confirmCatalog(catInit);
                         return null;
                     }
                 });
+                catInit.setFailOnStartupErrors(startupFailOnCatalogErrors);
                 launcher.catalogInitialization(catInit);
                 
                 launcher.persistMode(persistMode);
@@ -557,9 +570,10 @@ public class Main extends AbstractMain {
             BrooklynLauncher launcher;
             launcher = BrooklynLauncher.newInstance();
             launcher.localBrooklynPropertiesFile(localBrooklynProperties)
-                    .ignorePersistenceErrors(ignorePersistenceErrors)
-                    .ignoreWebErrors(ignoreWebErrors)
-                    .ignoreAppErrors(ignoreAppErrors)
+                    .ignorePersistenceErrors(!startupFailOnPersistenceErrors)
+                    .ignoreCatalogErrors(!startupFailOnCatalogErrors)
+                    .ignoreWebErrors(startupContinueOnWebErrors)
+                    .ignoreAppErrors(!startupFailOnManagedAppsErrors)
                     .locations(Strings.isBlank(locations) ? 
ImmutableList.<String>of() : 
JavaStringEscapes.unwrapJsonishListIfPossible(locations));
             
             launcher.webconsole(!noConsole);
@@ -597,17 +611,15 @@ public class Main extends AbstractMain {
             return launcher;
         }
 
-        /** method intended for subclassing, to add items to the catalog */
+        /** method intended for subclassing, to add custom items to the 
catalog */
         protected void populateCatalog(BrooklynCatalog catalog) {
-            // Force load of catalog (so web console is up to date)
-            confirmCatalog(catalog);
-
             // nothing else added here
         }
 
-        protected void confirmCatalog(BrooklynCatalog catalog) {
+        protected void confirmCatalog(CatalogInitialization catInit) {
             // Force load of catalog (so web console is up to date)
             Stopwatch time = Stopwatch.createStarted();
+            BrooklynCatalog catalog = 
catInit.getManagementContext().getCatalog();
             Iterable<CatalogItem<Object, Object>> items = 
catalog.getCatalogItems();
             for (CatalogItem<Object, Object> item: items) {
                 try {
@@ -617,14 +629,7 @@ public class Main extends AbstractMain {
                     }
                     log.debug("Catalog loaded spec "+spec+" for item "+item);  
                    
                 } catch (Throwable throwable) {
-                    // swallow errors, apart from interrupted
-                    if (throwable instanceof InterruptedException)
-                        throw new 
RuntimeInterruptedException((InterruptedException) throwable);
-                    if (throwable instanceof RuntimeInterruptedException)
-                        throw (RuntimeInterruptedException) throwable;
-
-                    log.error("Error loading catalog item '"+item+"': 
"+throwable);
-                    log.debug("Trace for error loading catalog item 
'"+item+"': "+throwable, throwable);
+                    catInit.handleException(throwable, item);
                 }
             }
             log.debug("Catalog (size "+Iterables.size(items)+") confirmed in 
"+Duration.of(time));                      
@@ -777,9 +782,10 @@ public class Main extends AbstractMain {
                     .add("bindAddress", bindAddress)
                     .add("noConsole", noConsole)
                     .add("noConsoleSecurity", noConsoleSecurity)
-                    .add("ignorePersistenceErrors", ignorePersistenceErrors)
-                    .add("ignoreWebErrors", ignoreWebErrors)
-                    .add("ignoreAppErrors", ignoreAppErrors)
+                    .add("startupFailOnPersistenceErrors", 
startupFailOnPersistenceErrors)
+                    .add("startupFailsOnCatalogErrors", 
startupFailOnCatalogErrors)
+                    .add("startupContinueOnWebErrors", 
startupContinueOnWebErrors)
+                    .add("startupFailOnManagedAppsErrors", 
startupFailOnManagedAppsErrors)
                     .add("stopWhichAppsOnShutdown", stopWhichAppsOnShutdown)
                     .add("noShutdownOnExit", noShutdownOnExit)
                     .add("stopOnKeyPress", stopOnKeyPress)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java
----------------------------------------------------------------------
diff --git 
a/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java 
b/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java
index 4d3b1be..71f53a5 100644
--- a/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java
+++ b/usage/launcher/src/main/java/brooklyn/launcher/BrooklynLauncher.java
@@ -152,6 +152,7 @@ public class BrooklynLauncher {
     
     private boolean ignoreWebErrors = false;
     private boolean ignorePersistenceErrors = true;
+    private boolean ignoreCatalogErrors = true;
     private boolean ignoreAppErrors = true;
     
     private StopWhichAppsOnShutdown stopWhichAppsOnShutdown = 
StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED;
@@ -401,6 +402,11 @@ public class BrooklynLauncher {
         return this;
     }
 
+    public BrooklynLauncher ignoreCatalogErrors(boolean ignoreCatalogErrors) {
+        this.ignoreCatalogErrors = ignoreCatalogErrors;
+        return this;
+    }
+
     public BrooklynLauncher ignoreWebErrors(boolean ignoreWebErrors) {
         this.ignoreWebErrors = ignoreWebErrors;
         return this;
@@ -562,6 +568,10 @@ public class BrooklynLauncher {
         // Create the management context
         initManagementContext();
 
+        // Inform catalog initialization that it is starting up
+        CatalogInitialization catInit = 
((ManagementContextInternal)managementContext).getCatalogInitialization();
+        catInit.setStartingUp(true);
+
         // Start webapps as soon as mgmt context available -- can use them to 
detect progress of other processes
         if (startWebApps) {
             try {
@@ -586,15 +596,16 @@ public class BrooklynLauncher {
         }
 
         try {
-            // run cat init now if it hasn't yet been run
-            CatalogInitialization catInit = 
((ManagementContextInternal)managementContext).getCatalogInitialization();
+            // run cat init now if it hasn't yet been run; 
+            // will also run if there was an ignored error in catalog above, 
allowing it to fail startup here if requested
             if (catInit!=null && !catInit.hasRun()) {
                 LOG.debug("Loading catalog as part of launcher (persistence 
did not run it)");
-                catInit.populateCatalog(managementContext, true, null);
+                catInit.populateCatalog(true, null);
             }
         } catch (Exception e) {
-            handleSubsystemStartupError(true, "initial catalog", e);
+            handleSubsystemStartupError(ignoreCatalogErrors, "initial 
catalog", e);
         }
+        catInit.setStartingUp(false);
 
         // Create the locations. Must happen after persistence is started in 
case the
         // management context's catalog is loaded from persisted state. 
(Location
@@ -612,7 +623,7 @@ public class BrooklynLauncher {
             try {
                 startBrooklynNode();
             } catch (Exception e) {
-                handleSubsystemStartupError(true, "brooklyn node / self 
entity", e);
+                handleSubsystemStartupError(ignoreAppErrors, "brooklyn node / 
self entity", e);
             }
         }
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/21707da8/usage/launcher/src/test/java/brooklyn/launcher/BrooklynLauncherTest.java
----------------------------------------------------------------------
diff --git 
a/usage/launcher/src/test/java/brooklyn/launcher/BrooklynLauncherTest.java 
b/usage/launcher/src/test/java/brooklyn/launcher/BrooklynLauncherTest.java
index b4f963e..0886390 100644
--- a/usage/launcher/src/test/java/brooklyn/launcher/BrooklynLauncherTest.java
+++ b/usage/launcher/src/test/java/brooklyn/launcher/BrooklynLauncherTest.java
@@ -317,9 +317,9 @@ public class BrooklynLauncherTest {
     @Test  // takes a bit of time because starts webapp, but also tests rest 
api so useful
     public void testErrorsCaughtByApiAndRestApiWorks() throws Exception {
         launcher = newLauncherForTests(true)
-                .catalogInitialization(new CatalogInitialization(null, false, 
null, false).addPopulationCallback(new Function<ManagementContext, Void>() {
+                .catalogInitialization(new CatalogInitialization(null, false, 
null, false).addPopulationCallback(new Function<CatalogInitialization, Void>() {
                     @Override
-                    public Void apply(ManagementContext input) {
+                    public Void apply(CatalogInitialization input) {
                         throw new 
RuntimeException("deliberate-exception-for-testing");
                     }
                 }))


Reply via email to