uk.org.openeyes.oink.facade.ITFacadeRoute.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.openeyes.oink.facade.ITFacadeRoute.java

Source

/*******************************************************************************
 * OINK - Copyright (c) 2014 OpenEyes Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package uk.org.openeyes.oink.facade;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.camel.CamelContext;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.BasicScheme;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.hl7.fhir.instance.formats.JsonComposer;
import org.hl7.fhir.instance.formats.JsonParser;
import org.hl7.fhir.instance.formats.ParserBase.ResourceOrFeed;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import uk.org.openeyes.oink.domain.FhirBody;
import uk.org.openeyes.oink.domain.OINKRequestMessage;
import uk.org.openeyes.oink.domain.OINKResponseMessage;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.ShutdownSignalException;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:camel-context-test.xml" })
public class ITFacadeRoute {

    private static Properties testProperties;

    private static ConnectionFactory factory;

    private final static String THIRD_PARTY_QUEUE_NAME = "openeyes.in";

    private volatile AssertionError thirdPartyAssertionError;

    @Autowired
    CamelContext camelCtx;

    @BeforeClass
    public static void setUp() throws IOException {
        // Load properties
        testProperties = new Properties();
        InputStream is = ITFacadeRoute.class.getResourceAsStream("/facade-test.properties");
        testProperties.load(is);

        // Prepare RabbitMQ Client
        factory = new ConnectionFactory();
        factory.setHost(testProperties.getProperty("rabbit.host"));
        factory.setPort(Integer.parseInt(testProperties.getProperty("rabbit.port")));
        factory.setUsername(testProperties.getProperty("rabbit.username"));
        factory.setPassword(testProperties.getProperty("rabbit.password"));
        factory.setVirtualHost(testProperties.getProperty("rabbit.vhost"));

    }

    @Before
    public void before() {
        thirdPartyAssertionError = null;
    }

    @Test
    @DirtiesContext
    public void testSimplePatientPost() throws Exception {

        /*
         * Set up Third Party Service
         */

        // Specify what the third party service should receive
        IncomingMessageVerifier v = new IncomingMessageVerifier() {
            @Override
            public void isValid(OINKRequestMessage incoming) {
                Assert.assertEquals(uk.org.openeyes.oink.domain.HttpMethod.POST, incoming.getMethod());
                Assert.assertEquals("/Patient", incoming.getResourcePath());

                try {
                    // FHIR Resource Impl Team haven't implemented equals() yet
                    JsonComposer composer = new JsonComposer();
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    composer.compose(os, incoming.getBody().getResource(), false);
                    String receivedJson = os.toString();
                    String expectedJson = IOUtils
                            .toString(this.getClass().getResourceAsStream("/example-messages/fhir/patient.json"));
                    Assert.assertEquals(expectedJson, receivedJson);
                } catch (Exception e) {
                    Assert.assertTrue(false);
                }

            }
        };

        // Specify what the third party service should return
        OINKResponseMessage mockResponse = new OINKResponseMessage();
        mockResponse.setStatus(201);
        mockResponse.setBody(null);

        // Start the third party service
        SimulatedThirdParty thirdp = new SimulatedThirdParty(v, mockResponse);
        thirdp.start();

        /*
         * Make REST request
         */

        // Prepare request
        HttpClient client = new HttpClient();

        PostMethod method = new PostMethod(testProperties.getProperty("facade.uri") + "/Patient");

        method.addRequestHeader("Content-Type", "application/json+fhir");

        InputStream is = this.getClass().getResourceAsStream("/example-messages/fhir/patient.json");
        method.setRequestEntity(new InputStreamRequestEntity(is));
        client.executeMethod(method);
        thirdp.close();

        /*
         * Process REST response
         */
        byte[] responseBody = method.getResponseBody();
        String s = method.getResponseBodyAsString();
        int responseCode = method.getStatusCode();
        method.releaseConnection();

        if (thirdPartyAssertionError != null) {
            throw thirdPartyAssertionError;
        }

        Assert.assertEquals(HttpStatus.SC_CREATED, responseCode);
        Assert.assertNull(method.getResponseHeader("Content-Type"));
        Assert.assertArrayEquals(responseBody, new byte[] {});

    }

    @Test
    @DirtiesContext
    public void testSimplePatientGet() throws Exception {

        /*
         * Set up Third Party Service
         */

        // Specify what the third party service should receive
        IncomingMessageVerifier v = new IncomingMessageVerifier() {
            @Override
            public void isValid(OINKRequestMessage incoming) {
                Assert.assertEquals(uk.org.openeyes.oink.domain.HttpMethod.GET, incoming.getMethod());
                Assert.assertEquals("/Patient/2342452", incoming.getResourcePath());
                Assert.assertNull(incoming.getBody());
            }
        };

        // Specify what the third party service should return
        OINKResponseMessage mockResponse = new OINKResponseMessage();
        mockResponse.setStatus(200);
        mockResponse.setBody(buildFhirBodyFromResource("/example-messages/fhir/patient.json"));

        // Start the third party service
        SimulatedThirdParty thirdp = new SimulatedThirdParty(v, mockResponse);
        thirdp.start();

        /*
         * Make REST request
         */

        // Prepare request
        HttpClient client = new HttpClient();

        HttpMethod method = new GetMethod(testProperties.getProperty("facade.uri") + "/Patient/2342452");

        client.executeMethod(method);
        thirdp.close();

        /*
         * Process REST response
         */
        byte[] responseBody = method.getResponseBody();
        String responseJson = new String(responseBody);
        int responseCode = method.getStatusCode();
        String responseContentType = method.getResponseHeader("Content-Type").getValue();
        method.releaseConnection();

        if (thirdPartyAssertionError != null) {
            throw thirdPartyAssertionError;
        }

        Assert.assertEquals(HttpStatus.SC_OK, responseCode);
        Assert.assertEquals("application/json+fhir", responseContentType);
        Assert.assertEquals(IOUtils.toString(
                this.getClass().getResourceAsStream("/example-messages/fhir/patient.json"), "UTF-8"), responseJson);
    }

    private static FhirBody buildFhirBodyFromResource(String resourcePath) throws Exception {
        InputStream is = ITFacadeRoute.class.getResourceAsStream(resourcePath);
        FhirBody body = null;
        JsonParser parser = new JsonParser();
        ResourceOrFeed res = parser.parseGeneral(is);
        if (res.getFeed() != null) {
            body = new FhirBody(res.getFeed());
        } else if (res.getResource() != null) {
            body = new FhirBody(res.getResource());
        }
        return body;
    }

    private interface IncomingMessageVerifier {
        public void isValid(OINKRequestMessage incoming);
    }

    private class SimulatedThirdParty extends Thread {

        private IncomingMessageVerifier verifier;
        private OINKResponseMessage messageToReplyWith;

        public SimulatedThirdParty(IncomingMessageVerifier verifier, OINKResponseMessage messageToReplyWith) {
            super();
            this.verifier = verifier;
            this.messageToReplyWith = messageToReplyWith;
        }

        boolean isRunning = true;

        @Override
        public void run() {
            try {
                simulateThirdParty();
            } catch (AssertionError e) {
                thirdPartyAssertionError = e;
            } catch (ShutdownSignalException e) {
            } catch (ConsumerCancelledException e) {
            } catch (IOException e) {
            } catch (InterruptedException e) {
            }
        }

        public void close() {
            isRunning = false;
        }

        public void simulateThirdParty()
                throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {
            // Build consumer
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            channel.queueDeclare(THIRD_PARTY_QUEUE_NAME, false, false, true, null);
            channel.queueBind(THIRD_PARTY_QUEUE_NAME, testProperties.getProperty("rabbit.defaultExchange"),
                    THIRD_PARTY_QUEUE_NAME);
            QueueingConsumer consumer = new QueueingConsumer(channel);
            channel.basicConsume(THIRD_PARTY_QUEUE_NAME, true, consumer);

            while (isRunning) {
                // Get delivery (timeout if necessary)
                QueueingConsumer.Delivery delivery = consumer.nextDelivery(5000);
                if (delivery != null) {
                    isRunning = false;
                } else {
                    continue;
                }

                BasicProperties props = delivery.getProperties();

                // Extract request message
                OINKRequestMessage message = camelCtx.getTypeConverter().convertTo(OINKRequestMessage.class,
                        delivery.getBody());

                // Check is valid
                verifier.isValid(message);

                // Prepare an empty response
                com.rabbitmq.client.AMQP.BasicProperties replyProps = new AMQP.BasicProperties.Builder()
                        .correlationId(props.getCorrelationId()).build();

                byte[] responseBody = camelCtx.getTypeConverter().convertTo(byte[].class, messageToReplyWith);

                channel.basicPublish(testProperties.getProperty("rabbit.defaultExchange"), props.getReplyTo(),
                        replyProps, responseBody);
            }
            connection.close();
        }

    }

}