Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit 1c41f5c

Browse files
committed
Netty Container and Connector for Jersey.
Change-Id: I19b7a19c69d1e1ad90b7458cf46e8668fa4fb14b
1 parent 9f5b39d commit 1c41f5c

File tree

53 files changed

+4708
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4708
-144
lines changed

bom/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@
126126
<artifactId>jersey-container-jdk-http</artifactId>
127127
<version>${project.version}</version>
128128
</dependency>
129+
<dependency>
130+
<groupId>org.glassfish.jersey.containers</groupId>
131+
<artifactId>jersey-container-netty-http</artifactId>
132+
<version>${project.version}</version>
133+
</dependency>
129134
<dependency>
130135
<groupId>org.glassfish.jersey.containers</groupId>
131136
<artifactId>jersey-container-servlet</artifactId>

connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/HelloWorldTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public void failed(Throwable error) {
231231
}
232232
});
233233
}
234-
latch.await(10 * getAsyncTimeoutMultiplier(), TimeUnit.SECONDS);
234+
assertTrue(latch.await(10 * getAsyncTimeoutMultiplier(), TimeUnit.SECONDS));
235235
final long toc = System.currentTimeMillis();
236236
Logger.getLogger(HelloWorldTest.class.getName()).info("Executed in: " + (toc - tic));
237237

connectors/netty-connector/pom.xml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5+
6+
Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
7+
8+
The contents of this file are subject to the terms of either the GNU
9+
General Public License Version 2 only ("GPL") or the Common Development
10+
and Distribution License("CDDL") (collectively, the "License"). You
11+
may not use this file except in compliance with the License. You can
12+
obtain a copy of the License at
13+
http://glassfish.java.net/public/CDDL+GPL_1_1.html
14+
or packager/legal/LICENSE.txt. See the License for the specific
15+
language governing permissions and limitations under the License.
16+
17+
When distributing the software, include this License Header Notice in each
18+
file and include the License file at packager/legal/LICENSE.txt.
19+
20+
GPL Classpath Exception:
21+
Oracle designates this particular file as subject to the "Classpath"
22+
exception as provided by Oracle in the GPL Version 2 section of the License
23+
file that accompanied this code.
24+
25+
Modifications:
26+
If applicable, add the following below the License Header, with the fields
27+
enclosed by brackets [] replaced by your own identifying information:
28+
"Portions Copyright [year] [name of copyright owner]"
29+
30+
Contributor(s):
31+
If you wish your version of this file to be governed by only the CDDL or
32+
only the GPL Version 2, indicate your decision by adding "[Contributor]
33+
elects to include this software in this distribution under the [CDDL or GPL
34+
Version 2] license." If you don't indicate a single choice of license, a
35+
recipient has the option to distribute your version of this file under
36+
either the CDDL, the GPL Version 2 or to extend the choice of license to
37+
its licensees as provided above. However, if you add GPL Version 2 code
38+
and therefore, elected the GPL Version 2 license, then the option applies
39+
only if the new code is made subject to such option by the copyright
40+
holder.
41+
42+
-->
43+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
45+
<modelVersion>4.0.0</modelVersion>
46+
47+
<parent>
48+
<groupId>org.glassfish.jersey.connectors</groupId>
49+
<artifactId>project</artifactId>
50+
<version>3.0-SNAPSHOT</version>
51+
</parent>
52+
53+
<artifactId>jersey-netty-connector</artifactId>
54+
<packaging>jar</packaging>
55+
<name>jersey-connectors-netty</name>
56+
57+
<description>Jersey Client Transport via Netty</description>
58+
59+
<properties>
60+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
61+
</properties>
62+
63+
<dependencies>
64+
<dependency>
65+
<groupId>io.netty</groupId>
66+
<artifactId>netty-all</artifactId>
67+
</dependency>
68+
69+
<dependency>
70+
<!-- cannot be netty, since netty container depends on netty connector. -->
71+
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
72+
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
73+
<version>${project.version}</version>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>com.google.guava</groupId>
78+
<artifactId>guava</artifactId>
79+
<scope>test</scope>
80+
</dependency>
81+
</dependencies>
82+
83+
<build>
84+
<plugins>
85+
<plugin>
86+
<groupId>com.sun.istack</groupId>
87+
<artifactId>maven-istack-commons-plugin</artifactId>
88+
<inherited>true</inherited>
89+
</plugin>
90+
<plugin>
91+
<groupId>org.codehaus.mojo</groupId>
92+
<artifactId>build-helper-maven-plugin</artifactId>
93+
<inherited>true</inherited>
94+
</plugin>
95+
<plugin>
96+
<groupId>org.apache.maven.plugins</groupId>
97+
<artifactId>maven-compiler-plugin</artifactId>
98+
</plugin>
99+
</plugins>
100+
</build>
101+
102+
</project>
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3+
*
4+
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
5+
*
6+
* The contents of this file are subject to the terms of either the GNU
7+
* General Public License Version 2 only ("GPL") or the Common Development
8+
* and Distribution License("CDDL") (collectively, the "License"). You
9+
* may not use this file except in compliance with the License. You can
10+
* obtain a copy of the License at
11+
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
12+
* or packager/legal/LICENSE.txt. See the License for the specific
13+
* language governing permissions and limitations under the License.
14+
*
15+
* When distributing the software, include this License Header Notice in each
16+
* file and include the License file at packager/legal/LICENSE.txt.
17+
*
18+
* GPL Classpath Exception:
19+
* Oracle designates this particular file as subject to the "Classpath"
20+
* exception as provided by Oracle in the GPL Version 2 section of the License
21+
* file that accompanied this code.
22+
*
23+
* Modifications:
24+
* If applicable, add the following below the License Header, with the fields
25+
* enclosed by brackets [] replaced by your own identifying information:
26+
* "Portions Copyright [year] [name of copyright owner]"
27+
*
28+
* Contributor(s):
29+
* If you wish your version of this file to be governed by only the CDDL or
30+
* only the GPL Version 2, indicate your decision by adding "[Contributor]
31+
* elects to include this software in this distribution under the [CDDL or GPL
32+
* Version 2] license." If you don't indicate a single choice of license, a
33+
* recipient has the option to distribute your version of this file under
34+
* either the CDDL, the GPL Version 2 or to extend the choice of license to
35+
* its licensees as provided above. However, if you add GPL Version 2 code
36+
* and therefore, elected the GPL Version 2 license, then the option applies
37+
* only if the new code is made subject to such option by the copyright
38+
* holder.
39+
*/
40+
41+
package org.glassfish.jersey.netty.connector;
42+
43+
import java.io.ByteArrayInputStream;
44+
import java.io.IOException;
45+
import java.io.InputStream;
46+
import java.util.Map;
47+
import java.util.concurrent.LinkedBlockingDeque;
48+
49+
import javax.ws.rs.core.Response;
50+
51+
import io.netty.buffer.ByteBuf;
52+
import io.netty.channel.ChannelHandlerContext;
53+
import io.netty.channel.SimpleChannelInboundHandler;
54+
import io.netty.handler.codec.http.HttpContent;
55+
import io.netty.handler.codec.http.HttpHeaderNames;
56+
import io.netty.handler.codec.http.HttpObject;
57+
import io.netty.handler.codec.http.HttpResponse;
58+
import io.netty.handler.codec.http.HttpUtil;
59+
import io.netty.handler.codec.http.LastHttpContent;
60+
import io.netty.util.concurrent.Future;
61+
import io.netty.util.concurrent.GenericFutureListener;
62+
import jersey.repackaged.com.google.common.util.concurrent.SettableFuture;
63+
import org.glassfish.jersey.client.ClientRequest;
64+
import org.glassfish.jersey.client.ClientResponse;
65+
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
66+
import org.glassfish.jersey.netty.connector.internal.NettyInputStream;
67+
68+
/**
69+
* Jersey implementation of Netty channel handler.
70+
*
71+
* @author Pavel Bucek (pavel.bucek at oracle.com)
72+
*/
73+
class JerseyClientHandler extends SimpleChannelInboundHandler<HttpObject> {
74+
75+
private final NettyConnector connector;
76+
private final LinkedBlockingDeque<InputStream> isList = new LinkedBlockingDeque<>();
77+
78+
private final AsyncConnectorCallback asyncConnectorCallback;
79+
private final ClientRequest jerseyRequest;
80+
private final SettableFuture future;
81+
82+
JerseyClientHandler(NettyConnector nettyConnector, ClientRequest request,
83+
AsyncConnectorCallback callback, SettableFuture future) {
84+
this.connector = nettyConnector;
85+
this.asyncConnectorCallback = callback;
86+
this.jerseyRequest = request;
87+
this.future = future;
88+
}
89+
90+
@Override
91+
public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
92+
if (msg instanceof HttpResponse) {
93+
final HttpResponse response = (HttpResponse) msg;
94+
95+
final ClientResponse jerseyResponse = new ClientResponse(new Response.StatusType() {
96+
@Override
97+
public int getStatusCode() {
98+
return response.status().code();
99+
}
100+
101+
@Override
102+
public Response.Status.Family getFamily() {
103+
return Response.Status.Family.familyOf(response.status().code());
104+
}
105+
106+
@Override
107+
public String getReasonPhrase() {
108+
return response.status().reasonPhrase();
109+
}
110+
}, jerseyRequest);
111+
112+
for (Map.Entry<String, String> entry : response.headers().entries()) {
113+
jerseyResponse.getHeaders().add(entry.getKey(), entry.getValue());
114+
}
115+
116+
// request entity handling.
117+
if ((response.headers().contains(HttpHeaderNames.CONTENT_LENGTH) && HttpUtil.getContentLength(response) > 0)
118+
|| HttpUtil.isTransferEncodingChunked(response)) {
119+
120+
ctx.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
121+
@Override
122+
public void operationComplete(Future<? super Void> future) throws Exception {
123+
isList.add(NettyInputStream.END_OF_INPUT_ERROR);
124+
}
125+
});
126+
127+
jerseyResponse.setEntityStream(new NettyInputStream(isList));
128+
} else {
129+
jerseyResponse.setEntityStream(new InputStream() {
130+
@Override
131+
public int read() throws IOException {
132+
return -1;
133+
}
134+
});
135+
}
136+
137+
if (asyncConnectorCallback != null) {
138+
connector.executorService.execute(new Runnable() {
139+
@Override
140+
public void run() {
141+
asyncConnectorCallback.response(jerseyResponse);
142+
future.set(jerseyResponse);
143+
}
144+
});
145+
}
146+
147+
}
148+
if (msg instanceof HttpContent) {
149+
150+
HttpContent httpContent = (HttpContent) msg;
151+
152+
ByteBuf content = httpContent.content();
153+
154+
if (content.isReadable()) {
155+
// copy bytes - when netty reads last chunk, it automatically closes the channel, which invalidates all
156+
// relates ByteBuffs.
157+
byte[] bytes = new byte[content.readableBytes()];
158+
content.getBytes(content.readerIndex(), bytes);
159+
isList.add(new ByteArrayInputStream(bytes));
160+
}
161+
162+
if (msg instanceof LastHttpContent) {
163+
isList.add(NettyInputStream.END_OF_INPUT);
164+
}
165+
}
166+
}
167+
168+
@Override
169+
public void exceptionCaught(ChannelHandlerContext ctx, final Throwable cause) {
170+
if (asyncConnectorCallback != null) {
171+
172+
if (asyncConnectorCallback != null) {
173+
connector.executorService.execute(new Runnable() {
174+
@Override
175+
public void run() {
176+
asyncConnectorCallback.failure(cause);
177+
}
178+
});
179+
}
180+
}
181+
isList.add(NettyInputStream.END_OF_INPUT_ERROR);
182+
}
183+
}

0 commit comments

Comments
 (0)