org.gridgain.grid.GridFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.gridgain.grid.GridFactory.java

Source

// Copyright (C) GridGain Systems Licensed under GPLv3, http://www.gnu.org/licenses/gpl.html

/*  _________        _____ __________________        _____
 *  __  ____/___________(_)______  /__  ____/______ ____(_)_______
 *  _  / __  __  ___/__  / _  __  / _  / __  _  __ `/__  / __  __ \
 *  / /_/ /  _  /    _  /  / /_/ /  / /_/ /  / /_/ / _  /  _  / / /
 *  \____/   /_/     /_/   \_,__/   \____/   \__,_/  /_/   /_/ /_/
 */

package org.gridgain.grid;

import org.apache.commons.logging.*;
import org.gridgain.grid.cache.*;
import org.gridgain.grid.kernal.*;
import org.gridgain.grid.lang.*;
import org.gridgain.grid.loaders.cmdline.*;
import org.gridgain.grid.loaders.servlet.*;
import org.gridgain.grid.logger.*;
import org.gridgain.grid.logger.log4j.*;
import org.gridgain.grid.marshaller.*;
import org.gridgain.grid.marshaller.optimized.*;
import org.gridgain.grid.resources.*;
import org.gridgain.grid.spi.*;
import org.gridgain.grid.spi.authentication.*;
import org.gridgain.grid.spi.authentication.noop.*;
import org.gridgain.grid.spi.checkpoint.*;
import org.gridgain.grid.spi.checkpoint.sharedfs.*;
import org.gridgain.grid.spi.collision.*;
import org.gridgain.grid.spi.collision.fifoqueue.*;
import org.gridgain.grid.spi.communication.*;
import org.gridgain.grid.spi.communication.tcp.*;
import org.gridgain.grid.spi.deployment.*;
import org.gridgain.grid.spi.deployment.local.*;
import org.gridgain.grid.spi.discovery.*;
import org.gridgain.grid.spi.discovery.multicast.*;
import org.gridgain.grid.spi.eventstorage.*;
import org.gridgain.grid.spi.eventstorage.memory.*;
import org.gridgain.grid.spi.failover.*;
import org.gridgain.grid.spi.failover.always.*;
import org.gridgain.grid.spi.loadbalancing.*;
import org.gridgain.grid.spi.loadbalancing.roundrobin.*;
import org.gridgain.grid.spi.metrics.*;
import org.gridgain.grid.spi.metrics.jdk.*;
import org.gridgain.grid.spi.securesession.*;
import org.gridgain.grid.spi.securesession.noop.*;
import org.gridgain.grid.spi.swapspace.*;
import org.gridgain.grid.spi.swapspace.leveldb.*;
import org.gridgain.grid.spi.topology.*;
import org.gridgain.grid.spi.topology.basic.*;
import org.gridgain.grid.thread.*;
import org.gridgain.grid.typedef.*;
import org.gridgain.grid.typedef.internal.*;
import org.gridgain.grid.util.worker.*;
import org.jetbrains.annotations.*;
import org.springframework.beans.*;
import org.springframework.beans.factory.xml.*;
import org.springframework.context.*;
import org.springframework.context.support.*;
import org.springframework.core.io.*;

import javax.management.*;
import java.io.*;
import java.lang.management.*;
import java.net.*;
import java.util.*;
import java.util.Map.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

import static org.gridgain.grid.GridConfiguration.*;
import static org.gridgain.grid.GridFactoryState.*;
import static org.gridgain.grid.GridSystemProperties.*;
import static org.gridgain.grid.cache.GridCacheMode.*;
import static org.gridgain.grid.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. Some examples
 * of Grid loaders are:
 * <ul>
 * <li>{@link GridCommandLineLoader}</li>
 * <li>{@link org.gridgain.grid.loaders.jboss.GridJbossLoader}</li>
 * <li>{@link org.gridgain.grid.loaders.weblogic.GridWeblogicStartup} and {@link org.gridgain.grid.loaders.weblogic.GridWeblogicShutdown}</li>
 * <li>{@link org.gridgain.grid.loaders.websphere.GridWebsphereLoader}</li>
 * <li>{@link org.gridgain.grid.loaders.glassfish.GridGlassfishLoader}</li>
 * <li>{@link GridServletLoader}</li>
 * </ul>
 * <h1 class="header">Examples</h1>
 * Use {@link #start()} method to start grid with default configuration. You can also use
 * {@link GridConfigurationAdapter} to override some default configuration. Below is an
 * example on how to start grid with <strong>URI deployment</strong>.
 * <pre name="code" class="java">
 * GridConfigurationAdapter cfg = new GridConfigurationAdapter();
 *
 * GridUriDeployment deploySpi = new GridUriDeployment();
 *
 * deploySpi.setUriList(Collections.singletonList("classes://tmp/output/classes"));
 *
 * cfg.setDeploymentSpi(deploySpi);
 *
 * GridFactory.start(cfg);
 * </pre>
 * Here is how a grid instance can be configured from Spring XML configuration file. The
 * example below configures a grid instance with additional user attributes
 * (see {@link GridNode#attributes()}) and specifies a grid name:
 * <pre name="code" class="xml">
 * &lt;bean id="grid.cfg" class="org.gridgain.grid.GridConfigurationAdapter" scope="singleton"&gt;
 *     ...
 *     &lt;property name="gridName" value="grid"/&gt;
 *     &lt;property name="userAttributes"&gt;
 *         &lt;map&gt;
 *             &lt;entry key="group" value="worker"/&gt;
 *             &lt;entry key="grid.node.benchmark"&gt;
 *                 &lt;bean class="org.gridgain.grid.benchmarks.GridLocalNodeBenchmark" init-method="start"/&gt;
 *             &lt;/entry&gt;
 *         &lt;/map&gt;
 *     &lt;/property&gt;
 *     ...
 * &lt;/bean&gt;
 * </pre>
 * A grid instance with Spring configuration above can be started as following. Note that
 * you do not need to pass path to Spring XML file if you are using
 * {@code GRIDGAIN_HOME/config/default-spring.xml}. Also note, that the path can be
 * absolute or relative to GRIDGAIN_HOME.
 * <pre name="code" class="java">
 * ...
 * G.start("/path/to/spring/xml/file.xml");
 * ...
 * </pre>
 * You can also instantiate grid directly from Spring without using {@code GridFactory}.
 * For more information refer to {@link GridSpringBean} documentation.
    
 * @author 2012 Copyright (C) GridGain Systems
 * @version 4.0.2c.12042012
 */
public class GridFactory {
    /**
     * This is restart code that can be used by external tools, like Shell scripts,
     * to auto-restart the GridGain JVM process. Note that there is no standard way
     * for a JVM to restart itself from Java application and therefore we rely on
     * external tools to provide that capability.
     * <p>
     * Note that standard <tt>ggstart.{sh|bat}</tt> scripts support restarting when
     * JVM process exits with this code.
     */
    public static final int RESTART_EXIT_CODE = 250;

    /**
     * This is kill code that can be used by external tools, like Shell scripts,
     * to auto-stop the GridGain JVM process without restarting.
     */
    public static final int KILL_EXIT_CODE = 130;

    /** Default configuration path relative to GridGain home. */
    private static final String DFLT_CFG = "config/default-spring.xml";

    /** License file name. */
    private static final String LIC_FILE_NAME = "gridgain-license.xml";

    /** Default grid. */
    private static volatile GridNamedInstance dfltGrid;

    /** Map of named grids. */
    private static final Map<String, GridNamedInstance> grids = new HashMap<String, GridNamedInstance>();

    /** Map of grid states ever started in this JVM. */
    private static final Map<String, GridFactoryState> gridStates = new HashMap<String, GridFactoryState>();

    /** List of state listeners. */
    private static final List<GridFactoryListener> lsnrs = new ArrayList<GridFactoryListener>();

    /** Synchronization mutex. */
    private static final Object mux = new Object();

    /** */
    private static volatile boolean daemon;

    /**
     * Checks runtime version to be 1.5.x or 1.6.x or 1.7.x.
     * This will load pretty much first so we must do these checks here.
     */
    static {
        // Check 1.7 just in case for forward compatibility.
        if (!U.jdkVersion().contains("1.6") && !U.jdkVersion().contains("1.7"))
            throw new IllegalStateException("GridGain requires Java 6 or above. Current Java version "
                    + "is not supported: " + U.jdkVersion());

        String ggHome = X.getSystemOrEnv(GG_HOME);

        if (ggHome != null)
            System.setProperty(GG_HOME, ggHome);

        // Turn off default logging for Spring Framework.
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", null);
    }

    /**
     * Enforces singleton.
     */
    protected GridFactory() {
        // No-op.
    }

    /**
     * Sets 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 GridConfiguration#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) {
        GridFactory.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 GridConfiguration#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 GridFactoryState 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 GridFactoryState state(@Nullable String name) {
        GridNamedInstance grid;

        synchronized (mux) {
            grid = name == null ? dfltGrid : grids.get(name);
        }

        if (grid == null) {
            GridFactoryState state;

            synchronized (mux) {
                state = gridStates.get(name);
            }

            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 GridJob#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 default grid. This method is identical to {@code G.stop(null, cancel, wait)} apply.
     * If wait parameter is set to {@code true} then it will wait for all
     * tasks to be finished.
     *
     * @param cancel If {@code true} then all jobs currently executing on
     *      default grid will be cancelled by calling {@link GridJob#cancel()}
     *      method. Note that just like with {@link Thread#interrupt()}, it is
     *      up to the actual job to exit from execution.
     * @param wait If {@code true} then method will wait for all tasks being
     *      executed until they finish their 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, boolean wait) {
        return stop(null, cancel, wait);
    }

    /**
     * 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.
     * It does not wait for the tasks to finish their execution.
     *
     * @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 GridJob#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) {
        return stop(name, cancel, false);
    }

    /**
     * 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 GridJob#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.
     * @param wait If {@code true} then method will wait for all tasks being
     *      executed until they finish their execution.
     * @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, boolean wait) {
        GridNamedInstance grid;

        synchronized (mux) {
            grid = name == null ? dfltGrid : grids.get(name);
        }

        if (grid != null && grid.state() == STARTED) {
            grid.stop(cancel, wait);

            boolean fireEvt = false;

            synchronized (mux) {
                if (name == null) {
                    if (dfltGrid == grid) { // This particular grid was just stopped.
                        fireEvt = true;

                        dfltGrid = null;
                    }
                } else if (grids.get(name) == grid) { // This particular grid was just stopped.
                    fireEvt = true;

                    grids.remove(name);
                }
            }

            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.
     * It does not wait for the tasks to finish their execution.
     * <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 GridJob#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) {
        stopAll(cancel, 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 GridJob#cancel()}
     *      method. Note that just like with {@link Thread#interrupt()}, it is
     *      up to the actual job to exit from execution
     * @param wait If {@code true} then method will wait for all tasks being
     *      executed until they finish their execution.
     */
    public static void stopAll(boolean cancel, boolean wait) {
        Collection<GridNamedInstance> cp = new ArrayList<GridNamedInstance>();

        synchronized (mux) {
            if (dfltGrid != null)
                cp.add(dfltGrid);

            cp.addAll(grids.values());
        }

        // Stop the rest and clear grids map.
        for (GridNamedInstance grid : cp) {
            grid.stop(cancel, wait);

            boolean fireEvt;

            synchronized (mux) {
                if (grid.getName() == null) {
                    fireEvt = dfltGrid != null;

                    dfltGrid = null;
                } else
                    fireEvt = grids.remove(grid.getName()) != null;
            }

            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 GridJob#cancel()}
     *      method. Note that just like with {@link Thread#interrupt()}, it is
     *      up to the actual job to exit from execution.
     * @param wait If {@code true} then method will wait for all tasks being
     *      executed until they finish their execution.
     * @see #RESTART_EXIT_CODE
     */
    public static void restart(boolean cancel, boolean wait) {
        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 (" + 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(RESTART_EXIT_CODE));

            stopAll(cancel, wait);

            // This basically leaves loaders hang - we accept it.
            System.exit(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 #KILL_EXIT_CODE}.
     *
     * @param cancel If {@code true} then all jobs currently executing on
     *      all grids will be cancelled by calling {@link GridJob#cancel()}
     *      method. Note that just like with {@link Thread#interrupt()}, it is
     *      up to the actual job to exit from execution.
     * @param wait If {@code true} then method will wait for all tasks being
     *      executed until they finish their execution.
     * @see #KILL_EXIT_CODE
     */
    public static void kill(boolean cancel, boolean wait) {
        stopAll(cancel, wait);

        // This basically leaves loaders hang - we accept it.
        System.exit(KILL_EXIT_CODE);
    }

    /**
     * Starts grid with default configuration. By default this method will
     * use grid configuration defined in {@code GRIDGAIN_HOME/config/default-spring.xml}
     * configuration file. If such file is not found, then all system defaults will be used.
     *
     * @return Started grid.
     * @throws GridException If default grid could not be started. This exception will be thrown
     *      also if default grid has already been started.
     */
    public static Grid start() throws GridException {
        return start((ApplicationContext) null);
    }

    /**
     * Starts grid with default configuration. By default this method will
     * use grid configuration defined in {@code GRIDGAIN_HOME/config/default-spring.xml}
     * configuration file. If such file is not found, then all system defaults will be used.
     *
     * @param springCtx Optional Spring application context.
     * @return Started grid.
     * @throws GridException If default grid could not be started. This exception will be thrown
     *      also if default grid has already been started.
     */
    public static Grid start(@Nullable ApplicationContext springCtx) throws GridException {
        URL url = U.resolveGridGainUrl(DFLT_CFG);

        if (url != null)
            return start(DFLT_CFG, springCtx);

        U.warn(null, "Default Spring XML file not found (is GRIDGAIN_HOME set?): " + DFLT_CFG);

        return start0(new GridConfigurationAdapter(), 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 GridException If grid could not be started. This exception will be thrown
     *      also if named grid has already been started.
     */
    public static Grid start(GridConfiguration cfg) throws GridException {
        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}. If provided, this
     *      context can be injected into grid tasks and grid jobs using
     *      {@link GridSpringApplicationContextResource @GridSpringApplicationContextResource} annotation.
     * @return Started grid.
     * @throws GridException If grid could not be started. This exception will be thrown
     *      also if named grid has already been started.
     */
    public static Grid start(GridConfiguration cfg, @Nullable ApplicationContext springCtx) throws GridException {
        A.notNull(cfg, "cfg");

        return start0(cfg, 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 GridException 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 Grid start(@Nullable String springCfgPath) throws GridException {
        return springCfgPath == null ? start() : start(springCfgPath, null);
    }

    /**
     * Automatically starts default grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     * If default grid has already been started prior to this method invocation then
     * closures are executed with existing grid and not starting a new one. Accordingly
     * this method does not stop the default grid if it didn't start it.
     * <p>
     * Note also that this method assumes there are <b>no concurrent modifications</b>
     * of default grid state (either via {@code stop()} or {@code start()} methods).
     *
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException If grid could not be started or Spring XML configuration file
     *      is invalid. It is also thrown if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped (if it was started by this method).
     */
    public static void in(@Nullable GridInClosure<Grid>... ps) throws GridException {
        if (!F.isEmpty(ps)) {
            assert ps != null;

            boolean newGrid;

            synchronized (mux) {
                newGrid = dfltGrid == null;
            }

            Grid g = newGrid ? start() : grid();

            try {
                runIn(g, ps);
            } finally {
                if (newGrid)
                    stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid. Note
     * that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param springCfgPath Spring XML configuration file path or URL.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(@Nullable String springCfgPath, @Nullable GridInClosure<Grid>... ps)
            throws GridException {
        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = start(springCfgPath);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid. Note
     * that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param springCfgPath Spring XML configuration file path or URL.
     * @param ctx Optional spring application context.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(@Nullable String springCfgPath, @Nullable ApplicationContext ctx,
            @Nullable GridInClosure<Grid>... ps) throws GridException {

        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = springCfgPath == null ? start(ctx) : start(springCfgPath, ctx);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param ctx Optional spring application context.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(@Nullable ApplicationContext ctx, @Nullable GridInClosure<Grid>... ps)
            throws GridException {
        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = start(ctx);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param cfg Grid configuration. This cannot be {@code null}.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(GridConfiguration cfg, @Nullable GridInClosure<Grid>... ps) throws GridException {
        A.notNull(cfg, "cfg");

        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = start(cfg);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param cfg Grid configuration. This cannot be {@code null}.
     * @param ctx Optional spring application context.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(GridConfiguration cfg, @Nullable ApplicationContext ctx,
            @Nullable GridInClosure<Grid>... ps) throws GridException {
        A.notNull(cfg, "cfg");

        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = start(cfg, ctx);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param springCfgUrl Grid configuration.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(@Nullable URL springCfgUrl, @Nullable GridInClosure<Grid>... ps) throws GridException {
        A.notNull(springCfgUrl, "springCfgUrl");

        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = springCfgUrl == null ? start() : start(springCfgUrl);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Automatically starts specified grid, executes provided closures and stop the grid.
     * Note that grid instance will be stopped with the cancel flag set to {@code true}.
     *
     * @param springCfgUrl Grid configuration.
     * @param ctx Optional spring application context.
     * @param ps Set of closures to execute. If none provided - this method is no-op.
     * @throws GridException 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. It is also thrown
     *      if closure produces an exception.
     *      <p>
     *      Note that if a closure produces an exception no further closures will be
     *      executed and grid instance will be stopped.
     */
    public static void in(@Nullable URL springCfgUrl, @Nullable ApplicationContext ctx,
            @Nullable GridInClosure<Grid>... ps) throws GridException {
        if (!F.isEmpty(ps)) {
            assert ps != null;

            Grid g = springCfgUrl == null ? start(ctx) : start(springCfgUrl, ctx);

            try {
                runIn(g, ps);
            } finally {
                stop(g.name(), true);
            }
        }
    }

    /**
     * Executes given closures with provided grid instance.
     *
     * @param g Grid instance.
     * @param ps Closures to execute.
     * @throws GridException Thrown in case of any error.
     */
    private static void runIn(Grid g, GridInClosure<Grid>... ps) throws GridException {
        assert g != null;
        assert ps != null;

        for (GridInClosure<Grid> p : ps)
            try {
                p.apply(g);
            } catch (Throwable e) {
                throw U.cast(e);
            }
    }

    /**
     * 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 ctx Spring application context.
     * @return Started grid. If Spring configuration contains multiple grid instances,
     *      then the 1st found instance is returned.
     * @throws GridException 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 Grid start(String springCfgPath, @Nullable ApplicationContext ctx) throws GridException {
        A.notNull(springCfgPath, "springCfgPath");

        URL url;

        try {
            url = new URL(springCfgPath);
        } catch (MalformedURLException e) {
            url = U.resolveGridGainUrl(springCfgPath);

            if (url == null)
                throw new GridException("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 start(url, ctx);
    }

    /**
     * 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 GridException 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 Grid start(URL springCfgUrl) throws GridException {
        return start(springCfgUrl, 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 ctx Optional Spring application context.
     * @return Started grid. If Spring configuration contains multiple grid instances,
     *      then the 1st found instance is returned.
     * @throws GridException 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.
     */
    // Warning is due to Spring.
    public static Grid start(URL springCfgUrl, @Nullable ApplicationContext ctx) throws GridException {
        A.notNull(springCfgUrl, "springCfgUrl");

        boolean isLog4jUsed = GridFactory.class.getClassLoader()
                .getResource("org/apache/log4j/Appender.class") != null;

        Object rootLog = null;

        Object nullApp = null;

        if (isLog4jUsed)
            try {
                // Add no-op logger to remove no-appender warning.
                Class logCls = Class.forName("org.apache.log4j.Logger");

                rootLog = logCls.getMethod("getRootLogger").invoke(logCls);

                nullApp = Class.forName("org.apache.log4j.varia.NullAppender").newInstance();

                Class appCls = Class.forName("org.apache.log4j.Appender");

                rootLog.getClass().getMethod("addAppender", appCls).invoke(rootLog, nullApp);
            } catch (Exception e) {
                throw new GridException("Failed to add no-op logger for Log4j.", e);
            }

        GenericApplicationContext springCtx;

        try {
            springCtx = new GenericApplicationContext();

            new XmlBeanDefinitionReader(springCtx).loadBeanDefinitions(new UrlResource(springCfgUrl));

            springCtx.refresh();
        } catch (BeansException e) {
            throw new GridException("Failed to instantiate Spring XML application context [springUrl="
                    + springCfgUrl + ", err=" + e.getMessage() + ']', e);
        }

        Map<String, GridConfiguration> cfgMap;

        try {
            cfgMap = springCtx.getBeansOfType(GridConfiguration.class);
        } catch (BeansException e) {
            throw new GridException(
                    "Failed to instantiate bean [type=" + GridConfiguration.class + ", err=" + e.getMessage() + ']',
                    e);
        }

        if (cfgMap == null)
            throw new GridException("Failed to find a single grid factory configuration in: " + springCfgUrl);

        if (isLog4jUsed) {
            try {
                // Remove previously added no-op logger.
                Class appenderCls = Class.forName("org.apache.log4j.Appender");

                rootLog.getClass().getMethod("removeAppender", appenderCls).invoke(rootLog, nullApp);
            } catch (Exception e) {
                throw new GridException("Failed to remove previously added no-op logger for Log4j.", e);
            }
        }

        if (cfgMap.isEmpty())
            throw new GridException("Can't find grid factory configuration in: " + springCfgUrl);

        List<GridNamedInstance> grids = new ArrayList<GridNamedInstance>(cfgMap.size());

        try {
            for (GridConfiguration cfg : cfgMap.values()) {
                assert cfg != null;

                // Use either user defined context or our one.
                GridNamedInstance grid = start0(cfg, ctx == null ? springCtx : ctx);

                // Add it if it was not stopped during startup.
                if (grid != null)
                    grids.add(grid);
            }
        } catch (GridException e) {
            // Stop all instances started so far.
            for (GridNamedInstance grid : grids) {
                try {
                    grid.stop(true, false);
                } catch (Exception e1) {
                    U.error(grid.log, "Error when stopping grid: " + grid, e1);
                }
            }

            throw e;
        }

        // Return the first grid started.
        GridNamedInstance res = !grids.isEmpty() ? grids.get(0) : null;

        return res != null ? res.grid() : null;
    }

    /**
     * Starts grid with given configuration.
     *
     * @param cfg Grid configuration.
     * @param ctx Optional Spring application context.
     * @return Started grid.
     * @throws GridException If grid could not be started.
     */
    private static GridNamedInstance start0(GridConfiguration cfg, @Nullable ApplicationContext ctx)
            throws GridException {
        assert cfg != null;

        String name = cfg.getGridName();

        GridNamedInstance grid;

        boolean single;

        synchronized (mux) {
            if (name == null) {
                // If default grid is started - throw exception.
                if (dfltGrid != null)
                    throw new GridException("Default grid instance has already been started.");

                grid = dfltGrid = new GridNamedInstance(null);
            } else {
                if (name.isEmpty())
                    throw new GridException("Non default grid instances cannot have empty string name.");

                if (grids.containsKey(name))
                    throw new GridException("Grid instance with this name has already been started: " + name);

                grid = new GridNamedInstance(name);

                grids.put(name, grid);
            }

            single = (grids.size() == 1 && dfltGrid == null) || (grids.isEmpty() && dfltGrid != null);
        }

        boolean success = false;

        try {
            grid.start(cfg, single, ctx);

            notifyStateChange(name, STARTED);

            success = true;
        } finally {
            if (!success) {
                synchronized (mux) {
                    if (name == null)
                        dfltGrid = null;
                    else
                        grids.remove(name);

                    grid = null;
                }
            }
        }

        if (grid == null)
            throw new GridException("Failed to start grid with configuration: " + cfg);

        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 IllegalStateException Thrown if default grid was not properly
     *      initialized or grid instance was stopped or was not started.
     */
    public static Grid grid() throws IllegalStateException {
        return grid((String) null);
    }

    /**
     * Gets a list of all grids started so far.
     *
     * @return List of all grids started so far.
     */
    public static List<Grid> allGrids() {
        synchronized (mux) {
            List<Grid> allGrids = new ArrayList<Grid>(grids.size() + (dfltGrid == null ? 0 : 1));

            if (dfltGrid != null) {
                Grid g = dfltGrid.grid();

                if (g != null)
                    allGrids.add(g);
            }

            for (GridNamedInstance grid : grids.values()) {
                Grid g = grid.grid();

                if (g != null)
                    allGrids.add(g);
            }

            return allGrids;
        }
    }

    /**
     * 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 IllegalStateException Thrown if grid was not properly
     *      initialized or grid instance was stopped or was not started.
     */
    public static Grid grid(UUID locNodeId) throws IllegalStateException {
        A.notNull(locNodeId, "locNodeId");

        synchronized (mux) {
            if (dfltGrid != null) {
                GridKernal g = dfltGrid.grid();

                if (g != null && g.getLocalNodeId().equals(locNodeId))
                    return g;
            }

            for (GridNamedInstance grid : grids.values()) {
                GridKernal g = grid.grid();

                if (g != null && g.getLocalNodeId().equals(locNodeId))
                    return g;
            }
        }

        throw new IllegalStateException("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 IllegalStateException Thrown if default grid was not properly
     *      initialized or grid instance was stopped or was not started.
     */
    public static Grid grid(@Nullable String name) throws IllegalStateException {
        GridNamedInstance grid;

        synchronized (mux) {
            grid = name == null ? dfltGrid : grids.get(name);
        }

        Grid res;

        if (grid == null || (res = grid.grid()) == 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(GridFactoryListener lsnr) {
        A.notNull(lsnr, "lsnr");

        synchronized (lsnrs) {
            if (!lsnrs.contains(lsnr))
                lsnrs.add(lsnr);
        }
    }

    /**
     * Removes lsnr added by {@link #addListener(GridFactoryListener)} method.
     *
     * @param lsnr Listener to remove.
     * @return {@code true} if lsnr was added before, {@code false} otherwise.
     */
    public static boolean removeListener(GridFactoryListener lsnr) {
        A.notNull(lsnr, "lsnr");

        synchronized (lsnrs) {
            return lsnrs.remove(lsnr);
        }
    }

    /**
     * @param gridName Grid instance name.
     * @param state Factory state.
     */
    private static void notifyStateChange(String gridName, GridFactoryState state) {
        Collection<GridFactoryListener> locCp;

        synchronized (lsnrs) {
            locCp = new ArrayList<GridFactoryListener>(lsnrs);
        }

        synchronized (mux) {
            gridStates.put(gridName, state);
        }

        for (GridFactoryListener lsnr : locCp)
            lsnr.onStateChange(gridName, state);
    }

    /**
     * Grid data container.
     *
     * @author 2012 Copyright (C) GridGain Systems
     * @version 4.0.2c.12042012
     */
    private static final class GridNamedInstance {
        /** Map of registered MBeans. */
        private static final Map<MBeanServer, GridMBeanServerData> mbeans = new HashMap<MBeanServer, GridMBeanServerData>();

        /** */
        private static final String[] EMPTY_STR_ARR = new String[0];

        /** Empty array of caches. */
        private static final GridCacheConfiguration[] EMPTY_CACHE_CONFIGS = new GridCacheConfiguration[0];

        /** Grid name. */
        private final String name;

        /** Grid instance. */
        private volatile GridKernal 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;

        /** P2P executor service. */
        private ExecutorService p2pExecSvc;

        /** Auto P2P service flag. */
        private boolean isAutoP2PSvc;

        /** P2P executor service shutdown flag. */
        private boolean p2pSvcShutdown;

        /** Grid state. */
        private volatile GridFactoryState state = STOPPED;

        /** Shutdown hook. */
        private Thread shutdownHook;

        /** Grid log. */
        private GridLogger 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).
         */
        GridNamedInstance(@Nullable String name) {
            this.name = name;
        }

        /**
         * Gets grid name.
         *
         * @return Grid name.
         */
        String getName() {
            return name;
        }

        /**
         * Gets grid instance.
         *
         * @return Grid instance.
         */
        GridKernal grid() {
            if (starterThread != Thread.currentThread())
                U.awaitQuiet(startLatch);

            return grid;
        }

        /**
         * Gets grid state.
         *
         * @return Grid state.
         */
        GridFactoryState state() {
            if (starterThread != Thread.currentThread())
                U.awaitQuiet(startLatch);

            return state;
        }

        /**
         * @param spi SPI implementation.
         * @throws GridException Thrown in case if multi-instance is not supported.
         */
        private void ensureMultiInstanceSupport(GridSpi spi) throws GridException {
            GridSpiMultipleInstancesSupport ann = U.getAnnotation(spi.getClass(),
                    GridSpiMultipleInstancesSupport.class);

            if (ann == null || !ann.value())
                throw new GridException(
                        "SPI implementation doesn't support multiple grid instances in " + "the same VM: " + spi);
        }

        /**
         * @param spis SPI implementations.
         * @throws GridException Thrown in case if multi-instance is not supported.
         */
        private void ensureMultiInstanceSupport(GridSpi[] spis) throws GridException {
            for (GridSpi spi : spis)
                ensureMultiInstanceSupport(spi);
        }

        /**
         * Starts grid with given configuration.
         *
         * @param cfg Grid configuration (possibly {@code null}).
         * @param single Whether or not this is a single grid instance in current VM.
         * @param ctx Optional Spring application context.
         * @throws GridException If start failed.
         */
        synchronized void start(GridConfiguration cfg, boolean single, @Nullable ApplicationContext ctx)
                throws GridException {
            if (startGuard.compareAndSet(false, true)) {
                try {
                    starterThread = Thread.currentThread();

                    start0(cfg, single, ctx);
                } finally {
                    startLatch.countDown();
                }
            } else
                U.awaitQuiet(startLatch);
        }

        /**
         * @param cfg Grid configuration (possibly {@code null}).
         * @param single Whether or not this is a single grid instance in current VM.
         * @param ctx Optional Spring application context.
         * @throws GridException If start failed.
         */
        @SuppressWarnings("deprecation")
        private void start0(GridConfiguration cfg, boolean single, ApplicationContext ctx) throws GridException {
            assert grid == null : "Grid is already started: " + name;

            if (cfg == null)
                cfg = new GridConfigurationAdapter();

            GridConfigurationAdapter myCfg = new GridConfigurationAdapter();

            /*
             * 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());

            myCfg.setGridName(cfg.getGridName());

            UUID nodeId = cfg.getNodeId();

            if (nodeId == null)
                nodeId = UUID.randomUUID();

            GridLogger cfgLog = cfg.getGridLogger();

            if (cfgLog == null) {
                URL url = U.resolveGridGainUrl("config/default-log4j.xml");

                cfgLog = url == null || GridLog4jLogger.isConfigured() ? new GridLog4jLogger()
                        : new GridLog4jLogger(url);
            }

            assert cfgLog != null;

            cfgLog = new GridLoggerProxy(cfgLog, null, name, U.id8(nodeId));

            // Initialize factory's log.
            log = cfgLog.getLogger(G.class);

            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.
                System.setProperty(GG_HOME, ggHome);

            // Check GridGain home folder.
            if (ggHome == null)
                U.warn(log,
                        "Failed to detect GridGain installation home. It was neither provided in "
                                + "GridConfiguration nor it could be detected from " + GG_HOME
                                + " system property or environmental variable.",
                        "Failed to detect GridGain installation home.");
            else {
                File ggHomeFile = new File(ggHome);

                if (!ggHomeFile.exists() || !ggHomeFile.isDirectory())
                    throw new GridException("Invalid GridGain installation home folder: " + ggHome);
            }

            myCfg.setGridGainHome(ggHome);

            // Handle the license URL only for Enterprise Edition.
            if (U.isEnterprise()) {
                String licUrl = cfg.getLicenseUrl();

                if (licUrl == null) {
                    URL url = U.resolveGridGainUrl(LIC_FILE_NAME);

                    if (url != null)
                        try {
                            licUrl = url.toURI().toASCIIString();
                        } catch (URISyntaxException ignore) {
                            // Ignore here.
                        }

                    if (licUrl == null)
                        throw new GridException("License URL is not provided and cannot be determined.");
                }

                assert licUrl != null;

                myCfg.setLicenseUrl(licUrl);
            }

            // Copy values that don't need extra processing.
            myCfg.setPeerClassLoadingEnabled(cfg.isPeerClassLoadingEnabled());
            myCfg.setDeploymentMode(cfg.getDeploymentMode());
            myCfg.setNetworkTimeout(cfg.getNetworkTimeout());
            myCfg.setDiscoveryStartupDelay(cfg.getDiscoveryStartupDelay());
            myCfg.setMetricsHistorySize(cfg.getMetricsHistorySize());
            myCfg.setMetricsExpireTime(cfg.getMetricsExpireTime());
            myCfg.setLifecycleBeans(cfg.getLifecycleBeans());
            myCfg.setPeerClassLoadingMissedResourcesCacheSize(cfg.getPeerClassLoadingMissedResourcesCacheSize());
            myCfg.setIncludeEventTypes(cfg.getIncludeEventTypes());
            myCfg.setExcludeEventTypes(cfg.getExcludeEventTypes());
            myCfg.setDaemon(cfg.isDaemon());
            myCfg.setIncludeProperties(cfg.getIncludeProperties());
            myCfg.setLifeCycleEmailNotification(cfg.isLifeCycleEmailNotification());
            myCfg.setMetricsLogFrequency(cfg.getMetricsLogFrequency());
            myCfg.setLocalEventListeners(cfg.getLocalEventListeners());

            String ntfStr = X.getSystemOrEnv(GG_LIFECYCLE_EMAIL_NOTIFY);

            if (ntfStr != null)
                myCfg.setLifeCycleEmailNotification(Boolean.parseBoolean(ntfStr));

            // Local host.
            String locHost = X.getSystemOrEnv(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 = X.getSystemOrEnv(GG_DEP_MODE_OVERRIDE);

            if (!F.isEmpty(depModeName)) {
                try {
                    GridDeploymentMode depMode = GridDeploymentMode.valueOf(depModeName);

                    if (myCfg.getDeploymentMode() != depMode)
                        myCfg.setDeploymentMode(depMode);
                } catch (IllegalArgumentException e) {
                    throw new GridException("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();

            GridMarshaller marsh = cfg.getMarshaller();

            String[] p2pExclude = cfg.getPeerClassLoadingClassPathExclude();

            GridCommunicationSpi commSpi = cfg.getCommunicationSpi();
            GridDiscoverySpi discoSpi = cfg.getDiscoverySpi();
            GridEventStorageSpi evtSpi = cfg.getEventStorageSpi();
            GridCollisionSpi colSpi = cfg.getCollisionSpi();
            GridLocalMetricsSpi metricsSpi = cfg.getMetricsSpi();
            GridAuthenticationSpi authSpi = cfg.getAuthenticationSpi();
            GridSecureSessionSpi sesSpi = cfg.getSecureSessionSpi();
            GridDeploymentSpi deploySpi = cfg.getDeploymentSpi();
            GridCheckpointSpi[] cpSpi = cfg.getCheckpointSpi();
            GridTopologySpi[] topSpi = cfg.getTopologySpi();
            GridFailoverSpi[] failSpi = cfg.getFailoverSpi();
            GridLoadBalancingSpi[] loadBalancingSpi = cfg.getLoadBalancingSpi();
            GridSwapSpaceSpi[] swapspaceSpi = cfg.getSwapSpaceSpi();

            execSvc = cfg.getExecutorService();
            sysExecSvc = cfg.getSystemExecutorService();
            p2pExecSvc = cfg.getPeerClassLoadingExecutorService();

            if (execSvc == null) {
                isAutoExecSvc = true;

                execSvc = new GridThreadPoolExecutor(cfg.getGridName(), DFLT_PUBLIC_THREAD_CNT,
                        DFLT_PUBLIC_THREAD_CNT, 0, new LinkedBlockingQueue<Runnable>());

                // 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.
                // Note, that we do not pre-start threads here as system pool may
                // not be needed.
                sysExecSvc = new GridThreadPoolExecutor(cfg.getGridName(), DFLT_SYSTEM_THREAD_CNT,
                        DFLT_SYSTEM_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 GridThreadPoolExecutor(cfg.getGridName(), DFLT_P2P_THREAD_CNT, DFLT_P2P_THREAD_CNT,
                        0, new LinkedBlockingQueue<Runnable>());
            }

            execSvcShutdown = cfg.getExecutorServiceShutdown();
            sysSvcShutdown = cfg.getSystemExecutorServiceShutdown();
            p2pSvcShutdown = cfg.getPeerClassLoadingExecutorServiceShutdown();

            if (marsh == null)
                marsh = new GridOptimizedMarshaller();

            myCfg.setUserAttributes(attrs);
            myCfg.setMBeanServer(mbSrv == null ? ManagementFactory.getPlatformMBeanServer() : mbSrv);
            myCfg.setGridLogger(cfgLog);
            myCfg.setMarshaller(marsh);
            myCfg.setExecutorService(execSvc);
            myCfg.setSystemExecutorService(sysExecSvc);
            myCfg.setPeerClassLoadingExecutorService(p2pExecSvc);
            myCfg.setExecutorServiceShutdown(execSvcShutdown);
            myCfg.setSystemExecutorServiceShutdown(sysSvcShutdown);
            myCfg.setPeerClassLoadingExecutorServiceShutdown(p2pSvcShutdown);
            myCfg.setNodeId(nodeId);

            if (p2pExclude == null)
                p2pExclude = EMPTY_STR_ARR;

            myCfg.setPeerClassLoadingLocalClassPathExclude(p2pExclude);

            // Initialize default SPI implementations.

            if (commSpi == null)
                commSpi = new GridTcpCommunicationSpi();

            if (discoSpi == null)
                discoSpi = new GridMulticastDiscoverySpi();

            if (evtSpi == null)
                evtSpi = new GridMemoryEventStorageSpi();

            if (colSpi == null)
                colSpi = new GridFifoQueueCollisionSpi();

            if (metricsSpi == null)
                metricsSpi = new GridJdkLocalMetricsSpi();

            if (authSpi == null)
                authSpi = new GridNoopAuthenticationSpi();

            if (sesSpi == null)
                sesSpi = new GridNoopSecureSessionSpi();

            if (deploySpi == null)
                deploySpi = new GridLocalDeploymentSpi();

            if (cpSpi == null)
                cpSpi = new GridCheckpointSpi[] { new GridSharedFsCheckpointSpi() };

            if (topSpi == null)
                topSpi = new GridTopologySpi[] { new GridBasicTopologySpi() };

            if (failSpi == null)
                failSpi = new GridFailoverSpi[] { new GridAlwaysFailoverSpi() };

            if (loadBalancingSpi == null)
                loadBalancingSpi = new GridLoadBalancingSpi[] { new GridRoundRobinLoadBalancingSpi() };

            if (swapspaceSpi == null)
                swapspaceSpi = new GridSwapSpaceSpi[] { new GridLevelDbSwapSpaceSpi() };

            myCfg.setCommunicationSpi(commSpi);
            myCfg.setDiscoverySpi(discoSpi);
            myCfg.setCheckpointSpi(cpSpi);
            myCfg.setEventStorageSpi(evtSpi);
            myCfg.setMetricsSpi(metricsSpi);
            myCfg.setAuthenticationSpi(authSpi);
            myCfg.setSecureSessionSpi(sesSpi);
            myCfg.setDeploymentSpi(deploySpi);
            myCfg.setTopologySpi(topSpi);
            myCfg.setFailoverSpi(failSpi);
            myCfg.setCollisionSpi(colSpi);
            myCfg.setLoadBalancingSpi(loadBalancingSpi);
            myCfg.setSwapSpaceSpi(swapspaceSpi);

            // 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.setRestEnabled(cfg.isRestEnabled());
            myCfg.setRestJettyPath(cfg.getRestJettyPath());
            myCfg.setRestSecretKey(cfg.getRestSecretKey());
            myCfg.setRestAccessibleFolders(cfg.getRestAccessibleFolders());
            myCfg.setRestJettyPort(cfg.getRestJettyPort());
            myCfg.setRestTcpHost(cfg.getRestTcpHost());
            myCfg.setRestTcpNoDelay(cfg.isRestTcpNoDelay());
            myCfg.setRestTcpPort(cfg.getRestTcpPort());
            myCfg.setRestTcpSslClientAuth(cfg.isRestTcpSslClientAuth());
            myCfg.setRestTcpSslContextFactory(cfg.getRestTcpSslContextFactory());
            myCfg.setRestTcpSslEnabled(cfg.isRestTcpSslEnabled());

            // Validate segmentation configuration.
            if (!F.isEmpty(cfg.getSegmentationResolvers())) {
                // Segment check enabled, validate configuration.
                GridDiscoverySpiReconnectSupport ann = U.getAnnotation(discoSpi.getClass(),
                        GridDiscoverySpiReconnectSupport.class);

                if (cfg.getSegmentationPolicy() == RECONNECT && (ann == null || !ann.value())) {
                    throw new GridException("Discovery SPI does not support reconnect (either change segmentation "
                            + "policy or discovery SPI implementation to one that supports reconnect), "
                            + "like GridTcpDiscoverySpi.");
                }

                if ((cfg.getSegmentationPolicy() == RESTART_JVM || cfg.getSegmentationPolicy() == RECONNECT)
                        && !cfg.isWaitForSegmentOnStart()) {
                    U.warn(log, "Found potential configuration problem (forgot to enable waiting for segment"
                            + "on start?) [segPlc=" + cfg.getSegmentationPolicy() + ", wait=false]");
                }

                if (cfg.getSegmentationPolicy() == RECONNECT) {
                    GridCacheConfiguration[] cacheCfgs = cfg.getCacheConfiguration();

                    if (cacheCfgs != null) {
                        for (GridCacheConfiguration cc : cacheCfgs)
                            if (cc.getCacheMode() == REPLICATED || cc.getCacheMode() == PARTITIONED)
                                throw new GridException("RECONNECT segmentation policy is not supported "
                                        + "when running distributed data grid.");
                    }
                }
            }

            myCfg.setSegmentationResolvers(cfg.getSegmentationResolvers());
            myCfg.setSegmentationPolicy(cfg.getSegmentationPolicy());
            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 = X.getSystemOrEnv(GG_SMTP_FROM);

            if (fromEmail != null)
                myCfg.setSmtpFromEmail(fromEmail);

            String smtpHost = X.getSystemOrEnv(GG_SMTP_HOST);

            if (smtpHost != null)
                myCfg.setSmtpHost(smtpHost);

            String smtpUsername = X.getSystemOrEnv(GG_SMTP_USERNAME);

            if (smtpUsername != null)
                myCfg.setSmtpUsername(smtpUsername);

            String smtpPwd = X.getSystemOrEnv(GG_SMTP_PWD);

            if (smtpPwd != null)
                myCfg.setSmtpPassword(smtpPwd);

            String smtpPort = X.getSystemOrEnv(GG_SMTP_PORT);

            if (smtpPort != null)
                try {
                    myCfg.setSmtpPort(Integer.parseInt(smtpPort));
                } catch (NumberFormatException e) {
                    U.error(log, "Invalid SMTP port override value (safely ignored): " + smtpPort, e);
                }

            String smtpSsl = X.getSystemOrEnv(GG_SMTP_SSL);

            if (smtpSsl != null)
                myCfg.setSmtpSsl(Boolean.parseBoolean(smtpSsl));

            String adminEmails = X.getSystemOrEnv(GG_ADMIN_EMAILS);

            if (adminEmails != null)
                myCfg.setAdminEmails(adminEmails.split(","));

            GridCacheConfiguration[] cacheCfgs = cfg.getCacheConfiguration();

            if (cacheCfgs != null) {
                if (cacheCfgs.length > 0) {
                    if (!discoOrdered(discoSpi) && !relaxDiscoveryOrdered())
                        throw new GridException("Discovery SPI implementation does not support node ordering and "
                                + "cannot be used with cache (use SPI with @GridDiscoverySpiOrderSupport annotation, "
                                + "like GridTcpDiscoverySpi)");

                    GridCacheConfiguration[] clone = cacheCfgs.clone();

                    for (int i = 0; i < cacheCfgs.length; i++)
                        clone[i] = new GridCacheConfigurationAdapter(cacheCfgs[i]);

                    myCfg.setCacheConfiguration(clone);
                } else
                    myCfg.setCacheConfiguration(cacheCfgs);
            } else {
                cacheCfgs = discoOrdered(discoSpi) || relaxDiscoveryOrdered()
                        ? new GridCacheConfiguration[] { new GridCacheConfigurationAdapter() }
                        : EMPTY_CACHE_CONFIGS;

                myCfg.setCacheConfiguration(cacheCfgs);
            }

            try {
                Class helperCls = Class.forName("org.gridgain.grid.util.GridConfigurationHelper");

                helperCls.getMethod("overrideConfiguration", GridConfiguration.class, Properties.class,
                        String.class, GridLogger.class).invoke(helperCls, myCfg, System.getProperties(), name, log);
            } catch (Exception ignored) {
                // No-op.
            }

            // Ensure that SPIs support multiple grid instances, if required.
            if (!single) {
                ensureMultiInstanceSupport(deploySpi);
                ensureMultiInstanceSupport(commSpi);
                ensureMultiInstanceSupport(discoSpi);
                ensureMultiInstanceSupport(cpSpi);
                ensureMultiInstanceSupport(evtSpi);
                ensureMultiInstanceSupport(topSpi);
                ensureMultiInstanceSupport(colSpi);
                ensureMultiInstanceSupport(failSpi);
                ensureMultiInstanceSupport(metricsSpi);
                ensureMultiInstanceSupport(authSpi);
                ensureMultiInstanceSupport(sesSpi);
                ensureMultiInstanceSupport(loadBalancingSpi);
                ensureMultiInstanceSupport(swapspaceSpi);
            }

            // Register GridFactory MBean for current grid instance.
            try {
                registerFactoryMbean(myCfg.getMBeanServer());
            } catch (GridException e) {
                stopExecutor(log);

                throw e;
            }
            // Catch Throwable to protect against any possible failure.
            catch (Throwable e) {
                stopExecutor(log);

                throw new GridException("Unexpected exception when starting grid.", e);
            }

            boolean started = false;

            try {
                GridKernal grid0 = new GridKernal(ctx);

                // Init here to make grid available to lifecycle listeners.
                grid = grid0;

                grid0.start(myCfg, new CA() {
                    @Override
                    public void apply() {
                        startLatch.countDown();
                    }
                });

                state = STARTED;

                if (log.isDebugEnabled())
                    log.debug("Grid factory started ok: " + name);

                started = true;
            } catch (GridException e) {
                stopExecutor(log);

                unregisterFactoryMBean();

                throw e;
            }
            // Catch Throwable to protect against any possible failure.
            catch (Throwable e) {
                stopExecutor(log);

                unregisterFactoryMBean();

                throw new GridException("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 (!"true".equalsIgnoreCase(X.getSystemOrEnv(GG_NO_SHUTDOWN_HOOK))) {
                try {
                    Runtime.getRuntime().addShutdownHook(shutdownHook = new Thread() {
                        @Override
                        public void run() {
                            if (log.isInfoEnabled())
                                log.info("Invoking shutdown hook...");

                            GridNamedInstance.this.stop(true, false);
                        }
                    });

                    if (log.isDebugEnabled())
                        log.debug("Shutdown hook is installed.");
                } catch (IllegalStateException e) {
                    stop(true, false);

                    throw new GridException("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 discoSpi Discovery SPI.
         * @return {@code True} if ordering is supported.
         */
        private static boolean discoOrdered(GridDiscoverySpi discoSpi) {
            GridDiscoverySpiOrderSupport ann = U.getAnnotation(discoSpi.getClass(),
                    GridDiscoverySpiOrderSupport.class);

            return ann != null && ann.value();
        }

        /**
         * @return Checks if disco ordering should be enforced.
         */
        private static boolean relaxDiscoveryOrdered() {
            return "true".equalsIgnoreCase(System.getProperty(GG_NO_DISCO_ORDER));
        }

        /**
         * Stops grid.
         *
         * @param cancel Flag indicating whether all currently running jobs
         *      should be cancelled.
         * @param wait If {@code true} then method will wait for all task being
         *      executed until they finish their execution.
         */
        void stop(boolean cancel, boolean wait) {
            // 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, wait);
        }

        /**
         * @param cancel Flag indicating whether all currently running jobs
         *      should be cancelled.
         * @param wait If {@code true} then method will wait for all task being
         *      executed until they finish their execution.
         */
        private synchronized void stop0(boolean cancel, boolean wait) {
            GridKernal 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 GridFactory MBean.
            unregisterFactoryMBean();

            try {
                grid0.stop(cancel, wait);

                if (log.isDebugEnabled())
                    log.debug("Grid instance stopped ok: " + name);
            } catch (Throwable e) {
                U.error(log, "Failed to properly stop grid instance due to undeclared exception.", e);
            } finally {
                state = grid0.context().segmented() ? STOPPED_ON_SEGMENTATION : STOPPED;

                grid = null;

                stopExecutor(log);

                log = null;
            }
        }

        /**
         * Stops executor service if it has been started.
         *
         * @param log Grid logger.
         */
        private void stopExecutor(GridLogger log) {
            assert log != null;
            assert execSvc != null;
            assert sysExecSvc != null;
            assert p2pExecSvc != null;

            /*
             * 1.
             * Attempt to stop all still active grid workers.
             * Note that these runnable should have been stopped
             * by the kernal. We are trying to be defensive here
             * so the logic is repetitive with kernal.
             */
            for (GridWorker w : GridWorkerGroup.instance(name).activeWorkers()) {
                String n1 = w.gridName() == null ? "" : w.gridName();
                String n2 = name == null ? "" : name;

                /*
                 * We should never get a runnable from one grid instance
                 * in the runnable group for another grid instance.
                 */
                assert n1.equals(n2);

                U.warn(log, "Runnable job outlived grid: " + w.name());

                U.cancel(w);
                U.join(w, log);
            }

            // Release memory.
            GridWorkerGroup.removeInstance(name);

            /*
             * 2.
             * If it was us who started the executor services than we
             * stop it. Otherwise, we do no-op since executor service
             * was started before us.
             */
            if (isAutoExecSvc || execSvcShutdown) {
                U.shutdownNow(getClass(), execSvc, log);

                execSvc = null;
            }

            if (isAutoSysSvc || sysSvcShutdown) {
                U.shutdownNow(getClass(), sysExecSvc, log);

                sysExecSvc = null;
            }

            if (isAutoP2PSvc || p2pSvcShutdown) {
                U.shutdownNow(getClass(), p2pExecSvc, log);

                p2pExecSvc = null;
            }
        }

        /**
         * Registers delegate Mbean instance for {@link GridFactory}.
         *
         * @param srv MBeanServer where mbean should be registered.
         * @throws GridException If registration failed.
         */
        private void registerFactoryMbean(MBeanServer srv) throws GridException {
            synchronized (mbeans) {
                GridMBeanServerData data = mbeans.get(srv);

                if (data == null) {
                    try {
                        GridFactoryMBean mbean = new GridFactoryMBeanAdapter();

                        ObjectName objName = U.makeMBeanName(null, "Kernal", GridFactory.class.getSimpleName());

                        // Make check if MBean was already registered.
                        if (!srv.queryMBeans(objName, null).isEmpty())
                            throw new GridException("MBean was already registered: " + objName);
                        else {
                            objName = U.registerMBean(srv, null, "Kernal", GridFactory.class.getSimpleName(), mbean,
                                    GridFactoryMBean.class);

                            data = new GridMBeanServerData(objName);

                            mbeans.put(srv, data);

                            if (log.isDebugEnabled())
                                log.debug("Registered MBean: " + objName);
                        }
                    } catch (JMException e) {
                        throw new GridException("Failed to register MBean.", e);
                    }
                }

                assert data != null;

                data.addGrid(name);
                data.setCounter(data.getCounter() + 1);
            }
        }

        /**
         * Unregister delegate Mbean instance for {@link GridFactory}.
         */
        private void unregisterFactoryMBean() {
            synchronized (mbeans) {
                Iterator<Entry<MBeanServer, GridMBeanServerData>> iter = mbeans.entrySet().iterator();

                while (iter.hasNext()) {
                    Entry<MBeanServer, GridMBeanServerData> entry = iter.next();

                    if (entry.getValue().containsGrid(name)) {
                        GridMBeanServerData data = entry.getValue();

                        assert data != null;

                        // Unregister MBean if no grid instances started for current MBeanServer.
                        if (data.getCounter() == 1) {
                            try {
                                entry.getKey().unregisterMBean(data.getMbean());

                                if (log.isDebugEnabled())
                                    log.debug("Unregistered MBean: " + data.getMbean());
                            } catch (JMException e) {
                                U.error(log, "Failed to unregister MBean.", e);
                            }

                            iter.remove();
                        } else {
                            // Decrement counter.
                            data.setCounter(data.getCounter() - 1);
                            data.removeGrid(name);
                        }
                    }
                }
            }
        }

        /**
         * Grid factory MBean data container.
         * Contains necessary data for selected MBeanServer.
         *
         * @author 2012 Copyright (C) GridGain Systems
         * @version 4.0.2c.12042012
         */
        private static class GridMBeanServerData {
            /** Set of grid names for selected MBeanServer. */
            private Collection<String> gridNames = new HashSet<String>();

            /** */
            private ObjectName mbean;

            /** Count of grid instances. */
            private int cnt;

            /**
             * Create data container.
             *
             * @param mbean Object name of MBean.
             */
            GridMBeanServerData(ObjectName mbean) {
                assert mbean != null;

                this.mbean = mbean;
            }

            /**
             * Add grid name.
             *
             * @param gridName Grid name.
             */
            public void addGrid(String gridName) {
                gridNames.add(gridName);
            }

            /**
             * Remove grid name.
             *
             * @param gridName Grid name.
             */
            public void removeGrid(String gridName) {
                gridNames.remove(gridName);
            }

            /**
             * Returns {@code true} if data contains the specified
             * grid name.
             *
             * @param gridName Grid name.
             * @return {@code true} if data contains the specified grid name.
             */
            public boolean containsGrid(String gridName) {
                return gridNames.contains(gridName);
            }

            /**
             * Gets name used in MBean server.
             *
             * @return Object name of MBean.
             */
            public ObjectName getMbean() {
                return mbean;
            }

            /**
             * Gets number of grid instances working with MBeanServer.
             *
             * @return Number of grid instances.
             */
            public int getCounter() {
                return cnt;
            }

            /**
             * Sets number of grid instances working with MBeanServer.
             *
             * @param cnt Number of grid instances.
             */
            public void setCounter(int cnt) {
                this.cnt = cnt;
            }
        }
    }
}