Java tutorial
/** * Copyright (C) Posten Norge AS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package no.digipost.api.client; import no.digipost.api.client.DigipostClientMock.ValidatingMarshaller; import no.digipost.api.client.errorhandling.ErrorCode; import no.digipost.api.client.representations.*; import no.digipost.api.client.util.MockfriendlyResponse.MockedResponseBuilder; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.NotImplementedException; import org.bouncycastle.openssl.PEMWriter; import org.glassfish.jersey.media.multipart.BodyPart; import org.glassfish.jersey.media.multipart.MultiPart; import org.joda.time.DateTime; import org.xml.sax.helpers.DefaultHandler; import javax.ws.rs.ProcessingException; import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.ConnectException; import java.net.URI; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import static java.lang.Integer.parseInt; import static javax.ws.rs.core.Response.Status.NOT_FOUND; import static javax.ws.rs.core.Response.Status.OK; import static no.digipost.api.client.representations.DeliveryMethod.DIGIPOST; import static no.digipost.api.client.representations.MessageStatus.COMPLETE; public class ApiServiceMock implements ApiService { private final EncryptionKey fakeEncryptionKey; public enum Method { GET_CONTENT, MULTIPART_MESSAGE, GET_DOCUMENTS_EVENTS } final Map<Method, RequestsAndResponses> requestsAndResponsesMap = new HashMap<>(); private final ValidatingMarshaller marshaller; public ApiServiceMock(ValidatingMarshaller validatingMarshaller) { this.marshaller = validatingMarshaller; this.fakeEncryptionKey = createFakeEncryptionKey(); init(); } static EncryptionKey createFakeEncryptionKey() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (Writer osWriter = new OutputStreamWriter(baos); PEMWriter writer = new PEMWriter(osWriter)) { KeyPairGenerator factory = KeyPairGenerator.getInstance("RSA"); factory.initialize(2048); KeyPair keyPair = factory.generateKeyPair(); writer.writeObject(keyPair.getPublic()); } catch (Exception e) { throw new RuntimeException("Failed creation of fake encryption key.", e); } EncryptionKey fakeKey = new EncryptionKey(); fakeKey.setKeyId("fake-hash"); fakeKey.setValue(new String(baos.toByteArray())); return fakeKey; } private void init() { requestsAndResponsesMap.clear(); requestsAndResponsesMap.put(Method.GET_CONTENT, new RequestsAndResponses()); requestsAndResponsesMap.put(Method.GET_DOCUMENTS_EVENTS, new RequestsAndResponses()); requestsAndResponsesMap.put(Method.MULTIPART_MESSAGE, new RequestsAndResponses(new MultipartRequestMatcher())); } public void reset() { init(); } @Override public EntryPoint getEntryPoint() { throw new NotImplementedException("This is a mock"); } @Override public Response multipartMessage(final MultiPart multiPart) { Message message = null; List<ContentPart> contentParts = new ArrayList<>(); for (BodyPart bodyPart : multiPart.getBodyParts()) { if (bodyPart.getMediaType().toString().equals(MediaTypes.DIGIPOST_MEDIA_TYPE_V6)) { message = (Message) bodyPart.getEntity(); } else { contentParts.add(new ContentPart(bodyPart.getMediaType())); } } if (message == null) { throw new IllegalArgumentException("MultiPart does not contain Message"); } if (marshaller != null) { marshaller.marshal(message, new DefaultHandler()); } String subject = message.primaryDocument.subject; RequestsAndResponses requestsAndResponses = this.requestsAndResponsesMap.get(Method.MULTIPART_MESSAGE); Response response = requestsAndResponses.getResponse(subject); requestsAndResponses.addRequest(new DigipostRequest(message, contentParts)); return response; } @Override public Response identifyAndGetEncryptionKey(Identification identification) { IdentificationResultWithEncryptionKey mockEntity = new IdentificationResultWithEncryptionKey( IdentificationResult.digipost("fake.address#1234"), fakeEncryptionKey); return MockedResponseBuilder.create().status(OK.getStatusCode()).entity(mockEntity).build(); } @Override public Response getEncryptionKeyForPrint() { return MockedResponseBuilder.create().status(OK.getStatusCode()).entity(fakeEncryptionKey).build(); } @Override public Response createMessage(final Message message) { throw new NotImplementedException("This is a mock"); } @Override public Response fetchExistingMessage(final URI location) { throw new NotImplementedException("This is a mock"); } @Override public Response getEncryptionKey(final URI location) { throw new NotImplementedException("This is a mock"); } @Override public Response addContent(final Document document, final InputStream letterContent) { throw new NotImplementedException("This is a mock"); } @Override public Response send(final MessageDelivery createdMessage) { throw new NotImplementedException("This is a mock"); } @Override public Recipients search(final String searchString) { throw new NotImplementedException("This is a mock"); } @Override public Autocomplete searchSuggest(final String searchString) { throw new NotImplementedException("This is a mock"); } @Override public void addFilter(final ClientRequestFilter filter) { throw new NotImplementedException("This is a mock"); } @Override public Response identifyRecipient(final Identification identification) { throw new NotImplementedException("This is a mock"); } @Override public Response getDocumentEvents(final String organisation, final String partId, final DateTime from, final DateTime to, final int offset, final int maxResults) { RequestsAndResponses requestsAndResponses = this.requestsAndResponsesMap.get(Method.GET_DOCUMENTS_EVENTS); Response response = requestsAndResponses.getResponse(); if (response != null) { return response; } else { return MockedResponseBuilder.create().status(OK.getStatusCode()).entity(new DocumentEvents()).build(); } } @Override public Response getContent(String path) { RequestsAndResponses requestsAndResponses = this.requestsAndResponsesMap.get(Method.GET_CONTENT); Response response = requestsAndResponses.getResponse(); if (response != null) { return response; } else { return MockedResponseBuilder.create().status(NOT_FOUND.getStatusCode()).build(); } } public static class RequestMatcher { public Response findResponse(String requestString) { return null; } } public static class RequestsAndResponses { private final Queue<Response> responseQueue = new ConcurrentLinkedQueue<>(); private final RequestMatcher requestMatcher; private final Map<String, MockRequest> requestMap; RequestsAndResponses() { this(new RequestMatcher()); } RequestsAndResponses(RequestMatcher requestMatcher) { this.requestMatcher = requestMatcher; this.requestMap = Collections.synchronizedMap(new LinkedHashMap<String, MockRequest>() { @Override protected boolean removeEldestEntry(Map.Entry<String, MockRequest> eldest) { return size() > 100; } }); } public void addExpectedResponse(Response response) { responseQueue.add(response); } public Response getResponse() { return getResponse("default"); } public Response getResponse(String requestString) { Response response = responseQueue.poll(); if (response != null) { return response; } return requestMatcher.findResponse(requestString); } public void addRequest(MockRequest request) { requestMap.put(request.getKey(), request); } public MockRequest getRequest(String requestKey) { return requestMap.get(requestKey); } public Map<String, MockRequest> getRequests() { return requestMap; } } public static class MockRequest { private final String key; public MockRequest(String key) { this.key = key; } public String getKey() { return key; } } public static class MultipartRequestMatcher extends RequestMatcher { public static Response DEFAULT_RESPONSE = MockedResponseBuilder.create().status(OK.getStatusCode()) .entity(new MessageDelivery(UUID.randomUUID().toString(), DIGIPOST, COMPLETE, DateTime.now())) .build(); public static ProcessingException CONNECTION_REFUSED = new ProcessingException( new ConnectException("Connection refused")); public static final Map<String, Response> responses = new HashMap<>(); public static final Map<String, RuntimeException> errors = new HashMap<>(); static { responses.put("200:OK", DEFAULT_RESPONSE); errors.put("CONNECTION_REFUSED", CONNECTION_REFUSED); } @Override public Response findResponse(String requestString) { if (responses.containsKey(requestString)) { return responses.get(requestString); } else if (errors.containsKey(requestString)) { throw errors.get(requestString); } else if (requestString.matches("^[0-9]{3}:(.)+")) { String[] split = requestString.split(":"); if (ErrorCode.isKnown(split[1])) { ErrorCode errorCode = ErrorCode.resolve(split[1]); ErrorType translated = EnumUtils.getEnum(ErrorType.class, errorCode.getOverriddenErrorType().name()); return MockedResponseBuilder.create().status(parseInt(split[0])) .entity(new ErrorMessage(translated != null ? translated : ErrorType.SERVER, errorCode.name(), "Generic error-message from digipost-api-client-mock")) .build(); } else { throw new IllegalArgumentException("ErrorCode " + split[1] + " is unknown"); } } else { return DEFAULT_RESPONSE; } } } public static class DigipostRequest extends MockRequest { public final Message message; public final List<ContentPart> contentParts; public DigipostRequest(Message message, List<ContentPart> contentParts) { super(message.messageId); this.message = message; this.contentParts = contentParts; } } public static class ContentPart { public final MediaType mediaType; public ContentPart(MediaType mediaType) { this.mediaType = mediaType; } } }