Skip to content

Commit

Permalink
Merge branch 'v0.9.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
jchambers committed Apr 15, 2017
2 parents 50cb71e + d2b9161 commit 35586ba
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 106 deletions.
46 changes: 7 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@ If you use [Maven](http://maven.apache.org/), you can add Pushy to your project
<dependency>
<groupId>com.relayrides</groupId>
<artifactId>pushy</artifactId>
<version>0.9.1</version>
<version>0.9.3</version>
</dependency>
```

It's very important to note that you will also need to have either `netty-tcnative` (1.1.33.Fork24 or newer) or `alpn-boot`, as discussed in the [system requirements](#system-requirements) section below.
If you don't use Maven (or something else that understands Maven dependencies, like Gradle), you can [download Pushy as a `.jar` file](https://github.com/relayrides/pushy/releases/download/pushy-0.9.3/pushy-0.9.3.jar) and add it to your project directly. You'll also need to make sure you have Pushy's runtime dependencies on your classpath. They are:

If you don't use Maven (or something else that understands Maven dependencies, like Gradle), you can [download Pushy as a `.jar` file](https://github.com/relayrides/pushy/releases/download/pushy-0.9.1/pushy-0.9.1.jar) and add it to your project directly. You'll also need to make sure you have Pushy's runtime dependencies on your classpath. They are:

- [netty 4.1.6](http://netty.io/)
- [netty 4.1.9](http://netty.io/)
- [netty-tcnative-2.0.0.Final](http://netty.io/wiki/forked-tomcat-native.html)
- [gson 2.6](https://github.com/google/gson)
- [slf4j 1.7.6](http://www.slf4j.org/) (and possibly an SLF4J binding, as described in the [logging](#logging) section below)
- [alpn-api](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html) if you've opted to use a native SSL provider (`alpn-api` is included in `alpn-boot`); please see the [system requirements](#system-requirements) section for details)
- [alpn-api](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html)

Pushy itself requires Java 7 or newer to build and run.

Expand Down Expand Up @@ -130,38 +129,7 @@ When shutting down, clients will wait for all sent-but-not-acknowledged notifica

## System requirements

Pushy works with Java 7 and newer, but has some additional dependencies depending on the environment in which it is running.

The APNs protocol is built on top of the [HTTP/2 protocol](https://http2.github.io/). HTTP/2 is a relatively new protocol, and relies on some new developments that aren't yet wide-spread in the Java world. In particular:

1. HTTP/2 depends on [ALPN](https://tools.ietf.org/html/rfc7301), a TLS extension for protocol negotiation. No version of Java has native ALPN support at this time. The ALPN requirement may be met either by [using a native SSL provider](#using-a-native-ssl-provider) or by [using Jetty's ALPN implementation](#using-jettys-alpn-implementation) under Java 7 or 8.
2. The HTTP/2 specification requires the use of [ciphers](https://httpwg.github.io/specs/rfc7540.html#rfc.section.9.2.2) that weren't introduced in Java until Java 8. Using a native SSL provider is the best way to meet this requirement under Java 7. A native SSL provider isn't a requirement under Java 8, but may still yield performance gains.

Generally speaking, a native SSL provider is the best way to fulfill the system requirements imposed by HTTP/2 because installation is fairly straightforward, it works for Java 7 onward and generally offers better SSL performance than the JDK SSL provider.

### Using a native SSL provider

Using a native SSL provider (like [OpenSSL](https://www.openssl.org/), [BoringSSL](https://boringssl.googlesource.com/boringssl/), or [LibreSSL](http://www.libressl.org/)) via `netty-tcnative` fulfills the ALPN and cipher suite requirements imposed by HTTP/2 under all supported versions of Java. To use a native SSL provider, you'll need to add `netty-tcnative` as a dependency to your project. The `netty-tcnative` wiki provides [detailed instructions](http://netty.io/wiki/forked-tomcat-native.html), but in short, you'll need to add one additional platform-specific dependency to your project; we recommend using a statically-linked "uber jar" flavor for supported operating systems/CPU architectures (currently `linux-x86_64`, `osx-x86_64`, and `windows-x86_64`). This approach will meet all requirements imposed by HTTP/2 under Java 7 and 8.

To add the netty-tcnative uber-jar, you'll just need to add the following dependency (if you're using Maven):

```xml
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>1.1.33.Fork24</version>
</dependency>
```

Otherwise, you may add the jar to your classpath by the means of your choice.

Please note that Pushy requires netty-tcnative 1.1.33.Fork24 or newer. Additionally, you'll need [`alpn-api`](http://mvnrepository.com/artifact/org.eclipse.jetty.alpn/alpn-api) as a `runtime` dependency for your project. If you're managing dependencies manually, you'll just need to make sure the latest version of `alpn-api` is available on your classpath.

### Using Jetty's ALPN implementation

As an alternative to a native SSL provider, Jetty's ALPN implementation. Please note that if you're not using Oracle JDK 8 or newer (or if you're using a JDK other than Oracle's), you'll need to meet the cipher suite requirement separately; you may do so either by using a native SSL provider (which also fulfills the ALPN requirement) or by using another cryptography provider (which is beyond the scope of this document).

Using Jetty's ALPN implementation is somewhat more complicated than using a native SSL provider. You'll need to choose a version of `alpn-boot` specific to the version (down to the update!) of the JDK you're using, and then add it to your *boot* class path (note that this is *not* the same as your regular classpath). [Detailed instructions](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html) are provided by Jetty. If you choose to use the `alpn-boot` approach instead of a native SSL provider, we strongly recommend using [`jetty-alpn-agent`](https://github.com/jetty-project/jetty-alpn-agent), which will automatically choose the correct version of `alpn-boot` for your JRE.
Pushy works with Java 7 and newer. By default, it depends on `netty-tcnative` and should work "out of the box" for most users. Users who can't (or choose not to) use `netty-tcnative` will need to take extra steps to [configure a JDK SSL provider](https://github.com/relayrides/pushy/wiki/Using-a-JDK-SSL-provider).

## Metrics

Expand Down Expand Up @@ -221,4 +189,4 @@ If you plan to use Pushy inside an application container (like Tomcat), you may

Pushy is available under the [MIT License](https://github.com/relayrides/pushy/blob/master/LICENSE.md).

The current version of Pushy is 0.9.1. We consider it to be fully functional (and use it in production!), but the public API may change significantly before a 1.0 release.
The current version of Pushy is 0.9.3. We consider it to be fully functional (and use it in production!), but the public API may change significantly before a 1.0 release.
13 changes: 6 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
<artifactId>netty-handler-proxy</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand Down Expand Up @@ -64,12 +69,6 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>1.1.33.Fork26</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand All @@ -82,7 +81,7 @@
</licenses>

<properties>
<netty.version>4.1.8.Final</netty.version>
<netty.version>4.1.9.Final</netty.version>
<slf4j.version>1.7.21</slf4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
Expand Down
8 changes: 4 additions & 4 deletions pushy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<groupId>io.netty</groupId>
<artifactId>netty-handler-proxy</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
Expand All @@ -42,10 +46,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
17 changes: 1 addition & 16 deletions pushy/src/main/java/com/relayrides/pushy/apns/ApnsClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,22 +270,6 @@ protected void setConnectionTimeout(final int timeoutMillis) {
}
}

/**
* Sets the buffer usage watermark range for this client. When a the amount of buffered and not-yet-flushed data in
* the client's network channel exceeds the given "high-water" mark, the channel will begin rejecting new data until
* enough data has been flushed to cross the given "low-water" mark. Notifications sent when the client's network
* channel is "flooded" will fail with a {@link ClientBusyException}.
*
* @param writeBufferWatermark the buffer usage watermark range for the client's network channel
*
* @since 0.8.2
*/
protected void setChannelWriteBufferWatermark(final WriteBufferWaterMark writeBufferWaterMark) {
synchronized (this.bootstrap) {
this.bootstrap.option(ChannelOption.WRITE_BUFFER_WATER_MARK, writeBufferWaterMark);
}
}

/**
* Sets the metrics listener for this client. Metrics listeners gather information that describes the performance
* and behavior of a client, and are completely optional.
Expand Down Expand Up @@ -889,6 +873,7 @@ public Future<Void> disconnect() {

synchronized (this.bootstrap) {
this.reconnectionPromise = null;

if (this.scheduledReconnectFuture != null) {
this.scheduledReconnectFuture.cancel(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ public class ApnsClientBuilder {
private InputStream trustedServerCertificateInputStream;
private X509Certificate[] trustedServerCertificates;

private SslProvider preferredSslProvider;

private EventLoopGroup eventLoopGroup;

private ApnsClientMetricsListener metricsListener;
Expand Down Expand Up @@ -141,22 +139,6 @@ public ApnsClientBuilder setTrustedServerCertificateChain(final X509Certificate.
return this;
}

/**
* Sets the SSL provider to be used by the client under construction. By default, the client will use a native SSL
* provider if available and fall back to the JDK provider otherwise.
*
* @param sslProvider the SSL provider to be used by the client under construction, or {@code null} to choose a
* provider automatically
*
* @return a reference to this builder
*
* @since 0.9
*/
public ApnsClientBuilder setSslProvider(final SslProvider sslProvider) {
this.preferredSslProvider = sslProvider;
return this;
}

/**
* <p>Sets the event loop group to be used by the client under construction. If not set (or if {@code null}), the
* client will create and manage its own event loop group.</p>
Expand Down Expand Up @@ -288,21 +270,17 @@ public ApnsClient build() throws SSLException {
{
final SslProvider sslProvider;

if (this.preferredSslProvider != null) {
sslProvider = this.preferredSslProvider;
} else {
if (OpenSsl.isAvailable()) {
if (OpenSsl.isAlpnSupported()) {
log.info("Native SSL provider is available and supports ALPN; will use native provider.");
sslProvider = SslProvider.OPENSSL;
} else {
log.info("Native SSL provider is available, but does not support ALPN; will use JDK SSL provider.");
sslProvider = SslProvider.JDK;
}
if (OpenSsl.isAvailable()) {
if (OpenSsl.isAlpnSupported()) {
log.info("Native SSL provider is available and supports ALPN; will use native provider.");
sslProvider = SslProvider.OPENSSL;
} else {
log.info("Native SSL provider not available; will use JDK SSL provider.");
log.info("Native SSL provider is available, but does not support ALPN; will use JDK SSL provider.");
sslProvider = SslProvider.JDK;
}
} else {
log.info("Native SSL provider not available; will use JDK SSL provider.");
sslProvider = SslProvider.JDK;
}

final SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public ApnsPayloadBuilder setAlertBody(final String alertBody) {
*/
public ApnsPayloadBuilder setLocalizedAlertMessage(final String localizedAlertKey, final String... alertArguments) {
this.localizedAlertKey = localizedAlertKey;
this.localizedAlertArguments = alertArguments.length > 0 ? alertArguments : null;
this.localizedAlertArguments = (alertArguments != null && alertArguments.length > 0) ? alertArguments : null;

this.alertBody = null;

Expand Down Expand Up @@ -211,7 +211,7 @@ public ApnsPayloadBuilder setAlertTitle(final String alertTitle) {
*/
public ApnsPayloadBuilder setLocalizedAlertTitle(final String localizedAlertTitleKey, final String... alertTitleArguments) {
this.localizedAlertTitleKey = localizedAlertTitleKey;
this.localizedAlertTitleArguments = alertTitleArguments.length > 0 ? alertTitleArguments : null;
this.localizedAlertTitleArguments = (alertTitleArguments != null && alertTitleArguments.length > 0) ? alertTitleArguments : null;

this.alertTitle = null;

Expand Down Expand Up @@ -255,7 +255,7 @@ public ApnsPayloadBuilder setAlertSubtitle(final String alertSubtitle) {
*/
public ApnsPayloadBuilder setLocalizedAlertSubtitle(final String localizedAlertSubtitleKey, final String... alertSubtitleArguments) {
this.localizedAlertSubtitleKey = localizedAlertSubtitleKey;
this.localizedAlertSubtitleArguments = alertSubtitleArguments.length > 0 ? alertSubtitleArguments : null;
this.localizedAlertSubtitleArguments = (alertSubtitleArguments != null && alertSubtitleArguments.length > 0) ? alertSubtitleArguments : null;

this.alertSubtitle = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.relayrides.pushy.apns.util.SimpleApnsPushNotification;

import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.ssl.SslProvider;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

Expand Down Expand Up @@ -59,8 +58,6 @@ public class ApnsClientTest {
private MockApnsServer server;
private ApnsClient client;

private SslProvider preferredSslProvider;

private static class TestMetricsListener implements ApnsClientMetricsListener {

private final List<Long> writeFailures = new ArrayList<>();
Expand Down Expand Up @@ -211,12 +208,9 @@ public void setUp() throws Exception {

this.server.start(PORT).await();

this.preferredSslProvider = "jdk".equals(System.getenv("PUSHY_SSL_PROVIDER")) ? SslProvider.JDK : null;

this.client = new ApnsClientBuilder()
.setTrustedServerCertificateChain(CA_CERTIFICATE)
.setEventLoopGroup(EVENT_LOOP_GROUP)
.setSslProvider(this.preferredSslProvider)
.build();

this.client.connect(HOST, PORT).await();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ public void testSetLocalizedAlertBody() {
assertNull(alert.get("body"));
}

// We're happy here as long as nothing explodes
this.builder.setLocalizedAlertMessage(alertKey, null);

final String[] alertArgs = new String[] { "Moose", "helicopter" };
this.builder.setLocalizedAlertMessage(alertKey, alertArgs);

Expand All @@ -121,7 +124,6 @@ public void testSetLocalizedAlertBody() {
assertEquals(alertArgs.length, argsArray.size());
assertTrue(argsArray.containsAll(java.util.Arrays.asList(alertArgs)));
}

}

@Test
Expand Down Expand Up @@ -161,6 +163,9 @@ public void testSetLocalizedAlertTitle() {
assertNull(alert.get("title"));
}

// We're happy here as long as nothing explodes
this.builder.setLocalizedAlertTitle(localizedAlertTitleKey, null);

final String[] alertArgs = new String[] { "Moose", "helicopter" };
this.builder.setLocalizedAlertTitle(localizedAlertTitleKey, alertArgs);

Expand Down Expand Up @@ -215,6 +220,9 @@ public void testSetLocalizedAlertSubitle() {
assertNull(alert.get("subtitle"));
}

// We're happy here as long as nothing explodes
this.builder.setLocalizedAlertSubtitle(subtitleKey, null);

final String[] subtitleArgs = new String[] { "Moose", "helicopter" };
this.builder.setLocalizedAlertSubtitle(subtitleKey, subtitleArgs);

Expand Down

0 comments on commit 35586ba

Please sign in to comment.