You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vk...@apache.org on 2015/02/02 04:27:54 UTC

[02/52] [abbrv] incubator-ignite git commit: GridNamedInstance -> IgniteNamedInstance GridgainEx -> IgnitionEx

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/c5247ab3/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
new file mode 100644
index 0000000..acab6d0
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java
@@ -0,0 +1,2399 @@
+/*
+ * 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.ignite.internal;
+
+import org.apache.ignite.*;
+import org.apache.ignite.cache.*;
+import org.apache.ignite.cache.affinity.rendezvous.*;
+import org.apache.ignite.configuration.*;
+import org.apache.ignite.fs.*;
+import org.apache.ignite.internal.util.*;
+import org.apache.ignite.lang.*;
+import org.apache.ignite.lifecycle.*;
+import org.apache.ignite.logger.*;
+import org.apache.ignite.logger.java.*;
+import org.apache.ignite.marshaller.*;
+import org.apache.ignite.marshaller.jdk.*;
+import org.apache.ignite.marshaller.optimized.*;
+import org.apache.ignite.mxbean.*;
+import org.apache.ignite.spi.*;
+import org.apache.ignite.spi.authentication.*;
+import org.apache.ignite.spi.authentication.noop.*;
+import org.apache.ignite.spi.indexing.*;
+import org.apache.ignite.streamer.*;
+import org.apache.ignite.thread.*;
+import org.apache.ignite.internal.processors.resource.*;
+import org.apache.ignite.internal.processors.spring.*;
+import org.apache.ignite.plugin.segmentation.*;
+import org.apache.ignite.spi.checkpoint.*;
+import org.apache.ignite.spi.checkpoint.noop.*;
+import org.apache.ignite.spi.collision.*;
+import org.apache.ignite.spi.collision.noop.*;
+import org.apache.ignite.spi.communication.*;
+import org.apache.ignite.spi.communication.tcp.*;
+import org.apache.ignite.spi.deployment.*;
+import org.apache.ignite.spi.deployment.local.*;
+import org.apache.ignite.spi.discovery.*;
+import org.apache.ignite.spi.discovery.tcp.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.*;
+import org.apache.ignite.spi.eventstorage.*;
+import org.apache.ignite.spi.eventstorage.memory.*;
+import org.apache.ignite.spi.failover.*;
+import org.apache.ignite.spi.failover.always.*;
+import org.apache.ignite.spi.loadbalancing.*;
+import org.apache.ignite.spi.loadbalancing.roundrobin.*;
+import org.apache.ignite.spi.securesession.*;
+import org.apache.ignite.spi.securesession.noop.*;
+import org.apache.ignite.spi.swapspace.*;
+import org.apache.ignite.spi.swapspace.file.*;
+import org.apache.ignite.spi.swapspace.noop.*;
+import org.apache.ignite.internal.util.typedef.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.jdk8.backport.*;
+import org.jetbrains.annotations.*;
+
+import javax.management.*;
+import java.io.*;
+import java.lang.management.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+import java.util.Map.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+import java.util.logging.*;
+
+import static org.apache.ignite.configuration.IgniteConfiguration.*;
+import static org.apache.ignite.IgniteState.*;
+import static org.apache.ignite.IgniteSystemProperties.*;
+import static org.apache.ignite.cache.CacheAtomicityMode.*;
+import static org.apache.ignite.cache.CacheDistributionMode.*;
+import static org.apache.ignite.cache.CacheMode.*;
+import static org.apache.ignite.cache.CachePreloadMode.*;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*;
+import static org.apache.ignite.internal.IgniteComponentType.*;
+import static org.apache.ignite.plugin.segmentation.GridSegmentationPolicy.*;
+
+/**
+ * This class defines a factory for the main GridGain API. It controls Grid life cycle
+ * and allows listening for grid events.
+ * <h1 class="header">Grid Loaders</h1>
+ * Although user can apply grid factory directly to start and stop grid, grid is
+ * often started and stopped by grid loaders. Grid loaders can be found in
+ * {@link org.apache.ignite.startup} package, for example:
+ * <ul>
+ * <li>{@code GridCommandLineStartup}</li>
+ * <li>{@code GridServletStartup}</li>
+ * </ul>
+ * <h1 class="header">Examples</h1>
+ * Use {@link #start()} method to start grid with default configuration. You can also use
+ * {@link org.apache.ignite.configuration.IgniteConfiguration} to override some default configuration. Below is an
+ * example on how to start grid with <strong>URI deployment</strong>.
+ * <pre name="code" class="java">
+ * GridConfiguration cfg = new GridConfiguration();
+ */
+public class IgnitionEx {
+    /** Default configuration path relative to GridGain home. */
+    public static final String DFLT_CFG = "config/default-config.xml";
+
+    /** Map of named grids. */
+    private static final ConcurrentMap<Object, IgniteNamedInstance> grids = new ConcurrentHashMap8<>();
+
+    /** Map of grid states ever started in this JVM. */
+    private static final Map<Object, IgniteState> gridStates = new ConcurrentHashMap8<>();
+
+    /** Mutex to synchronize updates of default grid reference. */
+    private static final Object dfltGridMux = new Object();
+
+    /** Default grid. */
+    private static volatile IgniteNamedInstance dfltGrid;
+
+    /** Default grid state. */
+    private static volatile IgniteState dfltGridState;
+
+    /** List of state listeners. */
+    private static final Collection<IgniteListener> lsnrs = new GridConcurrentHashSet<>(4);
+
+    /** */
+    private static volatile boolean daemon;
+
+    /**
+     * Checks runtime version to be 1.7.x or 1.8.x.
+     * This will load pretty much first so we must do these checks here.
+     */
+    static {
+        // Check 1.8 just in case for forward compatibility.
+        if (!U.jdkVersion().contains("1.7") &&
+            !U.jdkVersion().contains("1.8"))
+            throw new IllegalStateException("GridGain requires Java 7 or above. Current Java version " +
+                "is not supported: " + U.jdkVersion());
+
+        // To avoid nasty race condition in UUID.randomUUID() in JDK prior to 6u34.
+        // For details please see:
+        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7071826
+        // http://www.oracle.com/technetwork/java/javase/2col/6u34-bugfixes-1733379.html
+        // http://hg.openjdk.java.net/jdk6/jdk6/jdk/rev/563d392b3e5c
+        UUID.randomUUID();
+    }
+
+    /**
+     * Enforces singleton.
+     */
+    private IgnitionEx() {
+        // No-op.
+    }
+
+    /**
+     * Sets daemon flag.
+     * <p>
+     * If daemon flag is set then all grid instances created by the factory will be
+     * daemon, i.e. the local node for these instances will be a daemon node. Note that
+     * if daemon flag is set - it will override the same settings in {@link org.apache.ignite.configuration.IgniteConfiguration#isDaemon()}.
+     * Note that you can set on and off daemon flag at will.
+     *
+     * @param daemon Daemon flag to set.
+     */
+    public static void setDaemon(boolean daemon) {
+        IgnitionEx.daemon = daemon;
+    }
+
+    /**
+     * Gets daemon flag.
+     * <p>
+     * If daemon flag it set then all grid instances created by the factory will be
+     * daemon, i.e. the local node for these instances will be a daemon node. Note that
+     * if daemon flag is set - it will override the same settings in {@link org.apache.ignite.configuration.IgniteConfiguration#isDaemon()}.
+     * Note that you can set on and off daemon flag at will.
+     *
+     * @return Daemon flag.
+     */
+    public static boolean isDaemon() {
+        return daemon;
+    }
+
+    /**
+     * Gets state of grid default grid.
+     *
+     * @return Default grid state.
+     */
+    public static IgniteState state() {
+        return state(null);
+    }
+
+    /**
+     * Gets states of named grid. If name is {@code null}, then state of
+     * default no-name grid is returned.
+     *
+     * @param name Grid name. If name is {@code null}, then state of
+     *      default no-name grid is returned.
+     * @return Grid state.
+     */
+    public static IgniteState state(@Nullable String name) {
+        IgniteNamedInstance grid = name != null ? grids.get(name) : dfltGrid;
+
+        if (grid == null) {
+            IgniteState state = name != null ? gridStates.get(name) : dfltGridState;
+
+            return state != null ? state : STOPPED;
+        }
+
+        return grid.state();
+    }
+
+    /**
+     * Stops default grid. This method is identical to {@code G.stop(null, cancel)} apply.
+     * Note that method does not wait for all tasks to be completed.
+     *
+     * @param cancel If {@code true} then all jobs currently executing on
+     *      default grid will be cancelled by calling {@link org.apache.ignite.compute.ComputeJob#cancel()}
+     *      method. Note that just like with {@link Thread#interrupt()}, it is
+     *      up to the actual job to exit from execution
+     * @return {@code true} if default grid instance was indeed stopped,
+     *      {@code false} otherwise (if it was not started).
+     */
+    public static boolean stop(boolean cancel) {
+        return stop(null, cancel);
+    }
+
+    /**
+     * Stops named grid. If {@code cancel} flag is set to {@code true} then
+     * all jobs currently executing on local node will be interrupted. If
+     * grid name is {@code null}, then default no-name grid will be stopped.
+     * If wait parameter is set to {@code true} then grid will wait for all
+     * tasks to be finished.
+     *
+     * @param name Grid name. If {@code null}, then default no-name grid will
+     *      be stopped.
+     * @param cancel If {@code true} then all jobs currently will be cancelled
+     *      by calling {@link org.apache.ignite.compute.ComputeJob#cancel()} method. Note that just like with
+     *      {@link Thread#interrupt()}, it is up to the actual job to exit from
+     *      execution. If {@code false}, then jobs currently running will not be
+     *      canceled. In either case, grid node will wait for completion of all
+     *      jobs running on it before stopping.
+     * @return {@code true} if named grid instance was indeed found and stopped,
+     *      {@code false} otherwise (the instance with given {@code name} was
+     *      not found).
+     */
+    public static boolean stop(@Nullable String name, boolean cancel) {
+        IgniteNamedInstance grid = name != null ? grids.get(name) : dfltGrid;
+
+        if (grid != null && grid.state() == STARTED) {
+            grid.stop(cancel);
+
+            boolean fireEvt;
+
+            if (name != null)
+                fireEvt = grids.remove(name, grid);
+            else {
+                synchronized (dfltGridMux) {
+                    fireEvt = dfltGrid == grid;
+
+                    if (fireEvt)
+                        dfltGrid = null;
+                }
+            }
+
+            if (fireEvt)
+                notifyStateChange(grid.getName(), grid.state());
+
+            return true;
+        }
+
+        // We don't have log at this point...
+        U.warn(null, "Ignoring stopping grid instance that was already stopped or never started: " + name);
+
+        return false;
+    }
+
+    /**
+     * Stops <b>all</b> started grids. If {@code cancel} flag is set to {@code true} then
+     * all jobs currently executing on local node will be interrupted.
+     * If wait parameter is set to {@code true} then grid will wait for all
+     * tasks to be finished.
+     * <p>
+     * <b>Note:</b> it is usually safer and more appropriate to stop grid instances individually
+     * instead of blanket operation. In most cases, the party that started the grid instance
+     * should be responsible for stopping it.
+     *
+     * @param cancel If {@code true} then all jobs currently executing on
+     *      all grids will be cancelled by calling {@link org.apache.ignite.compute.ComputeJob#cancel()}
+     *      method. Note that just like with {@link Thread#interrupt()}, it is
+     *      up to the actual job to exit from execution
+     */
+    public static void stopAll(boolean cancel) {
+        IgniteNamedInstance dfltGrid0 = dfltGrid;
+
+        if (dfltGrid0 != null) {
+            dfltGrid0.stop(cancel);
+
+            boolean fireEvt;
+
+            synchronized (dfltGridMux) {
+                fireEvt = dfltGrid == dfltGrid0;
+
+                if (fireEvt)
+                    dfltGrid = null;
+            }
+
+            if (fireEvt)
+                notifyStateChange(dfltGrid0.getName(), dfltGrid0.state());
+        }
+
+        // Stop the rest and clear grids map.
+        for (IgniteNamedInstance grid : grids.values()) {
+            grid.stop(cancel);
+
+            boolean fireEvt = grids.remove(grid.getName(), grid);
+
+            if (fireEvt)
+                notifyStateChange(grid.getName(), grid.state());
+        }
+    }
+
+    /**
+     * Restarts <b>all</b> started grids. If {@code cancel} flag is set to {@code true} then
+     * all jobs currently executing on the local node will be interrupted.
+     * If {@code wait} parameter is set to {@code true} then grid will wait for all
+     * tasks to be finished.
+     * <p>
+     * <b>Note:</b> it is usually safer and more appropriate to stop grid instances individually
+     * instead of blanket operation. In most cases, the party that started the grid instance
+     * should be responsible for stopping it.
+     * <p>
+     * Note also that restarting functionality only works with the tools that specifically
+     * support GridGain's protocol for restarting. Currently only standard <tt>ggstart.{sh|bat}</tt>
+     * scripts support restarting of JVM GridGain's process.
+     *
+     * @param cancel If {@code true} then all jobs currently executing on
+     *      all grids will be cancelled by calling {@link org.apache.ignite.compute.ComputeJob#cancel()}
+     *      method. Note that just like with {@link Thread#interrupt()}, it is
+     *      up to the actual job to exit from execution.
+     * @see org.apache.ignite.Ignition#RESTART_EXIT_CODE
+     */
+    public static void restart(boolean cancel) {
+        String file = System.getProperty(GG_SUCCESS_FILE);
+
+        if (file == null)
+            U.warn(null, "Cannot restart node when restart not enabled.");
+        else {
+            try {
+                new File(file).createNewFile();
+            }
+            catch (IOException e) {
+                U.error(null, "Failed to create restart marker file (restart aborted): " + e.getMessage());
+
+                return;
+            }
+
+            U.log(null, "Restarting node. Will exit (" + Ignition.RESTART_EXIT_CODE + ").");
+
+            // Set the exit code so that shell process can recognize it and loop
+            // the start up sequence again.
+            System.setProperty(GG_RESTART_CODE, Integer.toString(Ignition.RESTART_EXIT_CODE));
+
+            stopAll(cancel);
+
+            // This basically leaves loaders hang - we accept it.
+            System.exit(Ignition.RESTART_EXIT_CODE);
+        }
+    }
+
+    /**
+     * Stops <b>all</b> started grids. If {@code cancel} flag is set to {@code true} then
+     * all jobs currently executing on the local node will be interrupted.
+     * If {@code wait} parameter is set to {@code true} then grid will wait for all
+     * tasks to be finished.
+     * <p>
+     * <b>Note:</b> it is usually safer and more appropriate to stop grid instances individually
+     * instead of blanket operation. In most cases, the party that started the grid instance
+     * should be responsible for stopping it.
+     * <p>
+     * Note that upon completion of this method, the JVM with forcefully exist with
+     * exit code {@link org.apache.ignite.Ignition#KILL_EXIT_CODE}.
+     *
+     * @param cancel If {@code true} then all jobs currently executing on
+     *      all grids will be cancelled by calling {@link org.apache.ignite.compute.ComputeJob#cancel()}
+     *      method. Note that just like with {@link Thread#interrupt()}, it is
+     *      up to the actual job to exit from execution.
+     * @see org.apache.ignite.Ignition#KILL_EXIT_CODE
+     */
+    public static void kill(boolean cancel) {
+        stopAll(cancel);
+
+        // This basically leaves loaders hang - we accept it.
+        System.exit(Ignition.KILL_EXIT_CODE);
+    }
+
+    /**
+     * Starts grid with default configuration. By default this method will
+     * use grid configuration defined in {@code GRIDGAIN_HOME/config/default-config.xml}
+     * configuration file. If such file is not found, then all system defaults will be used.
+     *
+     * @return Started grid.
+     * @throws IgniteCheckedException If default grid could not be started. This exception will be thrown
+     *      also if default grid has already been started.
+     */
+    public static Ignite start() throws IgniteCheckedException {
+        return start((GridSpringResourceContext)null);
+    }
+
+    /**
+     * Starts grid with default configuration. By default this method will
+     * use grid configuration defined in {@code GRIDGAIN_HOME/config/default-config.xml}
+     * configuration file. If such file is not found, then all system defaults will be used.
+     *
+     * @param springCtx Optional Spring application context, possibly {@code null}.
+     *      Spring bean definitions for bean injection are taken from this context.
+     *      If provided, this context can be injected into grid tasks and grid jobs using
+     *      {@link org.apache.ignite.resources.IgniteSpringApplicationContextResource @IgniteSpringApplicationContextResource} annotation.
+     * @return Started grid.
+     * @throws IgniteCheckedException If default grid could not be started. This exception will be thrown
+     *      also if default grid has already been started.
+     */
+    public static Ignite start(@Nullable GridSpringResourceContext springCtx) throws IgniteCheckedException {
+        URL url = U.resolveGridGainUrl(DFLT_CFG);
+
+        if (url != null)
+            return start(DFLT_CFG, null, springCtx);
+
+        U.warn(null, "Default Spring XML file not found (is GRIDGAIN_HOME set?): " + DFLT_CFG);
+
+        return start0(new GridStartContext(new IgniteConfiguration(), null, springCtx)).grid();
+    }
+
+    /**
+     * Starts grid with given configuration. Note that this method is no-op if grid with the name
+     * provided in given configuration is already started.
+     *
+     * @param cfg Grid configuration. This cannot be {@code null}.
+     * @return Started grid.
+     * @throws IgniteCheckedException If grid could not be started. This exception will be thrown
+     *      also if named grid has already been started.
+     */
+    public static Ignite start(IgniteConfiguration cfg) throws IgniteCheckedException {
+        return start(cfg, null);
+    }
+
+    /**
+     * Starts grid with given configuration. Note that this method is no-op if grid with the name
+     * provided in given configuration is already started.
+     *
+     * @param cfg Grid configuration. This cannot be {@code null}.
+     * @param springCtx Optional Spring application context, possibly {@code null}.
+     *      Spring bean definitions for bean injection are taken from this context.
+     *      If provided, this context can be injected into grid tasks and grid jobs using
+     *      {@link org.apache.ignite.resources.IgniteSpringApplicationContextResource @IgniteSpringApplicationContextResource} annotation.
+     * @return Started grid.
+     * @throws IgniteCheckedException If grid could not be started. This exception will be thrown
+     *      also if named grid has already been started.
+     */
+    public static Ignite start(IgniteConfiguration cfg, @Nullable GridSpringResourceContext springCtx) throws IgniteCheckedException {
+        A.notNull(cfg, "cfg");
+
+        return start0(new GridStartContext(cfg, null, springCtx)).grid();
+    }
+
+    /**
+     * Starts all grids specified within given Spring XML configuration file. If grid with given name
+     * is already started, then exception is thrown. In this case all instances that may
+     * have been started so far will be stopped too.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgPath Spring XML configuration file path or URL.
+     * @return Started grid. If Spring configuration contains multiple grid instances,
+     *      then the 1st found instance is returned.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static Ignite start(@Nullable String springCfgPath) throws IgniteCheckedException {
+        return springCfgPath == null ? start() : start(springCfgPath, null);
+    }
+
+    /**
+     * Starts all grids specified within given Spring XML configuration file. If grid with given name
+     * is already started, then exception is thrown. In this case all instances that may
+     * have been started so far will be stopped too.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgPath Spring XML configuration file path or URL.
+     * @param gridName Grid name that will override default.
+     * @return Started grid. If Spring configuration contains multiple grid instances,
+     *      then the 1st found instance is returned.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static Ignite start(@Nullable String springCfgPath, @Nullable String gridName) throws IgniteCheckedException {
+        if (springCfgPath == null) {
+            IgniteConfiguration cfg = new IgniteConfiguration();
+
+            if (cfg.getGridName() == null && !F.isEmpty(gridName))
+                cfg.setGridName(gridName);
+
+            return start(cfg);
+        }
+        else
+            return start(springCfgPath, gridName, null);
+    }
+
+    /**
+     * Start Grid for interop scenario.
+     *
+     * @param springCfgPath Spring config path.
+     * @param gridName Grid name.
+     * @param cfgClo Configuration closure.
+     * @return Started Grid.
+     * @throws IgniteCheckedException If failed.
+     */
+    public static Ignite startInterop(@Nullable String springCfgPath, @Nullable String gridName,
+        IgniteClosure<IgniteConfiguration, IgniteConfiguration> cfgClo) throws IgniteCheckedException {
+        URL url = resolveSpringUrl(springCfgPath);
+
+        return start(url, gridName, null, cfgClo);
+    }
+
+    /**
+     * Loads all grid configurations specified within given Spring XML configuration file.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgUrl Spring XML configuration file path or URL. This cannot be {@code null}.
+     * @return Tuple containing all loaded configurations and Spring context used to load them.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> loadConfigurations(
+        URL springCfgUrl) throws IgniteCheckedException {
+        IgniteSpringProcessor spring = SPRING.create(false);
+
+        return spring.loadConfigurations(springCfgUrl);
+    }
+
+    /**
+     * Loads all grid configurations specified within given Spring XML configuration file.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgPath Spring XML configuration file path. This cannot be {@code null}.
+     * @return Tuple containing all loaded configurations and Spring context used to load them.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> loadConfigurations(
+        String springCfgPath) throws IgniteCheckedException {
+        A.notNull(springCfgPath, "springCfgPath");
+
+        URL url;
+
+        try {
+            url = new URL(springCfgPath);
+        }
+        catch (MalformedURLException e) {
+            url = U.resolveGridGainUrl(springCfgPath);
+
+            if (url == null)
+                throw new IgniteCheckedException("Spring XML configuration path is invalid: " + springCfgPath +
+                    ". Note that this path should be either absolute or a relative local file system path, " +
+                    "relative to META-INF in classpath or valid URL to GRIDGAIN_HOME.", e);
+        }
+
+        return loadConfigurations(url);
+    }
+
+    /**
+     * Loads first found grid configuration specified within given Spring XML configuration file.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgUrl Spring XML configuration file path or URL. This cannot be {@code null}.
+     * @return First found configuration and Spring context used to load it.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static IgniteBiTuple<IgniteConfiguration, GridSpringResourceContext> loadConfiguration(URL springCfgUrl)
+        throws IgniteCheckedException {
+        IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> t = loadConfigurations(springCfgUrl);
+
+        return F.t(F.first(t.get1()), t.get2());
+    }
+
+    /**
+     * Loads first found grid configuration specified within given Spring XML configuration file.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgPath Spring XML configuration file path. This cannot be {@code null}.
+     * @return First found configuration and Spring context used to load it.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static IgniteBiTuple<IgniteConfiguration, GridSpringResourceContext> loadConfiguration(String springCfgPath)
+        throws IgniteCheckedException {
+        IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> t =
+            loadConfigurations(springCfgPath);
+
+        return F.t(F.first(t.get1()), t.get2());
+    }
+
+    /**
+     * Starts all grids specified within given Spring XML configuration file. If grid with given name
+     * is already started, then exception is thrown. In this case all instances that may
+     * have been started so far will be stopped too.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgPath Spring XML configuration file path or URL. This cannot be {@code null}.
+     * @param gridName Grid name that will override default.
+     * @param springCtx Optional Spring application context, possibly {@code null}.
+     *      Spring bean definitions for bean injection are taken from this context.
+     *      If provided, this context can be injected into grid tasks and grid jobs using
+     *      {@link org.apache.ignite.resources.IgniteSpringApplicationContextResource @IgniteSpringApplicationContextResource} annotation.
+     * @return Started grid. If Spring configuration contains multiple grid instances,
+     *      then the 1st found instance is returned.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static Ignite start(String springCfgPath, @Nullable String gridName,
+        @Nullable GridSpringResourceContext springCtx) throws IgniteCheckedException {
+        URL url = resolveSpringUrl(springCfgPath);
+
+        return start(url, gridName, springCtx);
+    }
+
+    /**
+     * Starts all grids specified within given Spring XML configuration file URL. If grid with given name
+     * is already started, then exception is thrown. In this case all instances that may
+     * have been started so far will be stopped too.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgUrl Spring XML configuration file URL. This cannot be {@code null}.
+     * @return Started grid. If Spring configuration contains multiple grid instances,
+     *      then the 1st found instance is returned.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static Ignite start(URL springCfgUrl) throws IgniteCheckedException {
+        return start(springCfgUrl, null, null);
+    }
+
+    /**
+     * Starts all grids specified within given Spring XML configuration file URL. If grid with given name
+     * is already started, then exception is thrown. In this case all instances that may
+     * have been started so far will be stopped too.
+     * <p>
+     * Usually Spring XML configuration file will contain only one Grid definition. Note that
+     * Grid configuration bean(s) is retrieved form configuration file by type, so the name of
+     * the Grid configuration bean is ignored.
+     *
+     * @param springCfgUrl Spring XML configuration file URL. This cannot be {@code null}.
+     * @param gridName Grid name that will override default.
+     * @param springCtx Optional Spring application context, possibly {@code null}.
+     *      Spring bean definitions for bean injection are taken from this context.
+     *      If provided, this context can be injected into grid tasks and grid jobs using
+     *      {@link org.apache.ignite.resources.IgniteSpringApplicationContextResource @IgniteSpringApplicationContextResource} annotation.
+     * @return Started grid. If Spring configuration contains multiple grid instances,
+     *      then the 1st found instance is returned.
+     * @throws IgniteCheckedException If grid could not be started or configuration
+     *      read. This exception will be thrown also if grid with given name has already
+     *      been started or Spring XML configuration file is invalid.
+     */
+    public static Ignite start(URL springCfgUrl, @Nullable String gridName,
+        @Nullable GridSpringResourceContext springCtx) throws IgniteCheckedException {
+        return start(springCfgUrl, gridName, springCtx, null);
+    }
+
+    /**
+     * Internal Spring-based start routine.
+     *
+     * @param springCfgUrl Spring XML configuration file URL. This cannot be {@code null}.
+     * @param gridName Grid name that will override default.
+     * @param springCtx Optional Spring application context.
+     * @param cfgClo Optional closure to change configuration before it is used to start the grid.
+     * @return Started grid.
+     * @throws IgniteCheckedException If failed.
+     */
+    private static Ignite start(URL springCfgUrl, @Nullable String gridName,
+        @Nullable GridSpringResourceContext springCtx,
+        @Nullable IgniteClosure<IgniteConfiguration, IgniteConfiguration> cfgClo)
+        throws IgniteCheckedException {
+        A.notNull(springCfgUrl, "springCfgUrl");
+
+        boolean isLog4jUsed = U.gridClassLoader().getResource("org/apache/log4j/Appender.class") != null;
+
+        IgniteBiTuple<Object, Object> t = null;
+
+        Collection<Handler> savedHnds = null;
+
+        if (isLog4jUsed)
+            t = U.addLog4jNoOpLogger();
+        else
+            savedHnds = U.addJavaNoOpLogger();
+
+        IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> cfgMap;
+
+        try {
+            cfgMap = loadConfigurations(springCfgUrl);
+        }
+        finally {
+            if (isLog4jUsed && t != null)
+                U.removeLog4jNoOpLogger(t);
+
+            if (!isLog4jUsed)
+                U.removeJavaNoOpLogger(savedHnds);
+        }
+
+        List<IgniteNamedInstance> grids = new ArrayList<>(cfgMap.size());
+
+        try {
+            for (IgniteConfiguration cfg : cfgMap.get1()) {
+                assert cfg != null;
+
+                if (cfg.getGridName() == null && !F.isEmpty(gridName))
+                    cfg.setGridName(gridName);
+
+                if (cfgClo != null) {
+                    cfg = cfgClo.apply(cfg);
+
+                    assert cfg != null;
+                }
+
+                // Use either user defined context or our one.
+                IgniteNamedInstance grid = start0(
+                    new GridStartContext(cfg, springCfgUrl, springCtx == null ? cfgMap.get2() : springCtx));
+
+                // Add it if it was not stopped during startup.
+                if (grid != null)
+                    grids.add(grid);
+            }
+        }
+        catch (IgniteCheckedException e) {
+            // Stop all instances started so far.
+            for (IgniteNamedInstance grid : grids) {
+                try {
+                    grid.stop(true);
+                }
+                catch (Exception e1) {
+                    U.error(grid.log, "Error when stopping grid: " + grid, e1);
+                }
+            }
+
+            throw e;
+        }
+
+        // Return the first grid started.
+        IgniteNamedInstance res = !grids.isEmpty() ? grids.get(0) : null;
+
+        return res != null ? res.grid() : null;
+    }
+
+    /**
+     * Resolve Spring configuration URL.
+     *
+     * @param springCfgPath Spring XML configuration file path or URL. This cannot be {@code null}.
+     * @return URL.
+     * @throws IgniteCheckedException If failed.
+     */
+    private static URL resolveSpringUrl(String springCfgPath) throws IgniteCheckedException {
+        A.notNull(springCfgPath, "springCfgPath");
+
+        URL url;
+
+        try {
+            url = new URL(springCfgPath);
+        }
+        catch (MalformedURLException e) {
+            url = U.resolveGridGainUrl(springCfgPath);
+
+            if (url == null)
+                throw new IgniteCheckedException("Spring XML configuration path is invalid: " + springCfgPath +
+                    ". Note that this path should be either absolute or a relative local file system path, " +
+                    "relative to META-INF in classpath or valid URL to GRIDGAIN_HOME.", e);
+        }
+
+        return url;
+    }
+
+    /**
+     * Starts grid with given configuration.
+     *
+     * @param startCtx Start context.
+     * @return Started grid.
+     * @throws IgniteCheckedException If grid could not be started.
+     */
+    private static IgniteNamedInstance start0(GridStartContext startCtx) throws IgniteCheckedException {
+        assert startCtx != null;
+
+        String name = startCtx.config().getGridName();
+
+        if (name != null && name.isEmpty())
+            throw new IgniteCheckedException("Non default grid instances cannot have empty string name.");
+
+        IgniteNamedInstance grid = new IgniteNamedInstance(name);
+
+        IgniteNamedInstance old;
+
+        if (name != null)
+            old = grids.putIfAbsent(name, grid);
+        else {
+            synchronized (dfltGridMux) {
+                old = dfltGrid;
+
+                if (old == null)
+                    dfltGrid = grid;
+            }
+        }
+
+        if (old != null) {
+            if (name == null)
+                throw new IgniteCheckedException("Default grid instance has already been started.");
+            else
+                throw new IgniteCheckedException("Grid instance with this name has already been started: " + name);
+        }
+
+        if (startCtx.config().getWarmupClosure() != null)
+            startCtx.config().getWarmupClosure().apply(startCtx.config());
+
+        startCtx.single(grids.size() == 1);
+
+        boolean success = false;
+
+        try {
+            grid.start(startCtx);
+
+            notifyStateChange(name, STARTED);
+
+            success = true;
+        }
+        finally {
+            if (!success) {
+                if (name != null)
+                    grids.remove(name, grid);
+                else {
+                    synchronized (dfltGridMux) {
+                        if (dfltGrid == grid)
+                            dfltGrid = null;
+                    }
+                }
+
+                grid = null;
+            }
+        }
+
+        if (grid == null)
+            throw new IgniteCheckedException("Failed to start grid with provided configuration.");
+
+        return grid;
+    }
+
+    /**
+     * Gets an instance of default no-name grid. Note that
+     * caller of this method should not assume that it will return the same
+     * instance every time.
+     * <p>
+     * This method is identical to {@code G.grid(null)} apply.
+     *
+     * @return An instance of default no-name grid. This method never returns
+     *      {@code null}.
+     * @throws org.apache.ignite.IgniteIllegalStateException Thrown if default grid was not properly
+     *      initialized or grid instance was stopped or was not started.
+     */
+    public static Ignite grid() throws IgniteIllegalStateException {
+        return grid((String)null);
+    }
+
+    /**
+     * Gets a list of all grids started so far.
+     *
+     * @return List of all grids started so far.
+     */
+    public static List<Ignite> allGrids() {
+        List<Ignite> allIgnites = new ArrayList<>(grids.size() + 1);
+
+        for (IgniteNamedInstance grid : grids.values()) {
+            Ignite g = grid.grid();
+
+            if (g != null)
+                allIgnites.add(g);
+        }
+
+        IgniteNamedInstance dfltGrid0 = dfltGrid;
+
+        if (dfltGrid0 != null) {
+            IgniteKernal g = dfltGrid0.grid();
+
+            if (g != null)
+                allIgnites.add(g);
+        }
+
+        return allIgnites;
+    }
+
+    /**
+     * Gets a grid instance for given local node ID. Note that grid instance and local node have
+     * one-to-one relationship where node has ID and instance has name of the grid to which
+     * both grid instance and its node belong. Note also that caller of this method
+     * should not assume that it will return the same instance every time.
+     *
+     * @param locNodeId ID of local node the requested grid instance is managing.
+     * @return An instance of named grid. This method never returns
+     *      {@code null}.
+     * @throws org.apache.ignite.IgniteIllegalStateException Thrown if grid was not properly
+     *      initialized or grid instance was stopped or was not started.
+     */
+    public static Ignite grid(UUID locNodeId) throws IgniteIllegalStateException {
+        A.notNull(locNodeId, "locNodeId");
+
+        IgniteNamedInstance dfltGrid0 = dfltGrid;
+
+        if (dfltGrid0 != null) {
+            IgniteKernal g = dfltGrid0.grid();
+
+            if (g != null && g.getLocalNodeId().equals(locNodeId))
+                return g;
+        }
+
+        for (IgniteNamedInstance grid : grids.values()) {
+            IgniteKernal g = grid.grid();
+
+            if (g != null && g.getLocalNodeId().equals(locNodeId))
+                return g;
+        }
+
+        throw new IgniteIllegalStateException("Grid instance with given local node ID was not properly " +
+            "started or was stopped: " + locNodeId);
+    }
+
+    /**
+     * Gets an named grid instance. If grid name is {@code null} or empty string,
+     * then default no-name grid will be returned. Note that caller of this method
+     * should not assume that it will return the same instance every time.
+     * <p>
+     * Note that Java VM can run multiple grid instances and every grid instance (and its
+     * node) can belong to a different grid. Grid name defines what grid a particular grid
+     * instance (and correspondingly its node) belongs to.
+     *
+     * @param name Grid name to which requested grid instance belongs to. If {@code null},
+     *      then grid instance belonging to a default no-name grid will be returned.
+     * @return An instance of named grid. This method never returns
+     *      {@code null}.
+     * @throws org.apache.ignite.IgniteIllegalStateException Thrown if default grid was not properly
+     *      initialized or grid instance was stopped or was not started.
+     */
+    public static Ignite grid(@Nullable String name) throws IgniteIllegalStateException {
+        IgniteNamedInstance grid = name != null ? grids.get(name) : dfltGrid;
+
+        Ignite res;
+
+        if (grid == null || (res = grid.grid()) == null)
+            throw new IgniteIllegalStateException("Grid instance was not properly started " +
+                "or was already stopped: " + name);
+
+        return res;
+    }
+
+    /**
+     * Gets grid instance without waiting its initialization.
+     *
+     * @param name Grid name.
+     * @return Grid instance.
+     */
+    public static IgniteKernal gridx(@Nullable String name) {
+        IgniteNamedInstance grid = name != null ? grids.get(name) : dfltGrid;
+
+        IgniteKernal res;
+
+        if (grid == null || (res = grid.gridx()) == null)
+            throw new IllegalStateException("Grid instance was not properly started or was already stopped: " + name);
+
+        return res;
+    }
+
+    /**
+     * Adds a lsnr for grid life cycle events.
+     * <p>
+     * Note that unlike other listeners in GridGain this listener will be
+     * notified from the same thread that triggers the state change. Because of
+     * that it is the responsibility of the user to make sure that listener logic
+     * is light-weight and properly handles (catches) any runtime exceptions, if any
+     * are expected.
+     *
+     * @param lsnr Listener for grid life cycle events. If this listener was already added
+     *      this method is no-op.
+     */
+    public static void addListener(IgniteListener lsnr) {
+        A.notNull(lsnr, "lsnr");
+
+        lsnrs.add(lsnr);
+    }
+
+    /**
+     * Removes lsnr added by {@link #addListener(org.apache.ignite.lifecycle.IgniteListener)} method.
+     *
+     * @param lsnr Listener to remove.
+     * @return {@code true} if lsnr was added before, {@code false} otherwise.
+     */
+    public static boolean removeListener(IgniteListener lsnr) {
+        A.notNull(lsnr, "lsnr");
+
+        return lsnrs.remove(lsnr);
+    }
+
+    /**
+     * @param gridName Grid instance name.
+     * @param state Factory state.
+     */
+    private static void notifyStateChange(@Nullable String gridName, IgniteState state) {
+        if (gridName != null)
+            gridStates.put(gridName, state);
+        else
+            dfltGridState = state;
+
+        for (IgniteListener lsnr : lsnrs)
+            lsnr.onStateChange(gridName, state);
+    }
+
+    /**
+     * Start context encapsulates all starting parameters.
+     */
+    private static final class GridStartContext {
+        /** User-defined configuration. */
+        private IgniteConfiguration cfg;
+
+        /** Optional configuration path. */
+        private URL cfgUrl;
+
+        /** Optional Spring application context. */
+        private GridSpringResourceContext springCtx;
+
+        /** Whether or not this is a single grid instance in current VM. */
+        private boolean single;
+
+        /**
+         *
+         * @param cfg User-defined configuration.
+         * @param cfgUrl Optional configuration path.
+         * @param springCtx Optional Spring application context.
+         */
+        GridStartContext(IgniteConfiguration cfg, @Nullable URL cfgUrl, @Nullable GridSpringResourceContext springCtx) {
+            assert(cfg != null);
+
+            this.cfg = cfg;
+            this.cfgUrl = cfgUrl;
+            this.springCtx = springCtx;
+        }
+
+        /**
+         * @return Whether or not this is a single grid instance in current VM.
+         */
+        public boolean single() {
+            return single;
+        }
+
+        /**
+         * @param single Whether or not this is a single grid instance in current VM.
+         */
+        public void single(boolean single) {
+            this.single = single;
+        }
+
+        /**
+         * @return User-defined configuration.
+         */
+        IgniteConfiguration config() {
+            return cfg;
+        }
+
+        /**
+         * @param cfg User-defined configuration.
+         */
+        void config(IgniteConfiguration cfg) {
+            this.cfg = cfg;
+        }
+
+        /**
+         * @return Optional configuration path.
+         */
+        URL configUrl() {
+            return cfgUrl;
+        }
+
+        /**
+         * @param cfgUrl Optional configuration path.
+         */
+        void configUrl(URL cfgUrl) {
+            this.cfgUrl = cfgUrl;
+        }
+
+        /**
+         * @return Optional Spring application context.
+         */
+        public GridSpringResourceContext springContext() {
+            return springCtx;
+        }
+    }
+
+    /**
+     * Grid data container.
+     */
+    private static final class IgniteNamedInstance {
+        /** Map of registered MBeans. */
+        private static final Map<MBeanServer, GridMBeanServerData> mbeans =
+            new HashMap<>();
+
+        /** */
+        private static final String[] EMPTY_STR_ARR = new String[0];
+
+        /** Empty array of caches. */
+        private static final CacheConfiguration[] EMPTY_CACHE_CONFIGS = new CacheConfiguration[0];
+
+        /** Grid name. */
+        private final String name;
+
+        /** Grid instance. */
+        private volatile IgniteKernal grid;
+
+        /** Executor service. */
+        private ExecutorService execSvc;
+
+        /** Auto executor service flag. */
+        private boolean isAutoExecSvc;
+
+        /** Executor service shutdown flag. */
+        private boolean execSvcShutdown;
+
+        /** System executor service. */
+        private ExecutorService sysExecSvc;
+
+        /** Auto system service flag. */
+        private boolean isAutoSysSvc;
+
+        /** System executor service shutdown flag. */
+        private boolean sysSvcShutdown;
+
+        /** Management executor service. */
+        private ExecutorService mgmtExecSvc;
+
+        /** Auto management service flag. */
+        private boolean isAutoMgmtSvc;
+
+        /** Management executor service shutdown flag. */
+        private boolean mgmtSvcShutdown;
+
+        /** P2P executor service. */
+        private ExecutorService p2pExecSvc;
+
+        /** Auto P2P service flag. */
+        private boolean isAutoP2PSvc;
+
+        /** P2P executor service shutdown flag. */
+        private boolean p2pSvcShutdown;
+
+        /** GGFS executor service. */
+        private ExecutorService ggfsExecSvc;
+
+        /** Auto GGFS service flag. */
+        private boolean isAutoGgfsSvc;
+
+        /** GGFS executor service shutdown flag. */
+        private boolean ggfsSvcShutdown;
+
+        /** REST requests executor service. */
+        private ExecutorService restExecSvc;
+
+        /** Auto REST service flag. */
+        private boolean isAutoRestSvc;
+
+        /** REST executor service shutdown flag. */
+        private boolean restSvcShutdown;
+
+        /** Utility cache executor service. */
+        private ExecutorService utilityCacheExecSvc;
+
+        /** Grid state. */
+        private volatile IgniteState state = STOPPED;
+
+        /** Shutdown hook. */
+        private Thread shutdownHook;
+
+        /** Grid log. */
+        private IgniteLogger log;
+
+        /** Start guard. */
+        private final AtomicBoolean startGuard = new AtomicBoolean();
+
+        /** Start latch. */
+        private final CountDownLatch startLatch = new CountDownLatch(1);
+
+        /**
+         * Thread that starts this named instance. This field can be non-volatile since
+         * it makes sense only for thread where it was originally initialized.
+         */
+        @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
+        private Thread starterThread;
+
+        /**
+         * Creates un-started named instance.
+         *
+         * @param name Grid name (possibly {@code null} for default grid).
+         */
+        IgniteNamedInstance(@Nullable String name) {
+            this.name = name;
+        }
+
+        /**
+         * Gets grid name.
+         *
+         * @return Grid name.
+         */
+        String getName() {
+            return name;
+        }
+
+        /**
+         * Gets grid instance.
+         *
+         * @return Grid instance.
+         */
+        IgniteKernal grid() {
+            if (starterThread != Thread.currentThread())
+                U.awaitQuiet(startLatch);
+
+            return grid;
+        }
+
+        /**
+         * Gets grid instance without waiting for its initialization.
+         *
+         * @return Grid instance.
+         */
+        public IgniteKernal gridx() {
+            return grid;
+        }
+
+        /**
+         * Gets grid state.
+         *
+         * @return Grid state.
+         */
+        IgniteState state() {
+            if (starterThread != Thread.currentThread())
+                U.awaitQuiet(startLatch);
+
+            return state;
+        }
+
+        /**
+         * @param spi SPI implementation.
+         * @throws IgniteCheckedException Thrown in case if multi-instance is not supported.
+         */
+        private void ensureMultiInstanceSupport(IgniteSpi spi) throws IgniteCheckedException {
+            IgniteSpiMultipleInstancesSupport ann = U.getAnnotation(spi.getClass(),
+                IgniteSpiMultipleInstancesSupport.class);
+
+            if (ann == null || !ann.value())
+                throw new IgniteCheckedException("SPI implementation doesn't support multiple grid instances in " +
+                    "the same VM: " + spi);
+        }
+
+        /**
+         * @param spis SPI implementations.
+         * @throws IgniteCheckedException Thrown in case if multi-instance is not supported.
+         */
+        private void ensureMultiInstanceSupport(IgniteSpi[] spis) throws IgniteCheckedException {
+            for (IgniteSpi spi : spis)
+                ensureMultiInstanceSupport(spi);
+        }
+
+        /**
+         * Starts grid with given configuration.
+         *
+         * @param startCtx Starting context.
+         * @throws IgniteCheckedException If start failed.
+         */
+        synchronized void start(GridStartContext startCtx) throws IgniteCheckedException {
+            if (startGuard.compareAndSet(false, true)) {
+                try {
+                    starterThread = Thread.currentThread();
+
+                    start0(startCtx);
+                }
+                catch (Exception e) {
+                    if (log != null)
+                        stopExecutors(log);
+
+                    throw e;
+                }
+                finally {
+                    startLatch.countDown();
+                }
+            }
+            else
+                U.awaitQuiet(startLatch);
+        }
+
+        /**
+         * @param startCtx Starting context.
+         * @throws IgniteCheckedException If start failed.
+         */
+        @SuppressWarnings({"unchecked", "TooBroadScope"})
+        private void start0(GridStartContext startCtx) throws IgniteCheckedException {
+            assert grid == null : "Grid is already started: " + name;
+
+            IgniteConfiguration cfg = startCtx.config();
+
+            if (cfg == null)
+                cfg = new IgniteConfiguration();
+
+            IgniteConfiguration myCfg = new IgniteConfiguration();
+
+            String ggHome = cfg.getGridGainHome();
+
+            // Set GridGain home.
+            if (ggHome == null)
+                ggHome = U.getGridGainHome();
+            else
+                // If user provided GRIDGAIN_HOME - set it as a system property.
+                U.setGridGainHome(ggHome);
+
+            U.setWorkDirectory(cfg.getWorkDirectory(), ggHome);
+
+            /*
+             * Set up all defaults and perform all checks.
+             */
+
+            // Ensure invariant.
+            // It's a bit dirty - but this is a result of late refactoring
+            // and I don't want to reshuffle a lot of code.
+            assert F.eq(name, cfg.getGridName());
+
+            // Set configuration URL, if any, into system property.
+            if (startCtx.configUrl() != null)
+                System.setProperty(GG_CONFIG_URL, startCtx.configUrl().toString());
+
+            myCfg.setGridName(cfg.getGridName());
+
+            UUID nodeId = cfg.getNodeId();
+
+            if (nodeId == null)
+                nodeId = UUID.randomUUID();
+
+            IgniteLogger cfgLog = initLogger(cfg.getGridLogger(), nodeId);
+
+            assert cfgLog != null;
+
+            cfgLog = new GridLoggerProxy(cfgLog, null, name, U.id8(nodeId));
+
+            // Initialize factory's log.
+            log = cfgLog.getLogger(G.class);
+
+            // Check GridGain home folder (after log is available).
+            if (ggHome != null) {
+                File ggHomeFile = new File(ggHome);
+
+                if (!ggHomeFile.exists() || !ggHomeFile.isDirectory())
+                    throw new IgniteCheckedException("Invalid GridGain installation home folder: " + ggHome);
+            }
+
+            myCfg.setGridGainHome(ggHome);
+
+            // Copy values that don't need extra processing.
+            myCfg.setLicenseUrl(cfg.getLicenseUrl());
+            myCfg.setPeerClassLoadingEnabled(cfg.isPeerClassLoadingEnabled());
+            myCfg.setDeploymentMode(cfg.getDeploymentMode());
+            myCfg.setNetworkTimeout(cfg.getNetworkTimeout());
+            myCfg.setClockSyncSamples(cfg.getClockSyncSamples());
+            myCfg.setClockSyncFrequency(cfg.getClockSyncFrequency());
+            myCfg.setDiscoveryStartupDelay(cfg.getDiscoveryStartupDelay());
+            myCfg.setMetricsHistorySize(cfg.getMetricsHistorySize());
+            myCfg.setMetricsExpireTime(cfg.getMetricsExpireTime());
+            myCfg.setMetricsUpdateFrequency(cfg.getMetricsUpdateFrequency());
+            myCfg.setLifecycleBeans(cfg.getLifecycleBeans());
+            myCfg.setLocalEventListeners(cfg.getLocalEventListeners());
+            myCfg.setPeerClassLoadingMissedResourcesCacheSize(cfg.getPeerClassLoadingMissedResourcesCacheSize());
+            myCfg.setIncludeEventTypes(cfg.getIncludeEventTypes());
+            myCfg.setDaemon(cfg.isDaemon());
+            myCfg.setIncludeProperties(cfg.getIncludeProperties());
+            myCfg.setLifeCycleEmailNotification(cfg.isLifeCycleEmailNotification());
+            myCfg.setMetricsLogFrequency(cfg.getMetricsLogFrequency());
+            myCfg.setNetworkSendRetryDelay(cfg.getNetworkSendRetryDelay());
+            myCfg.setNetworkSendRetryCount(cfg.getNetworkSendRetryCount());
+            myCfg.setSecurityCredentialsProvider(cfg.getSecurityCredentialsProvider());
+            myCfg.setServiceConfiguration(cfg.getServiceConfiguration());
+            myCfg.setWarmupClosure(cfg.getWarmupClosure());
+            myCfg.setInteropConfiguration(cfg.getInteropConfiguration());
+            myCfg.setPluginConfigurations(cfg.getPluginConfigurations());
+            myCfg.setTransactionsConfiguration(new TransactionsConfiguration(cfg.getTransactionsConfiguration()));
+            myCfg.setQueryConfiguration(cfg.getQueryConfiguration());
+
+            ClientConnectionConfiguration clientCfg = cfg.getClientConnectionConfiguration();
+
+            if (clientCfg == null) {
+                // If client config is not provided then create config copying values from GridConfiguration.
+                if (cfg.isRestEnabled()) {
+                    clientCfg = new ClientConnectionConfiguration();
+
+                    clientCfg.setClientMessageInterceptor(cfg.getClientMessageInterceptor());
+                    clientCfg.setRestAccessibleFolders(cfg.getRestAccessibleFolders());
+                    clientCfg.setRestExecutorService(cfg.getRestExecutorService());
+                    clientCfg.setRestExecutorServiceShutdown(cfg.getRestExecutorServiceShutdown());
+                    clientCfg.setRestIdleTimeout(cfg.getRestIdleTimeout());
+                    clientCfg.setRestJettyPath(cfg.getRestJettyPath());
+                    clientCfg.setRestPortRange(cfg.getRestPortRange());
+                    clientCfg.setRestSecretKey(cfg.getRestSecretKey());
+                    clientCfg.setRestTcpDirectBuffer(cfg.isRestTcpDirectBuffer());
+                    clientCfg.setRestTcpHost(cfg.getRestTcpHost());
+                    clientCfg.setRestTcpNoDelay(cfg.isRestTcpNoDelay());
+                    clientCfg.setRestTcpPort(cfg.getRestTcpPort());
+                    clientCfg.setRestTcpReceiveBufferSize(cfg.getRestTcpReceiveBufferSize());
+                    clientCfg.setRestTcpSelectorCount(cfg.getRestTcpSelectorCount());
+                    clientCfg.setRestTcpSendBufferSize(cfg.getRestTcpSendBufferSize());
+                    clientCfg.setRestTcpSendQueueLimit(cfg.getRestTcpSendQueueLimit());
+                    clientCfg.setRestTcpSslClientAuth(cfg.isRestTcpSslClientAuth());
+                    clientCfg.setRestTcpSslContextFactory(cfg.getRestTcpSslContextFactory());
+                    clientCfg.setRestTcpSslEnabled(cfg.isRestTcpSslEnabled());
+                }
+            }
+            else
+                clientCfg = new ClientConnectionConfiguration(clientCfg);
+
+
+            String ntfStr = IgniteSystemProperties.getString(GG_LIFECYCLE_EMAIL_NOTIFY);
+
+            if (ntfStr != null)
+                myCfg.setLifeCycleEmailNotification(Boolean.parseBoolean(ntfStr));
+
+            // Local host.
+            String locHost = IgniteSystemProperties.getString(GG_LOCAL_HOST);
+
+            myCfg.setLocalHost(F.isEmpty(locHost) ? cfg.getLocalHost() : locHost);
+
+            // Override daemon flag if it was set on the factory.
+            if (daemon)
+                myCfg.setDaemon(true);
+
+            // Check for deployment mode override.
+            String depModeName = IgniteSystemProperties.getString(GG_DEP_MODE_OVERRIDE);
+
+            if (!F.isEmpty(depModeName)) {
+                if (!F.isEmpty(cfg.getCacheConfiguration())) {
+                    U.quietAndInfo(log, "Skipping deployment mode override for caches (custom closure " +
+                        "execution may not work for console Visor)");
+                }
+                else {
+                    try {
+                        IgniteDeploymentMode depMode = IgniteDeploymentMode.valueOf(depModeName);
+
+                        if (myCfg.getDeploymentMode() != depMode)
+                            myCfg.setDeploymentMode(depMode);
+                    }
+                    catch (IllegalArgumentException e) {
+                        throw new IgniteCheckedException("Failed to override deployment mode using system property " +
+                            "(are there any misspellings?)" +
+                            "[name=" + GG_DEP_MODE_OVERRIDE + ", value=" + depModeName + ']', e);
+                    }
+                }
+            }
+
+            Map<String, ?> attrs = cfg.getUserAttributes();
+
+            if (attrs == null)
+                attrs = Collections.emptyMap();
+
+            MBeanServer mbSrv = cfg.getMBeanServer();
+
+            IgniteMarshaller marsh = cfg.getMarshaller();
+
+            String[] p2pExclude = cfg.getPeerClassLoadingLocalClassPathExclude();
+
+            CommunicationSpi commSpi = cfg.getCommunicationSpi();
+            DiscoverySpi discoSpi = cfg.getDiscoverySpi();
+            EventStorageSpi evtSpi = cfg.getEventStorageSpi();
+            CollisionSpi colSpi = cfg.getCollisionSpi();
+            AuthenticationSpi authSpi = cfg.getAuthenticationSpi();
+            SecureSessionSpi sesSpi = cfg.getSecureSessionSpi();
+            DeploymentSpi deploySpi = cfg.getDeploymentSpi();
+            CheckpointSpi[] cpSpi = cfg.getCheckpointSpi();
+            FailoverSpi[] failSpi = cfg.getFailoverSpi();
+            LoadBalancingSpi[] loadBalancingSpi = cfg.getLoadBalancingSpi();
+            SwapSpaceSpi swapspaceSpi = cfg.getSwapSpaceSpi();
+            GridIndexingSpi indexingSpi = cfg.getIndexingSpi();
+
+            execSvc = cfg.getExecutorService();
+            sysExecSvc = cfg.getSystemExecutorService();
+            p2pExecSvc = cfg.getPeerClassLoadingExecutorService();
+            mgmtExecSvc = cfg.getManagementExecutorService();
+            ggfsExecSvc = cfg.getGgfsExecutorService();
+
+            if (execSvc == null) {
+                isAutoExecSvc = true;
+
+                execSvc = new IgniteThreadPoolExecutor(
+                    "pub-" + cfg.getGridName(),
+                    DFLT_PUBLIC_CORE_THREAD_CNT,
+                    DFLT_PUBLIC_MAX_THREAD_CNT,
+                    DFLT_PUBLIC_KEEP_ALIVE_TIME,
+                    new LinkedBlockingQueue<Runnable>(DFLT_PUBLIC_THREADPOOL_QUEUE_CAP));
+
+                // Pre-start all threads as they are guaranteed to be needed.
+                ((ThreadPoolExecutor)execSvc).prestartAllCoreThreads();
+            }
+
+            if (sysExecSvc == null) {
+                isAutoSysSvc = true;
+
+                // Note that since we use 'LinkedBlockingQueue', number of
+                // maximum threads has no effect.
+                sysExecSvc = new IgniteThreadPoolExecutor(
+                    "sys-" + cfg.getGridName(),
+                    DFLT_SYSTEM_CORE_THREAD_CNT,
+                    DFLT_SYSTEM_MAX_THREAD_CNT,
+                    DFLT_SYSTEM_KEEP_ALIVE_TIME,
+                    new LinkedBlockingQueue<Runnable>(DFLT_SYSTEM_THREADPOOL_QUEUE_CAP));
+
+                // Pre-start all threads as they are guaranteed to be needed.
+                ((ThreadPoolExecutor)sysExecSvc).prestartAllCoreThreads();
+            }
+
+            if (mgmtExecSvc == null) {
+                isAutoMgmtSvc = true;
+
+                // Note that since we use 'LinkedBlockingQueue', number of
+                // maximum threads has no effect.
+                // Note, that we do not pre-start threads here as management pool may
+                // not be needed.
+                mgmtExecSvc = new IgniteThreadPoolExecutor(
+                    "mgmt-" + cfg.getGridName(),
+                    DFLT_MGMT_THREAD_CNT,
+                    DFLT_MGMT_THREAD_CNT,
+                    0,
+                    new LinkedBlockingQueue<Runnable>());
+            }
+
+            if (p2pExecSvc == null) {
+                isAutoP2PSvc = true;
+
+                // Note that since we use 'LinkedBlockingQueue', number of
+                // maximum threads has no effect.
+                // Note, that we do not pre-start threads here as class loading pool may
+                // not be needed.
+                p2pExecSvc = new IgniteThreadPoolExecutor(
+                    "p2p-" + cfg.getGridName(),
+                    DFLT_P2P_THREAD_CNT,
+                    DFLT_P2P_THREAD_CNT,
+                    0,
+                    new LinkedBlockingQueue<Runnable>());
+            }
+
+            if (ggfsExecSvc == null) {
+                isAutoGgfsSvc = true;
+
+                int procCnt = Runtime.getRuntime().availableProcessors();
+
+                // Note that we do not pre-start threads here as ggfs pool may not be needed.
+                ggfsExecSvc = new IgniteThreadPoolExecutor(
+                    "ggfs-" + cfg.getGridName(),
+                    procCnt,
+                    procCnt,
+                    0,
+                    new LinkedBlockingQueue<Runnable>());
+            }
+
+            restExecSvc = clientCfg != null ? clientCfg.getRestExecutorService() : null;
+
+            if (restExecSvc != null && !cfg.isRestEnabled()) {
+                U.warn(log, "REST executor service is configured, but REST is disabled in configuration " +
+                    "(safely ignoring).");
+            }
+            else if (restExecSvc == null && clientCfg != null) {
+                isAutoRestSvc = true;
+
+                restExecSvc = new IgniteThreadPoolExecutor(
+                    "rest-" + cfg.getGridName(),
+                    DFLT_REST_CORE_THREAD_CNT,
+                    DFLT_REST_MAX_THREAD_CNT,
+                    DFLT_REST_KEEP_ALIVE_TIME,
+                    new LinkedBlockingQueue<Runnable>(DFLT_REST_THREADPOOL_QUEUE_CAP)
+                );
+
+                clientCfg.setRestExecutorService(restExecSvc);
+            }
+
+            utilityCacheExecSvc = new IgniteThreadPoolExecutor(
+                "utility-" + cfg.getGridName(),
+                DFLT_SYSTEM_CORE_THREAD_CNT,
+                DFLT_SYSTEM_MAX_THREAD_CNT,
+                DFLT_SYSTEM_KEEP_ALIVE_TIME,
+                new LinkedBlockingQueue<Runnable>(DFLT_SYSTEM_THREADPOOL_QUEUE_CAP));
+
+            execSvcShutdown = cfg.getExecutorServiceShutdown();
+            sysSvcShutdown = cfg.getSystemExecutorServiceShutdown();
+            mgmtSvcShutdown = cfg.getManagementExecutorServiceShutdown();
+            p2pSvcShutdown = cfg.getPeerClassLoadingExecutorServiceShutdown();
+            ggfsSvcShutdown = cfg.getGgfsExecutorServiceShutdown();
+            restSvcShutdown = clientCfg != null && clientCfg.isRestExecutorServiceShutdown();
+
+            if (marsh == null) {
+                if (!U.isHotSpot()) {
+                    U.warn(log, "GridOptimizedMarshaller is not supported on this JVM " +
+                        "(only Java HotSpot VMs are supported). Switching to standard JDK marshalling - " +
+                        "object serialization performance will be significantly slower.",
+                        "To enable fast marshalling upgrade to recent 1.6 or 1.7 HotSpot VM release.");
+
+                    marsh = new IgniteJdkMarshaller();
+                }
+                else if (!IgniteOptimizedMarshaller.available()) {
+                    U.warn(log, "GridOptimizedMarshaller is not supported on this JVM " +
+                        "(only recent 1.6 and 1.7 versions HotSpot VMs are supported). " +
+                        "To enable fast marshalling upgrade to recent 1.6 or 1.7 HotSpot VM release. " +
+                        "Switching to standard JDK marshalling - " +
+                        "object serialization performance will be significantly slower.",
+                        "To enable fast marshalling upgrade to recent 1.6 or 1.7 HotSpot VM release.");
+
+                    marsh = new IgniteJdkMarshaller();
+                }
+                else
+                    marsh = new IgniteOptimizedMarshaller();
+            }
+            else if (marsh instanceof IgniteOptimizedMarshaller && !U.isHotSpot()) {
+                U.warn(log, "Using GridOptimizedMarshaller on untested JVM (only Java HotSpot VMs were tested) - " +
+                    "object serialization behavior could yield unexpected results.",
+                    "Using GridOptimizedMarshaller on untested JVM.");
+            }
+
+            myCfg.setUserAttributes(attrs);
+            myCfg.setMBeanServer(mbSrv == null ? ManagementFactory.getPlatformMBeanServer() : mbSrv);
+            myCfg.setGridLogger(cfgLog);
+            myCfg.setMarshaller(marsh);
+            myCfg.setMarshalLocalJobs(cfg.isMarshalLocalJobs());
+            myCfg.setExecutorService(execSvc);
+            myCfg.setSystemExecutorService(sysExecSvc);
+            myCfg.setManagementExecutorService(mgmtExecSvc);
+            myCfg.setPeerClassLoadingExecutorService(p2pExecSvc);
+            myCfg.setGgfsExecutorService(ggfsExecSvc);
+            myCfg.setExecutorServiceShutdown(execSvcShutdown);
+            myCfg.setSystemExecutorServiceShutdown(sysSvcShutdown);
+            myCfg.setManagementExecutorServiceShutdown(mgmtSvcShutdown);
+            myCfg.setPeerClassLoadingExecutorServiceShutdown(p2pSvcShutdown);
+            myCfg.setGgfsExecutorServiceShutdown(ggfsSvcShutdown);
+            myCfg.setNodeId(nodeId);
+
+            IgniteFsConfiguration[] ggfsCfgs = cfg.getGgfsConfiguration();
+
+            if (ggfsCfgs != null) {
+                IgniteFsConfiguration[] clone = ggfsCfgs.clone();
+
+                for (int i = 0; i < ggfsCfgs.length; i++)
+                    clone[i] = new IgniteFsConfiguration(ggfsCfgs[i]);
+
+                myCfg.setGgfsConfiguration(clone);
+            }
+
+            StreamerConfiguration[] streamerCfgs = cfg.getStreamerConfiguration();
+
+            if (streamerCfgs != null) {
+                StreamerConfiguration[] clone = streamerCfgs.clone();
+
+                for (int i = 0; i < streamerCfgs.length; i++)
+                    clone[i] = new StreamerConfiguration(streamerCfgs[i]);
+
+                myCfg.setStreamerConfiguration(clone);
+            }
+
+            if (p2pExclude == null)
+                p2pExclude = EMPTY_STR_ARR;
+
+            myCfg.setPeerClassLoadingLocalClassPathExclude(p2pExclude);
+
+            /*
+             * Initialize default SPI implementations.
+             */
+
+            if (commSpi == null)
+                commSpi = new TcpCommunicationSpi();
+
+            if (discoSpi == null)
+                discoSpi = new TcpDiscoverySpi();
+
+            if (discoSpi instanceof TcpDiscoverySpi) {
+                TcpDiscoverySpi tcpDisco = (TcpDiscoverySpi)discoSpi;
+
+                if (tcpDisco.getIpFinder() == null)
+                    tcpDisco.setIpFinder(new TcpDiscoveryMulticastIpFinder());
+            }
+
+            if (evtSpi == null)
+                evtSpi = new MemoryEventStorageSpi();
+
+            if (colSpi == null)
+                colSpi = new NoopCollisionSpi();
+
+            if (authSpi == null)
+                authSpi = new NoopAuthenticationSpi();
+
+            if (sesSpi == null)
+                sesSpi = new NoopSecureSessionSpi();
+
+            if (deploySpi == null)
+                deploySpi = new LocalDeploymentSpi();
+
+            if (cpSpi == null)
+                cpSpi = new CheckpointSpi[] {new NoopCheckpointSpi()};
+
+            if (failSpi == null)
+                failSpi = new FailoverSpi[] {new AlwaysFailoverSpi()};
+
+            if (loadBalancingSpi == null)
+                loadBalancingSpi = new LoadBalancingSpi[] {new RoundRobinLoadBalancingSpi()};
+
+            if (swapspaceSpi == null) {
+                boolean needSwap = false;
+
+                CacheConfiguration[] caches = cfg.getCacheConfiguration();
+
+                if (caches != null) {
+                    for (CacheConfiguration c : caches) {
+                        if (c.isSwapEnabled()) {
+                            needSwap = true;
+
+                            break;
+                        }
+                    }
+                }
+
+                swapspaceSpi = needSwap ? new FileSwapSpaceSpi() : new NoopSwapSpaceSpi();
+            }
+
+            if (indexingSpi == null)
+                indexingSpi = new GridNoopIndexingSpi();
+
+            myCfg.setCommunicationSpi(commSpi);
+            myCfg.setDiscoverySpi(discoSpi);
+            myCfg.setCheckpointSpi(cpSpi);
+            myCfg.setEventStorageSpi(evtSpi);
+            myCfg.setAuthenticationSpi(authSpi);
+            myCfg.setSecureSessionSpi(sesSpi);
+            myCfg.setDeploymentSpi(deploySpi);
+            myCfg.setFailoverSpi(failSpi);
+            myCfg.setCollisionSpi(colSpi);
+            myCfg.setLoadBalancingSpi(loadBalancingSpi);
+            myCfg.setSwapSpaceSpi(swapspaceSpi);
+            myCfg.setIndexingSpi(indexingSpi);
+
+            myCfg.setAddressResolver(cfg.getAddressResolver());
+
+            // Set SMTP configuration.
+            myCfg.setSmtpFromEmail(cfg.getSmtpFromEmail());
+            myCfg.setSmtpHost(cfg.getSmtpHost());
+            myCfg.setSmtpPort(cfg.getSmtpPort());
+            myCfg.setSmtpSsl(cfg.isSmtpSsl());
+            myCfg.setSmtpUsername(cfg.getSmtpUsername());
+            myCfg.setSmtpPassword(cfg.getSmtpPassword());
+            myCfg.setAdminEmails(cfg.getAdminEmails());
+
+            // REST configuration.
+            myCfg.setClientConnectionConfiguration(clientCfg);
+
+            // Portable configuration.
+            myCfg.setPortableConfiguration(cfg.getPortableConfiguration());
+
+            // Hadoop configuration.
+            myCfg.setHadoopConfiguration(cfg.getHadoopConfiguration());
+
+            // Validate segmentation configuration.
+            GridSegmentationPolicy segPlc = cfg.getSegmentationPolicy();
+
+            // 1. Warn on potential configuration problem: grid is not configured to wait
+            // for correct segment after segmentation happens.
+            if (!F.isEmpty(cfg.getSegmentationResolvers()) && segPlc == RESTART_JVM && !cfg.isWaitForSegmentOnStart()) {
+                U.warn(log, "Found potential configuration problem (forgot to enable waiting for segment" +
+                    "on start?) [segPlc=" + segPlc + ", wait=false]");
+            }
+
+            myCfg.setSegmentationResolvers(cfg.getSegmentationResolvers());
+            myCfg.setSegmentationPolicy(segPlc);
+            myCfg.setSegmentCheckFrequency(cfg.getSegmentCheckFrequency());
+            myCfg.setWaitForSegmentOnStart(cfg.isWaitForSegmentOnStart());
+            myCfg.setAllSegmentationResolversPassRequired(cfg.isAllSegmentationResolversPassRequired());
+
+            // Override SMTP configuration from system properties
+            // and environment variables, if specified.
+            String fromEmail = IgniteSystemProperties.getString(GG_SMTP_FROM);
+
+            if (fromEmail != null)
+                myCfg.setSmtpFromEmail(fromEmail);
+
+            String smtpHost = IgniteSystemProperties.getString(GG_SMTP_HOST);
+
+            if (smtpHost != null)
+                myCfg.setSmtpHost(smtpHost);
+
+            String smtpUsername = IgniteSystemProperties.getString(GG_SMTP_USERNAME);
+
+            if (smtpUsername != null)
+                myCfg.setSmtpUsername(smtpUsername);
+
+            String smtpPwd = IgniteSystemProperties.getString(GG_SMTP_PWD);
+
+            if (smtpPwd != null)
+                myCfg.setSmtpPassword(smtpPwd);
+
+            int smtpPort = IgniteSystemProperties.getInteger(GG_SMTP_PORT, -1);
+
+            if(smtpPort != -1)
+                myCfg.setSmtpPort(smtpPort);
+
+            myCfg.setSmtpSsl(IgniteSystemProperties.getBoolean(GG_SMTP_SSL));
+
+            String adminEmails = IgniteSystemProperties.getString(GG_ADMIN_EMAILS);
+
+            if (adminEmails != null)
+                myCfg.setAdminEmails(adminEmails.split(","));
+
+            CacheConfiguration[] cacheCfgs = cfg.getCacheConfiguration();
+
+            boolean hasHadoop = IgniteComponentType.HADOOP.inClassPath();
+
+            CacheConfiguration[] copies;
+
+            if (cacheCfgs != null && cacheCfgs.length > 0) {
+                if (!U.discoOrdered(discoSpi) && !U.relaxDiscoveryOrdered())
+                    throw new IgniteCheckedException("Discovery SPI implementation does not support node ordering and " +
+                        "cannot be used with cache (use SPI with @GridDiscoverySpiOrderSupport annotation, " +
+                        "like GridTcpDiscoverySpi)");
+
+                for (CacheConfiguration ccfg : cacheCfgs) {
+                    if (CU.isHadoopSystemCache(ccfg.getName()))
+                        throw new IgniteCheckedException("Cache name cannot be \"" + CU.SYS_CACHE_HADOOP_MR +
+                            "\" because it is reserved for internal purposes.");
+
+                    if (CU.isUtilityCache(ccfg.getName()))
+                        throw new IgniteCheckedException("Cache name cannot start with \"" + CU.UTILITY_CACHE_NAME +
+                            "\" because this prefix is reserved for internal purposes.");
+                }
+
+                copies = new CacheConfiguration[cacheCfgs.length + (hasHadoop ? 2 : 1)];
+
+                int cloneIdx = 1;
+
+                if (hasHadoop)
+                    copies[cloneIdx++] = CU.hadoopSystemCache();
+
+                for (CacheConfiguration ccfg : cacheCfgs)
+                    copies[cloneIdx++] = new CacheConfiguration(ccfg);
+            }
+            else if (hasHadoop) {
+                // Populate system caches
+                copies = new CacheConfiguration[hasHadoop ? 2 : 1];
+
+                copies[1] = CU.hadoopSystemCache();
+            }
+            else
+                copies = new CacheConfiguration[1];
+
+            // Always add utility cache.
+            copies[0] = utilitySystemCache(discoSpi instanceof TcpClientDiscoverySpi);
+
+            myCfg.setCacheConfiguration(copies);
+
+            myCfg.setCacheSanityCheckEnabled(cfg.isCacheSanityCheckEnabled());
+
+            try {
+                // Use reflection to avoid loading undesired classes.
+                Class helperCls = Class.forName("org.gridgain.grid.util.GridConfigurationHelper");
+
+                helperCls.getMethod("overrideConfiguration", IgniteConfiguration.class, Properties.class,
+                    String.class, IgniteLogger.class).invoke(helperCls, myCfg, System.getProperties(), name, log);
+            }
+            catch (Exception ignored) {
+                // No-op.
+            }
+
+            // Ensure that SPIs support multiple grid instances, if required.
+            if (!startCtx.single()) {
+                ensureMultiInstanceSupport(deploySpi);
+                ensureMultiInstanceSupport(commSpi);
+                ensureMultiInstanceSupport(discoSpi);
+                ensureMultiInstanceSupport(cpSpi);
+                ensureMultiInstanceSupport(evtSpi);
+                ensureMultiInstanceSupport(colSpi);
+                ensureMultiInstanceSupport(failSpi);
+                ensureMultiInstanceSupport(authSpi);
+                ensureMultiInstanceSupport(sesSpi);
+                ensureMultiInstanceSupport(loadBalancingSpi);
+                ensureMultiInstanceSupport(swapspaceSpi);
+            }
+
+            // Register GridGain MBean for current grid instance.
+            registerFactoryMbean(myCfg.getMBeanServer());
+
+            boolean started = false;
+
+            try {
+                IgniteKernal grid0 = new IgniteKernal(startCtx.springContext());
+
+                // Init here to make grid available to lifecycle listeners.
+                grid = grid0;
+
+                grid0.start(myCfg, utilityCacheExecSvc, new CA() {
+                    @Override public void apply() {
+                        startLatch.countDown();
+                    }
+                });
+
+                state = STARTED;
+
+                if (log.isDebugEnabled())
+                    log.debug("Grid factory started ok: " + name);
+
+                started = true;
+            }
+            catch (IgniteCheckedException e) {
+                unregisterFactoryMBean();
+
+                throw e;
+            }
+            // Catch Throwable to protect against any possible failure.
+            catch (Throwable e) {
+                unregisterFactoryMBean();
+
+                throw new IgniteCheckedException("Unexpected exception when starting grid.", e);
+            }
+            finally {
+                if (!started)
+                    // Grid was not started.
+                    grid = null;
+            }
+
+            // Do NOT set it up only if GRIDGAIN_NO_SHUTDOWN_HOOK=TRUE is provided.
+            if (!IgniteSystemProperties.getBoolean(GG_NO_SHUTDOWN_HOOK, false)) {
+                try {
+                    Runtime.getRuntime().addShutdownHook(shutdownHook = new Thread() {
+                        @Override public void run() {
+                            if (log.isInfoEnabled())
+                                log.info("Invoking shutdown hook...");
+
+                            IgniteNamedInstance.this.stop(true);
+                        }
+                    });
+
+                    if (log.isDebugEnabled())
+                        log.debug("Shutdown hook is installed.");
+                }
+                catch (IllegalStateException e) {
+                    stop(true);
+
+                    throw new IgniteCheckedException("Failed to install shutdown hook.", e);
+                }
+            }
+            else {
+                if (log.isDebugEnabled())
+                    log.debug("Shutdown hook has not been installed because environment " +
+                        "or system property " + GG_NO_SHUTDOWN_HOOK + " is set.");
+            }
+        }
+
+        /**
+         * @param cfgLog Configured logger.
+         * @param nodeId Local node ID.
+         * @return Initialized logger.
+         * @throws IgniteCheckedException If failed.
+         */
+        private IgniteLogger initLogger(@Nullable IgniteLogger cfgLog, UUID nodeId) throws IgniteCheckedException {
+            try {
+                if (cfgLog == null) {
+                    Class<?> log4jCls;
+
+                    try {
+                        log4jCls = Class.forName("org.gridgain.grid.logger.log4j.GridLog4jLogger");
+                    }
+                    catch (ClassNotFoundException | NoClassDefFoundError ignored) {
+                        log4jCls = null;
+                    }
+
+                    if (log4jCls != null) {
+                        URL url = U.resolveGridGainUrl("config/gridgain-log4j.xml");
+
+                        if (url == null) {
+                            File cfgFile = new File("config/gridgain-log4j.xml");
+
+                            if (!cfgFile.exists())
+                                cfgFile = new File("../config/gridgain-log4j.xml");
+
+                            if (cfgFile.exists()) {
+                                try {
+                                    url = cfgFile.toURI().toURL();
+                                }
+                                catch (MalformedURLException ignore) {
+                                    // No-op.
+                                }
+                            }
+                        }
+
+                        if (url != null) {
+                            boolean configured = (Boolean)log4jCls.getMethod("isConfigured").invoke(null);
+
+                            if (configured)
+                                url = null;
+                        }
+
+                        if (url != null) {
+                            Constructor<?> ctor = log4jCls.getConstructor(URL.class);
+
+                            cfgLog = (IgniteLogger)ctor.newInstance(url);
+                        }
+                        else
+                            cfgLog = (IgniteLogger)log4jCls.newInstance();
+                    }
+                    else
+                        cfgLog = new IgniteJavaLogger();
+                }
+
+                // Set node IDs for all file appenders.
+                if (cfgLog instanceof IgniteLoggerNodeIdAware)
+                    ((IgniteLoggerNodeIdAware)cfgLog).setNodeId(nodeId);
+
+                return cfgLog;
+            }
+            catch (Exception e) {
+                throw new IgniteCheckedException("Failed to create logger.", e);
+            }
+        }
+
+        /**
+         * Creates utility system cache configuration.
+         *
+         * @param client If {@code true} creates client-only cache configuration.
+         * @return Utility system cache configuration.
+         */
+        private CacheConfiguration utilitySystemCache(boolean client) {
+            CacheConfiguration cache = new CacheConfiguration();
+
+            cache.setName(CU.UTILITY_CACHE_NAME);
+            cache.setCacheMode(REPLICATED);
+            cache.setAtomicityMode(TRANSACTIONAL);
+            cache.setSwapEnabled(false);
+            cache.setQueryIndexEnabled(false);
+            cache.setPreloadMode(SYNC);
+            cache.setWriteSynchronizationMode(FULL_SYNC);
+            cache.setAffinity(new CacheRendezvousAffinityFunction(false, 100));
+
+            if (client)
+                cache.setDistributionMode(CLIENT_ONLY);
+
+            return cache;
+        }
+
+        /**
+         * Stops grid.
+         *
+         * @param cancel Flag indicating whether all currently running jobs
+         *      should be cancelled.
+         */
+        void stop(boolean cancel) {
+            // Stop cannot be called prior to start from public API,
+            // since it checks for STARTED state. So, we can assert here.
+            assert startGuard.get();
+
+            stop0(cancel);
+        }
+
+        /**
+         * @param cancel Flag indicating whether all currently running jobs
+         *      should be cancelled.
+         */
+        private synchronized void stop0(boolean cancel) {
+            IgniteKernal grid0 = grid;
+
+            // Double check.
+            if (grid0 == null) {
+                if (log != null)
+                    U.warn(log, "Attempting to stop an already stopped grid instance (ignore): " + name);
+
+                return;
+            }
+
+            if (shutdownHook != null)
+                try {
+                    Runtime.getRuntime().removeShutdownHook(shutdownHook);
+
+                    shutdownHook = null;
+
+                    if (log.isDebugEnabled())
+                        log.debug("Shutdown hook is removed.");
+                }
+                catch (IllegalStateException e) {
+                    // Shutdown is in progress...
+                    if (log.isDebugEnabled())
+                        log.debug("Shutdown is in progress (ignoring): " + e.getMessage());
+                }
+
+            // Unregister GridGain MBean.
+            unregisterFactoryMBean();
+
+            try {
+                grid0.stop(cancel);
+
+                if (log.isDebugEnabled())
+       

<TRUNCATED>