com.kixeye.chassis.transport.HybridServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for com.kixeye.chassis.transport.HybridServiceTest.java

Source

package com.kixeye.chassis.transport;

/*
 * #%L
 * Chassis Transport Core
 * %%
 * Copyright (C) 2014 KIXEYE, Inc
 * %%
 * 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.
 * #L%
 */

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.io.HexDump;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.kixeye.chassis.transport.dto.Envelope;
import com.kixeye.chassis.transport.http.SerDeHttpMessageConverter;
import com.kixeye.chassis.transport.serde.MessageSerDe;
import com.kixeye.chassis.transport.serde.converter.ProtobufMessageSerDe;
import com.kixeye.chassis.transport.utils.SocketUtils;
import com.kixeye.chassis.transport.websocket.ActionMapping;
import com.kixeye.chassis.transport.websocket.ActionPayload;
import com.kixeye.chassis.transport.websocket.QueuingWebSocketListener;
import com.kixeye.chassis.transport.websocket.WebSocketController;
import com.kixeye.chassis.transport.websocket.WebSocketMessageRegistry;

/**
 * Tests the Hybrid service support.
 * 
 * @author ebahtijaragic
 */
public class HybridServiceTest {
    private static final Logger logger = LoggerFactory.getLogger(HybridServiceTest.class);

    public static final ClientHttpRequestInterceptor LOGGING_INTERCEPTOR = new ClientHttpRequestInterceptor() {
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
                throws IOException {
            if (body.length > 0) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                HexDump.dump(body, 0, baos, 0);

                logger.info("Sending to [{}]: \n{}", request.getURI(), baos.toString(Charsets.UTF_8.name()).trim());
            } else {
                logger.info("Sending empty body to [{}]!", request.getURI());
            }

            return execution.execute(request, body);
        }
    };

    @Test
    public void testHybridService() throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("websocket.enabled", "true");
        properties.put("websocket.port", "" + SocketUtils.findAvailableTcpPort());
        properties.put("websocket.hostname", "localhost");

        properties.put("http.enabled", "true");
        properties.put("http.port", "" + SocketUtils.findAvailableTcpPort());
        properties.put("http.hostname", "localhost");

        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        StandardEnvironment environment = new StandardEnvironment();
        environment.getPropertySources().addFirst(new MapPropertySource("default", properties));
        context.setEnvironment(environment);
        context.register(PropertySourcesPlaceholderConfigurer.class);
        context.register(TransportConfiguration.class);
        context.register(TestCombinedService.class);

        WebSocketClient wsClient = new WebSocketClient();

        RestTemplate httpClient = new RestTemplate();

        try {
            context.refresh();

            final MessageSerDe serDe = context.getBean(ProtobufMessageSerDe.class);

            final WebSocketMessageRegistry messageRegistry = context.getBean(WebSocketMessageRegistry.class);

            messageRegistry.registerType("stuff", TestObject.class);

            wsClient.start();

            httpClient.setInterceptors(Lists.newArrayList(LOGGING_INTERCEPTOR));
            List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
            for (MessageSerDe messageSerDe : context.getBeansOfType(MessageSerDe.class).values()) {
                messageConverters.add(new SerDeHttpMessageConverter(messageSerDe));
            }
            messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
            httpClient.setMessageConverters(messageConverters);

            QueuingWebSocketListener webSocket = new QueuingWebSocketListener(serDe, messageRegistry, null);

            Session session = wsClient
                    .connect(webSocket, new URI("ws://localhost:" + properties.get("websocket.port") + "/protobuf"))
                    .get(5000, TimeUnit.MILLISECONDS);

            Envelope envelope = new Envelope("getStuff", null, null, null);

            session.getRemote().sendBytes(ByteBuffer.wrap(serDe.serialize(envelope)));

            TestObject response = webSocket.getResponse(5, TimeUnit.SECONDS);

            Assert.assertNotNull(response);
            Assert.assertEquals("stuff", response.value);

            byte[] rawStuff = serDe.serialize(new TestObject("more stuff"));

            envelope = new Envelope("setStuff", "stuff", null, ByteBuffer.wrap(rawStuff));

            session.getRemote().sendBytes(ByteBuffer.wrap(serDe.serialize(envelope)));

            response = webSocket.getResponse(5, TimeUnit.SECONDS);

            Assert.assertNotNull(response);
            Assert.assertEquals("stuff", response.value);

            envelope = new Envelope("getStuff", null, null, null);

            session.getRemote().sendBytes(ByteBuffer.wrap(serDe.serialize(envelope)));

            response = webSocket.getResponse(5, TimeUnit.SECONDS);

            Assert.assertNotNull(response);
            Assert.assertEquals("more stuff", response.value);

            response = httpClient.getForObject(
                    new URI("http://localhost:" + properties.get("http.port") + "/stuff/"), TestObject.class);

            Assert.assertNotNull(response);
            Assert.assertEquals("more stuff", response.value);

            response = httpClient.postForObject(
                    new URI("http://localhost:" + properties.get("http.port") + "/stuff/"),
                    new TestObject("even more stuff"), TestObject.class);

            Assert.assertNotNull(response);
            Assert.assertEquals("more stuff", response.value);

            response = httpClient.getForObject(
                    new URI("http://localhost:" + properties.get("http.port") + "/stuff/"), TestObject.class);

            Assert.assertNotNull(response);
            Assert.assertEquals("even more stuff", response.value);
        } finally {
            try {
                wsClient.stop();
            } finally {
                context.close();
            }
        }
    }

    @RestController
    @WebSocketController
    @RequestMapping("/stuff")
    public static class TestCombinedService {
        public final AtomicReference<TestObject> stuff = new AtomicReference<>(new TestObject("stuff"));

        @ActionMapping("getStuff")
        @RequestMapping(method = { RequestMethod.GET }, value = "/")
        public DeferredResult<TestObject> getStuff() {
            DeferredResult<TestObject> result = new DeferredResult<TestObject>();
            result.setResult(stuff.get());

            return result;
        }

        @ActionMapping("setStuff")
        @RequestMapping(method = { RequestMethod.POST }, value = "/")
        public DeferredResult<TestObject> setStuff(@RequestBody @ActionPayload TestObject request) {
            DeferredResult<TestObject> result = new DeferredResult<TestObject>();
            result.setResult(stuff.get());

            stuff.set(request);

            return result;
        }
    }

    public static class TestObject {
        public String value = null;

        public TestObject(String value) {
            this.value = value;
        }

        public TestObject() {

        }
    }
}