Skip to content

Commit cecead2

Browse files
Portability to Java 6 support
This framework should be able to be binary compatible with Java 6 as Netty does. This merge request allows minor changes to be able to be compatible. Also it upgrades dependencies and allows OPTION method (which was missing).
1 parent e008f9a commit cecead2

25 files changed

+436
-209
lines changed

pom.xml

+23-7
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@
6262
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
6363
<surefire.redirectTestOutputToFile>true</surefire.redirectTestOutputToFile>
6464

65-
<rs-api.version>2.0</rs-api.version>
66-
<netty.version>4.1.16.Final</netty.version>
67-
<slf4j.version>1.7.5</slf4j.version>
65+
<rs-api.version>2.1.1</rs-api.version>
66+
<netty.version>4.1.36.Final</netty.version>
67+
<slf4j.version>1.7.26</slf4j.version>
6868
<findbugs.version>2.0.1</findbugs.version>
6969
<beanutils.version>1.8.3</beanutils.version>
70-
<junit.version>4.11</junit.version>
71-
<logback.version>1.0.9</logback.version>
72-
<gson.version>2.2.4</gson.version>
70+
<junit.version>4.12</junit.version>
71+
<logback.version>1.2.3</logback.version>
72+
<gson.version>2.8.5</gson.version>
7373
</properties>
7474

7575
<dependencies>
@@ -135,10 +135,27 @@
135135
<version>${gson.version}</version>
136136
<scope>test</scope>
137137
</dependency>
138+
<dependency>
139+
<groupId>io.cdap.http</groupId>
140+
<artifactId>netty-http</artifactId>
141+
<version>1.2.0</version>
142+
</dependency>
138143
</dependencies>
139144

140145
<build>
141146
<plugins>
147+
<plugin>
148+
<groupId>org.codehaus.mojo</groupId>
149+
<artifactId>animal-sniffer-maven-plugin</artifactId>
150+
<version>1.16</version>
151+
<configuration>
152+
<signature>
153+
<groupId>org.codehaus.mojo.signature</groupId>
154+
<artifactId>java16</artifactId>
155+
<version>1.0</version>
156+
</signature>
157+
</configuration>
158+
</plugin>
142159
<!-- Compiler -->
143160
<plugin>
144161
<groupId>org.apache.maven.plugins</groupId>
@@ -174,7 +191,6 @@
174191
</execution>
175192
</executions>
176193
</plugin>
177-
178194
<!-- Checkstyle -->
179195
<plugin>
180196
<groupId>org.apache.maven.plugins</groupId>

src/main/java/io/cdap/http/AbstractHttpResponder.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.cdap.http;
1818

19+
import io.cdap.http.internal.InternalUtil;
1920
import io.netty.buffer.ByteBuf;
2021
import io.netty.buffer.Unpooled;
2122
import io.netty.handler.codec.http.DefaultHttpHeaders;
@@ -27,15 +28,13 @@
2728
import java.io.File;
2829
import java.io.IOException;
2930
import java.nio.ByteBuffer;
30-
import java.nio.charset.StandardCharsets;
3131

3232
/**
3333
* Base implementation of {@link HttpResponder} to simplify child implementations.
3434
*/
3535
public abstract class AbstractHttpResponder implements HttpResponder {
3636

3737
protected static final String OCTET_STREAM_TYPE = "application/octet-stream";
38-
3938
@Override
4039
public void sendJson(HttpResponseStatus status, String jsonString) {
4140
sendString(status, jsonString, new DefaultHttpHeaders().add(HttpHeaderNames.CONTENT_TYPE.toString(),
@@ -53,7 +52,7 @@ public void sendString(HttpResponseStatus status, String data, HttpHeaders heade
5352
sendStatus(status, headers);
5453
return;
5554
}
56-
ByteBuf buffer = Unpooled.wrappedBuffer(StandardCharsets.UTF_8.encode(data));
55+
ByteBuf buffer = Unpooled.wrappedBuffer(InternalUtil.UTF_8.encode(data));
5756
sendContent(status, buffer, addContentTypeIfMissing(new DefaultHttpHeaders().add(headers),
5857
"text/plain; charset=utf-8"));
5958
}
@@ -80,7 +79,7 @@ public void sendBytes(HttpResponseStatus status, ByteBuffer buffer, HttpHeaders
8079
}
8180

8281
@Override
83-
public void sendFile(File file) throws IOException {
82+
public void sendFile(File file) throws Throwable {
8483
sendFile(file, EmptyHttpHeaders.INSTANCE);
8584
}
8685

src/main/java/io/cdap/http/HttpResponder.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ public interface HttpResponder {
124124
*
125125
* @param file The file to send
126126
* @throws IOException if failed to open and read the file
127+
* @throws Throwable
127128
*/
128-
void sendFile(File file) throws IOException;
129+
void sendFile(File file) throws IOException, Throwable;
129130

130131
/**
131132
* Sends a file content back to client with response status 200. Default content type is "application/octet-stream",
@@ -134,8 +135,9 @@ public interface HttpResponder {
134135
* @param file The file to send
135136
* @param headers additional headers to send with the response.
136137
* @throws IOException if failed to open and read the file
138+
* @throws Throwable
137139
*/
138-
void sendFile(File file, HttpHeaders headers) throws IOException;
140+
void sendFile(File file, HttpHeaders headers) throws IOException, Throwable;
139141

140142
/**
141143
* Sends response back to client. The response body is produced by the given {@link BodyProducer}. This method

src/main/java/io/cdap/http/NettyHttpService.java

+11-16
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ private NettyHttpService(String serviceName,
129129
this.workerThreadPoolSize = workerThreadPoolSize;
130130
this.execThreadPoolSize = execThreadPoolSize;
131131
this.execThreadKeepAliveSecs = execThreadKeepAliveSecs;
132-
this.channelConfigs = new HashMap<>(channelConfigs);
133-
this.childChannelConfigs = new HashMap<>(childChannelConfigs);
132+
this.channelConfigs = new HashMap<ChannelOption, Object>(channelConfigs);
133+
this.childChannelConfigs = new HashMap<ChannelOption, Object>(childChannelConfigs);
134134
this.rejectedExecutionHandler = rejectedExecutionHandler;
135135
this.resourceHandler = new HttpResourceHandler(httpHandlers, handlerHooks, urlRewriter, exceptionHandler);
136136
this.handlerContext = new BasicHandlerContext(this.resourceHandler);
@@ -152,10 +152,9 @@ public static Builder builder(String serviceName) {
152152

153153
/**
154154
* Starts the HTTP service.
155-
*
156-
* @throws Exception if the service failed to started
155+
* @throws Throwable
157156
*/
158-
public synchronized void start() throws Exception {
157+
public synchronized void start() throws Throwable {
159158
if (state == State.RUNNING) {
160159
LOG.debug("Ignore start() call on HTTP service {} since it has already been started.", serviceName);
161160
return;
@@ -193,7 +192,6 @@ public synchronized void start() throws Exception {
193192
shutdownExecutorGroups(0, 5, TimeUnit.SECONDS, eventExecutorGroup);
194193
}
195194
} catch (Throwable t2) {
196-
t.addSuppressed(t2);
197195
}
198196
state = State.FAILED;
199197
throw t;
@@ -224,10 +222,9 @@ public boolean isSSLEnabled() {
224222
/**
225223
* Stops the HTTP service gracefully and release all resources. Same as calling {@link #stop(long, long, TimeUnit)}
226224
* with {@code 0} second quiet period and {@code 5} seconds timeout.
227-
*
228-
* @throws Exception if there is exception raised during shutdown.
225+
* @throws Throwable
229226
*/
230-
public void stop() throws Exception {
227+
public void stop() throws Throwable {
231228
stop(0, 5, TimeUnit.SECONDS);
232229
}
233230

@@ -239,9 +236,9 @@ public void stop() throws Exception {
239236
* {@linkplain EventExecutorGroup#shutdown()}
240237
* regardless if a task was submitted during the quiet period
241238
* @param unit the unit of {@code quietPeriod} and {@code timeout}
242-
* @throws Exception if there is exception raised during shutdown.
239+
* @throws Throwable
243240
*/
244-
public synchronized void stop(long quietPeriod, long timeout, TimeUnit unit) throws Exception {
241+
public synchronized void stop(long quietPeriod, long timeout, TimeUnit unit) throws Throwable {
245242
if (state == State.STOPPED) {
246243
LOG.debug("Ignore stop() call on HTTP service {} since it has already been stopped.", serviceName);
247244
return;
@@ -377,7 +374,7 @@ protected void initChannel(SocketChannel ch) throws Exception {
377374
*/
378375
private void shutdownExecutorGroups(long quietPeriod, long timeout, TimeUnit unit, EventExecutorGroup...groups) {
379376
Exception ex = null;
380-
List<Future<?>> futures = new ArrayList<>();
377+
List<Future<?>> futures = new ArrayList<Future<?>>();
381378
for (EventExecutorGroup group : groups) {
382379
if (group == null) {
383380
continue;
@@ -391,8 +388,6 @@ private void shutdownExecutorGroups(long quietPeriod, long timeout, TimeUnit uni
391388
} catch (Exception e) {
392389
if (ex == null) {
393390
ex = e;
394-
} else {
395-
ex.addSuppressed(e);
396391
}
397392
}
398393
}
@@ -449,8 +444,8 @@ protected Builder(String serviceName) {
449444
rejectedExecutionHandler = DEFAULT_REJECTED_EXECUTION_HANDLER;
450445
httpChunkLimit = DEFAULT_HTTP_CHUNK_LIMIT;
451446
port = 0;
452-
channelConfigs = new HashMap<>();
453-
childChannelConfigs = new HashMap<>();
447+
channelConfigs = new HashMap<ChannelOption, Object>();
448+
childChannelConfigs = new HashMap<ChannelOption, Object>();
454449
channelConfigs.put(ChannelOption.SO_BACKLOG, DEFAULT_CONNECTION_BACKLOG);
455450
sslHandlerFactory = null;
456451
exceptionHandler = new ExceptionHandler();

src/main/java/io/cdap/http/SSLHandlerFactory.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,16 @@ public SSLHandlerFactory(SslContext sslContext) {
7070
}
7171

7272
private static KeyStore getKeyStore(File keyStore, String keyStorePassword) throws Exception {
73-
try (InputStream is = new FileInputStream(keyStore)) {
73+
InputStream is = null;
74+
try {
75+
is = new FileInputStream(keyStore);
7476
KeyStore ks = KeyStore.getInstance("JKS");
7577
ks.load(is, keyStorePassword.toCharArray());
7678
return ks;
79+
} finally {
80+
if (is != null) {
81+
is.close();
82+
}
7783
}
7884
}
7985

src/main/java/io/cdap/http/internal/BasicHttpResponder.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import java.io.File;
5151
import java.io.IOException;
5252
import java.io.RandomAccessFile;
53-
import java.nio.charset.StandardCharsets;
5453
import java.util.concurrent.atomic.AtomicBoolean;
5554
import javax.annotation.Nullable;
5655

@@ -105,7 +104,7 @@ public void sendContent(HttpResponseStatus status, ByteBuf content, HttpHeaders
105104
}
106105

107106
@Override
108-
public void sendFile(File file, HttpHeaders headers) throws IOException {
107+
public void sendFile(File file, HttpHeaders headers) throws Throwable {
109108
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
110109
addContentTypeIfMissing(response.headers().add(headers), OCTET_STREAM_TYPE);
111110

@@ -136,7 +135,6 @@ public void sendFile(File file, HttpHeaders headers) throws IOException {
136135
try {
137136
raf.close();
138137
} catch (IOException ex) {
139-
t.addSuppressed(ex);
140138
}
141139
throw t;
142140
}
@@ -152,7 +150,7 @@ public void sendContent(HttpResponseStatus status, final BodyProducer bodyProduc
152150
// Response with error and close the connection
153151
sendContent(
154152
HttpResponseStatus.INTERNAL_SERVER_ERROR,
155-
Unpooled.copiedBuffer("Failed to determined content length. Cause: " + t.getMessage(), StandardCharsets.UTF_8),
153+
Unpooled.copiedBuffer("Failed to determined content length. Cause: " + t.getMessage(), InternalUtil.UTF_8),
156154
new DefaultHttpHeaders()
157155
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
158156
.set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=utf-8"));
@@ -197,7 +195,7 @@ boolean isResponded() {
197195
private ChannelFutureListener createBodyProducerCompletionListener(final BodyProducer bodyProducer) {
198196
return new ChannelFutureListener() {
199197
@Override
200-
public void operationComplete(ChannelFuture future) throws Exception {
198+
public void operationComplete(ChannelFuture future) {
201199
if (!future.isSuccess()) {
202200
callBodyProducerHandleError(bodyProducer, future.cause());
203201
channel.close();

src/main/java/io/cdap/http/internal/HandlerException.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
import io.netty.handler.codec.http.HttpUtil;
2525
import io.netty.handler.codec.http.HttpVersion;
2626

27-
import java.nio.charset.StandardCharsets;
28-
2927
/**
3028
*Creating Http Response for Exception messages.
3129
*/
@@ -48,7 +46,7 @@ final class HandlerException extends Exception {
4846

4947
HttpResponse createFailureResponse() {
5048
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, failureStatus,
51-
Unpooled.copiedBuffer(message, StandardCharsets.UTF_8));
49+
Unpooled.copiedBuffer(message, InternalUtil.UTF_8));
5250
HttpUtil.setContentLength(response, response.content().readableBytes());
5351
return response;
5452
}

src/main/java/io/cdap/http/internal/HttpResourceHandler.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import javax.annotation.Nullable;
4545
import javax.ws.rs.DELETE;
4646
import javax.ws.rs.GET;
47+
import javax.ws.rs.OPTIONS;
4748
import javax.ws.rs.POST;
4849
import javax.ws.rs.PUT;
4950
import javax.ws.rs.Path;
@@ -135,7 +136,7 @@ public HttpResourceHandler(Iterable<? extends HttpHandler> handlers, Iterable<?
135136
* @return String representation of HttpMethod from annotations or emptyString as a default.
136137
*/
137138
private Set<HttpMethod> getHttpMethods(Method method) {
138-
Set<HttpMethod> httpMethods = new HashSet<>();
139+
Set<HttpMethod> httpMethods = new HashSet<HttpMethod>();
139140

140141
if (method.isAnnotationPresent(GET.class)) {
141142
httpMethods.add(HttpMethod.GET);
@@ -149,6 +150,9 @@ private Set<HttpMethod> getHttpMethods(Method method) {
149150
if (method.isAnnotationPresent(DELETE.class)) {
150151
httpMethods.add(HttpMethod.DELETE);
151152
}
153+
if (method.isAnnotationPresent(OPTIONS.class)) {
154+
httpMethods.add(HttpMethod.OPTIONS);
155+
}
152156

153157
return Collections.unmodifiableSet(httpMethods);
154158
}
@@ -310,7 +314,8 @@ public HttpMethodInfo getDestinationMethod(HttpRequest request, HttpResponder re
310314

311315
LOG.trace("Routable destinations for request {}: {}", requestUri, routableDestinations);
312316
Iterable<String> requestUriParts = splitAndOmitEmpty(requestUri, '/');
313-
List<PatternPathRouterWithGroups.RoutableDestination<HttpResourceModel>> matchedDestinations = new ArrayList<>();
317+
List<PatternPathRouterWithGroups.RoutableDestination<HttpResourceModel>> matchedDestinations =
318+
new ArrayList<PatternPathRouterWithGroups.RoutableDestination<HttpResourceModel>>();
314319
long maxScore = 0;
315320

316321
for (PatternPathRouterWithGroups.RoutableDestination<HttpResourceModel> destination : routableDestinations) {
@@ -390,7 +395,7 @@ public void destroy(HandlerContext context) {
390395
}
391396

392397
private static <T> List<T> copyOf(Iterable<? extends T> iterable) {
393-
List<T> list = new ArrayList<>();
398+
List<T> list = new ArrayList<T>();
394399
for (T item : iterable) {
395400
list.add(item);
396401
}

src/main/java/io/cdap/http/internal/HttpResourceModel.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
public final class HttpResourceModel {
4949

5050
private static final Set<Class<? extends Annotation>> SUPPORTED_PARAM_ANNOTATIONS =
51-
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(PathParam.class, QueryParam.class, HeaderParam.class)));
51+
Collections.unmodifiableSet(new HashSet<Class<? extends Annotation>>
52+
(Arrays.asList(PathParam.class, QueryParam.class, HeaderParam.class)));
5253

5354
private final Set<HttpMethod> httpMethods;
5455
private final String path;
@@ -211,13 +212,15 @@ private List<Map<Class<? extends Annotation>, ParameterInfo<?>>> createParameter
211212
return Collections.emptyList();
212213
}
213214

214-
List<Map<Class<? extends Annotation>, ParameterInfo<?>>> result = new ArrayList<>();
215+
List<Map<Class<? extends Annotation>, ParameterInfo<?>>> result =
216+
new ArrayList<Map<Class<? extends Annotation>, ParameterInfo<?>>>();
215217
Type[] parameterTypes = method.getGenericParameterTypes();
216218
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
217219

218220
for (int i = 2; i < parameterAnnotations.length; i++) {
219221
Annotation[] annotations = parameterAnnotations[i];
220-
Map<Class<? extends Annotation>, ParameterInfo<?>> paramAnnotations = new IdentityHashMap<>();
222+
Map<Class<? extends Annotation>, ParameterInfo<?>> paramAnnotations =
223+
new IdentityHashMap<Class<? extends Annotation>, ParameterInfo<?>>();
221224

222225
for (Annotation annotation : annotations) {
223226
Class<? extends Annotation> annotationType = annotation.annotationType();
@@ -266,7 +269,7 @@ private static final class ParameterInfo<T> {
266269
private final Converter<T, Object> converter;
267270

268271
static <V> ParameterInfo<V> create(Annotation annotation, @Nullable Converter<V, Object> converter) {
269-
return new ParameterInfo<>(annotation, converter);
272+
return new ParameterInfo<V>(annotation, converter);
270273
}
271274

272275
private ParameterInfo(Annotation annotation, @Nullable Converter<T, Object> converter) {

0 commit comments

Comments
 (0)