// Copyright (C) 2013 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.index;

import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.Executor;
import com.google.gerrit.server.query.change.ChangeQueryRewriter;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.assistedinject.FactoryModuleBuilder;

import org.eclipse.jgit.lib.Config;

/**
 * Module for non-indexer-specific secondary index setup.
 * <p>
 * This module should not be used directly except by specific secondary indexer
 * implementations (e.g. Lucene).
 */
public class IndexModule extends LifecycleModule {
  public enum IndexType {
    SQL, LUCENE, SOLR;
  }

  /** Type of secondary index. */
  public static IndexType getIndexType(Injector injector) {
    Config cfg = injector.getInstance(
        Key.get(Config.class, GerritServerConfig.class));
    return cfg.getEnum("index", null, "type", IndexType.SQL);
  }

  private final int threads;

  public IndexModule(int threads) {
    this.threads = threads;
  }

  @Override
  protected void configure() {
    bind(ChangeQueryRewriter.class).to(IndexRewriteImpl.class);
    bind(IndexRewriteImpl.BasicRewritesImpl.class);
    bind(IndexCollection.class);
    listener().to(IndexCollection.class);
    install(new FactoryModuleBuilder()
        .implement(ChangeIndexer.class, ChangeIndexerImpl.class)
        .build(ChangeIndexer.Factory.class));
  }

  @Provides
  @Singleton
  @IndexExecutor
  ListeningScheduledExecutorService getIndexExecutor(
      @GerritServerConfig Config config,
      WorkQueue workQueue) {
    int threads = this.threads;
    if (threads <= 0) {
      threads = config.getInt("index", null, "threads", 0);
    }
    Executor executor;
    if (threads <= 0) {
      executor = workQueue.getDefaultQueue();
    } else {
      executor = workQueue.createQueue(threads, "index");
    }
    return MoreExecutors.listeningDecorator(executor);
  }

  @Provides
  ChangeIndexer getChangeIndexer(
      ChangeIndexer.Factory factory,
      IndexCollection indexes) {
    return factory.create(indexes);
  }
}

@@ -1055,16 +1055,57 @@
 writer;%0A
+import com.google.inject.AbstractModule;%0A
 import c
@@ -1915,71 +1915,307 @@
 ds;%0A
-%0A  public IndexModule(int threads) %7B%0A    this.threads = threads
+  private final ListeningScheduledExecutorService indexExecutor;%0A%0A  public IndexModule(int threads) %7B%0A    this.threads = threads;%0A    this.indexExecutor = null;%0A  %7D%0A%0A  public IndexModule(ListeningScheduledExecutorService indexExecutor) %7B%0A    this.threads = -1;%0A    this.indexExecutor = indexExecutor
 ;%0A  
@@ -2601,33 +2601,667 @@
 lass));%0A
-  %7D%0A%0A  @Provides%0A
+%0A    if (indexExecutor != null) %7B%0A      bind(ListeningScheduledExecutorService.class)%0A          .annotatedWith(IndexExecutor.class)%0A          .toInstance(indexExecutor);%0A    %7D else %7B%0A      install(new IndexExecutorModule(threads));%0A    %7D%0A  %7D%0A%0A  @Provides%0A  ChangeIndexer getChangeIndexer(%0A      ChangeIndexer.Factory factory,%0A      IndexCollection indexes) %7B%0A    return factory.create(indexes);%0A  %7D%0A%0A  private static class IndexExecutorModule extends AbstractModule %7B%0A    private final int threads;%0A%0A    private IndexExecutorModule(int threads) %7B%0A      this.threads = threads;%0A    %7D%0A%0A    @Override%0A    public void configure() %7B%0A    %7D%0A%0A    @Provides%0A  
   @Singl
@@ -3265,16 +3265,18 @@
 ngleton%0A
+  
   @Index
@@ -3284,16 +3284,18 @@
 xecutor%0A
+  
   Listen
@@ -3346,16 +3346,18 @@
 (%0A      
+ 
+ 
 @GerritS
@@ -3389,16 +3389,18 @@
 ,%0A      
+  
 WorkQueu
@@ -3418,16 +3418,18 @@
 ) %7B%0A    
+ 
+ 
 int thre
@@ -3444,24 +3444,26 @@
 is.threads;%0A
+  
     if (thre
@@ -3480,16 +3480,18 @@
 %7B%0A      
+  
 threads 
@@ -3536,26 +3536,30 @@
 s%22, 0);%0A    
-%7D%0A
+  %7D%0A  
     Executor
@@ -3569,24 +3569,26 @@
 ecutor;%0A    
+  
 if (threads 
@@ -3591,24 +3591,26 @@
 ads %3C= 0) %7B%0A
+  
       execut
@@ -3643,16 +3643,18 @@
 ueue();%0A
+  
     %7D el
@@ -3660,24 +3660,26 @@
 lse %7B%0A      
+  
 executor = w
@@ -3718,26 +3718,30 @@
 ndex%22);%0A    
-%7D%0A
+  %7D%0A  
     return M
@@ -3789,162 +3789,11 @@
 ;%0A  
-%7D%0A%0A  @Provides%0A  ChangeIndexer getChangeIndexer(%0A      ChangeIndexer.Factory factory,%0A      IndexCollection indexes) %7B%0A    return factory.create(indexes);
+  %7D
 %0A  %7D

Allow passing an executor directly into IndexModule