Merge branch 'stable-2.13'

* stable-2.13:
  HelloWebLink: Make the dummy image more visible

Change-Id: I5291aabcf3c57f76fe17c65a770c09fe80022412
diff --git a/.buckconfig b/.buckconfig
index 36c84eb..daef711 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -4,6 +4,8 @@
 
 [java]
   src_roots = java, resources
+  source_level = 8
+  target_level = 8
 
 [project]
   ignore = .git
diff --git a/.gitignore b/.gitignore
index 9ab384b..f69c160 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 /buck-cache
 /buck-out
 /bucklets
+*.iml
diff --git a/BUCK b/BUCK
index 0160c15..547d0e8 100644
--- a/BUCK
+++ b/BUCK
@@ -21,7 +21,6 @@
   name = 'cookbook_tests',
   srcs = glob(['src/test/java/**/*IT.java']),
   labels = ['cookbook-plugin'],
-  source_under_test = [':cookbook-plugin__plugin'],
   deps = GERRIT_PLUGIN_API + GERRIT_TESTS + [
     ':cookbook-plugin__plugin',
   ],
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..1ca5610
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,34 @@
+load("//tools/bzl:junit.bzl", "junit_tests")
+load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+
+MODULE = "com.googlesource.gerrit.plugins.cookbook.HelloForm"
+
+gerrit_plugin(
+    name = "cookbook-plugin",
+    srcs = glob(["src/main/java/**/*.java"]),
+    gwt_module = MODULE,
+    manifest_entries = [
+        "Gerrit-PluginName: cookbook",
+        "Gerrit-Module: com.googlesource.gerrit.plugins.cookbook.Module",
+        "Gerrit-HttpModule: com.googlesource.gerrit.plugins.cookbook.HttpModule",
+        "Gerrit-SshModule: com.googlesource.gerrit.plugins.cookbook.SshModule",
+        "Implementation-Title: Cookbook plugin",
+        "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/cookbook-plugin",
+    ],
+    resources = glob(["src/main/**/*"]),
+)
+
+junit_tests(
+    name = "cookbook_tests",
+    size = "small",
+    srcs = glob(["src/test/java/**/*IT.java"]),
+    tags = [
+        "cookbook-plugin",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":cookbook-plugin__plugin",
+        "//gerrit-acceptance-framework:lib",
+        "//gerrit-plugin-api:lib",
+    ],
+)
diff --git a/lib/BUCK b/lib/BUCK
index 9c596fa..d333cba 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1,13 +1,6 @@
 include_defs('//bucklets/maven_jar.bucklet')
 
 maven_jar(
-  name = 'guava',
-  id = 'com.google.guava:guava:19.0-rc2',
-  sha1 = '93e17f60bc524c2610b41c494bb829c11ca89436',
-  license = 'Apache2.0',
-)
-
-maven_jar(
   name = 'junit',
   id = 'junit:junit:4.11',
   sha1 = '4e031bb61df09069aeb2bffb4019e7a5034a4ee0',
@@ -20,7 +13,6 @@
   sha1 = 'bd17774d2dc0fffa884d42c07d2537e86c67acd6',
   license = 'DO_NOT_DISTRIBUTE',
   exported_deps = [
-    ':guava',
     ':junit',
   ],
 )
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK
index 2e795df..802c1b7 100644
--- a/lib/gerrit/BUCK
+++ b/lib/gerrit/BUCK
@@ -1,12 +1,11 @@
 include_defs('//bucklets/maven_jar.bucklet')
 
-VER = '2.13'
-REPO = MAVEN_CENTRAL
+VER = '2.14-SNAPSHOT'
+REPO = MAVEN_LOCAL
 
 maven_jar(
   name = 'acceptance-framework',
   id = 'com.google.gerrit:gerrit-acceptance-framework:' + VER,
-  sha1 = 'a6913a61196a8fccdb45e761f43a0b7e21867c90',
   license = 'Apache2.0',
   attach_source = False,
   repository = REPO,
@@ -15,7 +14,6 @@
 maven_jar(
   name = 'plugin-api',
   id = 'com.google.gerrit:gerrit-plugin-api:' + VER,
-  sha1 = 'e25d55b8f41627c4ae6b9d2069ec398638b219a3',
   license = 'Apache2.0',
   attach_source = False,
   repository = REPO,
@@ -24,7 +22,6 @@
 maven_jar(
   name = 'gwtui-api',
   id = 'com.google.gerrit:gerrit-plugin-gwtui:' + VER,
-  sha1 = '0890414f42fc1fd0fef0400a479836f558727234',
   license = 'Apache2.0',
   attach_source = False,
   repository = REPO,
diff --git a/lib/gwt/BUCK b/lib/gwt/BUCK
index 394ed92..26e55d3 100644
--- a/lib/gwt/BUCK
+++ b/lib/gwt/BUCK
@@ -1,27 +1,21 @@
 include_defs('//bucklets/maven_jar.bucklet')
 
-VER = '2.7.0'
+VERSION = '2.8.0'
 
 maven_jar(
   name = 'user',
-  id = 'com.google.gwt:gwt-user:' + VER,
-  sha1 = 'bdc7af42581745d3d79c2efe0b514f432b998a5b',
+  id = 'com.google.gwt:gwt-user:' + VERSION,
+  sha1 = '518579870499e15531f454f35dca0772d7fa31f7',
   license = 'Apache2.0',
   attach_source = False,
-  deps = [
-    ':javax-validation',
-    ':javax-validation_src',
-  ]
 )
 
 maven_jar(
   name = 'dev',
-  id = 'com.google.gwt:gwt-dev:' + VER,
-  sha1 = 'c2c3dd5baf648a0bb199047a818be5e560f48982',
+  id = 'com.google.gwt:gwt-dev:' + VERSION,
+  sha1 = 'f160a61272c5ebe805cd2d3d3256ed3ecf14893f',
   license = 'Apache2.0',
   attach_source = False,
-  exclude = ['org/eclipse/jetty/*'],
-  deps = [':json'],
 )
 
 maven_jar(
@@ -30,14 +24,50 @@
   bin_sha1 = 'b6bd7f9d78f6fdaa3c37dae18a4bd298915f328e',
   src_sha1 = '7a561191db2203550fbfa40d534d4997624cd369',
   license = 'Apache2.0',
-  visibility = [],
+  visibility = ['PUBLIC'],
 )
 
 maven_jar(
-  name = 'json',
-  id = 'org.json:json:20140107',
-  sha1 = 'd1ffca6e2482b002702c6a576166fd685e3370e3',
-  license = 'DO_NOT_DISTRIBUTE',
+  name = 'jsinterop-annotations',
+  id = 'com.google.jsinterop:jsinterop-annotations:1.0.0',
+  bin_sha1 = '23c3a3c060ffe4817e67673cc8294e154b0a4a95',
+  src_sha1 = '5d7c478efbfccc191430d7c118d7bd2635e43750',
+  license = 'Apache2.0',
+  visibility = ['PUBLIC'],
+)
+
+maven_jar(
+  name = 'ant',
+  id = 'ant:ant:1.6.5',
+  bin_sha1 = '7d18faf23df1a5c3a43613952e0e8a182664564b',
+  src_sha1 = '9e0a847494563f35f9b02846a1c1eb4aa2ee5a9a',
+  license = 'Apache2.0',
+  visibility = ['PUBLIC'],
+)
+
+maven_jar(
+  name = 'colt',
+  id = 'colt:colt:1.2.0',
   attach_source = False,
-  visibility = [],
+  bin_sha1 = '0abc984f3adc760684d49e0f11ddf167ba516d4f',
+  license = 'DO_NOT_DISTRIBUTE',
+  visibility = ['PUBLIC'],
+)
+
+maven_jar(
+  name = 'tapestry',
+  id = 'tapestry:tapestry:4.0.2',
+  attach_source = False,
+  bin_sha1 = 'e855a807425d522e958cbce8697f21e9d679b1f7',
+  license = 'Apache2.0',
+  visibility = ['PUBLIC'],
+)
+
+maven_jar(
+  name = 'w3c-css-sac',
+  id = 'org.w3c.css:sac:1.3',
+  attach_source = False,
+  bin_sha1 = 'cdb2dcb4e22b83d6b32b93095f644c3462739e82',
+  license = 'DO_NOT_DISTRIBUTE',
+  visibility = ['PUBLIC'],
 )
diff --git a/lib/ow2/BUCK b/lib/ow2/BUCK
index db6c76c..543bc09 100644
--- a/lib/ow2/BUCK
+++ b/lib/ow2/BUCK
@@ -1,32 +1,39 @@
 include_defs('//bucklets/maven_jar.bucklet')
 
-VERSION = '5.0.3'
+VERSION = '5.1'
 
 maven_jar(
   name = 'ow2-asm',
   id = 'org.ow2.asm:asm:' + VERSION,
-  sha1 = 'dcc2193db20e19e1feca8b1240dbbc4e190824fa',
+  sha1 = '5ef31c4fe953b1fd00b8a88fa1d6820e8785bb45',
   license = 'ow2',
 )
 
 maven_jar(
   name = 'ow2-asm-analysis',
   id = 'org.ow2.asm:asm-analysis:' + VERSION,
-  sha1 = 'c7126aded0e8e13fed5f913559a0dd7b770a10f3',
+  sha1 = '6d1bf8989fc7901f868bee3863c44f21aa63d110',
+  license = 'ow2',
+)
+
+maven_jar(
+  name = 'ow2-asm-commons',
+  id = 'org.ow2.asm:asm-commons:' + VERSION,
+  sha1 = '25d8a575034dd9cfcb375a39b5334f0ba9c8474e',
+  deps = [':ow2-asm-tree'],
   license = 'ow2',
 )
 
 maven_jar(
   name = 'ow2-asm-tree',
   id = 'org.ow2.asm:asm-tree:' + VERSION,
-  sha1 = '287749b48ba7162fb67c93a026d690b29f410bed',
+  sha1 = '87b38c12a0ea645791ead9d3e74ae5268d1d6c34',
   license = 'ow2',
 )
 
 maven_jar(
   name = 'ow2-asm-util',
   id = 'org.ow2.asm:asm-util:' + VERSION,
-  sha1 = '1512e5571325854b05fb1efce1db75fcced54389',
+  sha1 = 'b60e33a6bd0d71831e0c249816d01e6c1dd90a47',
   license = 'ow2',
 )
-
diff --git a/pom.xml b/pom.xml
index a36df53..a85d1a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,10 +22,11 @@
   <groupId>com.googlesource.gerrit.plugins</groupId>
   <artifactId>cookbook-plugin</artifactId>
   <packaging>jar</packaging>
-  <version>2.13</version>
+  <version>2.14-SNAPSHOT</version>
   <properties>
     <Gerrit-ApiType>plugin</Gerrit-ApiType>
     <Gerrit-ApiVersion>${project.version}</Gerrit-ApiVersion>
+    <GWT-Version>2.8.0</GWT-Version>
   </properties>
 
   <build>
@@ -60,8 +61,8 @@
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.3.2</version>
         <configuration>
-          <source>1.7</source>
-          <target>1.7</target>
+          <source>1.8</source>
+          <target>1.8</target>
           <encoding>UTF-8</encoding>
         </configuration>
       </plugin>
@@ -69,7 +70,7 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>gwt-maven-plugin</artifactId>
-        <version>2.7.0</version>
+        <version>${GWT-Version}</version>
         <configuration>
           <module>com.googlesource.gerrit.plugins.cookbook.HelloForm</module>
           <disableClassMetadata>true</disableClassMetadata>
@@ -104,7 +105,7 @@
     <dependency>
       <groupId>com.google.gwt</groupId>
       <artifactId>gwt-user</artifactId>
-      <version>2.7.0</version>
+      <version>${GWT-Version}</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
@@ -113,6 +114,12 @@
       <version>4.11</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.gerrit</groupId>
+      <artifactId>gerrit-acceptance-framework</artifactId>
+      <version>${Gerrit-ApiVersion}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <repositories>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/AssigneeValidator.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/AssigneeValidator.java
new file mode 100644
index 0000000..b7b66f5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/AssigneeValidator.java
@@ -0,0 +1,57 @@
+// Copyright (C) 2014 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.googlesource.gerrit.plugins.cookbook;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.query.QueryParseException;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import com.google.gerrit.server.query.change.ChangeQueryProcessor;
+import com.google.gerrit.server.validators.AssigneeValidationListener;
+import com.google.gerrit.server.validators.ValidationException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AssigneeValidator implements AssigneeValidationListener {
+  private static final Logger log =
+      LoggerFactory.getLogger(AssigneeValidationListener.class);
+
+  private static int MAX_ASSIGNED_CHANGES = 5;
+
+  @Inject
+  ChangeQueryBuilder queryBuilder;
+
+  @Inject
+  ChangeQueryProcessor queryProcessor;
+
+  @Override
+  public void validateAssignee(Change change, Account assignee)
+      throws ValidationException {
+    try {
+      if (queryProcessor
+          .query(queryBuilder.assignee(assignee.getPreferredEmail())).entities()
+          .size() > MAX_ASSIGNED_CHANGES) {
+        throw new ValidationException("Cannot assign user to more than "
+            + MAX_ASSIGNED_CHANGES + " changes");
+      }
+    } catch (OrmException | QueryParseException e) {
+      log.error("Failed to validate assignee for change " + change.getId(), e);
+      // Allow assignee.
+    }
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloProjectAction.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloProjectAction.java
index 8057bb7..0e5f6f0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloProjectAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloProjectAction.java
@@ -14,8 +14,6 @@
 
 package com.googlesource.gerrit.plugins.cookbook;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Strings;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.webui.UiAction;
 import com.google.gerrit.server.CurrentUser;
@@ -39,6 +37,20 @@
     this.user = user;
   }
 
+  private boolean isNullOrEmpty(String s) {
+    return s == null || s.isEmpty();
+  }
+
+  private Object firstNonNull(String first, String second) {
+    if (first != null) {
+      return first;
+    }
+    if (second != null) {
+      return second;
+    }
+    throw new NullPointerException();
+  }
+
   @Override
   public String apply(ProjectResource rsrc, Input input) {
     final String greeting = input.french
@@ -46,8 +58,8 @@
         : "Hello";
     return String.format("%s %s from project %s!",
         greeting,
-        Strings.isNullOrEmpty(input.message)
-            ? MoreObjects.firstNonNull(user.get().getUserName(), "world")
+        isNullOrEmpty(input.message)
+            ? firstNonNull(user.get().getUserName(), "world")
             : input.message,
         rsrc.getName());
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
index b17c871..7ac8eb3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
@@ -42,6 +42,7 @@
 import com.google.gerrit.server.git.validators.UploadValidationListener;
 import com.google.gerrit.server.plugins.ServerPluginProvider;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder.ChangeOperatorFactory;
+import com.google.gerrit.server.validators.AssigneeValidationListener;
 import com.google.gerrit.server.validators.HashtagValidationListener;
 import com.google.inject.AbstractModule;
 
@@ -75,6 +76,8 @@
         .to(MergeUserValidator.class);
     DynamicSet.bind(binder(), HashtagValidationListener.class)
         .to(HashtagValidator.class);
+    DynamicSet.bind(binder(), AssigneeValidationListener.class)
+        .to(AssigneeValidator.class);
     DynamicSet.bind(binder(), CommitValidationListener.class)
         .to(CommitValidator.class);
     DynamicSet.bind(binder(), NewProjectCreatedListener.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginContentScanner.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginContentScanner.java
index 794dca0..198e02a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginContentScanner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/pluginprovider/HelloSshPluginContentScanner.java
@@ -14,7 +14,6 @@
 
 package com.googlesource.gerrit.plugins.cookbook.pluginprovider;
 
-import com.google.common.base.Optional;
 import com.google.gerrit.server.plugins.InvalidPluginException;
 import com.google.gerrit.server.plugins.PluginContentScanner;
 import com.google.gerrit.server.plugins.PluginEntry;
@@ -26,6 +25,7 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Map;
+import java.util.Optional;
 import java.util.jar.Manifest;
 
 /**
@@ -74,8 +74,8 @@
    * Return plugin resource entry: not used in this sample.
    */
   @Override
-  public Optional<PluginEntry> getEntry(String resourcePath) throws IOException {
-    return Optional.absent();
+  public Optional<PluginEntry> getEntry(String resourcePath) {
+    return Optional.empty();
   }
 
   /**
diff --git a/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java b/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java
index 316c08e..ad38f8e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/cookbook/CookbookIT.java
@@ -16,13 +16,19 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.gerrit.acceptance.PluginDaemonTest;
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
 import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestPlugin;
 
 import org.junit.Test;
 
-public class CookbookIT extends PluginDaemonTest {
-
+@TestPlugin(
+    name = "cookbook",
+    sysModule = "com.googlesource.gerrit.plugins.cookbook.Module",
+    httpModule = "com.googlesource.gerrit.plugins.cookbook.HttpModule",
+    sshModule = "com.googlesource.gerrit.plugins.cookbook.SshModule"
+)
+public class CookbookIT extends LightweightPluginDaemonTest {
   @Test
   public void printTest() throws Exception {
     assertThat(adminSshSession.exec("cookbook print"))