org.openhim.mediator.e2e.E2EBase.java Source code

Java tutorial

Introduction

Here is the source code for org.openhim.mediator.e2e.E2EBase.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.openhim.mediator.e2e;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.openhim.mediator.denormalization.ATNAAuditingActor;
import org.openhim.mediator.denormalization.EnrichRegistryStoredQueryActor;
import org.openhim.mediator.engine.MediatorConfig;
import org.openhim.mediator.engine.MediatorServer;
import org.openhim.mediator.engine.RoutingTable;
import org.openhim.mediator.engine.StartupActorsConfig;
import org.openhim.mediator.engine.connectors.MLLPConnector;
import org.openhim.mediator.normalization.ParseRegistryStoredQueryActor;
import org.openhim.mediator.orchestration.RegistryActor;
import org.openhim.mediator.orchestration.RepositoryActor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

import static org.junit.Assert.*;

/**
 */
public class E2EBase {
    protected static abstract class MockPIXServer extends Thread {
        ServerSocket socket;
        int called = 0;

        public MockPIXServer(int port) {
            try {
                socket = new ServerSocket(port);
            } catch (IOException e) {
                e.printStackTrace();
                fail();
            }
        }

        public void kill() {
            IOUtils.closeQuietly(socket);
        }

        abstract String getResponse();

        abstract void onReceive(String receivedMessage);

        public void verifyCalled() {
            assertTrue(called > 0);
        }

        public void verifyCalled(int numTimesCalled) {
            assertTrue(called == numTimesCalled);
        }

        @Override
        public void run() {
            try {
                called = 0;
                do {
                    final Socket conn = socket.accept();

                    (new Thread() {
                        @Override
                        public void run() {
                            try {
                                ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024 * 1024);
                                InputStream in = conn.getInputStream();
                                int lastByte = -1;
                                int lastLastByte;
                                do {
                                    lastLastByte = lastByte;
                                    lastByte = in.read();
                                    if (lastByte != -1) {
                                        buffer.write(lastByte);
                                    }
                                } while (lastByte != -1 && lastLastByte != MLLPConnector.MLLP_FOOTER_FS
                                        && lastByte != MLLPConnector.MLLP_FOOTER_CR);

                                String receivedMessage = buffer.toString();
                                onReceive(receivedMessage);

                                conn.getOutputStream().write(MLLPConnector.wrapMLLP(getResponse()).getBytes());

                            } catch (IOException e) {
                                System.out.println("Warning: " + e.getMessage());
                            }
                        }
                    }).start();

                    called++;
                } while (!socket.isClosed());
            } catch (IOException e) {
                System.out.println("Warning: " + e.getMessage());
            }
        }
    }

    protected static class MockATNAServer extends Thread {
        ServerSocket socket;
        List<String> calledFor = Collections.synchronizedList(new LinkedList<String>());
        Integer activeConnections = 0;

        public MockATNAServer(int port) {
            try {
                socket = new ServerSocket(port);
            } catch (IOException e) {
                e.printStackTrace();
                fail();
            }
        }

        public void kill() {
            IOUtils.closeQuietly(socket);
        }

        public void verifyCalled() {
            waitOnActiveConnections(null);
            assertTrue(calledFor.size() > 0);
        }

        public void verifyCalled(int numTimesCalled) {
            waitOnActiveConnections(numTimesCalled);
            assertTrue(calledFor.size() == numTimesCalled);
        }

        public void verifyCalledFor(String eventType) {
            waitOnActiveConnections(null);
            for (String ev : calledFor) {
                if (ev.equals(eventType)) {
                    return;
                }
            }
            fail("ATNA audit should be sent for event " + eventType);
        }

        //atna runs asynchronously and will likely be only complete after a request finishes, so we need to wait
        private void waitOnActiveConnections(Integer expectedNumCalls) {
            int tries = 0;
            while ((activeConnections > 0 //are there active connections?
                    || (expectedNumCalls != null && calledFor.size() < expectedNumCalls)) //or maybe they haven't had a chance to run yet?
                    && tries < 600) //but don't wait for more than 60 seconds (600*100ms)
            {
                try {
                    Thread.sleep(100);

                    tries++;
                } catch (InterruptedException e) {
                }
            }
        }

        private void alive() {
            synchronized (activeConnections) {
                activeConnections++;
            }
        }

        private void dead() {
            synchronized (activeConnections) {
                activeConnections--;
            }
        }

        @Override
        public void run() {
            try {
                calledFor.clear();
                do {
                    final Socket conn = socket.accept();

                    (new Thread() {
                        @Override
                        public void run() {
                            try {
                                alive();
                                String message = IOUtils.toString(conn.getInputStream());

                                int startI = message.indexOf("EventTypeCode code=\"");
                                if (startI == -1) {
                                    fail("Unparseable ATNA audit received");
                                    return;
                                }

                                message = message.substring(startI + "EventTypeCode code=\"".length());
                                int endI = message.indexOf("\"");
                                if (endI == -1) {
                                    fail("Unparseable ATNA audit received");
                                    return;
                                }

                                message = message.substring(0, endI);
                                calledFor.add(message);
                            } catch (IOException e) {
                                System.out.println("Warning: " + e.getMessage());
                            } finally {
                                dead();
                            }
                        }
                    }).start();
                } while (!socket.isClosed());
            } catch (IOException e) {
                System.out.println("Warning: " + e.getMessage());
            }
        }
    }

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(8520);

    protected MediatorConfig testConfig;
    protected MediatorServer server;
    protected MockATNAServer atnaServer;

    private void loadTestConfig() throws RoutingTable.RouteAlreadyMappedException, IOException {
        testConfig = new MediatorConfig();
        testConfig.setProperties("mediator-e2e-test.properties");

        testConfig.setName("mediator-server-tests");
        testConfig.setServerHost("localhost");
        testConfig.setServerPort(8432);

        testConfig.setName(testConfig.getProperty("mediator.name"));
        testConfig.setServerHost(testConfig.getProperty("mediator.host"));
        testConfig.setServerPort(Integer.parseInt(testConfig.getProperty("mediator.port")));
        testConfig.setRootTimeout(Integer.parseInt(testConfig.getProperty("mediator.timeout")));

        testConfig.setCoreHost(testConfig.getProperty("core.host"));
        testConfig.setCoreAPIUsername(testConfig.getProperty("core.api.user"));
        testConfig.setCoreAPIPassword(testConfig.getProperty("core.api.password"));
        testConfig.setCoreAPIPort(Integer.parseInt(testConfig.getProperty("core.api.port")));

        RoutingTable routingTable = new RoutingTable();
        routingTable.addRoute("/xdsregistry", RegistryActor.class);
        routingTable.addRoute("/xdsrepository", RepositoryActor.class);
        testConfig.setRoutingTable(routingTable);

        StartupActorsConfig startupActors = new StartupActorsConfig();
        startupActors.addActor("parse-registry-stored-query", ParseRegistryStoredQueryActor.class);
        startupActors.addActor("enrich-registry-stored-query", EnrichRegistryStoredQueryActor.class);
        startupActors.addActor("atna-auditing", ATNAAuditingActor.class);
        testConfig.setStartupActors(startupActors);
    }

    @Before
    public void before() throws RoutingTable.RouteAlreadyMappedException, IOException {
        loadTestConfig();
        atnaServer = new MockATNAServer(Integer.parseInt(testConfig.getProperty("atna.tcpPort")));
        atnaServer.start();
        server = new MediatorServer(testConfig);
        server.start(false);
    }

    @After
    public void after() {
        atnaServer.kill();
        server.stop();
    }

    private HttpUriRequest buildUriRequest(String method, String body, URI uri)
            throws UnsupportedEncodingException {
        HttpUriRequest uriReq;

        switch (method) {
        case "GET":
            uriReq = new HttpGet(uri);
            break;
        case "POST":
            uriReq = new HttpPost(uri);
            StringEntity entity = new StringEntity(body);
            if (body.length() > 1024) {
                //always test big requests chunked
                entity.setChunked(true);
            }
            ((HttpPost) uriReq).setEntity(entity);
            break;
        case "PUT":
            uriReq = new HttpPut(uri);
            StringEntity putEntity = new StringEntity(body);
            ((HttpPut) uriReq).setEntity(putEntity);
            break;
        case "DELETE":
            uriReq = new HttpDelete(uri);
            break;
        default:
            throw new UnsupportedOperationException(method + " requests not supported");
        }

        return uriReq;
    }

    protected E2EHTTPResponse executeHTTPRequest(String method, String path, String body,
            Map<String, String> headers, Map<String, String> params) throws URISyntaxException, IOException {
        URIBuilder builder = new URIBuilder().setScheme("http").setHost(testConfig.getServerHost())
                .setPort(testConfig.getServerPort()).setPath(path);

        if (params != null) {
            Iterator<String> iter = params.keySet().iterator();
            while (iter.hasNext()) {
                String param = iter.next();
                builder.addParameter(param, params.get(param));
            }
        }

        HttpUriRequest uriReq = buildUriRequest(method, body, builder.build());

        if (headers != null) {
            Iterator<String> iter = headers.keySet().iterator();
            while (iter.hasNext()) {
                String header = iter.next();
                uriReq.addHeader(header, headers.get(header));
            }
        }

        RequestConfig.Builder reqConf = RequestConfig.custom().setConnectTimeout(1000)
                .setConnectionRequestTimeout(1000);
        CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(reqConf.build()).build();

        CloseableHttpResponse response = client.execute(uriReq);
        E2EHTTPResponse finalResponse = new E2EHTTPResponse();

        if (response.getEntity() != null && response.getEntity().getContent() != null) {
            finalResponse.body = IOUtils.toString(response.getEntity().getContent());
        }

        finalResponse.status = response.getStatusLine().getStatusCode();

        for (Header hdr : response.getAllHeaders()) {
            finalResponse.headers.put(hdr.getName(), hdr.getValue());
        }

        IOUtils.closeQuietly(response);
        return finalResponse;
    }

    public static class E2EHTTPResponse {
        Integer status;
        String body;
        Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    }
}