/**
   * Starts Grid instance. Note that if grid is already started, then it will be looked up and
   * returned from this method.
   *
   * @return Started grid.
   */
  private Grid startGrid() {
    Properties props = System.getProperties();

    gridName = props.getProperty(GRIDGAIN_NAME.name());

    if (!props.containsKey(GRIDGAIN_NAME.name()) || G.state(gridName) != GridFactoryState.STARTED) {
      selfStarted = true;

      // Set class loader for the spring.
      ClassLoader curCl = Thread.currentThread().getContextClassLoader();

      // Add no-op logger to remove no-appender warning.
      Appender app = new NullAppender();

      Logger.getRootLogger().addAppender(app);

      try {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

        Grid grid = G.start(cfgPath);

        gridName = grid.name();

        System.setProperty(GRIDGAIN_NAME.name(), grid.name());

        return grid;
      } catch (GridException e) {
        throw new GridRuntimeException("Failed to start grid: " + cfgPath, e);
      } finally {
        Logger.getRootLogger().removeAppender(app);

        Thread.currentThread().setContextClassLoader(curCl);
      }
    }

    return G.grid(gridName);
  }
  /**
   * Aspect implementation which executes grid-enabled methods on remote nodes.
   *
   * @param invoc Method invocation instance provided by JBoss AOP framework.
   * @return Method execution result.
   * @throws Throwable If method execution failed.
   */
  @SuppressWarnings({
    "ProhibitedExceptionDeclared",
    "ProhibitedExceptionThrown",
    "CatchGenericClass",
    "unchecked"
  })
  @Bind(
      pointcut = "execution(* *->@org.gridgain.grid.gridify.Gridify(..))",
      cflow = "org.gridgain.grid.gridify.aop.jboss.GridifyJbossAspect.CFLOW_STACK")
  public Object gridify(MethodInvocation invoc) throws Throwable {
    Method mtd = invoc.getMethod();

    Gridify ann = mtd.getAnnotation(Gridify.class);

    assert ann != null : "Intercepted method does not have gridify annotation.";

    // Since annotations in Java don't allow 'null' as default value
    // we have accept an empty string and convert it here.
    // NOTE: there's unintended behavior when user specifies an empty
    // string as intended grid name.
    // NOTE: the 'ann.gridName() == null' check is added to mitigate
    // annotation bugs in some scripting languages (e.g. Groovy).
    String gridName = F.isEmpty(ann.gridName()) ? null : ann.gridName();

    if (G.state(gridName) != STARTED) {
      throw new GridException("Grid is not locally started: " + gridName);
    }

    // Initialize defaults.
    GridifyArgument arg =
        new GridifyArgumentAdapter(
            mtd.getDeclaringClass(),
            mtd.getName(),
            mtd.getParameterTypes(),
            invoc.getArguments(),
            invoc.getTargetObject());

    if (!ann.interceptor().equals(GridifyInterceptor.class)) {
      // Check interceptor first.
      if (!ann.interceptor().newInstance().isGridify(ann, arg)) {
        return invoc.invokeNext();
      }
    }

    if (!ann.taskClass().equals(GridifyDefaultTask.class) && ann.taskName().length() > 0) {
      throw new GridException(
          "Gridify annotation must specify either Gridify.taskName() or "
              + "Gridify.taskClass(), but not both: "
              + ann);
    }

    try {
      Grid grid = G.grid(gridName);

      // If task class was specified.
      if (!ann.taskClass().equals(GridifyDefaultTask.class)) {
        return grid.execute(
                (Class<? extends GridTask<GridifyArgument, Object>>) ann.taskClass(),
                arg,
                ann.timeout())
            .get();
      }

      // If task name was not specified.
      if (ann.taskName().length() == 0) {
        return grid.execute(
                new GridifyDefaultTask(invoc.getActualMethod().getDeclaringClass()),
                arg,
                ann.timeout())
            .get();
      }

      // If task name was specified.
      return grid.execute(ann.taskName(), arg, ann.timeout()).get();
    } catch (Throwable e) {
      for (Class<?> ex : invoc.getMethod().getExceptionTypes()) {
        // Descend all levels down.
        Throwable cause = e.getCause();

        while (cause != null) {
          if (ex.isAssignableFrom(cause.getClass())) {
            throw cause;
          }

          cause = cause.getCause();
        }

        if (ex.isAssignableFrom(e.getClass())) {
          throw e;
        }
      }

      throw new GridifyRuntimeException("Undeclared exception thrown: " + e.getMessage(), e);
    }
  }