@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();
    }
  }
    public void replaceDestination(String destinationName) {
      MessageBus messageBus = MessageBusUtil.getMessageBus();

      Destination destination = messageBus.getDestination(destinationName);

      if (destination instanceof BaseAsyncDestination) {
        _asyncServiceDestinations.add(destination);

        messageBus.replace(createSynchronousDestination(destinationName));
      }

      if (destination == null) {
        _absentDestinationNames.add(destinationName);

        messageBus.addDestination(createSynchronousDestination(destinationName));
      }
    }
    public void restorePreviousSync() {
      if (_sync == null) {
        return;
      }

      ProxyModeThreadLocal.setForceSync(_forceSync);

      MessageBus messageBus = MessageBusUtil.getMessageBus();

      for (Destination destination : _asyncServiceDestinations) {
        messageBus.replace(destination);
      }

      _asyncServiceDestinations.clear();

      for (String absentDestinationName : _absentDestinationNames) {
        messageBus.removeDestination(absentDestinationName);
      }
    }
  public void destroy() {
    MessageBus messageBus = getMessageBus();

    for (Map.Entry<String, List<MessageListener>> messageListeners : _messageListeners.entrySet()) {

      String destinationName = messageListeners.getKey();

      for (MessageListener messageListener : messageListeners.getValue()) {

        messageBus.unregisterMessageListener(destinationName, messageListener);
      }
    }

    for (Destination destination : _destinations) {
      messageBus.removeDestination(destination.getName());

      destination.close();
    }

    for (Map.Entry<String, List<DestinationEventListener>> destinationEventListeners :
        _specificDestinationEventListeners.entrySet()) {

      String destinationName = destinationEventListeners.getKey();

      for (DestinationEventListener destinationEventListener :
          destinationEventListeners.getValue()) {

        messageBus.removeDestinationEventListener(destinationName, destinationEventListener);
      }
    }

    for (DestinationEventListener destinationEventListener : _globalDestinationEventListeners) {

      messageBus.removeDestinationEventListener(destinationEventListener);
    }
  }
  public void afterPropertiesSet() {
    MessageBus messageBus = getMessageBus();

    for (DestinationEventListener destinationEventListener : _globalDestinationEventListeners) {

      messageBus.addDestinationEventListener(destinationEventListener);
    }

    for (Destination destination : _destinations) {
      messageBus.addDestination(destination);
    }

    for (Map.Entry<String, List<DestinationEventListener>> destinationEventListeners :
        _specificDestinationEventListeners.entrySet()) {

      String destinationName = destinationEventListeners.getKey();

      for (DestinationEventListener destinationEventListener :
          destinationEventListeners.getValue()) {

        messageBus.addDestinationEventListener(destinationName, destinationEventListener);
      }
    }

    for (Destination destination : _replacementDestinations) {
      messageBus.replace(destination);
    }

    Thread currentThread = Thread.currentThread();

    ClassLoader contextClassLoader = currentThread.getContextClassLoader();

    try {
      ClassLoader operatingClassLoader = getOperatingClassloader();

      currentThread.setContextClassLoader(operatingClassLoader);

      for (Map.Entry<String, List<MessageListener>> messageListeners :
          _messageListeners.entrySet()) {

        String destinationName = messageListeners.getKey();

        for (MessageListener messageListener : messageListeners.getValue()) {

          messageBus.registerMessageListener(destinationName, messageListener);
        }
      }
    } finally {
      currentThread.setContextClassLoader(contextClassLoader);
    }
  }
  protected MessageBus setUpMessageBus() {
    MessageBus messageBus = Mockito.mock(MessageBus.class);

    _synchronousDestination = new SynchronousDestination();

    _synchronousDestination.setName(_TEST_DESTINATION_NAME);

    messageBus.addDestination(_synchronousDestination);

    Mockito.when(messageBus.getDestination(Matchers.anyString()))
        .then(
            new Answer<Destination>() {

              @Override
              public Destination answer(InvocationOnMock invocationOnMock) throws Throwable {

                String destinationName = (String) invocationOnMock.getArguments()[0];

                if (!Validator.equals(_synchronousDestination.getName(), destinationName)) {

                  throw new IllegalArgumentException("Invalid destination: " + destinationName);
                }

                return _synchronousDestination;
              }
            });

    Mockito.when(
            messageBus.registerMessageListener(
                Matchers.anyString(), Matchers.any(MessageListener.class)))
        .then(
            new Answer<Boolean>() {

              @Override
              public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {

                _synchronousDestination.register(
                    (MessageListener) invocationOnMock.getArguments()[1]);

                return true;
              }
            });

    Mockito.when(
            messageBus.unregisterMessageListener(
                Matchers.anyString(), Matchers.any(MessageListener.class)))
        .then(
            new Answer<Boolean>() {

              @Override
              public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {

                _synchronousDestination.unregister(
                    (MessageListener) invocationOnMock.getArguments()[1]);

                return true;
              }
            });

    return messageBus;
  }
  protected void reindex(ActionRequest actionRequest) throws Exception {
    String portletId = ParamUtil.getString(actionRequest, "portletId");

    long[] companyIds = PortalInstances.getCompanyIds();

    if (LuceneHelperUtil.isLoadIndexFromClusterEnabled()) {
      MessageValuesThreadLocal.setValue(ClusterLink.CLUSTER_FORWARD_MESSAGE, true);
    }

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

    if (Validator.isNull(portletId)) {
      for (long companyId : companyIds) {
        try {
          LuceneIndexer luceneIndexer = new LuceneIndexer(companyId);

          luceneIndexer.reindex();

          usedSearchEngineIds.addAll(luceneIndexer.getUsedSearchEngineIds());
        } catch (Exception e) {
          _log.error(e, e);
        }
      }
    } else {
      Portlet portlet = PortletLocalServiceUtil.getPortletById(companyIds[0], portletId);

      if (portlet == null) {
        return;
      }

      List<Indexer> indexers = portlet.getIndexerInstances();

      if (indexers == null) {
        return;
      }

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

      for (Indexer indexer : indexers) {
        searchEngineIds.add(indexer.getSearchEngineId());
      }

      for (String searchEngineId : searchEngineIds) {
        for (long companyId : companyIds) {
          SearchEngineUtil.deletePortletDocuments(searchEngineId, companyId, portletId);
        }
      }

      for (Indexer indexer : indexers) {
        for (long companyId : companyIds) {
          ShardUtil.pushCompanyService(companyId);

          try {
            indexer.reindex(new String[] {String.valueOf(companyId)});

            usedSearchEngineIds.add(indexer.getSearchEngineId());
          } catch (Exception e) {
            _log.error(e, e);
          } finally {
            ShardUtil.popCompanyService();
          }
        }
      }
    }

    if (LuceneHelperUtil.isLoadIndexFromClusterEnabled()) {
      Set<BaseAsyncDestination> searchWriterDestinations = new HashSet<BaseAsyncDestination>();

      MessageBus messageBus = MessageBusUtil.getMessageBus();

      for (String usedSearchEngineId : usedSearchEngineIds) {
        String searchWriterDestinationName =
            SearchEngineUtil.getSearchWriterDestinationName(usedSearchEngineId);

        Destination destination = messageBus.getDestination(searchWriterDestinationName);

        if (destination instanceof BaseAsyncDestination) {
          BaseAsyncDestination baseAsyncDestination = (BaseAsyncDestination) destination;

          searchWriterDestinations.add(baseAsyncDestination);
        }
      }

      submitClusterIndexLoadingSyncJob(searchWriterDestinations, companyIds);
    }
  }