Merge "Add REST client"
diff --git a/BUCK b/BUCK
index 2b74c47..39591cb 100644
--- a/BUCK
+++ b/BUCK
@@ -1,5 +1,15 @@
include_defs('//bucklets/gerrit_plugin.bucklet')
+# TODO: support standalone Buck build with 2.11
+#if STANDALONE_MODE:
+# HTTP_LIB = '//lib/http:http_lib'
+# GSON = '//lib/gson:gson'
+#else:
+# HTTP_LIB = '//plugins/importer/lib/http:http_lib'
+# GSON = '//plugins/importer/lib/gson:gson'
+HTTP_LIB = '//plugins/importer/lib/http:http_lib'
+GSON = '//plugins/importer/lib/gson:gson'
+
gerrit_plugin(
name = 'importer',
srcs = glob(['src/main/java/**/*.java']),
@@ -11,6 +21,10 @@
'Gerrit-Module: com.googlesource.gerrit.plugins.importer.Module',
'Gerrit-SshModule: com.googlesource.gerrit.plugins.importer.SshModule',
],
+ deps = [
+ HTTP_LIB,
+ GSON,
+ ],
)
# this is required for bucklets/tools/eclipse/project.py to work
diff --git a/lib/commons/BUCK b/lib/commons/BUCK
new file mode 100644
index 0000000..ba42a1f
--- /dev/null
+++ b/lib/commons/BUCK
@@ -0,0 +1,41 @@
+include_defs('//bucklets/maven_jar.bucklet')
+
+java_library(
+ name = 'commons_lib',
+ deps = [
+ ':codec',
+ ':io',
+ ':lang',
+ ],
+ visibility = ['PUBLIC'],
+)
+
+EXCLUDE = [
+ 'META-INF/LICENSE.txt',
+ 'META-INF/NOTICE.txt'
+]
+
+maven_jar(
+ name = 'codec',
+ id = 'commons-codec:commons-codec:1.4',
+ sha1 = '4216af16d38465bbab0f3dff8efa14204f7a399a',
+ license = 'Apache2.0',
+ exclude = EXCLUDE,
+)
+
+maven_jar(
+ name = 'io',
+ id = 'commons-io:commons-io:1.4',
+ sha1 = 'a8762d07e76cfde2395257a5da47ba7c1dbd3dce',
+ license = 'Apache2.0',
+ exclude = EXCLUDE,
+)
+
+maven_jar(
+ name = 'lang',
+ id = 'commons-lang:commons-lang:2.5',
+ sha1 = 'b0236b252e86419eef20c31a44579d2aee2f0a69',
+ license = 'Apache2.0',
+ exclude = EXCLUDE,
+)
+
diff --git a/lib/gson/BUCK b/lib/gson/BUCK
new file mode 100644
index 0000000..8892994
--- /dev/null
+++ b/lib/gson/BUCK
@@ -0,0 +1,8 @@
+include_defs('//bucklets/maven_jar.bucklet')
+
+maven_jar(
+ name = 'gson',
+ id = 'com.google.code.gson:gson:2.1',
+ sha1 = '2e66da15851f9f5b5079228f856c2f090ba98c38',
+ license = 'Apache2.0',
+)
diff --git a/lib/http/BUCK b/lib/http/BUCK
new file mode 100644
index 0000000..0b9d990
--- /dev/null
+++ b/lib/http/BUCK
@@ -0,0 +1,43 @@
+include_defs('//bucklets/gerrit_plugin.bucklet')
+include_defs('//bucklets/maven_jar.bucklet')
+
+# TODO: support standalone Buck build with 2.11
+#if STANDALONE_MODE:
+# COMMONS = '//lib/commons:commons_lib'
+# LOG = '//lib/log:jcl-over-slf4j'
+#else:
+# COMMONS = '//plugins/importer/lib/commons:commons_lib'
+# LOG = '//plugins/importer/lib/log:jcl-over-slf4j'
+COMMONS = '//plugins/importer/lib/commons:commons_lib'
+LOG = '//plugins/importer/lib/log:jcl-over-slf4j'
+
+java_library(
+ name = 'http_lib',
+ exported_deps = [
+ ':httpclient',
+ ':httpcore',
+ ],
+ visibility = ['PUBLIC'],
+)
+
+maven_jar(
+ name = 'httpclient',
+ id = 'org.apache.httpcomponents:httpclient:4.3.4',
+ bin_sha1 = 'a9a1fef2faefed639ee0d0fba5b3b8e4eb2ff2d8',
+ src_sha1 = '7a14aafed8c5e2c4e360a2c1abd1602efa768b1f',
+ license = 'Apache2.0',
+ deps = [
+ COMMONS,
+ ':httpcore',
+ LOG,
+ ],
+)
+
+maven_jar(
+ name = 'httpcore',
+ id = 'org.apache.httpcomponents:httpcore:4.3.2',
+ bin_sha1 = '31fbbff1ddbf98f3aa7377c94d33b0447c646b6e',
+ src_sha1 = '4809f38359edeea9487f747e09aa58ec8d3a54c5',
+ license = 'Apache2.0',
+)
+
diff --git a/lib/log/BUCK b/lib/log/BUCK
new file mode 100644
index 0000000..fc994d6
--- /dev/null
+++ b/lib/log/BUCK
@@ -0,0 +1,8 @@
+include_defs('//bucklets/maven_jar.bucklet')
+
+maven_jar(
+ name = 'jcl-over-slf4j',
+ id = 'org.slf4j:jcl-over-slf4j:1.7.7',
+ sha1 = '56003dcd0a31deea6391b9e2ef2f2dc90b205a92',
+ license = 'slf4j',
+)
diff --git a/pom.xml b/pom.xml
index 2a881fb..3a9818a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,24 @@
<encoding>UTF-8</encoding>
</configuration>
</plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.3</version>
+ <configuration>
+ <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+ <createDependencyReducedPom>false</createDependencyReducedPom>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
@@ -75,5 +93,15 @@
<version>${Gerrit-ApiVersion}</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.3.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ <version>4.3.2</version>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java
new file mode 100755
index 0000000..4cd58dd
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java
@@ -0,0 +1,67 @@
+// Copyright (C) 2015 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.importer;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.RawParseUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.ByteBuffer;
+
+public class HttpResponse {
+
+ protected org.apache.http.HttpResponse response;
+ protected Reader reader;
+
+ HttpResponse(org.apache.http.HttpResponse response) {
+ this.response = response;
+ }
+
+ public Reader getReader() throws IllegalStateException, IOException {
+ if (reader == null && response.getEntity() != null) {
+ reader = new InputStreamReader(response.getEntity().getContent());
+ }
+ return reader;
+ }
+
+ public void consume() throws IllegalStateException, IOException {
+ Reader reader = getReader();
+ if (reader != null) {
+ while (reader.read() != -1);
+ }
+ }
+
+ public int getStatusCode() {
+ return response.getStatusLine().getStatusCode();
+ }
+
+ public String getEntityContent() throws IOException {
+ Preconditions.checkNotNull(response, "Response is not initialized.");
+ Preconditions.checkNotNull(response.getEntity(),
+ "Response.Entity is not initialized.");
+ ByteBuffer buf = IO.readWholeStream(
+ response.getEntity().getContent(),
+ 1024);
+ return RawParseUtils.decode(
+ buf.array(),
+ buf.arrayOffset(),
+ buf.limit())
+ .trim();
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java
new file mode 100755
index 0000000..bce528b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java
@@ -0,0 +1,62 @@
+// Copyright (C) 2015 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.importer;
+
+import com.google.common.base.CharMatcher;
+
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+import java.io.IOException;
+import java.net.URI;
+
+public class HttpSession {
+
+ protected final String url;
+ private final String user;
+ private final String pass;
+ private HttpClient client;
+
+ public HttpSession(String url, String user, String pass) {
+ this.url = CharMatcher.is('/').trimTrailingFrom(url);
+ this.user = user;
+ this.pass = pass;
+ }
+
+ public HttpResponse get(String path) throws IOException {
+ HttpGet get = new HttpGet(url + path);
+ return new HttpResponse(getClient().execute(get));
+ }
+
+ protected HttpClient getClient() {
+ if (client == null) {
+ URI uri = URI.create(url);
+ BasicCredentialsProvider creds = new BasicCredentialsProvider();
+ creds.setCredentials(new AuthScope(uri.getHost(), uri.getPort()),
+ new UsernamePasswordCredentials(user, pass));
+ client = HttpClientBuilder
+ .create()
+ .setDefaultCredentialsProvider(creds)
+ .setMaxConnPerRoute(10)
+ .setMaxConnTotal(1024)
+ .build();
+ }
+ return client;
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/RestResponse.java b/src/main/java/com/googlesource/gerrit/plugins/importer/RestResponse.java
new file mode 100755
index 0000000..512db6e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/RestResponse.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2015 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.importer;
+
+import static com.google.gerrit.httpd.restapi.RestApiServlet.JSON_MAGIC;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+public class RestResponse extends HttpResponse {
+
+ RestResponse(org.apache.http.HttpResponse response) {
+ super(response);
+ }
+
+ @Override
+ public Reader getReader() throws IllegalStateException, IOException {
+ if (reader == null && response.getEntity() != null) {
+ reader = new InputStreamReader(response.getEntity().getContent());
+ reader.skip(JSON_MAGIC.length);
+ }
+ return reader;
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/RestSession.java b/src/main/java/com/googlesource/gerrit/plugins/importer/RestSession.java
new file mode 100755
index 0000000..f02ecf7
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/RestSession.java
@@ -0,0 +1,117 @@
+// Copyright (C) 2015 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.importer;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.gerrit.extensions.restapi.RawInput;
+import com.google.gerrit.server.OutputFormat;
+
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.message.BasicHeader;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+public class RestSession extends HttpSession {
+
+ public RestSession(String url, String user, String pass) {
+ super(url, user, pass);
+ }
+
+ @Override
+ public RestResponse get(String endPoint) throws IOException {
+ HttpGet get = new HttpGet(url + "/a" + endPoint);
+ return new RestResponse(getClient().execute(get));
+ }
+
+ public RestResponse put(String endPoint) throws IOException {
+ return put(endPoint, null);
+ }
+
+ public RestResponse put(String endPoint, Object content) throws IOException {
+ HttpPut put = new HttpPut(url + "/a" + endPoint);
+ if (content != null) {
+ put.addHeader(new BasicHeader("Content-Type", "application/json"));
+ put.setEntity(new StringEntity(
+ OutputFormat.JSON_COMPACT.newGson().toJson(content),
+ Charsets.UTF_8.name()));
+ }
+ return new RestResponse(getClient().execute(put));
+ }
+
+ public RestResponse putRaw(String endPoint, RawInput stream) throws IOException {
+ Preconditions.checkNotNull(stream);
+ HttpPut put = new HttpPut(url + "/a" + endPoint);
+ put.addHeader(new BasicHeader("Content-Type", stream.getContentType()));
+ put.setEntity(new BufferedHttpEntity(
+ new InputStreamEntity(
+ stream.getInputStream(),
+ stream.getContentLength())));
+ return new RestResponse(getClient().execute(put));
+ }
+
+ public RestResponse post(String endPoint) throws IOException {
+ return post(endPoint, null);
+ }
+
+ public RestResponse post(String endPoint, Object content) throws IOException {
+ HttpPost post = new HttpPost(url + "/a" + endPoint);
+ if (content != null) {
+ post.addHeader(new BasicHeader("Content-Type", "application/json"));
+ post.setEntity(new StringEntity(
+ OutputFormat.JSON_COMPACT.newGson().toJson(content),
+ Charsets.UTF_8.name()));
+ }
+ return new RestResponse(getClient().execute(post));
+ }
+
+ public RestResponse delete(String endPoint) throws IOException {
+ HttpDelete delete = new HttpDelete(url + "/a" + endPoint);
+ return new RestResponse(getClient().execute(delete));
+ }
+
+
+ public static RawInput newRawInput(final String content) throws IOException {
+ Preconditions.checkNotNull(content);
+ Preconditions.checkArgument(!content.isEmpty());
+ return new RawInput() {
+ byte bytes[] = content.getBytes(StandardCharsets.UTF_8);
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ @Override
+ public String getContentType() {
+ return "application/octet-stream";
+ }
+
+ @Override
+ public long getContentLength() {
+ return bytes.length;
+ }
+ };
+ }
+}