brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [3/7] brooklyn-server git commit: [BROOKLYN-183] Reuse classic init code, loading CAMP platform
Date Mon, 14 Mar 2016 14:53:51 GMT
[BROOKLYN-183] Reuse classic init code, loading CAMP platform


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

Branch: refs/heads/master
Commit: 090b16cd8b58072c45204bd642f54124d67bccb7
Parents: e6b3ad9
Author: Svetoslav Neykov <svetoslav.neykov@cloudsoftcorp.com>
Authored: Tue Mar 8 12:06:01 2016 +0200
Committer: Svetoslav Neykov <svetoslav.neykov@cloudsoftcorp.com>
Committed: Wed Mar 9 18:27:48 2016 +0200

----------------------------------------------------------------------
 .../apache/brooklyn/core/BrooklynVersion.java   |  45 +-
 .../brooklyn/core/BrooklynVersionService.java   |  39 +
 .../org/apache/brooklyn/core/OsgiLauncher.java  | 558 --------------
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  33 +
 karaf/features/src/main/feature/feature.xml     |   1 +
 karaf/init/pom.xml                              |   1 +
 .../brooklyn/launcher/osgi/OsgiLauncher.java    | 106 +++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  47 +-
 .../java/org/apache/brooklyn/AssemblyTest.java  |   4 +-
 launcher-common/pom.xml                         |  10 +
 .../brooklyn/launcher/common/BasicLauncher.java | 766 +++++++++++++++++++
 .../common/BrooklynPropertiesFactoryHelper.java |  69 +-
 .../brooklyn/launcher/BrooklynLauncher.java     | 726 ++----------------
 .../resources/OSGI-INF/blueprint/service.xml    |   3 -
 14 files changed, 1128 insertions(+), 1280 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/core/src/main/java/org/apache/brooklyn/core/BrooklynVersion.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynVersion.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynVersion.java
index f18e707..12d6889 100644
--- a/core/src/main/java/org/apache/brooklyn/core/BrooklynVersion.java
+++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynVersion.java
@@ -23,7 +23,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicReference;
@@ -31,43 +35,37 @@ import java.util.jar.Attributes;
 
 import javax.annotation.Nullable;
 
-import org.osgi.framework.Constants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.mgmt.classloading.OsgiBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.rt.felix.ManifestHelper;
-import org.apache.brooklyn.util.core.osgi.Osgis;
+import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.osgi.OsgiUtil;
 import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Strings;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
 
 /**
  * Wraps the version of Brooklyn.
  * <p>
  * Also retrieves the SHA-1 from any OSGi bundle, and checks that the maven and osgi versions match.
  */
-public class BrooklynVersion {
+public class BrooklynVersion implements BrooklynVersionService {
 
     private static final Logger log = LoggerFactory.getLogger(BrooklynVersion.class);
 
@@ -101,6 +99,7 @@ public class BrooklynVersion {
         checkVersions();
     }
 
+    @Override
     public void checkVersions() {
         String mvnVersion = getVersionFromMavenProperties();
         if (mvnVersion != null && !VERSION_FROM_STATIC.equals(mvnVersion)) {
@@ -129,16 +128,19 @@ public class BrooklynVersion {
         return "0.0.0-SNAPSHOT";
     }
 
+    @Override
     @Nullable
     public String getVersionFromMavenProperties() {
         return versionProperties.getProperty(MVN_VERSION_PROPERTY_NAME);
     }
 
+    @Override
     @Nullable
     public String getVersionFromOsgiManifest() {
         return versionProperties.getProperty(OSGI_VERSION_PROPERTY_NAME);
     }
 
+    @Override
     @Nullable
     /** SHA1 of the last commit to brooklyn at the time this build was made.
      * For SNAPSHOT builds of course there may have been further non-committed changes. */
@@ -146,10 +148,12 @@ public class BrooklynVersion {
         return versionProperties.getProperty(OSGI_SHA1_PROPERTY_NAME);
     }
 
+    @Override
     public String getVersion() {
         return VERSION_FROM_STATIC;
     }
 
+    @Override
     public boolean isSnapshot() {
         return (getVersion().indexOf("-SNAPSHOT") >= 0);
     }
@@ -268,6 +272,7 @@ public class BrooklynVersion {
         return false;
     }
 
+    @Override
     public void logSummary() {
         log.debug("Brooklyn version " + getVersion() + " (git SHA1 " + getSha1FromOsgiManifest() + ")");
     }
@@ -284,6 +289,10 @@ public class BrooklynVersion {
         return INSTANCE.getVersion();
     }
 
+    public static BrooklynVersion getInstance() {
+        return INSTANCE;
+    }
+
     /**
      * @param mgmt The context to search for features.
      * @return An iterable containing all features found in the management context's classpath and catalogue.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/core/src/main/java/org/apache/brooklyn/core/BrooklynVersionService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynVersionService.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynVersionService.java
new file mode 100644
index 0000000..6e4e33c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynVersionService.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core;
+
+public interface BrooklynVersionService {
+
+    void checkVersions();
+
+    String getVersionFromMavenProperties();
+
+    String getVersionFromOsgiManifest();
+
+    /** SHA1 of the last commit to brooklyn at the time this build was made.
+     * For SNAPSHOT builds of course there may have been further non-committed changes. */
+    String getSha1FromOsgiManifest();
+
+    String getVersion();
+
+    boolean isSnapshot();
+
+    void logSummary();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/core/src/main/java/org/apache/brooklyn/core/OsgiLauncher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/OsgiLauncher.java b/core/src/main/java/org/apache/brooklyn/core/OsgiLauncher.java
deleted file mode 100644
index c652bda..0000000
--- a/core/src/main/java/org/apache/brooklyn/core/OsgiLauncher.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright 2016 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.brooklyn.core;
-
-import com.google.common.base.Function;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Iterables;
-import groovy.lang.GroovyClassLoader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.concurrent.TimeoutException;
-import org.apache.brooklyn.api.catalog.BrooklynCatalog;
-import org.apache.brooklyn.api.catalog.CatalogItem;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityManager;
-import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
-import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
-import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecordPersister;
-import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
-import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
-import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
-import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
-import org.apache.brooklyn.core.mgmt.internal.BrooklynShutdownHooks;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
-import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
-import org.apache.brooklyn.core.mgmt.persist.PersistMode;
-import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
-import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
-import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
-import org.apache.brooklyn.core.objs.BrooklynTypes;
-import org.apache.brooklyn.core.server.BrooklynServerConfig;
-import org.apache.brooklyn.core.server.BrooklynServerPaths;
-import org.apache.brooklyn.util.core.ResourceUtils;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
-import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
-import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.io.FileUtil;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.stream.Streams;
-import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Initializer for brooklyn-core when running in an OSGi environment.
- *
- * Temporarily here; should be totally contained in blueprint beans' init-methods.
- */
-// TODO move to brooklyn-karaf-init
-public class OsgiLauncher {
-
-    private static final Logger log = LoggerFactory.getLogger(OsgiLauncher.class);
-
-    private ManagementContext managementContext;
-
-    private boolean ignoreCatalogErrors = true;
-    private boolean ignorePersistenceErrors = true;
-
-    private HighAvailabilityMode highAvailabilityMode = HighAvailabilityMode.DISABLED;
-
-    private PersistMode persistMode = PersistMode.DISABLED;
-    private String persistenceDir = null;
-    private String persistenceLocation = null;
-    private Duration persistPeriod = Duration.ONE_SECOND;
-
-    public void start() {
-        // Configure launcher
-//        ShutdownHandler shutdownHandler = new AppShutdownHandler();
-        try {
-//            initBrooklynProperties();
-            initCatalog();
-
-            // TODO
-//            launcher.stopWhichAppsOnShutdown(stopWhichAppsOnShutdownMode);
-//            launcher.shutdownHandler(shutdownHandler);
-//
-//            computeAndSetApp(launcher, utils, loader);
-//            customize(launcher);
-//        } catch (FatalConfigurationRuntimeException e) {
-//            throw e;
-//        } catch (Exception e) {
-//            throw new FatalConfigurationRuntimeException("Fatal error configuring Brooklyn launch: " + e.getMessage(), e);
-//        }
-//
-//        try {
-            launcherStart();
-        } catch (FatalRuntimeException e) {
-            // rely on caller logging this propagated exception
-            throw e;
-        } catch (Exception e) {
-            // for other exceptions we log it, possibly redundantly but better too much than too little
-            Exceptions.propagateIfFatal(e);
-            log.error("Error launching brooklyn: " + Exceptions.collapseText(e), e);
-            try {
-                shutdown();
-            } catch (Exception e2) {
-                log.warn("Subsequent error during termination: " + e2);
-                log.debug("Details of subsequent error during termination: " + e2, e2);
-            }
-            Exceptions.propagate(e);
-        }
-
-        // TODO
-//        if (verbose) {
-//            Entities.dumpInfo(launcher.getApplications());
-//        }
-    }
-
-    private void initCatalog() {
-        // TODO
-//            StopWhichAppsOnShutdown stopWhichAppsOnShutdownMode = computeStopWhichAppsOnShutdown();
-//
-//            computeLocations();
-
-//            ResourceUtils utils = ResourceUtils.create(this);
-//            GroovyClassLoader loader = new GroovyClassLoader(getClass().getClassLoader());
-//
-//            // First, run a setup script if the user has provided one
-//            if (script != null) {
-//                execGroovyScript(utils, loader, script);
-//            }
-        // TODO: extract method for catalog initialization
-        CatalogInitialization catInit = new CatalogInitialization();
-        catInit.addPopulationCallback(new Function<CatalogInitialization, Void>() {
-            @Override
-            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
-                confirmCatalog(catInit);
-                return null;
-            }
-        });
-        catInit.setFailOnStartupErrors(!ignoreCatalogErrors);
-//            launcher.catalogInitialization(catInit);
-    }
-
-//    private void initBrooklynProperties() {
-//        BrooklynProperties.Factory.Builder builder = BrooklynProperties.Factory.builderDefault();
-//
-//        if (globalBrooklynPropertiesFile != null) {
-//            File globalProperties = new File(Os.tidyPath(globalBrooklynPropertiesFile));
-//            if (globalProperties.exists()) {
-//                globalProperties = resolveSymbolicLink(globalProperties);
-//                checkFileReadable(globalProperties);
-//                    // brooklyn.properties stores passwords (web-console and cloud credentials),
-//                // so ensure it has sensible permissions
-//                checkFilePermissionsX00(globalProperties);
-//                log.debug("Using global properties file " + globalProperties);
-//            } else {
-//                log.debug("Global properties file " + globalProperties + " does not exist, will ignore");
-//            }
-//            builder.globalPropertiesFile(globalProperties.getAbsolutePath());
-//        } else {
-//            log.debug("Global properties file disabled");
-//            builder.globalPropertiesFile(null);
-//        }
-//
-//        if (localBrooklynPropertiesFile != null) {
-//            File localProperties = new File(Os.tidyPath(localBrooklynPropertiesFile));
-//            localProperties = resolveSymbolicLink(localProperties);
-//            checkFileReadable(localProperties);
-//            checkFilePermissionsX00(localProperties);
-//            builder.localPropertiesFile(localProperties.getAbsolutePath());
-//        }
-//
-//        managementContext = new LocalManagementContext(builder, brooklynAdditionalProperties);
-//
-//        // not needed: called by osgi framework
-////            // We created the management context, so we are responsible for terminating it
-////            BrooklynShutdownHooks.invokeTerminateOnShutdown(managementContext);
-//    }
-//    /**
-//     * @return The canonical path of the argument.
-//     */
-//    private File resolveSymbolicLink(File f) {
-//        File f2 = f;
-//        try {
-//            f2 = f.getCanonicalFile();
-//            if (Files.isSymbolicLink(f.toPath())) {
-//                log.debug("Resolved symbolic link: {} -> {}", f, f2);
-//            }
-//        } catch (IOException e) {
-//            log.warn("Could not determine canonical name of file " + f + "; returning original file", e);
-//        }
-//        return f2;
-//    }
-//
-//    private void checkFileReadable(File f) {
-//        if (!f.exists()) {
-//            throw new FatalRuntimeException("File " + f + " does not exist");
-//        }
-//        if (!f.isFile()) {
-//            throw new FatalRuntimeException(f + " is not a file");
-//        }
-//        if (!f.canRead()) {
-//            throw new FatalRuntimeException(f + " is not readable");
-//        }
-//    }
-//
-//    private void checkFilePermissionsX00(File f) {
-//
-//        Maybe<String> permission = FileUtil.getFilePermissions(f);
-//        if (permission.isAbsent()) {
-//            log.debug("Could not determine permissions of file; assuming ok: " + f);
-//        } else {
-//            if (!permission.get().subSequence(4, 10).equals("------")) {
-//                throw new FatalRuntimeException("Invalid permissions for file " + f + "; expected ?00 but was " + permission.get());
-//            }
-//        }
-//    }
-
-    /* equivalent of launcher.start() in Main.java */
-    private void launcherStart() {
-        // not needed: management context already running (courtesy of blueprint.xml)
-//        // Create the management context
-//        initManagementContext();
-
-        // Inform catalog initialization that it is starting up
-        CatalogInitialization catInit = ((ManagementContextInternal) managementContext).getCatalogInitialization();
-        catInit.setStartingUp(true);
-
-        // not needed: webapps are started as different features (brooklyn-rest-resources-cxf, brooklyn-jsgui etc)
-//        // Start webapps as soon as mgmt context available -- can use them to detect progress of other processes
-//        if (startWebApps) {
-//            try {
-//                startWebApps();
-//            } catch (Exception e) {
-//                handleSubsystemStartupError(ignoreWebErrors, "core web apps", e);
-//            }
-//        }
-        // not needed: camp is a separate karaf feature - let it initialize itself
-//        // Add a CAMP platform
-//        campPlatform = new BrooklynCampPlatformLauncherNoServer()
-//                .useManagementContext(managementContext)
-//                .launch()
-//                .getCampPlatform();
-        try {
-            initPersistence();
-            startPersistence();
-        } catch (Exception e) {
-            handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
-        }
-
-        try {
-            // 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.hasRunOfficialInitialization()) {
-                if (persistMode == PersistMode.DISABLED) {
-                    log.debug("Loading catalog as part of launch sequence (it was not loaded as part of any rebind sequence)");
-                    catInit.populateCatalog(ManagementNodeState.MASTER, true, true, null);
-                } else {
-                    // should have loaded during rebind
-                    ManagementNodeState state = managementContext.getHighAvailabilityManager().getNodeState();
-                    log.warn("Loading catalog for " + state + " as part of launch sequence (it was not loaded as part of the rebind sequence)");
-                    catInit.populateCatalog(state, true, true, null);
-                }
-            }
-        } catch (Exception e) {
-            handleSubsystemStartupError(ignoreCatalogErrors, "initial catalog", e);
-        }
-        catInit.setStartingUp(false);
-
-        // no need for command-line locations
-//        // Create the locations. Must happen after persistence is started in case the
-//        // management context's catalog is loaded from persisted state. (Location
-//        // resolution uses the catalog's classpath to scan for resolvers.)
-//        locations.addAll(managementContext.getLocationRegistry().resolve(locationSpecs));
-        // Already rebinded successfully, so previous apps are now available.
-        // Allow the startup to be visible in console for newly created apps.
-        ((LocalManagementContext) managementContext).noteStartupComplete();
-
-//        // TODO create apps only after becoming master, analogously to catalog initialization
-//        try {
-//            createApps();
-//            startApps();
-//        } catch (Exception e) {
-//            handleSubsystemStartupError(ignoreAppErrors, "brooklyn autostart apps", e);
-//        }
-//        if (startBrooklynNode) {
-//            try {
-//                startBrooklynNode();
-//            } catch (Exception e) {
-//                handleSubsystemStartupError(ignoreAppErrors, "brooklyn node / self entity", e);
-//            }
-//        }
-//
-        if (persistMode != PersistMode.DISABLED) {
-            // Make sure the new apps are persisted in case process exits immediately.
-            managementContext.getRebindManager().forcePersistNow(false, null);
-        }
-    }
-
-    public void shutdown() {
-        // not needed: webserver is in other bundles
-//        if (webServer != null) {
-//            try {
-//                webServer.stop();
-//            } catch (Exception e) {
-//                LOG.warn("Error stopping web-server; continuing with termination", e);
-//            }
-//        }
-
-        // TODO Do we want to do this as part of managementContext.terminate, so after other threads are terminated etc?
-        // Otherwise the app can change between this persist and the terminate.
-        if (persistMode != PersistMode.DISABLED) {
-            try {
-                Stopwatch stopwatch = Stopwatch.createStarted();
-                if (managementContext.getHighAvailabilityManager().getPersister() != null) {
-                    managementContext.getHighAvailabilityManager().getPersister().waitForWritesCompleted(Duration.TEN_SECONDS);
-                }
-                managementContext.getRebindManager().waitForPendingComplete(Duration.TEN_SECONDS, true);
-                log.info("Finished waiting for persist; took " + Time.makeTimeStringRounded(stopwatch));
-            } catch (RuntimeInterruptedException e) {
-                Thread.currentThread().interrupt(); // keep going with shutdown
-                log.warn("Persistence interrupted during shutdown: " + e, e);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt(); // keep going with shutdown
-                log.warn("Persistence interrupted during shutdown: " + e, e);
-            } catch (TimeoutException e) {
-                log.warn("Timeout after 10 seconds waiting for persistence to write all data; continuing");
-            }
-        }
-
-        // not needed; called using blueprint.xml
-//        if (managementContext instanceof ManagementContextInternal) {
-//            ((ManagementContextInternal) managementContext).terminate();
-//        }
-        // TODO
-//        for (Location loc : locations) {
-//            if (loc instanceof Closeable) {
-//                Streams.closeQuietly((Closeable) loc);
-//            }
-//        }
-    }
-
-    /**
-     * method intended for subclassing, to add custom items to the catalog
-     *
-     * @todo Remove ?
-     */
-    protected void populateCatalog(BrooklynCatalog catalog) {
-        // nothing else added here
-    }
-
-    protected void confirmCatalog(CatalogInitialization catInit) {
-        Stopwatch time = Stopwatch.createStarted();
-        BrooklynCatalog catalog = catInit.getManagementContext().getCatalog();
-        Iterable<CatalogItem<Object, Object>> items = catalog.getCatalogItems();
-        for (CatalogItem<Object, Object> item : items) {
-            try {
-                if (item.getCatalogItemType() == CatalogItem.CatalogItemType.TEMPLATE) {
-                    // skip validation of templates, they might contain instructions,
-                    // and additionally they might contain multiple items in which case
-                    // the validation below won't work anyway (you need to go via a deployment plan)
-                } else {
-                    @SuppressWarnings({"unchecked", "rawtypes"})
-                    Object spec = catalog.createSpec((CatalogItem) item);
-                    if (spec instanceof EntitySpec) {
-                        BrooklynTypes.getDefinedEntityType(((EntitySpec<?>) spec).getType());
-                    }
-                    log.debug("Catalog loaded spec " + spec + " for item " + item);
-                }
-            } catch (Throwable throwable) {
-                catInit.handleException(throwable, item);
-            }
-        }
-        log.debug("Catalog (size " + Iterables.size(items) + ") confirmed in " + Duration.of(time));
-    }
-
-    private void handleSubsystemStartupError(boolean ignoreSuchErrors, String system, Exception e) {
-        Exceptions.propagateIfFatal(e);
-        if (ignoreSuchErrors) {
-            log.error("Subsystem for " + system + " had startup error (continuing with startup): " + e, e);
-            if (managementContext != null) {
-                ((ManagementContextInternal) managementContext).errors().add(e);
-            }
-        } else {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    protected void initPersistence() {
-        // Prepare the rebind directory, and initialise the RebindManager as required
-        final PersistenceObjectStore objectStore;
-        if (persistMode == PersistMode.DISABLED) {
-            log.info("Persistence disabled");
-            objectStore = null;
-
-        } else {
-            try {
-                BrooklynProperties brooklynProperties = ((ManagementContextInternal) managementContext).getBrooklynProperties();
-                if (persistenceLocation == null) {
-                    persistenceLocation = brooklynProperties.getConfig(BrooklynServerConfig.PERSISTENCE_LOCATION_SPEC);
-                }
-                persistenceDir = BrooklynServerPaths.newMainPersistencePathResolver(brooklynProperties).location(persistenceLocation).dir(persistenceDir).resolve();
-                objectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(managementContext, persistenceLocation, persistenceDir,
-                        persistMode, highAvailabilityMode);
-
-                RebindManager rebindManager = managementContext.getRebindManager();
-
-                BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
-                        objectStore,
-                        ((ManagementContextInternal) managementContext).getBrooklynProperties(),
-                        managementContext.getCatalogClassLoader());
-                PersistenceExceptionHandler persistenceExceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
-                ((RebindManagerImpl) rebindManager).setPeriodicPersistPeriod(persistPeriod);
-                rebindManager.setPersister(persister, persistenceExceptionHandler);
-            } catch (FatalConfigurationRuntimeException e) {
-                throw e;
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                log.debug("Error initializing persistence subsystem (rethrowing): " + e, e);
-                throw new FatalRuntimeException("Error initializing persistence subsystem: "
-                        + Exceptions.collapseText(e), e);
-            }
-        }
-
-        // Initialise the HA manager as required
-        if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
-            log.info("High availability disabled");
-        } else {
-            if (objectStore == null) {
-                throw new FatalConfigurationRuntimeException("Cannot run in HA mode when no persistence configured.");
-            }
-
-            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
-            ManagementPlaneSyncRecordPersister persister
-                    = new ManagementPlaneSyncRecordPersisterToObjectStore(managementContext,
-                            objectStore,
-                            managementContext.getCatalogClassLoader());
-            // not needed: set from config keys
-//            ((HighAvailabilityManagerImpl) haManager).setHeartbeatTimeout(haHeartbeatTimeoutOverride);
-//            ((HighAvailabilityManagerImpl) haManager).setPollPeriod(haHeartbeatPeriodOverride);
-            haManager.setPersister(persister);
-        }
-    }
-
-    protected void startPersistence() {
-        // Now start the HA Manager and the Rebind manager, as required
-        if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
-            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
-            haManager.disabled();
-
-            if (persistMode != PersistMode.DISABLED) {
-                startPersistenceWithoutHA();
-            }
-
-        } else {
-            // Let the HA manager decide when objectstore.prepare and rebindmgr.rebind need to be called
-            // (based on whether other nodes in plane are already running).
-
-            HighAvailabilityMode startMode = null;
-            switch (highAvailabilityMode) {
-                case AUTO:
-                case MASTER:
-                case STANDBY:
-                case HOT_STANDBY:
-                case HOT_BACKUP:
-                    startMode = highAvailabilityMode;
-                    break;
-                case DISABLED:
-                    throw new IllegalStateException("Unexpected code-branch for high availability mode " + highAvailabilityMode);
-            }
-            if (startMode == null) {
-                throw new IllegalStateException("Unexpected high availability mode " + highAvailabilityMode);
-            }
-
-            log.debug("Management node (with HA) starting");
-            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
-            // prepare after HA mode is known, to prevent backups happening in standby mode
-            haManager.start(startMode);
-        }
-    }
-
-    private void startPersistenceWithoutHA() {
-        RebindManager rebindManager = managementContext.getRebindManager();
-        if (Strings.isNonBlank(persistenceLocation)) {
-            log.info("Management node (no HA) rebinding to entities at " + persistenceLocation + " in " + persistenceDir);
-        } else {
-            log.info("Management node (no HA) rebinding to entities on file system in " + persistenceDir);
-        }
-
-        ClassLoader classLoader = managementContext.getCatalogClassLoader();
-        try {
-            rebindManager.rebind(classLoader, null, ManagementNodeState.MASTER);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            log.debug("Error rebinding to persisted state (rethrowing): " + e, e);
-            throw new FatalRuntimeException("Error rebinding to persisted state: "
-                    + Exceptions.collapseText(e), e);
-        }
-        rebindManager.startPersistence();
-    }
-
-    public void setHighAvailabilityMode(HighAvailabilityMode highAvailabilityMode) {
-        this.highAvailabilityMode = highAvailabilityMode;
-    }
-
-    public void setIgnoreCatalogErrors(boolean ignoreCatalogErrors) {
-        this.ignoreCatalogErrors = ignoreCatalogErrors;
-    }
-
-    public void setIgnorePersistenceErrors(boolean ignorePersistenceErrors) {
-        this.ignorePersistenceErrors = ignorePersistenceErrors;
-    }
-
-    public void setManagementContext(ManagementContext managementContext) {
-        this.managementContext = managementContext;
-    }
-
-    public void setPersistMode(PersistMode persistMode) {
-        this.persistMode = persistMode;
-    }
-
-    public void setPersistenceDir(String persistenceDir) {
-        this.persistenceDir = persistenceDir;
-    }
-
-    public void setPersistenceLocation(String persistenceLocation) {
-        this.persistenceLocation = persistenceLocation;
-    }
-
-    public void setPersistPeriod(String persistPeriodDescription) {
-        this.persistPeriod = Duration.parse(persistPeriodDescription);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..6ce5c92
--- /dev/null
+++ b/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright 2015 The Apache Software Foundation.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.2.0"
+           xsi:schemaLocation="
+             http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
+             http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd
+             ">
+
+   <bean id="brooklynVersion"
+         class="org.apache.brooklyn.core.BrooklynVersion"
+         factory-method="getInstance" />
+
+   <service ref="brooklynVersion"
+            interface="org.apache.brooklyn.core.BrooklynVersionService" />
+
+</blueprint>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/karaf/features/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/karaf/features/src/main/feature/feature.xml b/karaf/features/src/main/feature/feature.xml
index adedf5a..c049f47 100644
--- a/karaf/features/src/main/feature/feature.xml
+++ b/karaf/features/src/main/feature/feature.xml
@@ -288,6 +288,7 @@
 
     <feature name="brooklyn-osgi-launcher" version="${project.version}" description="Brooklyn init">
         <feature>brooklyn-core</feature>
+        <feature>brooklyn-software-base</feature>
         <bundle>mvn:org.apache.brooklyn/brooklyn-launcher-common/${project.version}</bundle>
         <bundle>mvn:org.apache.brooklyn/brooklyn-karaf-init/${project.version}</bundle>
     </feature>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/karaf/init/pom.xml
----------------------------------------------------------------------
diff --git a/karaf/init/pom.xml b/karaf/init/pom.xml
index eed4169..7ca1c69 100644
--- a/karaf/init/pom.xml
+++ b/karaf/init/pom.xml
@@ -44,6 +44,7 @@
             <artifactId>brooklyn-launcher-common</artifactId>
             <version>${project.version}</version>
         </dependency>
+
         <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncher.java
----------------------------------------------------------------------
diff --git a/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncher.java b/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncher.java
new file mode 100644
index 0000000..d08504d
--- /dev/null
+++ b/karaf/init/src/main/java/org/apache/brooklyn/launcher/osgi/OsgiLauncher.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.brooklyn.launcher.osgi;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.core.BrooklynVersionService;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+import org.apache.brooklyn.launcher.common.BasicLauncher;
+import org.apache.brooklyn.util.time.Duration;
+
+/**
+ * Initializer for brooklyn-core when running in an OSGi environment.
+ *
+ * Temporarily here; should be totally contained in blueprint beans' init-methods.
+ */
+public class OsgiLauncher extends BasicLauncher<OsgiLauncher> {
+
+    private BrooklynVersionService brooklynVersion;
+
+    @Override
+    public OsgiLauncher start() {
+        // make sure brooklyn-core bundle is started
+        brooklynVersion.getVersion();
+
+        return super.start();
+    }
+
+    // init-method can't find the start method for some reason, provide an alternative
+    public void init() {
+        start();
+    }
+
+    public void setBrooklynVersion(BrooklynVersionService brooklynVersion) {
+        this.brooklynVersion = brooklynVersion;
+    }
+
+    public void setPersistenceLocation(@Nullable String persistenceLocationSpec) {
+        persistenceLocation(persistenceLocationSpec);
+    }
+
+
+    public void setBrooklynProperties(BrooklynProperties brooklynProperties){
+        brooklynProperties(brooklynProperties);
+    }
+
+    public void setIgnorePersistenceErrors(boolean ignorePersistenceErrors) {
+        ignorePersistenceErrors(ignorePersistenceErrors);
+    }
+
+    public void setIgnoreCatalogErrors(boolean ignoreCatalogErrors) {
+        ignoreCatalogErrors(ignoreCatalogErrors);
+    }
+
+    public void setIgnoreAppErrors(boolean ignoreAppErrors) {
+        ignoreAppErrors(ignoreAppErrors);
+    }
+
+    public void setPersistMode(PersistMode persistMode) {
+        persistMode(persistMode);
+    }
+
+    public void setHighAvailabilityMode(HighAvailabilityMode highAvailabilityMode) {
+        highAvailabilityMode(highAvailabilityMode);
+    }
+
+    public void setPersistenceDir(@Nullable String persistenceDir) {
+        persistenceDir(persistenceDir);
+    }
+
+    public void setPersistPeriod(String persistPeriod) {
+        persistPeriod(Duration.parse(persistPeriod));
+    }
+
+    public void setHaHeartbeatTimeout(String val) {
+        haHeartbeatTimeout(Duration.parse(val));
+    }
+
+    public void setStartBrooklynNode(boolean val) {
+        startBrooklynNode(val);
+    }
+
+    public void setHaHeartbeatPeriod(String val) {
+        haHeartbeatPeriod(Duration.parse(val));
+    }
+
+    public void setCopyPersistedState(String destinationDir) {
+        copyPersistedState(destinationDir);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 6b047be..7312531 100644
--- a/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -23,6 +23,10 @@ limitations under the License.
              http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd
              ">
 
+    <!-- Make sure core bundle is already started -->
+    <reference id="brooklynVersion"
+               interface="org.apache.brooklyn.core.BrooklynVersionService" />
+
     <cm:property-placeholder persistent-id="org.apache.brooklyn.osgilauncher" update-strategy="reload">
         <cm:default-properties>
             <cm:property name="ignoreCatalogErrors" value="true" />
@@ -36,36 +40,24 @@ limitations under the License.
             <cm:property name="localBrooklynPropertiesFile" value="" /> <!-- used to be settable through cli params -->
         </cm:default-properties>
     </cm:property-placeholder>
-    
+
     <bean id="propertiesBuilderFactory"
           class="org.apache.brooklyn.launcher.common.BrooklynPropertiesFactoryHelper">
         <argument value="${globalBrooklynPropertiesFile}" />
         <argument value="${localBrooklynPropertiesFile}" />
     </bean>
-    
+
     <bean id="propertiesBuilder"
           class="org.apache.brooklyn.core.internal.BrooklynProperties.Factory.Builder"
           factory-ref="propertiesBuilderFactory"
           factory-method="createPropertiesBuilder" />
 
-    <bean id="localManagementContextService"
-          class="org.apache.brooklyn.core.mgmt.internal.LocalManagementContext"
-          destroy-method="terminate">
-        <argument ref="propertiesBuilder" />
-    </bean>
-
-    <service ref="localManagementContextService">
-        <interfaces>
-            <value>org.apache.brooklyn.api.mgmt.ManagementContext</value>
-            <value>org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal</value>
-        </interfaces>
-    </service>
-
     <bean id="launcher"
-          class="org.apache.brooklyn.core.OsgiLauncher"
-          init-method="start">
+          class="org.apache.brooklyn.launcher.osgi.OsgiLauncher"
+          init-method="init">
 
-        <property name="managementContext" ref="localManagementContextService" />
+        <property name="brooklynVersion" ref="brooklynVersion" />
+        <property name="brooklynPropertiesBuilder" ref="propertiesBuilder" />
 
         <property name="ignoreCatalogErrors" value="${ignoreCatalogErrors}" />
         <property name="ignorePersistenceErrors" value="${ignorePersistenceErrors}" />
@@ -76,4 +68,23 @@ limitations under the License.
         <property name="persistPeriod" value="${persistPeriod}" />
     </bean>
 
+    <bean id="localManagementContextService"
+          class="org.apache.brooklyn.core.mgmt.internal.LocalManagementContext"
+          factory-ref="launcher"
+          factory-method="getManagementContext" />
+          
+    <bean id="campPlatform"
+          class="org.apache.brooklyn.camp.CampPlatform"
+          factory-ref="launcher"
+          factory-method="getCampPlatform" />
+
+    <!-- TODO shutdown -->
+
+    <service ref="localManagementContextService">
+        <interfaces>
+            <value>org.apache.brooklyn.api.mgmt.ManagementContext</value>
+            <value>org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal</value>
+        </interfaces>
+    </service>
+
 </blueprint>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/karaf/itest/src/test/java/org/apache/brooklyn/AssemblyTest.java
----------------------------------------------------------------------
diff --git a/karaf/itest/src/test/java/org/apache/brooklyn/AssemblyTest.java b/karaf/itest/src/test/java/org/apache/brooklyn/AssemblyTest.java
index c8389d6..22a4018 100644
--- a/karaf/itest/src/test/java/org/apache/brooklyn/AssemblyTest.java
+++ b/karaf/itest/src/test/java/org/apache/brooklyn/AssemblyTest.java
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
 import static org.ops4j.pax.exam.CoreOptions.maven;
-import static org.ops4j.pax.exam.MavenUtils.asInProject;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
@@ -30,6 +29,9 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRunti
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
 
 import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import javax.inject.Inject;
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/launcher-common/pom.xml
----------------------------------------------------------------------
diff --git a/launcher-common/pom.xml b/launcher-common/pom.xml
index de1fa47..e1c20a4 100644
--- a/launcher-common/pom.xml
+++ b/launcher-common/pom.xml
@@ -45,6 +45,16 @@
             <artifactId>brooklyn-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-software-base</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-camp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>org.testng</groupId>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
----------------------------------------------------------------------
diff --git a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
new file mode 100644
index 0000000..8ff0ea3
--- /dev/null
+++ b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
@@ -0,0 +1,766 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.launcher.common;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityManager;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
+import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecord;
+import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecordPersister;
+import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
+import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.camp.CampPlatform;
+import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
+import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.internal.BrooklynShutdownHooks;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
+import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
+import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
+import org.apache.brooklyn.core.server.BrooklynServerConfig;
+import org.apache.brooklyn.core.server.BrooklynServerPaths;
+import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
+import org.apache.brooklyn.entity.brooklynnode.LocalBrooklynNode;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
+import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * Example usage is:
+ *  * <pre>
+ * {@code
+ * BasicLauncher launcher = BasicLauncher.newInstance()
+ *     .application(new WebClusterDatabaseExample().appDisplayName("Web-cluster example"))
+ *     .location("localhost")
+ *     .start();
+ * 
+ * Entities.dumpInfo(launcher.getApplications());
+ * </pre>
+ */
+public class BasicLauncher<T extends BasicLauncher<T>> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BasicLauncher.class);
+
+    private final Map<String,Object> brooklynAdditionalProperties = Maps.newLinkedHashMap();
+    private BrooklynProperties brooklynProperties;
+    private ManagementContext managementContext;
+    
+    private final List<String> locationSpecs = new ArrayList<String>();
+    private final List<Location> locations = new ArrayList<Location>();
+
+    private final List<Application> appsToManage = new ArrayList<Application>();
+    @SuppressWarnings("deprecation") // TODO convert to EntitySpec; should be easy when users not allowed to pass in a builder
+    private final List<org.apache.brooklyn.core.entity.factory.ApplicationBuilder> appBuildersToManage = new ArrayList<org.apache.brooklyn.core.entity.factory.ApplicationBuilder>();
+    private final List<String> yamlAppsToManage = new ArrayList<String>();
+    private final List<Application> apps = new ArrayList<Application>();
+    
+    private boolean startBrooklynNode = false;
+    
+    private boolean ignorePersistenceErrors = true;
+    private boolean ignoreCatalogErrors = true;
+    private boolean ignoreAppErrors = true;
+    
+    private CatalogInitialization catalogInitialization = null;
+    
+    private PersistMode persistMode = PersistMode.DISABLED;
+    private HighAvailabilityMode highAvailabilityMode = HighAvailabilityMode.DISABLED;
+    private String persistenceDir;
+    private String persistenceLocation;
+    private Duration persistPeriod = Duration.ONE_SECOND;
+    // these default values come from config in HighAvailablilityManagerImpl
+    private Duration haHeartbeatTimeoutOverride = null;
+    private Duration haHeartbeatPeriodOverride = null;
+    
+    private boolean started;
+    
+    private BrooklynProperties.Factory.Builder brooklynPropertiesBuilder;
+
+    private CampPlatform campPlatform;
+
+    public ManagementContext getManagementContext() {
+        return managementContext;
+    }
+
+    public List<Application> getApplications() {
+        if (!started) throw new IllegalStateException("Cannot retrieve application until started");
+        return ImmutableList.copyOf(apps);
+    }
+
+    /** 
+     * Specifies that the launcher should manage the given Brooklyn application.
+     * The application must not yet be managed. 
+     * The application will not be started as part of this call (callers can
+     * subsequently call {@link #start()} or {@link #getApplications()}.
+     * 
+     * @see #application(ApplicationBuilder)
+     * 
+     * @deprecated since 0.9.0; instead use {@link #application(String)} for YAML apps, or {@link #application(EntitySpec)}.
+     *             Note that apps are now auto-managed on construction through EntitySpec/YAML.
+     */
+    @Deprecated
+    public T application(Application app) {
+        if (Entities.isManaged(app)) throw new IllegalArgumentException("Application must not already be managed");
+        appsToManage.add(checkNotNull(app, "app"));
+        return self();
+    }
+
+    /** 
+     * Specifies that the launcher should build and manage the given Brooklyn application.
+     * The application must not yet be managed. 
+     * The application will not be started as part of this call (callers can
+     * subsequently call {@link #start()} or {@link #getApplications()}.
+     * 
+     * @see #application(EntitySpec)
+     * 
+     * @deprecated since 0.9.0; instead use {@link #application(String)} for YAML apps, or {@link #application(EntitySpec)}.
+     *             Note that apps are now auto-managed on construction through EntitySpec/YAML.
+     */
+    public T application(org.apache.brooklyn.core.entity.factory.ApplicationBuilder appBuilder) {
+        LOG.warn("Caller supplied ApplicationBuilder; convert to EntitySpec as this style builder may not be supported in future.");
+        appBuildersToManage.add(checkNotNull(appBuilder, "appBuilder"));
+        return self();
+    }
+
+    /** 
+     * Specifies that the launcher should build and manage the Brooklyn application
+     * described by the given spec.
+     * The application will not be started as part of this call (callers can
+     * subsequently call {@link #start()} or {@link #getApplications()}.
+     * 
+     * @see #application(Application)
+     */
+    @SuppressWarnings("deprecation")  // when appsToManage is EntitySpec this will no longer be needed
+    public T application(EntitySpec<? extends StartableApplication> appSpec) {
+        appBuildersToManage.add(new org.apache.brooklyn.core.entity.factory.ApplicationBuilder(checkNotNull(appSpec, "appSpec")) {
+                @Override protected void doBuild() {
+                }});
+        return self();
+    }
+
+    /**
+     * Specifies that the launcher should build and manage the Brooklyn application
+     * described by the given YAML blueprint.
+     * The application will not be started as part of this call (callers can
+     * subsequently call {@link #start()} or {@link #getApplications()}.
+     *
+     * @see #application(Application)
+     */
+    public T application(String yaml) {
+        this.yamlAppsToManage.add(yaml);
+        return self();
+    }
+
+    /**
+     * Adds a location to be passed in on {@link #start()}, when that calls
+     * {@code application.start(locations)}.
+     */
+    public T location(Location location) {
+        locations.add(checkNotNull(location, "location"));
+        return self();
+    }
+
+    /**
+     * Give the spec of an application, to be created.
+     * 
+     * @see #location(Location)
+     */
+    public T location(String spec) {
+        locationSpecs.add(checkNotNull(spec, "spec"));
+        return self();
+    }
+    
+    public T locations(List<String> specs) {
+        locationSpecs.addAll(checkNotNull(specs, "specs"));
+        return self();
+    }
+
+    public T persistenceLocation(@Nullable String persistenceLocationSpec) {
+        persistenceLocation = persistenceLocationSpec;
+        return self();
+    }
+
+    /** 
+     * Specifies the management context this launcher should use. 
+     * If not specified a new one is created automatically.
+     */
+    public T managementContext(ManagementContext context) {
+        if (brooklynProperties != null) throw new IllegalStateException("Cannot set brooklynProperties and managementContext");
+        this.managementContext = context;
+        return self();
+    }
+
+    /**
+     * Specifies the brooklyn properties to be used. 
+     * Must not be set if managementContext is explicitly set.
+     */
+    public T brooklynProperties(BrooklynProperties brooklynProperties){
+        if (managementContext != null) throw new IllegalStateException("Cannot set brooklynProperties and managementContext");
+        if (this.brooklynProperties!=null && brooklynProperties!=null && this.brooklynProperties!=brooklynProperties)
+            LOG.warn("Brooklyn properties being reset in "+self()+"; set null first if you wish to clear it", new Throwable("Source of brooklyn properties reset"));
+        this.brooklynProperties = brooklynProperties;
+        return self();
+    }
+    
+    /**
+     * Specifies a property to be added to the brooklyn properties
+     */
+    public T brooklynProperties(String field, Object value) {
+        brooklynAdditionalProperties.put(checkNotNull(field, "field"), value);
+        return self();
+    }
+    public <C> T brooklynProperties(ConfigKey<C> key, C value) {
+        return brooklynProperties(key.getName(), value);
+    }
+
+    public T ignorePersistenceErrors(boolean ignorePersistenceErrors) {
+        this.ignorePersistenceErrors = ignorePersistenceErrors;
+        return self();
+    }
+
+    public T ignoreCatalogErrors(boolean ignoreCatalogErrors) {
+        this.ignoreCatalogErrors = ignoreCatalogErrors;
+        return self();
+    }
+
+    public T ignoreAppErrors(boolean ignoreAppErrors) {
+        this.ignoreAppErrors = ignoreAppErrors;
+        return self();
+    }
+
+    @Beta
+    public T catalogInitialization(CatalogInitialization catInit) {
+        if (this.catalogInitialization!=null)
+            throw new IllegalStateException("Initial catalog customization already set.");
+        this.catalogInitialization = catInit;
+        return self();
+    }
+
+    public T persistMode(PersistMode persistMode) {
+        this.persistMode = persistMode;
+        return self();
+    }
+
+    public T highAvailabilityMode(HighAvailabilityMode highAvailabilityMode) {
+        this.highAvailabilityMode = highAvailabilityMode;
+        return self();
+    }
+
+    public T persistenceDir(@Nullable String persistenceDir) {
+        this.persistenceDir = persistenceDir;
+        return self();
+    }
+
+    public T persistenceDir(@Nullable File persistenceDir) {
+        if (persistenceDir==null) return persistenceDir((String)null);
+        return persistenceDir(persistenceDir.getAbsolutePath());
+    }
+
+    public T persistPeriod(Duration persistPeriod) {
+        this.persistPeriod = persistPeriod;
+        return self();
+    }
+
+    public T haHeartbeatTimeout(Duration val) {
+        this.haHeartbeatTimeoutOverride = val;
+        return self();
+    }
+
+    public T startBrooklynNode(boolean val) {
+        this.startBrooklynNode = val;
+        return self();
+    }
+
+    /**
+     * Controls both the frequency of heartbeats, and the frequency of checking the health of other nodes.
+     */
+    public T haHeartbeatPeriod(Duration val) {
+        this.haHeartbeatPeriodOverride = val;
+        return self();
+    }
+
+    /**
+     * @param destinationDir Directory for state to be copied to
+     */
+    public void copyPersistedState(String destinationDir) {
+        copyPersistedState(destinationDir, null, null);
+    }
+
+    /**
+     * @param destinationDir Directory for state to be copied to
+     * @param destinationLocation Optional location if target for copied state is a blob store.
+     */
+    public void copyPersistedState(String destinationDir, @Nullable String destinationLocation) {
+        copyPersistedState(destinationDir, destinationLocation, null);
+    }
+
+    /**
+     * @param destinationDir Directory for state to be copied to
+     * @param destinationLocationSpec Optional location if target for copied state is a blob store.
+     * @param transformer Optional transformations to apply to retrieved state before it is copied.
+     */
+    public void copyPersistedState(String destinationDir, @Nullable String destinationLocationSpec, @Nullable CompoundTransformer transformer) {
+        initManagementContext();
+        try {
+            highAvailabilityMode = HighAvailabilityMode.HOT_STANDBY;
+            initPersistence();
+        } catch (Exception e) {
+            handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
+        }
+        
+        try {
+            BrooklynMementoRawData memento = managementContext.getRebindManager().retrieveMementoRawData();
+            if (transformer != null) memento = transformer.transform(memento);
+            
+            ManagementPlaneSyncRecord planeState = managementContext.getHighAvailabilityManager().loadManagementPlaneSyncRecord(true);
+            
+            LOG.info("Persisting state to "+destinationDir+(destinationLocationSpec!=null ? " @ "+destinationLocationSpec : ""));
+            PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
+                managementContext, destinationLocationSpec, destinationDir);
+            BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore);
+            BrooklynPersistenceUtils.writeManagerMemento(managementContext, planeState, destinationObjectStore);
+
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            LOG.debug("Error copying persisted state (rethrowing): " + e, e);
+            throw new FatalRuntimeException("Error copying persisted state: " +
+                Exceptions.collapseText(e), e);
+        }
+    }
+
+    /** @deprecated since 0.7.0 use {@link #copyPersistedState} instead */
+    // Make private after deprecation
+    @Deprecated
+    public BrooklynMementoRawData retrieveState() {
+        initManagementContext();
+        initPersistence();
+        return managementContext.getRebindManager().retrieveMementoRawData();
+    }
+
+    /**
+     * @param memento The state to copy
+     * @param destinationDir Directory for state to be copied to
+     * @param destinationLocationSpec Optional location if target for copied state is a blob store.
+     * @deprecated since 0.7.0 use {@link #copyPersistedState} instead
+     */
+    // Make private after deprecation
+    @Deprecated
+    public void persistState(BrooklynMementoRawData memento, String destinationDir, @Nullable String destinationLocationSpec) {
+        initManagementContext();
+        PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
+            managementContext, destinationLocationSpec, destinationDir);
+        BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore);
+    }
+
+    /**
+     * Starts the web server (with web console) and Brooklyn applications, as per the specifications configured. 
+     * @return An object containing details of the web server and the management context.
+     */
+    public T start() {
+        if (started) throw new IllegalStateException("Cannot start() or launch() multiple times");
+        started = true;
+
+        initManagementContext();
+
+        CatalogInitialization catInit = ((ManagementContextInternal)managementContext).getCatalogInitialization();
+
+        markCatalogStartingUp(catInit);
+        startingUp();
+        initCamp();
+        handlePersistence();
+        populateCatalog(catInit);
+        markCatalogStarted(catInit);
+        addLocations();
+        markStartupComplete();
+        initApps();
+        initBrooklynNode();
+
+        persist();
+        return self();
+    }
+
+    protected void persist() {
+        if (persistMode != PersistMode.DISABLED) {
+            // Make sure the new apps are persisted in case process exits immediately.
+            managementContext.getRebindManager().forcePersistNow(false, null);
+        }
+    }
+
+    protected void initBrooklynNode() {
+        if (startBrooklynNode) {
+            try {
+                startBrooklynNode();
+            } catch (Exception e) {
+                handleSubsystemStartupError(ignoreAppErrors, "brooklyn node / self entity", e);
+            }
+        }
+    }
+
+    protected void initApps() {
+        // TODO create apps only after becoming master, analogously to catalog initialization
+        try {
+            createApps();
+            startApps();
+        } catch (Exception e) {
+            handleSubsystemStartupError(ignoreAppErrors, "brooklyn autostart apps", e);
+        }
+    }
+
+    protected void markStartupComplete() {
+        // Already rebinded successfully, so previous apps are now available.
+        // Allow the startup to be visible in console for newly created apps.
+        ((LocalManagementContext)managementContext).noteStartupComplete();
+    }
+
+    protected void addLocations() {
+        // Create the locations. Must happen after persistence is started in case the
+        // management context's catalog is loaded from persisted state. (Location
+        // resolution uses the catalog's classpath to scan for resolvers.)
+        locations.addAll(managementContext.getLocationRegistry().resolve(locationSpecs));
+    }
+
+    protected void startingUp() {
+    }
+
+    private void markCatalogStarted(CatalogInitialization catInit) {
+        catInit.setStartingUp(false);
+    }
+
+    protected void populateCatalog(CatalogInitialization catInit) {
+        try {
+            // 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.hasRunOfficialInitialization()) {
+                if (persistMode==PersistMode.DISABLED) {
+                    LOG.debug("Loading catalog as part of launch sequence (it was not loaded as part of any rebind sequence)");
+                    catInit.populateCatalog(ManagementNodeState.MASTER, true, true, null);
+                } else {
+                    // should have loaded during rebind
+                    ManagementNodeState state = managementContext.getHighAvailabilityManager().getNodeState();
+                    LOG.warn("Loading catalog for "+state+" as part of launch sequence (it was not loaded as part of the rebind sequence)");
+                    catInit.populateCatalog(state, true, true, null);
+                }
+            }
+        } catch (Exception e) {
+            handleSubsystemStartupError(ignoreCatalogErrors, "initial catalog", e);
+        }
+    }
+
+    protected void handlePersistence() {
+        try {
+            initPersistence();
+            startPersistence();
+        } catch (Exception e) {
+            handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
+        }
+    }
+
+    protected void initCamp() {
+        // Add a CAMP platform
+        campPlatform = new BrooklynCampPlatformLauncherNoServer()
+                .useManagementContext(managementContext)
+                .launch()
+                .getCampPlatform();
+        // TODO start CAMP rest _server_ in the below (at /camp) ?
+    }
+
+    protected void markCatalogStartingUp(CatalogInitialization catInit) {
+        // Inform catalog initialization that it is starting up
+        catInit.setStartingUp(true);
+    }
+
+    protected void initManagementContext() {
+        // Create the management context
+        if (managementContext == null) {
+            managementContext = new LocalManagementContext(
+                    brooklynPropertiesBuilder,
+                    brooklynAdditionalProperties);
+
+            brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
+            
+        } else if (brooklynProperties == null) {
+            brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
+            brooklynProperties.addFromMap(brooklynAdditionalProperties);
+        }
+        
+        if (catalogInitialization!=null) {
+            ((ManagementContextInternal)managementContext).setCatalogInitialization(catalogInitialization);
+        }
+        
+    }
+
+    protected void handleSubsystemStartupError(boolean ignoreSuchErrors, String system, Exception e) {
+        Exceptions.propagateIfFatal(e);
+        if (ignoreSuchErrors) {
+            LOG.error("Subsystem for "+system+" had startup error (continuing with startup): "+e, e);
+            if (managementContext!=null)
+                ((ManagementContextInternal)managementContext).errors().add(e);
+        } else {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    protected void initPersistence() {
+        // Prepare the rebind directory, and initialise the RebindManager as required
+        final PersistenceObjectStore objectStore;
+        if (persistMode == PersistMode.DISABLED) {
+            LOG.info("Persistence disabled");
+            objectStore = null;
+            
+        } else {
+            try {
+                if (persistenceLocation == null) {
+                    persistenceLocation = brooklynProperties.getConfig(BrooklynServerConfig.PERSISTENCE_LOCATION_SPEC);
+                }
+                persistenceDir = BrooklynServerPaths.newMainPersistencePathResolver(brooklynProperties).location(persistenceLocation).dir(persistenceDir).resolve();
+                objectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(managementContext, persistenceLocation, persistenceDir, 
+                    persistMode, highAvailabilityMode);
+                    
+                RebindManager rebindManager = managementContext.getRebindManager();
+                
+                BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
+                    objectStore,
+                    ((ManagementContextInternal)managementContext).getBrooklynProperties(),
+                    managementContext.getCatalogClassLoader());
+                PersistenceExceptionHandler persistenceExceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
+                ((RebindManagerImpl) rebindManager).setPeriodicPersistPeriod(persistPeriod);
+                rebindManager.setPersister(persister, persistenceExceptionHandler);
+            } catch (FatalConfigurationRuntimeException e) {
+                throw e;
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                LOG.debug("Error initializing persistence subsystem (rethrowing): "+e, e);
+                throw new FatalRuntimeException("Error initializing persistence subsystem: "+
+                    Exceptions.collapseText(e), e);
+            }
+        }
+        
+        // Initialise the HA manager as required
+        if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
+            LOG.info("High availability disabled");
+        } else {
+            if (objectStore==null)
+                throw new FatalConfigurationRuntimeException("Cannot run in HA mode when no persistence configured.");
+
+            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+            ManagementPlaneSyncRecordPersister persister =
+                new ManagementPlaneSyncRecordPersisterToObjectStore(managementContext,
+                    objectStore,
+                    managementContext.getCatalogClassLoader());
+            ((HighAvailabilityManagerImpl)haManager).setHeartbeatTimeout(haHeartbeatTimeoutOverride);
+            ((HighAvailabilityManagerImpl)haManager).setPollPeriod(haHeartbeatPeriodOverride);
+            haManager.setPersister(persister);
+        }
+    }
+    
+    protected void startPersistence() {
+        // Now start the HA Manager and the Rebind manager, as required
+        if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
+            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+            haManager.disabled();
+
+            if (persistMode != PersistMode.DISABLED) {
+                startPersistenceWithoutHA();
+            }
+            
+        } else {
+            // Let the HA manager decide when objectstore.prepare and rebindmgr.rebind need to be called 
+            // (based on whether other nodes in plane are already running).
+            
+            HighAvailabilityMode startMode=null;
+            switch (highAvailabilityMode) {
+                case AUTO:
+                case MASTER:
+                case STANDBY:
+                case HOT_STANDBY:
+                case HOT_BACKUP:
+                    startMode = highAvailabilityMode;
+                    break;
+                case DISABLED:
+                    throw new IllegalStateException("Unexpected code-branch for high availability mode "+highAvailabilityMode);
+            }
+            if (startMode==null)
+                throw new IllegalStateException("Unexpected high availability mode "+highAvailabilityMode);
+            
+            LOG.debug("Management node (with HA) starting");
+            HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+            // prepare after HA mode is known, to prevent backups happening in standby mode
+            haManager.start(startMode);
+        }
+    }
+
+    private void startPersistenceWithoutHA() {
+        RebindManager rebindManager = managementContext.getRebindManager();
+        if (Strings.isNonBlank(persistenceLocation))
+            LOG.info("Management node (no HA) rebinding to entities at "+persistenceLocation+" in "+persistenceDir);
+        else
+            LOG.info("Management node (no HA) rebinding to entities on file system in "+persistenceDir);
+
+        ClassLoader classLoader = managementContext.getCatalogClassLoader();
+        try {
+            rebindManager.rebind(classLoader, null, ManagementNodeState.MASTER);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            LOG.debug("Error rebinding to persisted state (rethrowing): "+e, e);
+            throw new FatalRuntimeException("Error rebinding to persisted state: "+
+                Exceptions.collapseText(e), e);
+        }
+        rebindManager.startPersistence();
+    }
+
+    @SuppressWarnings("deprecation")
+    protected void createApps() {
+        for (org.apache.brooklyn.core.entity.factory.ApplicationBuilder appBuilder : appBuildersToManage) {
+            StartableApplication app = appBuilder.manage(managementContext);
+            apps.add(app);
+        }
+        for (Application app : appsToManage) {
+            Entities.startManagement(app, managementContext);
+            apps.add(app);
+        }
+        for (String blueprint : yamlAppsToManage) {
+            Application app = EntityManagementUtils.createUnstarted(managementContext, blueprint);
+            // Note: BrooklynAssemblyTemplateInstantiator automatically puts applications under management.
+            apps.add(app);
+        }
+    }
+
+    protected void startBrooklynNode() {
+        final String classpath = System.getenv("INITIAL_CLASSPATH");
+        if (Strings.isBlank(classpath)) {
+            LOG.warn("Cannot find INITIAL_CLASSPATH environment variable, skipping BrooklynNode entity creation");
+            return;
+        }
+
+        EntitySpec<LocalBrooklynNode> brooklynNodeSpec = EntitySpec.create(LocalBrooklynNode.class)
+            .configure(SoftwareProcess.ENTITY_STARTED, true)
+            .configure(BrooklynNode.CLASSPATH, Splitter.on(":").splitToList(classpath))
+            .displayName("Brooklyn Console");
+
+        brooklynNodeSpec = customizeBrooklynNodeSpec(brooklynNodeSpec);
+
+        if (brooklynNodeSpec != null) {
+            EntityManagementUtils.createStarting(managementContext,
+                    EntitySpec.create(BasicApplication.class)
+                        .displayName("Brooklyn")
+                        .child(brooklynNodeSpec));
+        }
+    }
+
+    /**
+     * Configure the node so it can connect to Brooklyn's REST API. Return null to skip registering the node
+     */
+    protected EntitySpec<LocalBrooklynNode> customizeBrooklynNodeSpec(EntitySpec<LocalBrooklynNode> brooklynNodeSpec) {
+        LOG.error("Skipping BrooklynNode registration. Configure a loopback REST endpoint configured for the node.");
+        return null;
+    }
+
+    protected void startApps() {
+        List<Throwable> appExceptions = Lists.newArrayList();
+        for (Application app : apps) {
+            if (app instanceof Startable) {
+
+                try {
+                    LOG.info("Starting brooklyn application {} in location{} {}", new Object[] { app, locations.size()!=1?"s":"", locations });
+                    ((Startable)app).start(locations);
+                } catch (Exception e) {
+                    LOG.error("Error starting "+app+": "+Exceptions.collapseText(e), Exceptions.getFirstInteresting(e));
+                    appExceptions.add(Exceptions.collapse(e));
+
+                    if (Thread.currentThread().isInterrupted()) {
+                        LOG.error("Interrupted while starting applications; aborting");
+                        break;
+                    }
+                }
+            }
+        }
+        if (!appExceptions.isEmpty()) {
+            Throwable t = Exceptions.create(appExceptions);
+            throw new FatalRuntimeException("Error starting applications: "+Exceptions.collapseText(t), t);
+        }
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    public PersistMode getPersistMode() {
+        return persistMode;
+    }
+
+    public List<Location> getLocations() {
+        return locations;
+    }
+
+    public CampPlatform getCampPlatform() {
+        return campPlatform;
+    }
+
+    @SuppressWarnings("unchecked")
+    private T self() {
+        return (T) this;
+    }
+
+    public void setBrooklynPropertiesBuilder(BrooklynProperties.Factory.Builder brooklynPropertiesBuilder) {
+        this.brooklynPropertiesBuilder = brooklynPropertiesBuilder;
+    }
+
+    public BrooklynProperties getBrooklynProperties() {
+        return brooklynProperties;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/090b16cd/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BrooklynPropertiesFactoryHelper.java
----------------------------------------------------------------------
diff --git a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BrooklynPropertiesFactoryHelper.java b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BrooklynPropertiesFactoryHelper.java
index 8f2a5e2..f41167a 100644
--- a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BrooklynPropertiesFactoryHelper.java
+++ b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BrooklynPropertiesFactoryHelper.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 
 import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.internal.BrooklynProperties.Factory.Builder;
 import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.io.FileUtil;
@@ -36,41 +37,61 @@ public class BrooklynPropertiesFactoryHelper {
 
     private final String globalBrooklynPropertiesFile;
     private final String localBrooklynPropertiesFile;
+    private final BrooklynProperties brooklynProperties;
 
     public BrooklynPropertiesFactoryHelper(String globalBrooklynPropertiesFile, String localBrooklynPropertiesFile) {
+        this(globalBrooklynPropertiesFile, localBrooklynPropertiesFile, null);
+    }
+
+    public BrooklynPropertiesFactoryHelper(BrooklynProperties brooklynProperties) {
+        this(null, null, brooklynProperties);
+    }
+
+    public BrooklynPropertiesFactoryHelper(String globalBrooklynPropertiesFile,
+            String localBrooklynPropertiesFile,
+            BrooklynProperties brooklynProperties) {
         this.globalBrooklynPropertiesFile = globalBrooklynPropertiesFile;
         this.localBrooklynPropertiesFile = localBrooklynPropertiesFile;
+        this.brooklynProperties = brooklynProperties;
     }
 
     public BrooklynProperties.Factory.Builder createPropertiesBuilder() {
-        BrooklynProperties.Factory.Builder builder = BrooklynProperties.Factory.builderDefault();
-
-        if (Strings.isNonEmpty(globalBrooklynPropertiesFile)) {
-            File globalProperties = new File(Os.tidyPath(globalBrooklynPropertiesFile));
-            if (globalProperties.exists()) {
-                globalProperties = resolveSymbolicLink(globalProperties);
-                checkFileReadable(globalProperties);
-                // brooklyn.properties stores passwords (web-console and cloud credentials),
-                // so ensure it has sensible permissions
-                checkFilePermissionsX00(globalProperties);
-                LOG.debug("Using global properties file " + globalProperties);
+        if (brooklynProperties == null) {
+            BrooklynProperties.Factory.Builder builder = BrooklynProperties.Factory.builderDefault();
+    
+            if (Strings.isNonEmpty(globalBrooklynPropertiesFile)) {
+                File globalProperties = new File(Os.tidyPath(globalBrooklynPropertiesFile));
+                if (globalProperties.exists()) {
+                    globalProperties = resolveSymbolicLink(globalProperties);
+                    checkFileReadable(globalProperties);
+                    // brooklyn.properties stores passwords (web-console and cloud credentials),
+                    // so ensure it has sensible permissions
+                    checkFilePermissionsX00(globalProperties);
+                    LOG.debug("Using global properties file " + globalProperties);
+                } else {
+                    LOG.debug("Global properties file " + globalProperties + " does not exist, will ignore");
+                }
+                builder.globalPropertiesFile(globalProperties.getAbsolutePath());
             } else {
-                LOG.debug("Global properties file " + globalProperties + " does not exist, will ignore");
+                LOG.debug("Global properties file disabled");
+                builder.globalPropertiesFile(null);
             }
-            builder.globalPropertiesFile(globalProperties.getAbsolutePath());
+            
+            if (Strings.isNonEmpty(localBrooklynPropertiesFile)) {
+                File localProperties = new File(Os.tidyPath(localBrooklynPropertiesFile));
+                localProperties = resolveSymbolicLink(localProperties);
+                checkFileReadable(localProperties);
+                checkFilePermissionsX00(localProperties);
+                builder.localPropertiesFile(localProperties.getAbsolutePath());
+            }
+            return builder;
         } else {
-            LOG.debug("Global properties file disabled");
-            builder.globalPropertiesFile(null);
-        }
-        
-        if (Strings.isNonEmpty(localBrooklynPropertiesFile)) {
-            File localProperties = new File(Os.tidyPath(localBrooklynPropertiesFile));
-            localProperties = resolveSymbolicLink(localProperties);
-            checkFileReadable(localProperties);
-            checkFilePermissionsX00(localProperties);
-            builder.localPropertiesFile(localProperties.getAbsolutePath());
+            if (globalBrooklynPropertiesFile != null)
+                LOG.warn("Ignoring globalBrooklynPropertiesFile "+globalBrooklynPropertiesFile+" because explicit brooklynProperties supplied");
+            if (localBrooklynPropertiesFile != null)
+                LOG.warn("Ignoring localBrooklynPropertiesFile "+localBrooklynPropertiesFile+" because explicit brooklynProperties supplied");
+            return Builder.fromProperties(brooklynProperties);
         }
-        return builder;
     }
 
     /**


Mime
View raw message