Merge "Added global request handlers to SshDaemon" into stable-2.8
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
index 2d444f0..a667197 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/EditMessageBox.java
@@ -55,6 +55,7 @@
     this.revision = revision;
     this.originalMessage = msg.trim();
     initWidget(uiBinder.createAndBindUi(this));
+    message.setText("");
     new TextBoxChangeListener(message) {
       public void onTextChanged(String newText) {
         save.setEnabled(!newText.trim()
@@ -65,8 +66,10 @@
 
   @Override
   protected void onLoad() {
-    message.setText(originalMessage);
-    save.setEnabled(false);
+    if (message.getText().isEmpty()) {
+      message.setText(originalMessage);
+      save.setEnabled(false);
+    }
     Scheduler.get().scheduleDeferred(new ScheduledCommand() {
       @Override
       public void execute() {
@@ -89,6 +92,7 @@
 
   @UiHandler("cancel")
   void onCancel(ClickEvent e) {
+    message.setText("");
     hide();
   }
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
index 0c2a3c6..966feee 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSshd.java
@@ -72,9 +72,9 @@
     sshd.set("listenAddress", SocketUtil.format(hostname, port));
 
     if (site.ssh_rsa.exists() || site.ssh_dsa.exists()) {
-      libraries.bouncyCastle.downloadRequired();
+      libraries.bouncyCastleSSL.downloadRequired();
     } else if (!site.ssh_key.exists()) {
-      libraries.bouncyCastle.downloadOptional();
+      libraries.bouncyCastleSSL.downloadOptional();
     }
 
     generateSshHostKeys();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
index a03144b..7f3f177 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
@@ -37,7 +37,8 @@
 
   private final Provider<LibraryDownloader> downloadProvider;
 
-  /* final */LibraryDownloader bouncyCastle;
+  /* final */LibraryDownloader bouncyCastleProvider;
+  /* final */LibraryDownloader bouncyCastleSSL;
   /* final */LibraryDownloader mysqlDriver;
   /* final */LibraryDownloader oracleDriver;
 
@@ -58,11 +59,11 @@
       throw new RuntimeException(e.getMessage(), e);
     }
 
-    for (final Field f : Libraries.class.getDeclaredFields()) {
+    for (Field f : Libraries.class.getDeclaredFields()) {
       if ((f.getModifiers() & Modifier.STATIC) == 0
           && f.getType() == LibraryDownloader.class) {
         try {
-          init(f, cfg);
+          f.set(this, downloadProvider.get());
         } catch (IllegalArgumentException e) {
           throw new IllegalStateException("Cannot initialize " + f.getName());
         } catch (IllegalAccessException e) {
@@ -70,17 +71,36 @@
         }
       }
     }
+
+    for (Field f : Libraries.class.getDeclaredFields()) {
+      if ((f.getModifiers() & Modifier.STATIC) == 0
+          && f.getType() == LibraryDownloader.class) {
+        try {
+          init(f, cfg);
+        } catch (IllegalArgumentException e) {
+          throw new IllegalStateException("Cannot configure " + f.getName());
+        } catch (IllegalAccessException e) {
+          throw new IllegalStateException("Cannot configure " + f.getName());
+        } catch (NoSuchFieldException e) {
+          throw new IllegalStateException("Cannot configure " + f.getName());
+        } catch (SecurityException e) {
+          throw new IllegalStateException("Cannot configure " + f.getName());
+        }
+      }
+    }
   }
 
-  private void init(final Field field, final Config cfg)
-      throws IllegalArgumentException, IllegalAccessException {
-    final String n = field.getName();
-    final LibraryDownloader dl = downloadProvider.get();
+  private void init(Field field, Config cfg) throws IllegalArgumentException,
+      IllegalAccessException, NoSuchFieldException, SecurityException {
+    String n = field.getName();
+    LibraryDownloader dl = (LibraryDownloader) field.get(this);
     dl.setName(get(cfg, n, "name"));
     dl.setJarUrl(get(cfg, n, "url"));
     dl.setSHA1(get(cfg, n, "sha1"));
     dl.setRemove(get(cfg, n, "remove"));
-    field.set(this, dl);
+    for (String d : cfg.getStringList("library", n, "needs")) {
+      dl.addNeeds((LibraryDownloader) getClass().getDeclaredField(d).get(this));
+    }
   }
 
   private static String get(Config cfg, String name, String key) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
index 7caf49a..adb5034 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
@@ -40,6 +40,8 @@
 import java.net.URL;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
 
 /** Get optional or required 3rd party library files into $site_path/lib. */
 class LibraryDownloader {
@@ -51,13 +53,17 @@
   private String jarUrl;
   private String sha1;
   private String remove;
+  private List<LibraryDownloader> needs;
+  private LibraryDownloader neededBy;
   private File dst;
   private boolean download; // download or copy
+  private boolean exists;
 
   @Inject
   LibraryDownloader(ConsoleUI ui, SitePaths site) {
     this.ui = ui;
     this.lib_dir = site.lib_dir;
+    this.needs = new ArrayList<LibraryDownloader>(2);
   }
 
   void setName(final String name) {
@@ -77,16 +83,27 @@
     this.remove = remove;
   }
 
+  void addNeeds(LibraryDownloader lib) {
+    needs.add(lib);
+  }
+
   void downloadRequired() {
-    this.required = true;
+    setRequired(true);
     download();
   }
 
   void downloadOptional() {
-    this.required = false;
+    required = false;
     download();
   }
 
+  private void setRequired(boolean r) {
+    required = r;
+    for (LibraryDownloader d : needs) {
+      d.setRequired(r);
+    }
+  }
+
   private void download() {
     if (jarUrl == null || !jarUrl.contains("/")) {
       throw new IllegalStateException("Invalid JarUrl for " + name);
@@ -102,9 +119,18 @@
     }
 
     dst = new File(lib_dir, jarName);
-    if (!dst.exists() && shouldGet()) {
+    if (dst.exists()) {
+      exists = true;
+    } else if (shouldGet()) {
       doGet();
     }
+
+    if (exists) {
+      for (LibraryDownloader d : needs) {
+        d.neededBy = this;
+        d.downloadRequired();
+      }
+    }
   }
 
   private boolean shouldGet() {
@@ -115,7 +141,11 @@
       final StringBuilder msg = new StringBuilder();
       msg.append("\n");
       msg.append("Gerrit Code Review is not shipped with %s\n");
-      if (required) {
+      if (neededBy != null) {
+        msg.append(String.format(
+            "** This library is required by %s. **\n",
+            neededBy.name));
+      } else if (required) {
         msg.append("**  This library is required for your configuration. **\n");
       } else {
         msg.append("  If available, Gerrit can take advantage of features\n");
@@ -171,6 +201,7 @@
     }
 
     if (dst.exists()) {
+      exists = true;
       IoUtil.loadJARs(dst);
     }
   }
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
index 6f80364..b5e702f 100644
--- a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
@@ -14,12 +14,20 @@
 
 
 # Version should match lib/bouncycastle/BUCK
-[library "bouncyCastle"]
-  name = Bouncy Castle Crypto v144
-  url = http://www.bouncycastle.org/download/bcprov-jdk16-144.jar
-  sha1 = 6327a5f7a3dc45e0fd735adb5d08c5a74c05c20c
+[library "bouncyCastleProvider"]
+  name = Bouncy Castle Crypto Provider v149
+  url = http://www.bouncycastle.org/download/bcprov-jdk15on-149.jar
+  sha1 = f5155f04330459104b79923274db5060c1057b99
   remove = bcprov-.*[.]jar
 
+# Version should match lib/bouncycastle/BUCK
+[library "bouncyCastleSSL"]
+  name = Bouncy Castle Crypto SSL v149
+  url = http://www.bouncycastle.org/download/bcpkix-jdk15on-149.jar
+  sha1 = 924cc7ad2f589630c97b918f044296ebf1bb6855
+  needs = bouncyCastleProvider
+  remove = bcpkix-.*[.]jar
+
 [library "mysqlDriver"]
   name = MySQL Connector/J 5.1.21
   url = http://repo2.maven.org/maven2/mysql/mysql-connector-java/5.1.21/mysql-connector-java-5.1.21.jar
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
index df1f447..9f56f94 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
@@ -41,7 +41,7 @@
       }
     });
 
-    assertNotNull(lib.bouncyCastle);
+    assertNotNull(lib.bouncyCastleProvider);
     assertNotNull(lib.mysqlDriver);
 
     verify(ui);
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index 1db7555..78032b4 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -52,6 +52,7 @@
   compile_deps = [
     '//lib/bouncycastle:bcprov',
     '//lib/bouncycastle:bcpg',
+    '//lib/bouncycastle:bcpkix',
   ],
   visibility = ['PUBLIC'],
 )
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
index a634b7c..c1dbc17 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/EditMessage.java
@@ -82,6 +82,11 @@
       OrmException, ResourceNotFoundException, IOException {
     if (Strings.isNullOrEmpty(input.message)) {
       throw new BadRequestException("message must be non-empty");
+    } else if (!rsrc.getPatchSet().getId()
+        .equals(rsrc.getChange().currentPatchSetId())) {
+      throw new ResourceConflictException(String.format(
+          "revision %s is not current revision",
+          rsrc.getPatchSet().getRevision().get()));
     }
 
     final Repository git;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
index 17c9060..40699c8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
@@ -173,17 +173,23 @@
     }
   }
 
+  @SuppressWarnings("deprecation")
+  private final PGPEncryptedDataGenerator cpk()
+      throws NoSuchProviderException, PGPException {
+    PGPEncryptedDataGenerator cpk =
+        new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, true, prng, "BC");
+    cpk.addMethod(dest);
+    return cpk;
+  }
+
   private byte[] encrypt(final String name, final Date date,
       final byte[] rawText) throws NoSuchProviderException, PGPException,
       IOException {
     final byte[] zText = compress(name, date, rawText);
-    final PGPEncryptedDataGenerator cpk =
-        new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, true, prng, "BC");
-    cpk.addMethod(dest);
 
     final ByteArrayOutputStream buf = new ByteArrayOutputStream();
     final ArmoredOutputStream aout = new ArmoredOutputStream(buf);
-    final OutputStream cout = cpk.open(aout, zText.length);
+    final OutputStream cout = cpk().open(aout, zText.length);
     cout.write(zText);
     cout.close();
     aout.close();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index f854b58..a53f617 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.project.ListBranches.BranchInfo;
 import com.google.gerrit.server.util.MagicBranch;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -64,14 +65,15 @@
     CreateBranch create(String ref);
   }
 
-  private final IdentifiedUser identifiedUser;
+  private final Provider<IdentifiedUser>  identifiedUser;
   private final GitRepositoryManager repoManager;
   private final GitReferenceUpdated referenceUpdated;
   private final ChangeHooks hooks;
   private String ref;
 
   @Inject
-  CreateBranch(IdentifiedUser identifiedUser, GitRepositoryManager repoManager,
+  CreateBranch(Provider<IdentifiedUser> identifiedUser,
+      GitRepositoryManager repoManager,
       GitReferenceUpdated referenceUpdated, ChangeHooks hooks,
       @Assisted String ref) {
     this.identifiedUser = identifiedUser;
@@ -135,7 +137,7 @@
         final RefUpdate u = repo.updateRef(ref);
         u.setExpectedOldObjectId(ObjectId.zeroId());
         u.setNewObjectId(object.copy());
-        u.setRefLogIdent(identifiedUser.newRefLogIdent());
+        u.setRefLogIdent(identifiedUser.get().newRefLogIdent());
         u.setRefLogMessage("created via REST from " + input.revision, false);
         final RefUpdate.Result result = u.update(rw);
         switch (result) {
@@ -143,7 +145,7 @@
           case NEW:
           case NO_CHANGE:
             referenceUpdated.fire(name.getParentKey(), u);
-            hooks.doRefUpdatedHook(name, u, identifiedUser.getAccount());
+            hooks.doRefUpdatedHook(name, u, identifiedUser.get().getAccount());
             break;
           case LOCK_FAILURE:
             if (repo.getRef(ref) != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
index a41c197..382d68c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
@@ -41,16 +41,16 @@
   static class Input {
   }
 
-  private final IdentifiedUser identifiedUser;
+  private final Provider<IdentifiedUser> identifiedUser;
   private final GitRepositoryManager repoManager;
   private final Provider<ReviewDb> dbProvider;
   private final GitReferenceUpdated referenceUpdated;
   private final ChangeHooks hooks;
 
   @Inject
-  DeleteBranch(IdentifiedUser identifiedUser, GitRepositoryManager repoManager,
-      Provider<ReviewDb> dbProvider, GitReferenceUpdated referenceUpdated,
-      ChangeHooks hooks) {
+  DeleteBranch(Provider<IdentifiedUser> identifiedUser,
+      GitRepositoryManager repoManager, Provider<ReviewDb> dbProvider,
+      GitReferenceUpdated referenceUpdated, ChangeHooks hooks) {
     this.identifiedUser = identifiedUser;
     this.repoManager = repoManager;
     this.dbProvider = dbProvider;
@@ -89,7 +89,7 @@
         case FAST_FORWARD:
         case FORCED:
           referenceUpdated.fire(rsrc.getNameKey(), u);
-          hooks.doRefUpdatedHook(rsrc.getBranchKey(), u, identifiedUser.getAccount());
+          hooks.doRefUpdatedHook(rsrc.getBranchKey(), u, identifiedUser.get().getAccount());
           break;
 
         case REJECTED_CURRENT_BRANCH:
diff --git a/lib/bouncycastle/BUCK b/lib/bouncycastle/BUCK
index 3d76ea6..99f960e 100644
--- a/lib/bouncycastle/BUCK
+++ b/lib/bouncycastle/BUCK
@@ -2,19 +2,27 @@
 
 # This version must match the version that also appears in
 # gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
-VERSION = '1.44'
+VERSION = '1.49'
 
 maven_jar(
   name = 'bcprov',
-  id = 'org.bouncycastle:bcprov-jdk16:' + VERSION,
-  sha1 = '6327a5f7a3dc45e0fd735adb5d08c5a74c05c20c',
+  id = 'org.bouncycastle:bcprov-jdk15on:' + VERSION,
+  sha1 = 'f5155f04330459104b79923274db5060c1057b99',
   license = 'DO_NOT_DISTRIBUTE', #'bouncycastle'
 )
 
 maven_jar(
   name = 'bcpg',
-  id = 'org.bouncycastle:bcpg-jdk16:' + VERSION,
-  sha1 = 'ee14f5a29cb3cf9c1edec034ab16e1bbd26e9647',
+  id = 'org.bouncycastle:bcpg-jdk15on:' + VERSION,
+  sha1 = '081d84be5b125e1997ab0e2244d1a2276b5de76c',
+  license = 'DO_NOT_DISTRIBUTE', #'bouncycastle'
+  deps = [':bcprov'],
+)
+
+maven_jar(
+  name = 'bcpkix',
+  id = 'org.bouncycastle:bcpkix-jdk15on:' + VERSION,
+  sha1 = '924cc7ad2f589630c97b918f044296ebf1bb6855',
   license = 'DO_NOT_DISTRIBUTE', #'bouncycastle'
   deps = [':bcprov'],
 )