All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.digipost.api.client.ApiServiceMock Maven / Gradle / Ivy

There is a newer version: 6.16.1
Show newest version
/**
 * 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.representations.sender.AuthorialSender;
import no.digipost.api.client.representations.sender.AuthorialSender.Type;
import no.digipost.api.client.representations.sender.SenderInformation;
import no.digipost.api.client.representations.sender.SenderStatus;
import no.digipost.api.client.util.MockfriendlyResponse.MockedResponseBuilder;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
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 java.util.Arrays.asList;
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.MessageStatus.COMPLETE;
import static no.digipost.api.client.representations.sender.SenderFeature.*;

public class ApiServiceMock implements ApiService {

	private final EncryptionKey fakeEncryptionKey;

	public enum Method {
		GET_CONTENT,
		MULTIPART_MESSAGE,
		GET_DOCUMENTS_EVENTS,
		GET_DOCUMENT_STATUS
	}

	final Map requestsAndResponsesMap = new HashMap<>();
	private final ValidatingMarshaller marshaller;
	private final long brokerId;

	public ApiServiceMock(ValidatingMarshaller validatingMarshaller) {
		this(42, validatingMarshaller);
	}
	public ApiServiceMock(long brokerId, ValidatingMarshaller validatingMarshaller) {
		this.marshaller = validatingMarshaller;
		this.fakeEncryptionKey = createFakeEncryptionKey();
		this.brokerId = brokerId;
		init();
	}

	static EncryptionKey createFakeEncryptionKey() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try (Writer osWriter = new OutputStreamWriter(baos); JcaPEMWriter writer = new JcaPEMWriter(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.GET_DOCUMENT_STATUS, 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 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 getDocumentStatus(Link linkToDocumentStatus) {
		return getDocumentStatus(1, "uuid");
	}

	@Override
	public Response getDocumentStatus(long senderId, String uuid) {
		RequestsAndResponses requestsAndResponses = this.requestsAndResponsesMap.get(Method.GET_DOCUMENT_STATUS);
		Response response = requestsAndResponses.getResponse();

		if (response != null) {
			return response;
		} else {
			return MockedResponseBuilder.create().status(OK.getStatusCode()).entity(new DocumentStatus()).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();
		}
	}

	@Override
	public SenderInformation getSenderInformation(long senderId) {
		return new SenderInformation(senderId, SenderStatus.VALID_SENDER, asList(DIGIPOST_DELIVERY, DELIVERY_DIRECT_TO_PRINT, PRINTVALIDATION_FONTS, PRINTVALIDATION_PDFVERSION));
	}

	@Override
	public SenderInformation getSenderInformation(String orgnr, String avsenderenhet) {
		return getSenderInformation(brokerId);
	}

	@Override
	public SenderInformation getSenderInformation(MayHaveSender mayHaveSender) {
		AuthorialSender authorialSender = AuthorialSender.resolve(brokerId, mayHaveSender);
		if (authorialSender.is(Type.ACCOUNT_ID)) {
			return getSenderInformation(authorialSender.getAccountId());
		} else {
			return getSenderInformation(authorialSender.getOrganization().organizationId, authorialSender.getOrganization().partId);
		}
	}


	public static class RequestMatcher {
		public Response findResponse(String requestString) {
			return null;
		}
	}

	public static class RequestsAndResponses {
		private final Queue responseQueue = new ConcurrentLinkedQueue<>();
		private final RequestMatcher requestMatcher;
		private final Map requestMap;

		RequestsAndResponses() {
			this(new RequestMatcher());
		}

		RequestsAndResponses(RequestMatcher requestMatcher) {
			this.requestMatcher = requestMatcher;
			this.requestMap = Collections.synchronizedMap(new LinkedHashMap() {
				@Override
				protected boolean removeEldestEntry(Map.Entry eldest) {
					return size() > 100;
				}
			});
		}

		public void addExpectedResponse(Response response) {
			responseQueue.add(new MockResponse(response));
		}
		public void addExpectedException(RuntimeException ex) {
			responseQueue.add(new MockResponse(ex));
		}

		public Response getResponse() {
			return getResponse("default");
		}

		public Response getResponse(String requestString) {
			ResponseProducer response = responseQueue.poll();
			if (response != null) {
				return response.getResponse();
			}

			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 getRequests() {
			return requestMap;
		}
	}

	public static interface ResponseProducer {
		Response getResponse();
	}
	public static class MockResponse implements ResponseProducer {

		private Response response;
		private RuntimeException exception;

		public MockResponse(Response response) {
			this.response = response;
		}
		public MockResponse(RuntimeException ex) {
			this.exception = ex;
		}

		@Override
		public Response getResponse() {
			if (exception != null) {
				throw exception;
			}
			return response;
		}
	}

	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(), Channel.DIGIPOST, COMPLETE, DateTime.now()))
				.build();
		public static ProcessingException CONNECTION_REFUSED = new ProcessingException(new ConnectException("Connection refused"));

		public static final Map responses = new HashMap<>();
		public static final Map 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 contentParts;

		public DigipostRequest(Message message, List 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;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy