diff options
author | Louis Ryan <lryan@google.com> | 2015-08-31 09:45:03 -0700 |
---|---|---|
committer | Louis Ryan <lryan@google.com> | 2015-09-03 13:58:23 -0700 |
commit | d6dc790f05c90ffba2c7a4356121ae4d586e467e (patch) | |
tree | 301e03df32dce3bebd3eaaebdbf6353a427c4cd3 /android | |
parent | aefefb50c4fd5cb15828470694c73d7ba42a79e0 (diff) | |
download | grpc-grpc-java-d6dc790f05c90ffba2c7a4356121ae4d586e467e.tar.gz |
Draft of Android specific Channe builder
Diffstat (limited to 'android')
-rw-r--r-- | android/build.gradle | 27 | ||||
-rw-r--r-- | android/delegate.gradle | 151 | ||||
-rw-r--r-- | android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java | 56 | ||||
-rw-r--r-- | android/src/main/AndroidManifest.xml | 34 | ||||
-rw-r--r-- | android/src/main/java/io/grpc/android/AndroidChannelBuilder.java | 139 |
5 files changed, 407 insertions, 0 deletions
diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 000000000..ecc5f6bd6 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,27 @@ +// We fork the android build to avoid classpath conflicts from buildscript. +task prereqs(dependsOn: [':grpc-okhttp:install', ':grpc-core:install']) {} + +task assemble(type: GradleBuild, dependsOn: 'prereqs') { + buildFile = 'delegate.gradle' + tasks = ['assemble'] +} + +task build(type: GradleBuild, dependsOn: 'prereqs') { + buildFile = 'delegate.gradle' + tasks = ['build'] +} + +task install(type: GradleBuild, dependsOn: 'prereqs') { + buildFile = 'delegate.gradle' + tasks = ['install'] +} + +task uploadArchives(type: GradleBuild, dependsOn: 'prereqs') { + buildFile = 'delegate.gradle' + tasks = ['uploadArchives'] +} + +task clean(type: GradleBuild) { + buildFile = 'delegate.gradle' + tasks = ['clean'] +} diff --git a/android/delegate.gradle b/android/delegate.gradle new file mode 100644 index 000000000..d653e8a03 --- /dev/null +++ b/android/delegate.gradle @@ -0,0 +1,151 @@ +buildscript { + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.+' + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+' + classpath 'com.github.dcendents:android-maven-plugin:1.2' + } +} +apply plugin: 'android-sdk-manager' +apply plugin: 'com.android.library' +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'signing' + +def properties = new Properties() +properties.load(new FileInputStream(file('../version.properties'))) + +description = 'gRPC: Android' +group = "io.grpc" +version = "${properties.version}" + +repositories { + mavenCentral() + mavenLocal() +} + +// Need to override to ensure maven artifact is generated with correct name +// Must match uploadTask.repositories.mavenDeployer.pom.artifactId +project.archivesBaseName = "grpc-android" + +android { + // Matches preinstalled on travis to keep CI build times down + compileSdkVersion 21 + buildToolsVersion '21.1.1' + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + lintOptions { + disable 'InvalidPackage', 'HardcodedText' + } +} + +// Disable JavaDoc doclint on Java 8. It's annoying. +if (JavaVersion.current().isJava8Compatible()) { + allprojects { + tasks.withType(Javadoc) { + options.addStringOption('Xdoclint:none', '-quiet') + } + } +} + +configurations { + javadocDeps +} + +dependencies { + compile "io.grpc:grpc-okhttp:${properties.version}" + javadocDeps "io.grpc:grpc-okhttp:${properties.version}" + + testCompile 'junit:junit:4.12' + testCompile 'org.mockito:mockito-core:1.9.5' +} + +signing { + required false + sign configurations.archives +} + +uploadArchives.repositories.mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + String stagingUrl + if (rootProject.hasProperty('repositoryId')) { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' + + rootProject.repositoryId + } else { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' + } + def configureAuth = { + if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) { + authentication(userName: rootProject.ossrhUsername, password: rootProject.ossrhPassword) + } + } + repository(url: stagingUrl, configureAuth) + snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/', configureAuth) + pom.artifactId = 'grpc-android' +} + +[ + install.repositories.mavenInstaller, + uploadArchives.repositories.mavenDeployer, +]*.pom*.whenConfigured { pom -> + pom.project { + name "$project.group:grpc-android" + description project.description + packaging 'aar' + url 'https://github.com/grpc/grpc-java' + + scm { + connection 'scm:svn:https://github.com/grpc/grpc-java.git' + developerConnection 'scm:svn:git@github.com:grpc/grpc-java.git' + url 'https://github.com/grpc/grpc-java' + } + + licenses { + license { + name 'BSD 3-Clause' + url 'http://opensource.org/licenses/BSD-3-Clause' + } + } + + developers { + developer { + id "grpc.io" + name "gRPC Contributors" + email "grpc-io@googlegroups.com" + url "http://grpc.io/" + // https://issues.gradle.org/browse/GRADLE-2719 + organization = "Google, Inc." + organizationUrl "https://www.google.com" + } + } + } +} + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + classpath += configurations.javadocDeps + destinationDir = file("../javadoc/") +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} diff --git a/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java b/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java new file mode 100644 index 000000000..fa49e91bd --- /dev/null +++ b/android/src/androidTest/java/io/grpc/android/AndroidChannelBuilderTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.android; + +import static org.junit.Assert.assertNotNull; + +import io.grpc.ManagedChannel; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link io.grpc.android.AndroidChannelBuilder}. + */ +@RunWith(JUnit4.class) +public class AndroidChannelBuilderTest { + + @Test + public void testDefaultProducesChannel() { + AndroidChannelBuilder channelBuilder = AndroidChannelBuilder.forAddress("localhost", 1234); + channelBuilder.userAgent("test"); + ManagedChannel channel = channelBuilder.build(); + assertNotNull(channel); + channel.shutdownNow(); + } +} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..e41a7da94 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2014, Google Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="io.grpc.android"> +</manifest> diff --git a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java new file mode 100644 index 000000000..0b549164f --- /dev/null +++ b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.android; + +import io.grpc.ClientInterceptor; +import io.grpc.ExperimentalApi; +import io.grpc.ManagedChannelBuilder; +import io.grpc.internal.ManagedChannelImpl; +import io.grpc.okhttp.NegotiationType; +import io.grpc.okhttp.OkHttpChannelBuilder; + +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * A {@link io.grpc.ManagedChannelBuilder} that provides a stable interface for producing + * {@link io.grpc.Channel} instances on Android. This allows applications to be resilient + * to changes such as defaulting to a new channel implementation or breaking API changes + * in existing ones. Configuration options will be added here only if they provide value + * to a broad set of users and are likely to be resilient to changes in the underlying channel + * implementation. + * + * <p>Developers needing advanced configuration are free to use the underlying channel + * implementations directly while assuming the risks associated with using an + * {@link io.grpc.ExperimentalApi}. + */ + +// TODO(lryan): +// - Document the various dangers of scheduling work onto Android Main/UI/whatever +// threads. Is any enforcement practical? Conversely is there a sensible default. I assume +// its also a bad idea to use huge numbers of threads too. +// - Provide SSL installation and detect ALPN/NPN support? +// - Allow for an alternate TrustManager ? for self-signed, pinning etc. Is there a good default +// impl for these variations blessed by security team? +// - Augment with user-agent with app id? +// - Specify a smaller flow-control window by default? Fewer concurrent streams? +public class AndroidChannelBuilder extends ManagedChannelBuilder<AndroidChannelBuilder> { + // Currently we only support OkHttp on Android. This will become dynamic as more transport + // implementations become available. + private final OkHttpChannelBuilder baseBuilder; + + public static AndroidChannelBuilder forAddress(String host, int port) { + return new AndroidChannelBuilder(OkHttpChannelBuilder.forAddress(host, port)); + } + + private AndroidChannelBuilder(OkHttpChannelBuilder builder) { + this.baseBuilder = builder; + } + + @Override + public AndroidChannelBuilder executor(ExecutorService executor) { + baseBuilder.executor(executor); + return this; + } + + @Override + public AndroidChannelBuilder intercept(List<ClientInterceptor> list) { + baseBuilder.intercept(list); + return this; + } + + @Override + public AndroidChannelBuilder intercept(ClientInterceptor... interceptors) { + baseBuilder.intercept(interceptors); + return this; + } + + @Override + public AndroidChannelBuilder userAgent(String userAgent) { + baseBuilder.userAgent(userAgent); + return this; + } + + /** + * Use of a plaintext connection to the server. By default a secure connection mechanism + * such as TLS will be used. + * + * <p>Should only be used for testing or for APIs where the use of such API or the data + * exchanged is not sensitive. + * + * @param skipNegotiation @{code true} if there is a priori knowledge that the endpoint supports + * plaintext, {@code false} if plaintext use must be negotiated. + */ + @ExperimentalApi("primarily for testing") + public AndroidChannelBuilder usePlaintext(boolean skipNegotiation) { + if (skipNegotiation) { + baseBuilder.negotiationType(NegotiationType.PLAINTEXT); + return this; + } else { + throw new IllegalArgumentException("Not currently supported"); + } + } + + /** + * Overrides the host used with TLS and HTTP virtual hosting. It does not change what host is + * actually connected to. + * + * <p>Should only be used for testing. + */ + @ExperimentalApi("primarily for testing") + public AndroidChannelBuilder overrideHostForAuthority(String host) { + baseBuilder.overrideHostForAuthority(host); + return this; + } + + @Override + public ManagedChannelImpl build() { + return baseBuilder.build(); + } +} |