Package fi.jumi.core.ipc.encoding

Source Code of fi.jumi.core.ipc.encoding.EncodingContract

// Copyright © 2011-2014, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package fi.jumi.core.ipc.encoding;

import fi.jumi.actors.eventizers.Event;
import fi.jumi.actors.eventizers.dynamic.DynamicEventizer;
import fi.jumi.actors.queue.MessageSender;
import fi.jumi.core.ipc.TestUtil;
import fi.jumi.core.ipc.buffer.IpcBuffer;
import fi.jumi.core.ipc.channel.*;
import fi.jumi.core.util.*;
import org.junit.Test;

import java.lang.reflect.*;
import java.util.*;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

public abstract class EncodingContract<T> {

    protected final Class<T> interfaceType;
    private final IpcProtocol.EncodingFactory<T> encodingFactory;

    public EncodingContract(IpcProtocol.EncodingFactory<T> encodingFactory) {
        this.interfaceType = getMyTypeArgument(0);
        this.encodingFactory = encodingFactory;
    }

    @SuppressWarnings("unchecked")
    private Class<T> getMyTypeArgument(int index) {
        ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass();
        assertThat(superclass.getRawType(), is((Type) EncodingContract.class));
        return (Class<T>) superclass.getActualTypeArguments()[index];
    }

    @Test
    public void encodes_and_decodes_all_events() throws Exception {
        SpyListener<T> spy = new SpyListener<>(interfaceType);
        exampleUsage(spy.getListener());
        spy.replay();
        IpcBuffer buffer = TestUtil.newIpcBuffer();

        // encode
        IpcProtocol<T> protocol = newIpcProtocol(buffer);
        protocol.start();
        exampleUsage(sendTo(protocol));
        protocol.close();

        // decode
        buffer.position(0);
        IpcReaders.decodeAll(protocol, spy.getListener());

        spy.verify();
    }

    @Test
    public void example_usage_invokes_every_method_in_the_interface() throws Exception {
        MethodInvocationSpy<T> spy = new MethodInvocationSpy<>(new DynamicEventizer<>(interfaceType));

        exampleUsage(spy.getProxy());

        for (Method method : interfaceType.getMethods()) {
            assertThat("invoked methods", spy.methodInvocations.keySet(), hasItem(method));
        }
    }

    protected abstract void exampleUsage(T listener) throws Exception;

    private static final Map<Class<?>, MessageEncoding<?>> encodingsByType = new HashMap<>();

    @Test
    public void the_interface_name_and_version_combination_is_unique() {
        MessageEncoding<T> actual = encodingFactory.create(null);

        for (MessageEncoding<?> other : encodingsByType.values()) {
            if (actual.getInterfaceName().equals(other.getInterfaceName()) &&
                    actual.getInterfaceVersion() == other.getInterfaceVersion()) {
                throw new AssertionError(actual.getClass().getName()
                        + " had the same interface name and version as " + other.getClass().getName()
                        + ": " + actual.getInterfaceName() + " v" + actual.getInterfaceVersion());
            }
        }

        encodingsByType.put(actual.getClass(), actual);
    }

    /**
     * NOTE: It might be desirable for backward compatibility reasons to loosen this restriction in the future, because
     * otherwise we will not be able to rename the Java classes without breaking backward compatibility.
     */
    @Test
    public void the_interface_name_is_in_sync_with_the_actual_Java_interface() throws ClassNotFoundException {
        MessageEncoding<T> encoding = encodingFactory.create(null);

        String interfaceName = encoding.getInterfaceName();

        assertThat(encoding, is(instanceOf(Class.forName(interfaceName))));
    }

    @Test
    public void interface_version_starts_from_1() {
        MessageEncoding<T> encoding = encodingFactory.create(null);

        int interfaceVersion = encoding.getInterfaceVersion();

        assertThat(interfaceVersion, is(greaterThanOrEqualTo(1)));
    }

    private IpcProtocol<T> newIpcProtocol(IpcBuffer buffer) {
        return new IpcProtocol<>(buffer, encodingFactory);
    }

    private T sendTo(MessageSender<Event<T>> target) {
        return new DynamicEventizer<>(interfaceType).newFrontend(target);
    }
}
TOP

Related Classes of fi.jumi.core.ipc.encoding.EncodingContract

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.