private void verifyClusterGroup() throws ManageActionException {
    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();

    String[] requiredClusterNodesIds = _clusterGroup.getClusterNodeIdsArray();

    for (String requiredClusterNodeId : requiredClusterNodesIds) {
      boolean verified = false;

      Iterator<ClusterNode> itr = clusterNodes.iterator();

      while (itr.hasNext()) {
        ClusterNode clusterNode = itr.next();

        String clusterNodeId = clusterNode.getClusterNodeId();

        if (clusterNodeId.equals(requiredClusterNodeId)) {
          itr.remove();

          verified = true;

          break;
        }
      }

      if (!verified) {
        throw new ManageActionException(
            "Cluster node " + requiredClusterNodeId + " is not available");
      }
    }
  }
  private static void _registerClusterOrder(
      HttpServletRequest request,
      ClusterNode clusterNode,
      String orderUuid,
      String productEntryName,
      int maxServers)
      throws Exception {

    MethodHandler methodHandler =
        new MethodHandler(_registerOrderMethodKey, orderUuid, productEntryName, maxServers);

    ClusterRequest clusterRequest =
        ClusterRequest.createUnicastRequest(methodHandler, clusterNode.getClusterNodeId());

    FutureClusterResponses futureClusterResponses = ClusterExecutorUtil.execute(clusterRequest);

    ClusterNodeResponses clusterNodeResponses =
        futureClusterResponses.get(20000, TimeUnit.MILLISECONDS);

    ClusterNodeResponse clusterNodeResponse = clusterNodeResponses.getClusterResponse(clusterNode);

    Map<String, Object> attributes = (Map<String, Object>) clusterNodeResponse.getResult();

    for (Map.Entry<String, Object> entry : attributes.entrySet()) {
      request.setAttribute(
          clusterNode.getClusterNodeId() + StringPool.UNDERLINE + entry.getKey(), entry.getValue());
    }
  }
  private ObjectValuePair<String, URL> _getBootupClusterNodeObjectValuePair(Address bootupAddress) {

    ClusterRequest clusterRequest =
        ClusterRequest.createUnicastRequest(
            new MethodHandler(_createTokenMethodKey, _CLUSTER_LINK_NODE_BOOTUP_RESPONSE_TIMEOUT),
            bootupAddress);

    FutureClusterResponses futureClusterResponses = ClusterExecutorUtil.execute(clusterRequest);

    BlockingQueue<ClusterNodeResponse> clusterNodeResponses =
        futureClusterResponses.getPartialResults();

    try {
      ClusterNodeResponse clusterNodeResponse =
          clusterNodeResponses.poll(
              _CLUSTER_LINK_NODE_BOOTUP_RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS);

      ClusterNode clusterNode = clusterNodeResponse.getClusterNode();

      InetSocketAddress inetSocketAddress = clusterNode.getPortalInetSocketAddress();

      if (inetSocketAddress == null) {
        StringBundler sb = new StringBundler(6);

        sb.append("Invalid cluster node InetSocketAddress ");
        sb.append(". The InetSocketAddress is set by the first ");
        sb.append("request or configured in portal.properties by the");
        sb.append("properties ");
        sb.append("\"portal.instance.http.inet.socket.address\" and ");
        sb.append("\"portal.instance.https.inet.socket.address\".");

        throw new Exception(sb.toString());
      }

      InetAddress inetAddress = inetSocketAddress.getAddress();

      String fileName = PortalUtil.getPathContext();

      if (!fileName.endsWith(StringPool.SLASH)) {
        fileName = fileName.concat(StringPool.SLASH);
      }

      fileName = fileName.concat("lucene/dump");

      URL url =
          new URL(_protocol, inetAddress.getHostAddress(), inetSocketAddress.getPort(), fileName);

      String transientToken = (String) clusterNodeResponse.getResult();

      return new ObjectValuePair<String, URL>(transientToken, url);
    } catch (Exception e) {
      throw new SystemException(e);
    }
  }
  protected void initLocalClusterNode() {
    InetAddress inetAddress = getBindInetAddress(_controlJChannel);

    ClusterNode clusterNode = new ClusterNode(PortalUUIDUtil.generate(), inetAddress);

    if (Validator.isNull(PropsValues.PORTAL_INSTANCE_PROTOCOL)) {
      _localClusterNode = clusterNode;

      return;
    }

    if (Validator.isNull(PropsValues.PORTAL_INSTANCE_INET_SOCKET_ADDRESS)) {
      throw new IllegalArgumentException(
          "Portal instance host name and port needs to be set in the "
              + "property \"portal.instance.inet.socket.address\"");
    }

    String[] parts =
        StringUtil.split(PropsValues.PORTAL_INSTANCE_INET_SOCKET_ADDRESS, CharPool.COLON);

    if (parts.length != 2) {
      throw new IllegalArgumentException(
          "Unable to parse the portal instance host name and port from "
              + PropsValues.PORTAL_INSTANCE_INET_SOCKET_ADDRESS);
    }

    InetAddress hostInetAddress = null;

    try {
      hostInetAddress = InetAddress.getByName(parts[0]);
    } catch (UnknownHostException uhe) {
      throw new IllegalArgumentException(
          "Unable to parse the portal instance host name and port from "
              + PropsValues.PORTAL_INSTANCE_INET_SOCKET_ADDRESS,
          uhe);
    }

    int port = -1;

    try {
      port = GetterUtil.getIntegerStrict(parts[1]);
    } catch (NumberFormatException nfe) {
      throw new IllegalArgumentException(
          "Unable to parse portal InetSocketAddress port from "
              + PropsValues.PORTAL_INSTANCE_INET_SOCKET_ADDRESS,
          nfe);
    }

    clusterNode.setPortalInetSocketAddress(new InetSocketAddress(hostInetAddress, port));

    clusterNode.setPortalProtocol(PropsValues.PORTAL_INSTANCE_PROTOCOL);

    _localClusterNode = clusterNode;
  }
  @Override
  public FutureClusterResponses execute(ClusterRequest clusterRequest) {
    if (!isEnabled()) {
      return null;
    }

    List<Address> addresses = prepareAddresses(clusterRequest);

    Set<String> clusterNodeIds = new HashSet<>();

    for (Address address : addresses) {
      ClusterNode clusterNode = _liveInstances.get(address);

      if (clusterNode != null) {
        clusterNodeIds.add(clusterNode.getClusterNodeId());
      }
    }

    FutureClusterResponses futureClusterResponses = new FutureClusterResponses(clusterNodeIds);

    if (!clusterRequest.isFireAndForget()) {
      String uuid = clusterRequest.getUuid();

      _futureClusterResponses.put(uuid, futureClusterResponses);
    }

    if (addresses.remove(_localAddress)) {
      ClusterNodeResponse clusterNodeResponse = executeClusterRequest(clusterRequest);

      if (!clusterRequest.isFireAndForget()) {
        futureClusterResponses.addClusterNodeResponse(clusterNodeResponse);
      }
    }

    if (clusterRequest.isMulticast()) {
      try {
        _controlJChannel.send(null, clusterRequest);
      } catch (Exception e) {
        throw new SystemException("Unable to send multicast request", e);
      }
    } else {
      for (Address address : addresses) {
        org.jgroups.Address jGroupsAddress = (org.jgroups.Address) address.getRealAddress();

        try {
          _controlJChannel.send(jGroupsAddress, clusterRequest);
        } catch (Exception e) {
          throw new SystemException("Unable to send unicast request", e);
        }
      }
    }

    return futureClusterResponses;
  }
  public static <T> T manageSync(ClusterNode clusterNode, ManageAction<T> manageAction)
      throws Exception {

    ClusterGroup clusterGroup = ClusterGroupLocalServiceUtil.createClusterGroup(0);

    clusterGroup.setClusterNodeIds(clusterNode.getClusterNodeId());

    FutureClusterResponses futureClusterResponses = manage(clusterGroup, manageAction);

    ClusterNodeResponses clusterNodeResponses = futureClusterResponses.get();

    ClusterNodeResponse clusterNodeResponse =
        clusterNodeResponses.getClusterResponse(clusterNode.getClusterNodeId());

    return (T) clusterNodeResponse.getResult();
  }
  public static void manageAsync(ClusterNode clusterNode, ManageAction<?> manageAction)
      throws Exception {

    ClusterGroup clusterGroup = ClusterGroupLocalServiceUtil.createClusterGroup(0);

    clusterGroup.setClusterNodeIds(clusterNode.getClusterNodeId());

    manage(clusterGroup, manageAction);
  }
  public static Map<String, String> getClusterServerInfo(String clusterNodeId) throws Exception {

    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();

    ClusterNode clusterNode = null;

    for (ClusterNode curClusterNode : clusterNodes) {
      String curClusterNodeId = curClusterNode.getClusterNodeId();

      if (curClusterNodeId.equals(clusterNodeId)) {
        clusterNode = curClusterNode;

        break;
      }
    }

    if (clusterNode == null) {
      return null;
    }

    try {
      if (clusterNode.equals(ClusterExecutorUtil.getLocalClusterNode())) {
        return getServerInfo();
      }

      ClusterRequest clusterRequest =
          ClusterRequest.createUnicastRequest(_getServerInfoMethodHandler, clusterNodeId);

      FutureClusterResponses futureClusterResponses = ClusterExecutorUtil.execute(clusterRequest);

      ClusterNodeResponses clusterNodeResponses =
          futureClusterResponses.get(20000, TimeUnit.MILLISECONDS);

      ClusterNodeResponse clusterNodeResponse =
          clusterNodeResponses.getClusterResponse(clusterNode);

      return (Map<String, String>) clusterNodeResponse.getResult();
    } catch (Exception e) {
      _log.error(e, e);

      throw e;
    }
  }
  protected void memberRemoved(List<Address> departAddresses) {
    List<ClusterNode> departClusterNodes = new ArrayList<>();

    for (Address departAddress : departAddresses) {
      ClusterNode departClusterNode = _liveInstances.remove(departAddress);

      if (departClusterNode == null) {
        continue;
      }

      departClusterNodes.add(departClusterNode);

      _clusterNodeAddresses.remove(departClusterNode.getClusterNodeId());
    }

    if (departClusterNodes.isEmpty()) {
      return;
    }

    ClusterEvent clusterEvent = ClusterEvent.depart(departClusterNodes);

    fireClusterEvent(clusterEvent);
  }
  private void _processJoinEvent(ClusterNode clusterNode) {
    Message message = new Message();

    message.put(ClusterLink.CLUSTER_FORWARD_MESSAGE, true);

    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();

    jsonObject.put("clusterNodeId", clusterNode.getClusterNodeId());
    jsonObject.put("command", "addClusterNode");

    message.setPayload(jsonObject.toString());

    MessageBusUtil.sendMessage(DestinationNames.LIVE_USERS, message);
  }
  protected boolean memberJoined(Address joinAddress, ClusterNode clusterNode) {

    _liveInstances.put(joinAddress, clusterNode);

    Address previousAddress =
        _clusterNodeAddresses.put(clusterNode.getClusterNodeId(), joinAddress);

    if (previousAddress != null) {
      return false;
    }

    ClusterEvent clusterEvent = ClusterEvent.join(clusterNode);

    fireClusterEvent(clusterEvent);

    return true;
  }
  public static void registerOrder(HttpServletRequest request) {
    String orderUuid = ParamUtil.getString(request, "orderUuid");
    String productEntryName = ParamUtil.getString(request, "productEntryName");
    int maxServers = ParamUtil.getInteger(request, "maxServers");

    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();

    if ((clusterNodes.size() <= 1)
        || Validator.isNull(productEntryName)
        || Validator.isNull(orderUuid)) {

      Map<String, Object> attributes = registerOrder(orderUuid, productEntryName, maxServers);

      for (Map.Entry<String, Object> entry : attributes.entrySet()) {
        request.setAttribute(entry.getKey(), entry.getValue());
      }
    } else {
      for (ClusterNode clusterNode : clusterNodes) {
        boolean register =
            ParamUtil.getBoolean(request, clusterNode.getClusterNodeId() + "_register");

        if (!register) {
          continue;
        }

        try {
          _registerClusterOrder(request, clusterNode, orderUuid, productEntryName, maxServers);
        } catch (Exception e) {
          _log.error(e, e);

          InetAddress inetAddress = clusterNode.getInetAddress();

          String message = "Error contacting " + inetAddress.getHostName();

          if (clusterNode.getPort() != -1) {
            message += StringPool.COLON + clusterNode.getPort();
          }

          request.setAttribute(clusterNode.getClusterNodeId() + "_ERROR_MESSAGE", message);
        }
      }
    }
  }
    @Override
    public void callback(BlockingQueue<ClusterNodeResponse> blockingQueue) {
      Address bootupAddress = null;

      do {
        _clusterNodeAddressesCount--;

        ClusterNodeResponse clusterNodeResponse = null;

        try {
          clusterNodeResponse =
              blockingQueue.poll(_CLUSTER_LINK_NODE_BOOTUP_RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
          _log.error("Unable to get cluster node response", e);
        }

        if (clusterNodeResponse == null) {
          if (_log.isDebugEnabled()) {
            _log.debug(
                "Unable to get cluster node response in "
                    + _CLUSTER_LINK_NODE_BOOTUP_RESPONSE_TIMEOUT
                    + TimeUnit.MILLISECONDS);
          }

          continue;
        }

        ClusterNode clusterNode = clusterNodeResponse.getClusterNode();

        if (clusterNode.getPortalInetSocketAddress() != null) {
          try {
            long remoteLastGeneration = (Long) clusterNodeResponse.getResult();

            if (remoteLastGeneration > _localLastGeneration) {
              bootupAddress = clusterNodeResponse.getAddress();

              break;
            }
          } catch (Exception e) {
            if (_log.isDebugEnabled()) {
              _log.debug("Suppress exception caused by remote method " + "invocation", e);
            }

            continue;
          }
        } else if (_log.isDebugEnabled()) {
          _log.debug("Cluster node " + clusterNode + " has invalid InetSocketAddress");
        }
      } while ((bootupAddress == null) && (_clusterNodeAddressesCount > 1));

      if (bootupAddress == null) {
        return;
      }

      if (_log.isInfoEnabled()) {
        _log.info("Start loading lucene index files from cluster node " + bootupAddress);
      }

      InputStream inputStream = null;

      try {
        inputStream = getLoadIndexesInputStreamFromCluster(_companyId, bootupAddress);

        _indexAccessor.loadIndex(inputStream);

        if (_log.isInfoEnabled()) {
          _log.info("Lucene index files loaded successfully");
        }
      } catch (Exception e) {
        _log.error("Unable to load index for company " + _companyId, e);
      } finally {
        if (inputStream != null) {
          try {
            inputStream.close();
          } catch (IOException ioe) {
            _log.error("Unable to close input stream for company " + _companyId, ioe);
          }
        }
      }
    }