protected void submitClusterIndexLoadingSyncJob(
      Set<BaseAsyncDestination> baseAsyncDestinations, long[] companyIds) throws Exception {

    if (_log.isInfoEnabled()) {
      StringBundler sb = new StringBundler(baseAsyncDestinations.size() + 1);

      sb.append("[");

      for (BaseAsyncDestination baseAsyncDestination : baseAsyncDestinations) {

        sb.append(baseAsyncDestination.getName());
        sb.append(", ");
      }

      sb.setStringAt("]", sb.index() - 1);

      _log.info("Synchronizecluster index loading for destinations " + sb.toString());
    }

    int totalWorkersMaxSize = 0;

    for (BaseAsyncDestination baseAsyncDestination : baseAsyncDestinations) {

      totalWorkersMaxSize += baseAsyncDestination.getWorkersMaxSize();
    }

    if (_log.isInfoEnabled()) {
      _log.info("There are " + totalWorkersMaxSize + " synchronization threads");
    }

    CountDownLatch countDownLatch = new CountDownLatch(totalWorkersMaxSize + 1);

    ClusterLoadingSyncJob slaveClusterLoadingSyncJob =
        new ClusterLoadingSyncJob(companyIds, countDownLatch, false);

    for (BaseAsyncDestination baseAsyncDestination : baseAsyncDestinations) {

      ThreadPoolExecutor threadPoolExecutor =
          PortalExecutorManagerUtil.getPortalExecutor(baseAsyncDestination.getName());

      for (int i = 0; i < baseAsyncDestination.getWorkersMaxSize(); i++) {
        threadPoolExecutor.execute(slaveClusterLoadingSyncJob);
      }
    }

    ClusterLoadingSyncJob masterClusterLoadingSyncJob =
        new ClusterLoadingSyncJob(companyIds, countDownLatch, true);

    ThreadPoolExecutor threadPoolExecutor =
        PortalExecutorManagerUtil.getPortalExecutor(EditServerAction.class.getName());

    threadPoolExecutor.execute(masterClusterLoadingSyncJob);
  }
  @Override
  public void startup(long companyId) {
    if (!PropsValues.INDEX_ON_STARTUP) {
      return;
    }

    if (_log.isInfoEnabled()) {
      _log.info("Indexing Lucene on startup");
    }

    LuceneIndexer luceneIndexer = new LuceneIndexer(companyId);

    if (PropsValues.INDEX_WITH_THREAD) {
      if (_luceneIndexThreadPoolExecutor == null) {

        // This should never be null except for the case where
        // VerifyProcessUtil#_verifyProcess(boolean) sets
        // PropsValues#INDEX_ON_STARTUP to true.

        _luceneIndexThreadPoolExecutor =
            PortalExecutorManagerUtil.getPortalExecutor(LuceneHelperImpl.class.getName());
      }

      _luceneIndexThreadPoolExecutor.execute(luceneIndexer);
    } else {
      luceneIndexer.reindex();
    }
  }
  @Override
  public void shutdown() {
    if (_luceneIndexThreadPoolExecutor != null) {
      _luceneIndexThreadPoolExecutor.shutdownNow();

      try {
        _luceneIndexThreadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS);
      } catch (InterruptedException ie) {
        _log.error("Lucene indexer shutdown interrupted", ie);
      }
    }

    if (isLoadIndexFromClusterEnabled()) {
      ClusterExecutorUtil.removeClusterEventListener(_loadIndexClusterEventListener);
    }

    MessageBus messageBus = MessageBusUtil.getMessageBus();

    for (String searchEngineId : SearchEngineUtil.getSearchEngineIds()) {
      String searchWriterDestinationName =
          SearchEngineUtil.getSearchWriterDestinationName(searchEngineId);

      Destination searchWriteDestination = messageBus.getDestination(searchWriterDestinationName);

      if (searchWriteDestination != null) {
        ThreadPoolExecutor threadPoolExecutor =
            PortalExecutorManagerUtil.getPortalExecutor(searchWriterDestinationName);

        int maxPoolSize = threadPoolExecutor.getMaxPoolSize();

        CountDownLatch countDownLatch = new CountDownLatch(maxPoolSize);

        ShutdownSyncJob shutdownSyncJob = new ShutdownSyncJob(countDownLatch);

        for (int i = 0; i < maxPoolSize; i++) {
          threadPoolExecutor.submit(shutdownSyncJob);
        }

        try {
          countDownLatch.await();
        } catch (InterruptedException ie) {
          _log.error("Shutdown waiting interrupted", ie);
        }

        List<Runnable> runnables = threadPoolExecutor.shutdownNow();

        if (_log.isDebugEnabled()) {
          _log.debug("Cancelled appending indexing jobs: " + runnables);
        }

        searchWriteDestination.close(true);
      }
    }

    for (IndexAccessor indexAccessor : _indexAccessors.values()) {
      indexAccessor.close();
    }
  }
  @Override
  public void initialize() {
    if (!isEnabled()) {
      return;
    }

    _executorService =
        PortalExecutorManagerUtil.getPortalExecutor(ClusterExecutorImpl.class.getName());

    PortalUtil.addPortalInetSocketAddressEventListener(this);

    if (PropsValues.CLUSTER_EXECUTOR_DEBUG_ENABLED) {
      addClusterEventListener(new DebuggingClusterEventListenerImpl());
    }

    if (PropsValues.LIVE_USERS_ENABLED) {
      addClusterEventListener(new LiveUsersClusterEventListenerImpl());
    }

    try {
      initControlChannel();

      _localAddress = new AddressImpl(_controlJChannel.getAddress());

      initLocalClusterNode();

      memberJoined(_localAddress, _localClusterNode);

      sendNotifyRequest();

      JGroupsReceiver jGroupsReceiver = (JGroupsReceiver) _controlJChannel.getReceiver();

      jGroupsReceiver.openLatch();
    } catch (Exception e) {
      if (_log.isErrorEnabled()) {
        _log.error("Unable to initialize", e);
      }

      throw new IllegalStateException(e);
    }
  }
  private LuceneHelperImpl() {
    if (PropsValues.INDEX_ON_STARTUP && PropsValues.INDEX_WITH_THREAD) {
      _luceneIndexThreadPoolExecutor =
          PortalExecutorManagerUtil.getPortalExecutor(LuceneHelperImpl.class.getName());
    }

    if (isLoadIndexFromClusterEnabled()) {
      _loadIndexClusterEventListener = new LoadIndexClusterEventListener();

      ClusterExecutorUtil.addClusterEventListener(_loadIndexClusterEventListener);
    }

    BooleanQuery.setMaxClauseCount(_LUCENE_BOOLEAN_QUERY_CLAUSE_MAX_SIZE);

    if (StringUtil.equalsIgnoreCase(Http.HTTPS, PropsValues.WEB_SERVER_PROTOCOL)) {

      _protocol = Http.HTTPS;
    } else {
      _protocol = Http.HTTP;
    }
  }