Skip to content

Commit 442f83b

Browse files
authored
Merge pull request #301 from digipost/tighten-http-and-marshalling
Tighten http and marshalling
2 parents 6768c03 + ca6e488 commit 442f83b

File tree

12 files changed

+127
-74
lines changed

12 files changed

+127
-74
lines changed

NOTICE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ This software includes third party software subject to the following licenses:
1414
Digipost Certificate Validator under The Apache Software License, Version 2.0
1515
Digipost JAXB Resolver - com.sun.xml.bind under The Apache Software License, Version 2.0
1616
JavaBeans Activation Framework API jar under CDDL/GPLv2+CE
17+
JAXB Tools :: JAXB Basics :: Runtime under BSD-Style License
1718
jaxb-api under CDDL 1.1 or GPL2 w/ CPE
18-
JAXB2 Basics - Runtime under BSD-Style License
1919
Old JAXB Core under CDDL+GPL License
2020
Old JAXB Runtime under Eclipse Distribution License - v 1.0
2121
Posten signering - API JAXB Classes under The Apache Software License, Version 2.0

bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<name>Posten signering - Java API Client BOM</name>
3131

3232
<properties>
33-
<signature.api.version>3.0.0-RC5</signature.api.version>
33+
<signature.api.version>3.0.0</signature.api.version>
3434
</properties>
3535

3636
<dependencyManagement>

lib/NOTICE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ This software includes third party software subject to the following licenses:
1414
Digipost Certificate Validator under The Apache Software License, Version 2.0
1515
Digipost JAXB Resolver - com.sun.xml.bind under The Apache Software License, Version 2.0
1616
JavaBeans Activation Framework API jar under CDDL/GPLv2+CE
17+
JAXB Tools :: JAXB Basics :: Runtime under BSD-Style License
1718
jaxb-api under CDDL 1.1 or GPL2 w/ CPE
18-
JAXB2 Basics - Runtime under BSD-Style License
1919
Old JAXB Core under CDDL+GPL License
2020
Old JAXB Runtime under Eclipse Distribution License - v 1.0
2121
Posten signering - API JAXB Classes under The Apache Software License, Version 2.0

lib/src/main/java/no/digipost/signature/client/asice/DocumentBundle.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ public DocumentBundle(final byte[] bytes) {
1414
public InputStream getInputStream() {
1515
return new ByteArrayInputStream(bytes);
1616
}
17+
18+
public byte[] toByteArray() {
19+
return bytes;
20+
}
1721
}

lib/src/main/java/no/digipost/signature/client/asice/manifest/CreateDirectManifest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import no.digipost.signature.client.core.internal.MaySpecifySender;
1313
import no.digipost.signature.client.direct.DirectJob;
1414
import no.digipost.signature.client.direct.DirectSigner;
15+
import no.digipost.signature.jaxb.JaxbMarshaller;
1516

1617
import java.util.ArrayList;
1718
import java.util.List;
@@ -23,6 +24,7 @@ public class CreateDirectManifest extends ManifestCreator<DirectJob> {
2324
private final MaySpecifySender defaultSenderConfiguration;
2425

2526
public CreateDirectManifest(MaySpecifySender defaultSenderConfiguration) {
27+
super(JaxbMarshaller.ForRequestsOfAllApis.singleton());
2628
this.defaultSenderConfiguration = defaultSenderConfiguration;
2729
}
2830

lib/src/main/java/no/digipost/signature/client/asice/manifest/CreatePortalManifest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import no.digipost.signature.client.portal.NotificationsUsingLookup;
2121
import no.digipost.signature.client.portal.PortalJob;
2222
import no.digipost.signature.client.portal.PortalSigner;
23+
import no.digipost.signature.jaxb.JaxbMarshaller;
2324

2425
import java.time.Clock;
2526
import java.time.Duration;
@@ -36,6 +37,7 @@ public class CreatePortalManifest extends ManifestCreator<PortalJob> {
3637
private final Clock clock;
3738

3839
public CreatePortalManifest(MaySpecifySender defaultSenderConfiguration, Clock clock) {
40+
super(JaxbMarshaller.ForRequestsOfAllApis.singleton());
3941
this.defaultSenderConfiguration = defaultSenderConfiguration;
4042
this.clock = clock;
4143
}

lib/src/main/java/no/digipost/signature/client/asice/manifest/ManifestCreator.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,19 @@
22

33
import no.digipost.signature.api.xml.XMLManifest;
44
import no.digipost.signature.client.core.SignatureJob;
5-
import no.digipost.signature.client.core.exceptions.RuntimeIOException;
5+
import no.digipost.signature.jaxb.JaxbMarshaller;
66

7-
import java.io.ByteArrayOutputStream;
8-
import java.io.IOException;
7+
public abstract class ManifestCreator<JOB extends SignatureJob> {
98

10-
import static no.digipost.signature.client.core.internal.xml.Marshalling.marshal;
9+
private final JaxbMarshaller marshaller;
1110

12-
public abstract class ManifestCreator<JOB extends SignatureJob> {
11+
protected ManifestCreator(JaxbMarshaller marshaller) {
12+
this.marshaller = marshaller;
13+
}
1314

1415
public Manifest createManifest(JOB job) {
1516
Object xmlManifest = buildXmlManifest(job);
16-
17-
try (ByteArrayOutputStream manifestStream = new ByteArrayOutputStream()) {
18-
marshal(xmlManifest, manifestStream);
19-
return new Manifest(manifestStream.toByteArray());
20-
} catch (IOException e) {
21-
throw new RuntimeIOException(e);
22-
}
17+
return new Manifest(marshaller.marshalToBytes(xmlManifest));
2318
}
2419

2520
abstract XMLManifest buildXmlManifest(JOB job);

lib/src/main/java/no/digipost/signature/client/core/internal/ClientExceptionMapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import no.digipost.signature.client.core.exceptions.UnexpectedResponseException;
77
import no.digipost.signature.client.core.internal.http.ResponseStatus;
88
import no.digipost.signature.client.core.internal.http.StatusCode;
9-
import no.digipost.signature.client.core.internal.xml.Marshalling;
9+
import no.digipost.signature.jaxb.JaxbMarshaller;
1010
import org.apache.hc.core5.http.ClassicHttpResponse;
1111
import org.apache.hc.core5.http.ContentType;
1212
import org.apache.hc.core5.http.HttpHeaders;
@@ -44,7 +44,7 @@ static XMLError extractError(ClassicHttpResponse response) {
4444
Optional<ContentType> contentType = Optional.ofNullable(response.getHeader(CONTENT_TYPE)).map(NameValuePair::getValue).map(ContentType::parse);
4545
if (contentType.filter(APPLICATION_XML::isSameMimeType).isPresent()) {
4646
try(InputStream body = response.getEntity().getContent()) {
47-
error = Marshalling.unmarshal(body, XMLError.class);
47+
error = JaxbMarshaller.ForResponsesOfAllApis.singleton().unmarshal(body, XMLError.class);
4848
} catch (IOException e) {
4949
throw new UncheckedIOException("Could not extract error from body.", e);
5050
}

lib/src/main/java/no/digipost/signature/client/core/internal/ClientHelper.java

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@
1515
import no.digipost.signature.client.core.exceptions.JobCannotBeCancelledException;
1616
import no.digipost.signature.client.core.exceptions.NotCancellableException;
1717
import no.digipost.signature.client.core.exceptions.TooEagerPollingException;
18+
import no.digipost.signature.client.core.internal.http.ApacheHttpMarshallingSupport;
1819
import no.digipost.signature.client.core.internal.http.ResponseStatus;
1920
import no.digipost.signature.client.core.internal.http.SignatureServiceRoot;
2021
import no.digipost.signature.client.core.internal.http.StatusCode;
21-
import no.digipost.signature.client.core.internal.xml.Marshalling;
2222
import no.digipost.signature.client.direct.WithSignerUrl;
23+
import no.digipost.signature.jaxb.JaxbMarshaller;
2324
import org.apache.hc.client5.http.classic.HttpClient;
2425
import org.apache.hc.client5.http.classic.methods.HttpGet;
25-
import org.apache.hc.client5.http.classic.methods.HttpPost;
2626
import org.apache.hc.client5.http.entity.mime.ByteArrayBody;
27-
import org.apache.hc.client5.http.entity.mime.InputStreamBody;
2827
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
2928
import org.apache.hc.client5.http.entity.mime.MultipartPartBuilder;
3029
import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -34,7 +33,6 @@
3433
import org.apache.hc.core5.http.ProtocolException;
3534
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
3635

37-
import java.io.ByteArrayOutputStream;
3836
import java.io.IOException;
3937
import java.io.InputStream;
4038
import java.io.UncheckedIOException;
@@ -59,6 +57,7 @@
5957
import static org.apache.hc.core5.http.ContentType.MULTIPART_MIXED;
6058
import static org.apache.hc.core5.http.HttpHeaders.ACCEPT;
6159
import static org.apache.hc.core5.http.HttpHeaders.CONTENT_TYPE;
60+
import static org.apache.hc.core5.http.io.support.ClassicRequestBuilder.post;
6261

6362
public class ClientHelper {
6463

@@ -69,37 +68,38 @@ public class ClientHelper {
6968

7069
private final SignatureServiceRoot serviceRoot;
7170
private final HttpClient httpClient;
71+
private final ApacheHttpMarshallingSupport requestMarshalling;
72+
private final JaxbMarshaller responseMarshaller;
7273

7374

7475
public ClientHelper(SignatureServiceRoot serviceRoot, HttpClient httpClient) {
76+
this(serviceRoot, httpClient, JaxbMarshaller.ForRequestsOfAllApis.singleton(), JaxbMarshaller.ForResponsesOfAllApis.singleton());
77+
}
78+
79+
public ClientHelper(SignatureServiceRoot serviceRoot, HttpClient httpClient, JaxbMarshaller requestMarshaller, JaxbMarshaller responseMarshaller) {
7580
this.serviceRoot = serviceRoot;
7681
this.httpClient = httpClient;
82+
this.requestMarshalling = new ApacheHttpMarshallingSupport(requestMarshaller);
83+
this.responseMarshaller = responseMarshaller;
7784
}
7885

7986
public <RESPONSE, REQUEST> RESPONSE sendSignatureJobRequest(ApiFlow<REQUEST, RESPONSE, ?> target, REQUEST signatureJobRequest, DocumentBundle documentBundle, Sender sender) {
80-
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
81-
multipartEntityBuilder.setContentType(MULTIPART_MIXED);
82-
83-
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
84-
Marshalling.marshal(signatureJobRequest, os);
85-
multipartEntityBuilder.addPart(MultipartPartBuilder.create()
86-
.setBody(new ByteArrayBody(os.toByteArray(), APPLICATION_XML, ""))
87+
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
88+
.setContentType(MULTIPART_MIXED)
89+
.addPart(MultipartPartBuilder.create()
90+
.setBody(requestMarshalling.createContentBody(signatureJobRequest))
8791
.addHeader(CONTENT_TYPE, APPLICATION_XML.getMimeType())
88-
.build());
89-
90-
multipartEntityBuilder.addPart(MultipartPartBuilder.create()
91-
.setBody(new InputStreamBody(documentBundle.getInputStream(), APPLICATION_OCTET_STREAM, ""))
92+
.build())
93+
.addPart(MultipartPartBuilder.create()
94+
.setBody(new ByteArrayBody(documentBundle.toByteArray(), APPLICATION_OCTET_STREAM, ""))
9295
.addHeader(CONTENT_TYPE, APPLICATION_OCTET_STREAM.getMimeType()).build());
93-
} catch (IOException e) {
94-
throw new UncheckedIOException(e);
95-
}
9696

97-
try (HttpEntity multiPart = multipartEntityBuilder.build()) {
98-
ClassicHttpRequest request = ClassicRequestBuilder
99-
.post(serviceRoot.constructUrl(uri -> uri.appendPath(target.path(sender))))
100-
.addHeader(ACCEPT, APPLICATION_XML.getMimeType())
101-
.build();
97+
ClassicHttpRequest request = ClassicRequestBuilder
98+
.post(serviceRoot.constructUrl(uri -> uri.appendPath(target.path(sender))))
99+
.addHeader(ACCEPT, APPLICATION_XML.getMimeType())
100+
.build();
102101

102+
try (HttpEntity multiPart = multipartEntityBuilder.build()) {
103103
request.setEntity(multiPart);
104104
return call(() -> {
105105
try {
@@ -114,14 +114,14 @@ public <RESPONSE, REQUEST> RESPONSE sendSignatureJobRequest(ApiFlow<REQUEST, RES
114114
}
115115

116116
public XMLDirectSignerResponse requestNewRedirectUrl(WithSignerUrl url) {
117-
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
118-
Marshalling.marshal(new XMLDirectSignerUpdateRequest().withRedirectUrl(new XMLEmptyElement()), os);
119-
ClassicHttpRequest request = new HttpPost(url.getSignerUrl());
120-
request.addHeader(ACCEPT, APPLICATION_XML.getMimeType());
121-
117+
ClassicHttpRequest request = post(url.getSignerUrl())
118+
.addHeader(ACCEPT, APPLICATION_XML.getMimeType())
119+
.setEntity(requestMarshalling.createEntity(new XMLDirectSignerUpdateRequest().withRedirectUrl(new XMLEmptyElement())))
120+
.build();
121+
try {
122122
return httpClient.execute(request, response -> parseResponse(response, XMLDirectSignerResponse.class));
123123
} catch (IOException e) {
124-
throw new UncheckedIOException(e);
124+
throw new HttpIOException(request, e);
125125
}
126126
}
127127

@@ -156,12 +156,12 @@ public XMLDirectSignatureJobStatusResponse sendSignatureJobStatusRequest(URI sta
156156

157157

158158
public void cancel(Cancellable cancellable) {
159-
if (cancellable.getCancellationUrl() != null) {
160-
postEmptyEntity(cancellable.getCancellationUrl().getUrl(), httpResponse -> ResponseStatus.fromHttpResponse(httpResponse)
161-
.throwIf(CONFLICT, status -> new JobCannotBeCancelledException(status, extractError(httpResponse))));
162-
} else {
163-
throw new NotCancellableException();
164-
}
159+
if (cancellable.getCancellationUrl() != null) {
160+
postEmptyEntity(cancellable.getCancellationUrl().getUrl(), httpResponse -> ResponseStatus.fromHttpResponse(httpResponse)
161+
.throwIf(CONFLICT, status -> new JobCannotBeCancelledException(status, extractError(httpResponse))));
162+
} else {
163+
throw new NotCancellableException();
164+
}
165165
}
166166

167167
public <RES> JobStatusResponse<RES> getStatusChange(ApiFlow<?, ?, RES> target, Sender sender) {
@@ -177,7 +177,7 @@ public <RES> JobStatusResponse<RES> getStatusChange(ApiFlow<?, ?, RES> target, S
177177
StatusCode status = ResponseStatus.fromHttpResponse(response)
178178
.throwIf(TOO_MANY_REQUESTS, s -> new TooEagerPollingException())
179179
.expect(SUCCESSFUL).orThrow(unexpectedStatus -> exceptionForGeneralError(response));
180-
RES statusResponseBody = status.equals(NO_CONTENT) ? null : Marshalling.unmarshal(response.getEntity().getContent(), target.statusResponseType);
180+
RES statusResponseBody = status.equals(NO_CONTENT) ? null : responseMarshaller.unmarshal(response.getEntity().getContent(), target.statusResponseType);
181181
return new JobStatusResponse<>(statusResponseBody, getNextPermittedPollTime(response));
182182
});
183183
} catch (IOException e) {
@@ -242,10 +242,10 @@ private void delete(URI uri) {
242242
});
243243
}
244244

245-
private static <T> T parseResponse(ClassicHttpResponse response, Class<T> responseType) {
245+
private <T> T parseResponse(ClassicHttpResponse response, Class<T> responseType) {
246246
ResponseStatus.fromHttpResponse(response).expect(SUCCESSFUL).orThrow(unexpectedStatus -> exceptionForGeneralError(response));
247247
try (InputStream body = response.getEntity().getContent()) {
248-
return Marshalling.unmarshal(body, responseType);
248+
return responseMarshaller.unmarshal(body, responseType);
249249
} catch (IOException e) {
250250
throw new HttpIOException(response, e);
251251
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package no.digipost.signature.client.core.internal.http;
2+
3+
import no.digipost.signature.jaxb.JaxbMarshaller;
4+
import org.apache.hc.client5.http.entity.mime.ContentBody;
5+
import org.apache.hc.core5.http.HttpEntity;
6+
import org.apache.hc.core5.http.io.entity.EntityTemplate;
7+
8+
import static org.apache.hc.core5.http.ContentType.APPLICATION_XML;
9+
10+
public final class ApacheHttpMarshallingSupport {
11+
12+
private final JaxbMarshaller marshaller;
13+
14+
public ApacheHttpMarshallingSupport(JaxbMarshaller marshaller) {
15+
this.marshaller = marshaller;
16+
}
17+
18+
public HttpEntity createEntity(Object jaxbObject) {
19+
return new EntityTemplate(-1, APPLICATION_XML, "UTF-8", out -> marshaller.marshal(jaxbObject, out));
20+
}
21+
22+
public ContentBody createContentBody(Object jaxbObject) {
23+
return createContentBody("", jaxbObject);
24+
}
25+
26+
public ContentBody createContentBody(String filename, Object jaxbObject) {
27+
return new IOCallbackContentBody(-1, APPLICATION_XML, filename, out -> marshaller.marshal(jaxbObject, out));
28+
}
29+
30+
}

0 commit comments

Comments
 (0)