Skip to content

Commit d1e0e9a

Browse files
author
James Bognar
committed
Next Generation RestClient
1 parent 83728c6 commit d1e0e9a

15 files changed

Lines changed: 1307 additions & 1 deletion

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to the Apache Software Foundation (ASF) under one or more
4+
contributor license agreements. See the NOTICE file distributed with
5+
this work for additional information regarding copyright ownership.
6+
The ASF licenses this file to You under the Apache License, Version 2.0
7+
(the "License"); you may not use this file except in compliance with
8+
the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-->
18+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
19+
20+
<modelVersion>4.0.0</modelVersion>
21+
22+
<parent>
23+
<groupId>org.apache.juneau</groupId>
24+
<artifactId>juneau-rest</artifactId>
25+
<version>9.2.1-SNAPSHOT</version>
26+
</parent>
27+
28+
<artifactId>juneau-ng-rest-client-apache-httpclient-50</artifactId>
29+
<name>Apache Juneau NG REST Client — Apache HttpClient 5.x Transport</name>
30+
<description>Apache HttpClient 5.x transport adapter for the next-generation Juneau REST client.</description>
31+
<packaging>bundle</packaging>
32+
33+
<properties>
34+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
35+
</properties>
36+
37+
<dependencies>
38+
<dependency>
39+
<groupId>org.apache.juneau</groupId>
40+
<artifactId>juneau-rest-client</artifactId>
41+
<version>${project.version}</version>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.apache.httpcomponents.client5</groupId>
45+
<artifactId>httpclient5</artifactId>
46+
<version>5.5.2</version>
47+
</dependency>
48+
</dependencies>
49+
50+
<build>
51+
<plugins>
52+
<plugin>
53+
<groupId>org.apache.felix</groupId>
54+
<artifactId>maven-bundle-plugin</artifactId>
55+
<extensions>true</extensions>
56+
<configuration>
57+
<supportIncrementalBuild>true</supportIncrementalBuild>
58+
</configuration>
59+
<executions>
60+
<execution>
61+
<id>bundle-manifest</id>
62+
<phase>process-classes</phase>
63+
<goals>
64+
<goal>manifest</goal>
65+
</goals>
66+
</execution>
67+
</executions>
68+
</plugin>
69+
<plugin>
70+
<groupId>org.apache.maven.plugins</groupId>
71+
<artifactId>maven-source-plugin</artifactId>
72+
<executions>
73+
<execution>
74+
<id>attach-sources</id>
75+
<phase>verify</phase>
76+
<goals>
77+
<goal>jar-no-fork</goal>
78+
</goals>
79+
</execution>
80+
</executions>
81+
</plugin>
82+
<plugin>
83+
<groupId>org.apache.maven.plugins</groupId>
84+
<artifactId>maven-jar-plugin</artifactId>
85+
</plugin>
86+
</plugins>
87+
</build>
88+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.juneau.ng.rest.client.apachehttpclient50;
18+
19+
import java.io.*;
20+
21+
import org.apache.hc.client5.http.impl.classic.*;
22+
import org.apache.hc.core5.http.*;
23+
import org.apache.hc.core5.http.io.entity.*;
24+
import org.apache.hc.core5.http.io.support.*;
25+
import org.apache.juneau.ng.rest.client.*;
26+
27+
/**
28+
* {@link HttpTransport} implementation backed by Apache HttpClient 5.x.
29+
*
30+
* <p>
31+
* This transport is auto-discovered via {@link java.util.ServiceLoader} when
32+
* {@code org.apache.httpcomponents.client5:httpclient5} is on the classpath. You can also instantiate it explicitly:
33+
*
34+
* <p class='bjava'>
35+
* <jv>transport</jv> = ApacheHc5Transport.<jsm>builder</jsm>()
36+
* .httpClient(HttpClients.createDefault())
37+
* .build();
38+
*
39+
* <jv>client</jv> = NgRestClient.<jsm>builder</jsm>()
40+
* .transport(<jv>transport</jv>)
41+
* .build();
42+
* </p>
43+
*
44+
* <p>
45+
* <b>Beta — API subject to change:</b> This type is part of the next-generation REST client and HTTP stack
46+
* ({@code org.apache.juneau.ng.*}).
47+
* It is not API-frozen: binary- and source-incompatible changes may appear in the <b>next major</b> Juneau release
48+
* (and possibly earlier).
49+
*
50+
* <h5 class='section'>See Also:</h5><ul>
51+
* <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/juneau-ng-rest-client">juneau-ng REST client</a>
52+
* </ul>
53+
*
54+
* @since 9.2.1
55+
*/
56+
@SuppressWarnings({
57+
"resource" // httpClient is owned by this transport and closed in close()
58+
})
59+
public final class ApacheHc5Transport implements HttpTransport {
60+
61+
private final CloseableHttpClient httpClient;
62+
63+
ApacheHc5Transport(ApacheHc5TransportBuilder builder) {
64+
this.httpClient = builder.httpClient != null ? builder.httpClient : HttpClients.createDefault();
65+
}
66+
67+
/**
68+
* Returns a new builder for this transport.
69+
*
70+
* @return A new builder. Never <jk>null</jk>.
71+
*/
72+
public static ApacheHc5TransportBuilder builder() {
73+
return new ApacheHc5TransportBuilder();
74+
}
75+
76+
/**
77+
* Returns a new instance backed by a default {@link CloseableHttpClient}.
78+
*
79+
* @return A new instance. Never <jk>null</jk>.
80+
*/
81+
public static ApacheHc5Transport create() {
82+
return builder().build();
83+
}
84+
85+
@Override /* HttpTransport */
86+
public TransportResponse execute(TransportRequest request) throws TransportException {
87+
var hcRequest = buildHcRequest(request);
88+
CloseableHttpResponse hcResponse;
89+
try {
90+
hcResponse = httpClient.execute(hcRequest);
91+
} catch (IOException e) {
92+
throw new TransportException("HTTP transport error: " + e.getMessage(), e);
93+
}
94+
return buildTransportResponse(hcResponse);
95+
}
96+
97+
@Override /* Closeable */
98+
public void close() throws IOException {
99+
httpClient.close();
100+
}
101+
102+
// -----------------------------------------------------------------------------------------------------------------
103+
// Internal helpers
104+
// -----------------------------------------------------------------------------------------------------------------
105+
106+
private static ClassicHttpRequest buildHcRequest(TransportRequest request) throws TransportException {
107+
var builder = ClassicRequestBuilder.create(request.getMethod()).setUri(request.getUri());
108+
for (var h : request.getHeaders())
109+
builder.addHeader(h.name(), h.value());
110+
var body = request.getBody();
111+
if (body != null)
112+
builder.setEntity(buildEntity(body));
113+
try {
114+
return builder.build();
115+
} catch (Exception e) {
116+
throw new TransportException("Failed to build HTTP request: " + e.getMessage(), e);
117+
}
118+
}
119+
120+
private static HttpEntity buildEntity(TransportBody body) {
121+
var ct = body.getContentType();
122+
var contentType = ct != null ? ContentType.parse(ct) : ContentType.APPLICATION_OCTET_STREAM;
123+
return new EntityTemplate(body.getContentLength(), contentType, null, body::writeTo);
124+
}
125+
126+
private static TransportResponse buildTransportResponse(CloseableHttpResponse hcResponse) throws TransportException {
127+
var builder = TransportResponse.builder()
128+
.statusCode(hcResponse.getCode())
129+
.reasonPhrase(hcResponse.getReasonPhrase())
130+
.closeCallback(hcResponse);
131+
for (var h : hcResponse.getHeaders())
132+
builder.header(h.getName(), h.getValue());
133+
var entity = hcResponse.getEntity();
134+
if (entity != null) {
135+
try {
136+
builder.body(entity.getContent());
137+
} catch (IOException e) {
138+
throw new TransportException("Failed to read response body: " + e.getMessage(), e);
139+
}
140+
}
141+
return builder.build();
142+
}
143+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.juneau.ng.rest.client.apachehttpclient50;
18+
19+
import org.apache.hc.client5.http.impl.classic.*;
20+
21+
/**
22+
* Fluent builder for {@link ApacheHc5Transport}.
23+
*
24+
* <p>
25+
* Obtain an instance via {@link ApacheHc5Transport#builder()}.
26+
*
27+
* <p>
28+
* <b>Beta — API subject to change:</b> This type is part of the next-generation REST client and HTTP stack
29+
* ({@code org.apache.juneau.ng.*}).
30+
* It is not API-frozen: binary- and source-incompatible changes may appear in the <b>next major</b> Juneau release
31+
* (and possibly earlier).
32+
*
33+
* <h5 class='section'>See Also:</h5><ul>
34+
* <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/juneau-ng-rest-client">juneau-ng REST client</a>
35+
* </ul>
36+
*
37+
* @since 9.2.1
38+
*/
39+
public final class ApacheHc5TransportBuilder {
40+
41+
CloseableHttpClient httpClient;
42+
43+
ApacheHc5TransportBuilder() {}
44+
45+
/**
46+
* Sets the underlying {@link CloseableHttpClient} to use.
47+
*
48+
* <p>
49+
* If not set, a default client is created via {@link HttpClients#createDefault()}.
50+
*
51+
* <p>
52+
* The transport takes ownership of the client and will close it when {@link ApacheHc5Transport#close()} is called.
53+
*
54+
* @param value The client to use. Must not be <jk>null</jk>.
55+
* @return This object.
56+
*/
57+
public ApacheHc5TransportBuilder httpClient(CloseableHttpClient value) {
58+
httpClient = value;
59+
return this;
60+
}
61+
62+
/**
63+
* Builds and returns the {@link ApacheHc5Transport}.
64+
*
65+
* @return A new instance. Never <jk>null</jk>.
66+
*/
67+
public ApacheHc5Transport build() {
68+
return new ApacheHc5Transport(this);
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.juneau.ng.rest.client.apachehttpclient50;
18+
19+
import org.apache.juneau.ng.rest.client.*;
20+
21+
/**
22+
* {@link HttpTransportProvider} implementation that supplies an {@link ApacheHc5Transport}.
23+
*
24+
* <p>
25+
* Registered via {@code META-INF/services/org.apache.juneau.ng.rest.client.HttpTransportProvider} so that
26+
* {@code NgRestClient} can auto-discover Apache HttpClient 5.x when this module is on the classpath.
27+
*
28+
* <p>
29+
* <b>Beta — API subject to change:</b> This type is part of the next-generation REST client and HTTP stack
30+
* ({@code org.apache.juneau.ng.*}).
31+
* It is not API-frozen: binary- and source-incompatible changes may appear in the <b>next major</b> Juneau release
32+
* (and possibly earlier).
33+
*
34+
* <h5 class='section'>See Also:</h5><ul>
35+
* <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/juneau-ng-rest-client">juneau-ng REST client</a>
36+
* </ul>
37+
*
38+
* @since 9.2.1
39+
*/
40+
public final class ApacheHc5TransportProvider implements HttpTransportProvider {
41+
42+
@Override /* HttpTransportProvider */
43+
public int getPriority() {
44+
return 60;
45+
}
46+
47+
@Override /* HttpTransportProvider */
48+
public boolean isAvailable() {
49+
try {
50+
Class.forName("org.apache.hc.client5.http.impl.classic.CloseableHttpClient");
51+
return true;
52+
} catch (ClassNotFoundException e) {
53+
return false;
54+
}
55+
}
56+
57+
@Override /* HttpTransportProvider */
58+
public HttpTransport create() {
59+
return ApacheHc5Transport.create();
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
org.apache.juneau.ng.rest.client.apachehttpclient50.ApacheHc5TransportProvider

0 commit comments

Comments
 (0)