// Copyright (C) 2012 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.pgm.init;

import com.google.common.base.Objects;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.plugins.PluginLoader;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

@Singleton
public class InitPluginStepsLoader {
  private final File pluginsDir;
  private final Injector initInjector;
  final ConsoleUI ui;

  @Inject
  public InitPluginStepsLoader(final ConsoleUI ui, final SitePaths sitePaths,
      final Injector initInjector) {
    this.pluginsDir = sitePaths.plugins_dir;
    this.initInjector = initInjector;
    this.ui = ui;
  }

  public Collection<InitStep> getInitSteps() {
    List<File> jars = scanJarsInPluginsDirectory();
    ArrayList<InitStep> pluginsInitSteps = new ArrayList<InitStep>();

    for (File jar : jars) {
      InitStep init = loadInitStep(jar);
      if (init != null) {
        pluginsInitSteps.add(init);
      }
    }
    return pluginsInitSteps;
  }

  @SuppressWarnings("resource")
  private InitStep loadInitStep(File jar) {
    try {
      ClassLoader pluginLoader =
          new URLClassLoader(new URL[] {jar.toURI().toURL()},
              InitPluginStepsLoader.class.getClassLoader());
      JarFile jarFile = new JarFile(jar);
      Attributes jarFileAttributes = jarFile.getManifest().getMainAttributes();
      String initClassName = jarFileAttributes.getValue("Gerrit-InitStep");
      if (initClassName == null) {
        return null;
      }
      @SuppressWarnings("unchecked")
      Class<? extends InitStep> initStepClass =
          (Class<? extends InitStep>) pluginLoader.loadClass(initClassName);
      return getPluginInjector(jar).getInstance(initStepClass);
    } catch (ClassCastException e) {
      ui.message(
          "WARN: InitStep from plugin %s does not implement %s (Exception: %s)",
          jar.getName(), InitStep.class.getName(), e.getMessage());
      return null;
    } catch (Exception e) {
      ui.message(
          "WARN: Cannot load and get plugin init step for %s (Exception: %s)",
          jar, e.getMessage());
      return null;
    }
  }

  private Injector getPluginInjector(File jarFile) throws IOException {
    final String pluginName =
        Objects.firstNonNull(PluginLoader.getGerritPluginName(jarFile),
            PluginLoader.nameOf(jarFile));
    return initInjector.createChildInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(String.class).annotatedWith(PluginName.class).toInstance(
            pluginName);
      }
    });
  }

  private List<File> scanJarsInPluginsDirectory() {
    if (pluginsDir == null || !pluginsDir.exists()) {
      return Collections.emptyList();
    }
    File[] matches = pluginsDir.listFiles(new FileFilter() {
      @Override
      public boolean accept(File pathname) {
        String n = pathname.getName();
        return (n.endsWith(".jar") && pathname.isFile());
      }
    });
    if (matches == null) {
      ui.message("WARN: Cannot list %s", pluginsDir.getAbsolutePath());
      return Collections.emptyList();
    }
    Arrays.sort(matches, new Comparator<File>() {
      @Override
      public int compare(File o1, File o2) {
        return o1.getName().compareTo(o2.getName());
      }
    });
    return Arrays.asList(matches);
  }
}

@@ -2117,40 +2117,8 @@
  %7D%0A%0A
-  @SuppressWarnings(%22resource%22)%0A
   pr
@@ -2165,24 +2165,20 @@
     try 
-%7B%0A      
+(URL
 ClassLoa
@@ -2196,16 +2196,19 @@
 oader =%0A
+   
         
@@ -2261,16 +2261,19 @@
 URL()%7D,%0A
+   
         
@@ -2331,16 +2331,19 @@
 ;%0A      
+   
 JarFile 
@@ -2365,24 +2365,28 @@
 arFile(jar);
+) %7B%0A
 %0A      Attri

Use Java 7 try-with-resources in InitPluginStepsLoader