com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtilTest.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtilTest.java

Source

/* ./liferay-liferay-portal-b66e4b4/portal-impl/test/unit/com/liferay/portal/nio/intraband/proxy/IntrabandProxyUtilTest.java */
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library 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 Lesser General Public License for more
 * details.
 */

package com.liferay.portal.nio.intraband.proxy;

import com.liferay.portal.asm.ASMUtil;
import com.liferay.portal.asm.MethodNodeGenerator;
import com.liferay.portal.kernel.io.Deserializer;
import com.liferay.portal.kernel.io.Serializer;
import com.liferay.portal.kernel.log.Jdk14LogImpl;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.log.LogWrapper;
import com.liferay.portal.kernel.nio.intraband.Datagram;
import com.liferay.portal.kernel.nio.intraband.Intraband;
import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
import com.liferay.portal.kernel.nio.intraband.SystemDataType;
import com.liferay.portal.kernel.nio.intraband.proxy.ExceptionHandler;
import com.liferay.portal.kernel.nio.intraband.proxy.IntrabandProxySkeleton;
import com.liferay.portal.kernel.nio.intraband.proxy.TargetLocator;
import com.liferay.portal.kernel.nio.intraband.proxy.annotation.Id;
import com.liferay.portal.kernel.nio.intraband.proxy.annotation.Proxy;
import com.liferay.portal.kernel.nio.intraband.rpc.RPCResponse;
import com.liferay.portal.kernel.nio.intraband.test.MockIntraband;
import com.liferay.portal.kernel.nio.intraband.test.MockRegistrationReference;
import com.liferay.portal.kernel.test.CaptureHandler;
import com.liferay.portal.kernel.test.JDKLoggerTestUtil;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.rule.NewEnv;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.MethodHandler;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.TextFormatter;
import com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtil.MethodComparator;
import com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtil.MethodsBag;
import com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtil.TemplateSkeleton;
import com.liferay.portal.nio.intraband.proxy.IntrabandProxyUtil.TemplateStub;
import com.liferay.portal.test.aspects.ReflectionUtilAdvice;
import com.liferay.portal.test.rule.AdviseWith;
import com.liferay.portal.test.rule.AspectJNewEnvTestRule;
import com.liferay.portal.util.FileImpl;
import com.liferay.portal.util.PropsValues;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.net.URL;
import java.net.URLClassLoader;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;

/**
 * @author Shuyang Zhou
 */
public class IntrabandProxyUtilTest {

    @ClassRule
    @Rule
    public static final AggregateTestRule aggregateTestRule = new AggregateTestRule(CodeCoverageAssertor.INSTANCE,
            AspectJNewEnvTestRule.INSTANCE);

    @Before
    public void setUp() {
        FileUtil fileUtil = new FileUtil();

        fileUtil.setFile(new FileImpl());
    }

    @Test
    public void testCheckField() {
        class TestClass {

            @SuppressWarnings("unused")
            private String _testField;
        }

        Field[] fields = TestClass.class.getDeclaredFields();

        IntrabandProxyUtil.checkField(fields, "noSuchField", String.class, true);

        IntrabandProxyUtil.checkField(fields, "_testField", String.class, false);

        try {
            IntrabandProxyUtil.checkField(fields, "_testField", Object.class, false);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(
                    "Field " + fields[0] + " is expected to be of type " + Object.class + " and not static",
                    iae.getMessage());
        }

        try {
            IntrabandProxyUtil.checkField(fields, "_testField", String.class, true);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals("Field " + fields[0] + " is expected to be of type " + String.class + " and static",
                    iae.getMessage());
        }
    }

    @Test
    public void testConstructor() {
        new IntrabandProxyUtil();
    }

    @Test
    public void testCreateProxyMethodNode() {
        List<Method> methods = new ArrayList<Method>(
                Arrays.asList(TestProxyMethodsInterface.class.getDeclaredMethods()));

        methods.addAll(Arrays.asList(TestProxyMethodsClass.class.getDeclaredMethods()));

        for (int i = 0; i < methods.size(); i++) {
            _doTestCreateProxyMethodNode(methods.get(i), i, "skeletonId", "TestClassStub");
        }
    }

    @Test
    public void testDeserializerRead() {
        MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "name", "()V", null, null);

        MethodNodeGenerator methodNodeGenerator = new MethodNodeGenerator(methodNode);

        InsnList insnList = methodNode.instructions;

        for (Type type : _types) {
            IntrabandProxyUtil.deserializerRead(methodNodeGenerator, type);

            AbstractInsnNode abstractInsnNode = insnList.getLast();

            String methodName = "readObject";

            Type returnType = Type.getType(Serializable.class);

            if (type.getSort() <= Type.DOUBLE) {
                String name = TextFormatter.format(type.getClassName(), TextFormatter.G);

                methodName = "read".concat(name);
                returnType = type;
            } else if (type.equals(Type.getType(String.class))) {
                methodName = "readString";
                returnType = Type.getType(String.class);

                _assertMethodInsnNode(abstractInsnNode, Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName(Deserializer.class), "readString", Type.getType(String.class));
            }

            _assertMethodInsnNode(abstractInsnNode, Opcodes.INVOKEVIRTUAL, Type.getInternalName(Deserializer.class),
                    methodName, returnType);
        }
    }

    @Test
    public void testExtractMethods() throws Exception {
        try {
            IntrabandProxyUtil.extractMethods(TestExtractMethodsClass1.class);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals("The @Id annotated method " + TestExtractMethodsClass1.class.getMethod("getId")
                    + " must not be static", iae.getMessage());
        }

        try {
            IntrabandProxyUtil.extractMethods(TestExtractMethodsClass2.class);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals("The @Id annotated method "
                    + TestExtractMethodsClass2.class.getMethod("getId", Object.class) + " must not have parameters",
                    iae.getMessage());
        }

        try {
            IntrabandProxyUtil.extractMethods(TestExtractMethodsClass3.class);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals("The @Id annotated method " + TestExtractMethodsClass3.class.getMethod("getId")
                    + " must not return String", iae.getMessage());
        }

        try {
            IntrabandProxyUtil.extractMethods(TestExtractMethodsClass4.class);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(
                    "Static proxy method violation for " + TestExtractMethodsClass4.class.getMethod("doStuff"),
                    iae.getMessage());
        }

        MethodsBag methodsBag = IntrabandProxyUtil.extractMethods(TestExtractMethodsClass5.class);

        List<Method> idMethods = methodsBag.idMethods;

        Assert.assertEquals(2, idMethods.size());
        Assert.assertTrue(idMethods.contains(TestExtractMethodsClass5.class.getMethod("getId1")));
        Assert.assertTrue(idMethods.contains(TestExtractMethodsClass5.class.getMethod("getId2")));

        List<Method> proxyMethods = methodsBag.proxyMethods;

        Assert.assertEquals(2, proxyMethods.size());
        Assert.assertEquals(TestExtractMethodsClass5.class.getMethod("doStuff1"), proxyMethods.get(0));
        Assert.assertEquals(TestExtractMethodsClass5.class.getMethod("doStuff2"), proxyMethods.get(1));

        List<Method> emptyMethods = methodsBag.emptyMethods;

        Assert.assertEquals(1, emptyMethods.size());
        Assert.assertEquals(TestExtractMethodsClass5.class.getMethod("doStuff4"), emptyMethods.get(0));

        String[] proxyMethodSignatures = methodsBag.proxyMethodSignatures;

        Assert.assertEquals(2, proxyMethodSignatures.length);
        Assert.assertEquals("doStuff1-()V", proxyMethodSignatures[0]);
        Assert.assertEquals("doStuff2-()V", proxyMethodSignatures[1]);
    }

    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testGenerateSkeletonClassFunction() throws Exception {
        _doTestGenerateSkeletonClassFunction(TestGenerateInterface1.class);
        _doTestGenerateSkeletonClassFunction(TestGenerateInterface2.class);
    }

    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testGenerateSkeletonClassStructure() throws Exception {
        _doTestGenerateSkeletonClassStructure(TestGenerateInterface1.class);
        _doTestGenerateSkeletonClassStructure(TestGenerateInterface2.class);
        _doTestGenerateSkeletonClassStructure(TestGenerateClass1.class);
        _doTestGenerateSkeletonClassStructure(TestGenerateClass2.class);
    }

    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testGenerateStubClassFunction() throws Exception {

        // <clinit> and <init> appending

        String skeletonId = "skeletonId";

        Class<?> stubClass = IntrabandProxyUtil.generateStubClass(_classLoader, TestGenerateStubFunction1.class,
                skeletonId);

        Constructor<?> constructor = stubClass.getConstructor(String.class, RegistrationReference.class,
                ExceptionHandler.class);

        String testId = "testId";

        AutoReplyMockIntraband autoReplyMockIntraband = new AutoReplyMockIntraband(skeletonId, testId);

        RegistrationReference registrationReference = new MockRegistrationReference(autoReplyMockIntraband);

        Object stubObject = null;

        try (CaptureHandler captureHandler = JDKLoggerTestUtil.configureJDKLogger(stubClass.getName(),
                Level.INFO)) {

            List<LogRecord> logRecords = captureHandler.getLogRecords();

            stubObject = constructor.newInstance(testId, registrationReference, WarnLogExceptionHandler.INSTANCE);

            Assert.assertEquals(2, logRecords.size());

            LogRecord logRecord = logRecords.get(0);

            Assert.assertEquals(stubClass.getName() + " in <clinit>", logRecord.getMessage());

            logRecord = logRecords.get(1);

            Assert.assertEquals(stubClass.getName() + " in <init>", logRecord.getMessage());
        }

        Assert.assertSame(registrationReference,
                ReflectionTestUtil.getFieldValue(stubObject, "_registrationReference"));
        Assert.assertSame(WarnLogExceptionHandler.INSTANCE,
                ReflectionTestUtil.getFieldValue(stubObject, "_exceptionHandler"));
        Assert.assertSame(autoReplyMockIntraband, ReflectionTestUtil.getFieldValue(stubObject, "_intraband"));

        // Id methods

        stubClass = IntrabandProxyUtil.generateStubClass(_classLoader, TestGenerateStubFunction2.class, skeletonId);

        constructor = stubClass.getConstructor(String.class, RegistrationReference.class, ExceptionHandler.class);

        stubObject = constructor.newInstance(testId, registrationReference, WarnLogExceptionHandler.INSTANCE);

        for (Method idMethod : _getIdMethods(TestGenerateStubFunction2.class)) {
            Assert.assertEquals(testId, ReflectionTestUtil.invoke(stubObject, idMethod.getName(), new Class<?>[0]));
        }

        // Proxy methods

        List<Method> proxyMethods = _getProxyMethods(TestGenerateStubFunction2.class);

        for (int i = 0; i < proxyMethods.size(); i++) {
            Method proxyMethod = proxyMethods.get(i);

            Class<?>[] parameterTypes = proxyMethod.getParameterTypes();

            Object[] args = new Object[parameterTypes.length];

            for (int j = 0; j < args.length; j++) {
                args[j] = _sampleValueMap.get(parameterTypes[j]);
            }

            autoReplyMockIntraband.setInvocation(proxyMethod, i);

            Object object = ReflectionTestUtil.invoke(stubObject, proxyMethod.getName(),
                    proxyMethod.getParameterTypes(), args);

            Assert.assertEquals(_sampleValueMap.get(proxyMethod.getReturnType()), object);
        }

        // Empty methods

        for (Method emptyMethod : _getEmptyMethods(TestGenerateStubFunction2.class)) {

            Assert.assertEquals(_defaultValueMap.get(emptyMethod.getReturnType()),
                    ReflectionTestUtil.invoke(stubObject, emptyMethod.getName(), new Class<?>[0]));
        }

        // Copied methods

        List<Method> copiedMethods = _getCopiedMethods(TestGenerateStubFunction2.class);

        Collections.sort(copiedMethods, new Comparator<Method>() {

            @Override
            public int compare(Method method1, Method method2) {
                String name1 = method1.getName();
                String name2 = method2.getName();

                return name1.compareTo(name2);
            }

        });

        try (CaptureHandler captureHandler = JDKLoggerTestUtil.configureJDKLogger(stubClass.getName(),
                Level.INFO)) {

            List<LogRecord> logRecords = captureHandler.getLogRecords();

            for (Method copiedMethod : copiedMethods) {
                ReflectionTestUtil.invoke(stubObject, copiedMethod.getName(), new Class<?>[0]);

                LogRecord logRecord = logRecords.get(logRecords.size() - 1);

                Assert.assertEquals(copiedMethod.getName(), logRecord.getMessage());
            }
        }
    }

    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testGenerateStubClassStructure() throws Exception {
        _doTestGenerateStubClassStructure(TestGenerateInterface1.class, "skeletonId");
        _doTestGenerateStubClassStructure(TestGenerateInterface2.class, "skeletonId");
        _doTestGenerateStubClassStructure(TestGenerateClass1.class, "skeletonId");
        _doTestGenerateStubClassStructure(TestGenerateClass2.class, "skeletonId");
    }

    @Test
    public void testGetClass() throws Exception {

        // getSkeletonClass()

        class TestClass {
        }

        ClassLoader classLoader = TestClass.class.getClassLoader();

        _doTestGetClass(classLoader, new MethodHandler(
                IntrabandProxyUtil.class.getDeclaredMethod("getSkeletonClass", ClassLoader.class, Class.class),
                classLoader, TestClass.class));

        // getStubClass()

        _doTestGetClass(classLoader,
                new MethodHandler(IntrabandProxyUtil.class.getMethod("getStubClass", Class.class, String.class),
                        TestClass.class, "skeletonId"));
    }

    @Test
    public void testGetProxyMethodSignatures() {
        class TestClass {
        }

        Assert.assertNull(IntrabandProxyUtil.getProxyMethodSignatures(TestClass.class));
    }

    @AdviseWith(adviceClasses = { ReflectionUtilAdvice.class })
    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testInitializationFailure() throws ClassNotFoundException {
        Throwable throwable = new Throwable();

        ReflectionUtilAdvice.setDeclaredMethodThrowable(throwable);

        try {
            new IntrabandProxyUtil();

            Assert.fail();
        } catch (ExceptionInInitializerError eiie) {
            Assert.assertSame(throwable, eiie.getCause());
        }
    }

    @Test
    public void testLoadClass() {
        Assert.assertNull(IntrabandProxyUtil.loadClass(_classLoader, Thread.class, "Proxy"));
        Assert.assertSame(ThreadLocal.class, IntrabandProxyUtil.loadClass(_classLoader, Thread.class, "Local"));
    }

    @Test
    public void testNewStubInstance() {
        Class<?> stubClass = IntrabandProxyUtil.getStubClass(TestGenerateInterface1.class, "skeletonId");

        IntrabandProxyUtil.newStubInstance(stubClass, "id", new MockRegistrationReference(null),
                WarnLogExceptionHandler.INSTANCE);

        try {
            IntrabandProxyUtil.newStubInstance(stubClass, "id", null, WarnLogExceptionHandler.INSTANCE);

            Assert.fail();
        } catch (RuntimeException re) {
            Throwable throwable = re.getCause();

            throwable = throwable.getCause();

            Assert.assertSame(NullPointerException.class, throwable.getClass());
            Assert.assertEquals("Registration reference is null", throwable.getMessage());
        }

        stubClass = IntrabandProxyUtil.getStubClass(TestGenerateInterface2.class, "skeletonId");

        try {
            IntrabandProxyUtil.newStubInstance(stubClass, "id", null, WarnLogExceptionHandler.INSTANCE);

            Assert.fail();
        } catch (RuntimeException re) {
            Throwable throwable = re.getCause();

            throwable = throwable.getCause();

            Assert.assertSame(NullPointerException.class, throwable.getClass());
            Assert.assertEquals("Registration reference is null", throwable.getMessage());
        }

        IntrabandProxyUtil.newStubInstance(stubClass, "id", new MockRegistrationReference(null),
                WarnLogExceptionHandler.INSTANCE);
    }

    @Test
    public void testRewriteGetProxyMethodSignaturesMethodNode() {
        class TestClass {

            @SuppressWarnings("unused")
            public final String[] PROXY_METHOD_SIGNATURES = _getProxyMethodSignatures();

            private String[] _getProxyMethodSignatures() {
                return new String[0];
            }
        }

        ClassNode classNode = _loadClass(TestClass.class);

        String[] proxyMethodSignatures = { "testSignature1", "testSignature2", "testSignature3" };

        IntrabandProxyUtil.rewriteGetProxyMethodSignaturesMethodNode(classNode, proxyMethodSignatures);

        MethodNode methodNode = ASMUtil.findMethodNode(classNode.methods, "_getProxyMethodSignatures",
                Type.getType(String[].class));

        InsnList insnList = methodNode.instructions;

        Iterator<AbstractInsnNode> iterator = insnList.iterator();

        _assertInsnNode(iterator.next(), Opcodes.ICONST_3);

        _assertTypeInsnNode(iterator.next(), Opcodes.ANEWARRAY, String.class);

        for (int i = 0; i < proxyMethodSignatures.length; i++) {
            _assertInsnNode(iterator.next(), Opcodes.DUP);
            _assertInsnNode(iterator.next(), Opcodes.ICONST_0 + i);
            _assertLdcInsnNode(iterator.next(), Opcodes.LDC, proxyMethodSignatures[i]);
            _assertInsnNode(iterator.next(), Opcodes.AASTORE);
        }

        _assertInsnNode(iterator.next(), Opcodes.ARETURN);

        Assert.assertFalse(iterator.hasNext());
    }

    @Test
    public void testSerializerWrite() {
        MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "name", "()V", null, null);

        MethodNodeGenerator methodNodeGenerator = new MethodNodeGenerator(methodNode);

        InsnList insnList = methodNode.instructions;

        for (Type type : _types) {
            IntrabandProxyUtil.serializerWrite(methodNodeGenerator, type);

            AbstractInsnNode abstractInsnNode = insnList.getLast();

            Assert.assertTrue(abstractInsnNode instanceof MethodInsnNode);

            MethodInsnNode methodInsnNode = (MethodInsnNode) abstractInsnNode;

            Assert.assertEquals(Opcodes.INVOKEVIRTUAL, abstractInsnNode.getOpcode());
            Assert.assertEquals(Type.getInternalName(Serializer.class), methodInsnNode.owner);

            if (type.getSort() <= Type.DOUBLE) {
                String name = TextFormatter.format(type.getClassName(), TextFormatter.G);

                Assert.assertEquals("write".concat(name), methodInsnNode.name);
                Assert.assertEquals(Type.getMethodDescriptor(Type.VOID_TYPE, type), methodInsnNode.desc);
            } else if (type.equals(Type.getType(String.class))) {
                Assert.assertEquals("writeString", methodInsnNode.name);
                Assert.assertEquals(Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)),
                        methodInsnNode.desc);
            } else {
                Assert.assertEquals("writeObject", methodInsnNode.name);
                Assert.assertEquals(Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Serializable.class)),
                        methodInsnNode.desc);
            }
        }
    }

    @Test
    public void testTemplateSkeleton() throws ClassNotFoundException {
        class TestTemplateSkeleton extends TemplateSkeleton {

            TestTemplateSkeleton(TargetLocator targetLocator) {
                super(targetLocator);
            }

            @Override
            protected void doDispatch(RegistrationReference registrationReference, Datagram datagram,
                    Deserializer deserializer) {

                int i = deserializer.readInt();

                if (i == 0) {
                    ReflectionTestUtil.invoke(this, "_sendResponse",
                            new Class<?>[] { RegistrationReference.class, Datagram.class, RPCResponse.class },
                            registrationReference, datagram, new RPCResponse("syncCall"));
                } else if (i == 1) {
                    ReflectionTestUtil.invoke(this, "_unknownMethodIndex", new Class<?>[] { int.class }, 1);
                }
            }
        }

        try {
            new TestTemplateSkeleton(null);

            Assert.fail();
        } catch (NullPointerException npe) {
            Assert.assertEquals("Target locator is null", npe.getMessage());
        }

        TestGenerateTargetLocator testGenerateTargetLocator = new TestGenerateTargetLocator(
                TestGenerateInterface1.class);

        TestTemplateSkeleton testTemplateSkeleton = new TestTemplateSkeleton(testGenerateTargetLocator);

        Assert.assertSame(testGenerateTargetLocator,
                ReflectionTestUtil.getFieldValue(testTemplateSkeleton, "_targetLocator"));

        MockIntraband mockIntraband = new MockIntraband();

        MockRegistrationReference mockRegistrationReference = new MockRegistrationReference(mockIntraband);

        Serializer serializer = new Serializer();

        serializer.writeInt(0);

        testTemplateSkeleton.dispatch(mockRegistrationReference,
                Datagram.createRequestDatagram(SystemDataType.PROXY.getValue(), new byte[0]),
                new Deserializer(serializer.toByteBuffer()));

        Datagram datagram = mockIntraband.getDatagram();

        Deserializer deserializer = new Deserializer(datagram.getDataByteBuffer());

        RPCResponse rpcResponse = deserializer.readObject();

        Assert.assertEquals("syncCall", rpcResponse.getResult());

        serializer = new Serializer();

        serializer.writeInt(1);

        try (CaptureHandler captureHandler = JDKLoggerTestUtil.configureJDKLogger(TemplateSkeleton.class.getName(),
                Level.SEVERE)) {

            testTemplateSkeleton.dispatch(mockRegistrationReference,
                    Datagram.createRequestDatagram(SystemDataType.PROXY.getValue(), new byte[0]),
                    new Deserializer(serializer.toByteBuffer()));

            List<LogRecord> logRecords = captureHandler.getLogRecords();

            Assert.assertEquals(1, logRecords.size());

            LogRecord logRecord = logRecords.get(0);

            Assert.assertEquals("Unable to dispatch", logRecord.getMessage());

            Throwable throwable = logRecord.getThrown();

            throwable = throwable.getCause();

            Assert.assertSame(IllegalArgumentException.class, throwable.getClass());
            Assert.assertEquals("Unknow method index 1 for proxy methods mappings {}", throwable.getMessage());
        }

        Assert.assertEquals("{0 -> a, 1 -> b, 2 -> c}",
                ReflectionTestUtil.invoke(testTemplateSkeleton, "_getProxyMethodsMapping",
                        new Class<?>[] { String[].class }, new Object[] { new String[] { "a", "b", "c" } }));
    }

    @Test
    public void testTemplateStub() {
        try {
            new TemplateStub(null, null, null);

            Assert.fail();
        } catch (NullPointerException npe) {
            Assert.assertEquals("Id is null", npe.getMessage());
        }

        try {
            new TemplateStub("id", null, null);

            Assert.fail();
        } catch (NullPointerException npe) {
            Assert.assertEquals("Registration reference is null", npe.getMessage());
        }

        final AtomicReference<RPCResponse> rpcResponseReference = new AtomicReference<>();

        MockIntraband mockIntraband = new MockIntraband() {

            @Override
            protected Datagram processDatagram(Datagram datagram) {
                Serializer serializer = new Serializer();

                serializer.writeObject(rpcResponseReference.get());

                return Datagram.createResponseDatagram(datagram, serializer.toByteBuffer());
            }

        };

        MockRegistrationReference mockRegistrationReference = new MockRegistrationReference(mockIntraband);

        TemplateStub templateStub = new TemplateStub("id", mockRegistrationReference, null);

        Assert.assertEquals("id", ReflectionTestUtil.getFieldValue(templateStub, "_id"));
        Assert.assertSame(mockRegistrationReference,
                ReflectionTestUtil.getFieldValue(templateStub, "_registrationReference"));
        Assert.assertNull(ReflectionTestUtil.getFieldValue(templateStub, "_exceptionHandler"));
        Assert.assertSame(mockIntraband, ReflectionTestUtil.getFieldValue(templateStub, "_intraband"));

        templateStub = new TemplateStub("id", mockRegistrationReference, WarnLogExceptionHandler.INSTANCE);

        Assert.assertEquals("id", ReflectionTestUtil.getFieldValue(templateStub, "_id"));
        Assert.assertSame(mockRegistrationReference,
                ReflectionTestUtil.getFieldValue(templateStub, "_registrationReference"));
        Assert.assertSame(WarnLogExceptionHandler.INSTANCE,
                ReflectionTestUtil.getFieldValue(templateStub, "_exceptionHandler"));
        Assert.assertSame(mockIntraband, ReflectionTestUtil.getFieldValue(templateStub, "_intraband"));

        ReflectionTestUtil.invoke(templateStub, "_send", new Class<?>[] { Serializer.class }, new Serializer());

        Assert.assertSame(mockRegistrationReference, mockIntraband.getRegistrationReference());

        Datagram datagram = mockIntraband.getDatagram();

        Assert.assertEquals(SystemDataType.PROXY.getValue(), datagram.getType());

        rpcResponseReference.set(new RPCResponse("syncSend"));

        Assert.assertEquals("syncSend", ReflectionTestUtil.invoke(templateStub, "_syncSend",
                new Class<?>[] { Serializer.class }, new Serializer()));

        try (CaptureHandler captureHandler = JDKLoggerTestUtil
                .configureJDKLogger(WarnLogExceptionHandler.class.getName(), Level.WARNING)) {

            String message = "RPC failure";

            rpcResponseReference.set(new RPCResponse(new Exception(message)));

            Assert.assertNull(ReflectionTestUtil.invoke(templateStub, "_syncSend",
                    new Class<?>[] { Serializer.class }, new Serializer()));

            List<LogRecord> logRecords = captureHandler.getLogRecords();

            Assert.assertEquals(1, logRecords.size());

            LogRecord logRecord = logRecords.get(0);

            Throwable throwable = logRecord.getThrown();

            Assert.assertEquals(message, throwable.getMessage());

            logRecords.clear();

            rpcResponseReference.set(new RPCResponse((Serializable) null));

            Assert.assertNull(ReflectionTestUtil.invoke(templateStub, "_syncSend",
                    new Class<?>[] { Serializer.class }, new Serializer()));

            Assert.assertTrue(logRecords.isEmpty());

            rpcResponseReference.set(null);

            ReflectionTestUtil.setFieldValue(templateStub, "_exceptionHandler", null);

            Assert.assertNull(ReflectionTestUtil.invoke(templateStub, "_syncSend",
                    new Class<?>[] { Serializer.class }, new Serializer()));
            Assert.assertTrue(logRecords.isEmpty());
        }
    }

    @AdviseWith(adviceClasses = { DisableProxyClassesDump.class })
    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testToClassProxyClassesDumpDisabled() throws FileNotFoundException {

        _doTestToClass(false, false);
    }

    @AdviseWith(adviceClasses = { EnableProxyClassesDump.class })
    @NewEnv(type = NewEnv.Type.CLASSLOADER)
    @Test
    public void testToClassProxyClassesDumpEnabled() throws FileNotFoundException {

        _doTestToClass(true, true);
        _doTestToClass(true, false);
    }

    @Test
    public void testValidate() throws Exception {
        _doTestValidate(true);
        _doTestValidate(false);
    }

    @Aspect
    public static class DisableProxyClassesDump {

        @Around("set(* com.liferay.portal.util.PropsValues." + "INTRABAND_PROXY_DUMP_CLASSES_ENABLED)")
        public Object disableClusterLink(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

            return proceedingJoinPoint.proceed(new Object[] { Boolean.FALSE });
        }

    }

    @Aspect
    public static class EnableProxyClassesDump {

        @Around("set(* com.liferay.portal.util.PropsValues." + "INTRABAND_PROXY_DUMP_CLASSES_ENABLED)")
        public Object enableClusterLink(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

            return proceedingJoinPoint.proceed(new Object[] { Boolean.TRUE });
        }

    }

    private static Object _readFromDeserializer(Deserializer deserializer, Class<?> clazz) {

        if (clazz == boolean.class) {
            return deserializer.readBoolean();
        } else if (clazz == byte.class) {
            return deserializer.readByte();
        } else if (clazz == char.class) {
            return deserializer.readChar();
        } else if (clazz == double.class) {
            return deserializer.readDouble();
        } else if (clazz == float.class) {
            return deserializer.readFloat();
        } else if (clazz == int.class) {
            return deserializer.readInt();
        } else if (clazz == long.class) {
            return deserializer.readLong();
        } else if (clazz == short.class) {
            return deserializer.readShort();
        } else if (clazz == String.class) {
            return deserializer.readString();
        } else {
            try {
                return deserializer.readObject();
            } catch (ClassNotFoundException cnfe) {
                throw new RuntimeException(cnfe);
            }
        }
    }

    private static void _writeToSerializer(Serializer serializer, Class<?> clazz) {

        if (clazz == boolean.class) {
            serializer.writeBoolean((Boolean) _sampleValueMap.get(boolean.class));
        } else if (clazz == byte.class) {
            serializer.writeByte((Byte) _sampleValueMap.get(byte.class));
        } else if (clazz == char.class) {
            serializer.writeChar((Character) _sampleValueMap.get(char.class));
        } else if (clazz == double.class) {
            serializer.writeDouble((Double) _sampleValueMap.get(double.class));
        } else if (clazz == float.class) {
            serializer.writeFloat((Float) _sampleValueMap.get(float.class));
        } else if (clazz == int.class) {
            serializer.writeInt((Integer) _sampleValueMap.get(int.class));
        } else if (clazz == long.class) {
            serializer.writeLong((Long) _sampleValueMap.get(long.class));
        } else if (clazz == short.class) {
            serializer.writeShort((Short) _sampleValueMap.get(short.class));
        } else if (clazz == String.class) {
            serializer.writeString((String) _sampleValueMap.get(String.class));
        } else {
            serializer.writeObject((Serializable) _sampleValueMap.get(clazz));
        }
    }

    private Field _assertDeclaredField(Class<?> clazz, String name, int modifiers, Class<?> type) throws Exception {

        Field field = clazz.getDeclaredField(name);

        field.setAccessible(true);

        Assert.assertEquals(modifiers, field.getModifiers());
        Assert.assertSame(type, field.getType());

        return field;
    }

    private void _assertDeclaredMethod(Class<?> clazz, String name, Class<?>[] parameterTypes, int modifiers,
            Class<?> returnType, Class<?>... exceptionTypes) throws Exception {

        Method method = clazz.getDeclaredMethod(name, parameterTypes);

        Assert.assertEquals(modifiers, method.getModifiers());
        Assert.assertSame(returnType, method.getReturnType());
        Assert.assertArrayEquals(exceptionTypes, method.getExceptionTypes());
    }

    private void _assertFieldInsnNode(AbstractInsnNode abstractInsnNode, int opcode, String owner, String name,
            Class<?> clazz) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        FieldInsnNode fieldInsnNode = (FieldInsnNode) abstractInsnNode;

        Assert.assertEquals(owner, fieldInsnNode.owner);
        Assert.assertEquals(name, fieldInsnNode.name);
        Assert.assertEquals(Type.getDescriptor(clazz), fieldInsnNode.desc);
    }

    private void _assertInsnNode(AbstractInsnNode abstractInsnNode, int opcode) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());
    }

    private void _assertIntInsnNode(AbstractInsnNode abstractInsnNode, int opcode, int operand) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        IntInsnNode intInsnNode = (IntInsnNode) abstractInsnNode;

        Assert.assertEquals(operand, intInsnNode.operand);
    }

    private LabelNode _assertJumpInsnNode(AbstractInsnNode abstractInsnNode, int opcode) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        JumpInsnNode jumpInsnNode = (JumpInsnNode) abstractInsnNode;

        return jumpInsnNode.label;
    }

    private void _assertLdcInsnNode(AbstractInsnNode abstractInsnNode, int opcode, Object obj) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        LdcInsnNode ldcInsnNode = (LdcInsnNode) abstractInsnNode;

        Assert.assertEquals(obj, ldcInsnNode.cst);
    }

    private void _assertMethodInsnNode(AbstractInsnNode abstractInsnNode, int opcode, String owner, String name,
            Type returnType, Type... argumentTypes) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        MethodInsnNode methodInsnNode = (MethodInsnNode) abstractInsnNode;

        Assert.assertEquals(owner, methodInsnNode.owner);
        Assert.assertEquals(name, methodInsnNode.name);
        Assert.assertEquals(Type.getMethodDescriptor(returnType, argumentTypes), methodInsnNode.desc);
    }

    private void _assertMethodNodeSignature(MethodNode methodNode, int access, String name, String desc,
            Class<?>... exceptionClasses) {

        Assert.assertEquals(access, methodNode.access);
        Assert.assertEquals(name, methodNode.name);
        Assert.assertEquals(desc, methodNode.desc);

        List<String> exceptions = new ArrayList<>(exceptionClasses.length);

        for (Class<?> exceptionClass : exceptionClasses) {
            exceptions.add(Type.getInternalName(exceptionClass));
        }

        Assert.assertEquals(exceptions, methodNode.exceptions);
    }

    private void _assertTypeInsnNode(AbstractInsnNode abstractInsnNode, int opcode, Class<?> clazz) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        TypeInsnNode typeInsnNode = (TypeInsnNode) abstractInsnNode;

        Assert.assertEquals(Type.getInternalName(clazz), typeInsnNode.desc);
    }

    private void _assertVarInsnNode(AbstractInsnNode abstractInsnNode, int opcode, int var) {

        Assert.assertEquals(opcode, abstractInsnNode.getOpcode());

        VarInsnNode varInsnNode = (VarInsnNode) abstractInsnNode;

        Assert.assertEquals(var, varInsnNode.var);
    }

    private String[] _buildProxyMethodSignatures(Class<?> clazz) {
        List<Method> proxyMethods = new ArrayList<>();

        for (Method method : ReflectionUtil.getVisibleMethods(clazz)) {
            if (method.getAnnotation(Proxy.class) != null) {
                proxyMethods.add(method);
            }
        }

        Collections.sort(proxyMethods, new MethodComparator());

        String[] proxyMethodSignatures = new String[proxyMethods.size()];

        for (int i = 0; i < proxyMethodSignatures.length; i++) {
            Method proxyMethod = proxyMethods.get(i);

            String name = proxyMethod.getName();

            proxyMethodSignatures[i] = name.concat(StringPool.DASH).concat(Type.getMethodDescriptor(proxyMethod));
        }

        return proxyMethodSignatures;
    }

    private void _doTestCreateProxyMethodNode(Method method, int index, String skeletonId,
            String stubInternalName) {

        MethodNode proxyMethodNode = IntrabandProxyUtil.createProxyMethodNode(method, index, skeletonId,
                Type.getType(stubInternalName));

        _assertMethodNodeSignature(proxyMethodNode, method.getModifiers() & ~Modifier.ABSTRACT, method.getName(),
                Type.getMethodDescriptor(method), method.getExceptionTypes());

        InsnList insnList = proxyMethodNode.instructions;

        Iterator<AbstractInsnNode> iterator = insnList.iterator();

        // NEW com/liferay/portal/kernel/io/Serializer

        _assertTypeInsnNode(iterator.next(), Opcodes.NEW, Serializer.class);

        // DUP

        _assertInsnNode(iterator.next(), Opcodes.DUP);

        // INVOKESPECIAL com/liferay/portal/kernel/io/Serializer <init> ()V

        _assertMethodInsnNode(iterator.next(), Opcodes.INVOKESPECIAL, Type.getInternalName(Serializer.class),
                "<init>", Type.VOID_TYPE);

        // ASTORE argumentsSize

        Type methodType = Type.getType(method);

        int argumentsAndReturnSizes = methodType.getArgumentsAndReturnSizes();

        int argumentsSize = argumentsAndReturnSizes >> 2;

        _assertVarInsnNode(iterator.next(), Opcodes.ASTORE, argumentsSize);

        // ALOAD argumentsSize

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize);

        // LDC skeletonId

        _assertLdcInsnNode(iterator.next(), Opcodes.LDC, skeletonId);

        // INVOKEVIRTUAL com/liferay/portal/kernel/io/Serializer writeString
        // (Ljava/lang/String;)V

        _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL, Type.getInternalName(Serializer.class),
                "writeString", Type.VOID_TYPE, Type.getType(String.class));

        // ALOAD argumentsSize

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize);

        // ALOAD 0

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, 0);

        // GETFIELD stubInternalName _id Ljava/lang/String;

        _assertFieldInsnNode(iterator.next(), Opcodes.GETFIELD, stubInternalName, "_id", String.class);

        // INVOKEVIRTUAL com/liferay/portal/kernel/io/Serializer writeString
        // (Ljava/lang/String;)V

        _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL, Type.getInternalName(Serializer.class),
                "writeString", Type.VOID_TYPE, Type.getType(String.class));

        // ALOAD argumentsSize

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize);

        if (index <= 5) {

            // ICONST_index

            _assertInsnNode(iterator.next(), Opcodes.ICONST_0 + index);
        } else {

            // BIPUSH index

            _assertIntInsnNode(iterator.next(), Opcodes.BIPUSH, index);
        }

        // INVOKEVIRTUAL com/liferay/portal/kernel/io/Serializer writeInt (I)V

        _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL, Type.getInternalName(Serializer.class),
                "writeInt", Type.VOID_TYPE, Type.INT_TYPE);

        Class<?>[] parameterTypes = method.getParameterTypes();

        int offset = 1;

        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterClass = parameterTypes[i];

            // ALOAD argumentsSize

            _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize);

            // xLOAD i

            Type parameterType = Type.getType(parameterClass);

            _assertVarInsnNode(iterator.next(), parameterType.getOpcode(Opcodes.ILOAD), offset);

            offset += parameterType.getSize();

            if (parameterClass.isPrimitive() || (parameterClass == String.class)) {

                String name = TextFormatter.format(parameterClass.getSimpleName(), TextFormatter.G);

                _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName(Serializer.class), "write".concat(name), Type.VOID_TYPE,
                        parameterType);
            } else {
                _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName(Serializer.class), "writeObject", Type.VOID_TYPE,
                        Type.getType(Serializable.class));
            }
        }

        // ALOAD 0

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, 0);

        // ALOAD argumentsSize

        _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize);

        Class<?> returnClass = method.getReturnType();

        Type returnType = Type.getType(returnClass);

        if (returnClass == void.class) {

            // INVOKESPECIAL stubInternalName _send
            // (Lcom/liferay/portal/kernel/io/Serializer;)V

            _assertMethodInsnNode(iterator.next(), Opcodes.INVOKESPECIAL, stubInternalName, "_send", Type.VOID_TYPE,
                    Type.getType(Serializer.class));

            _assertInsnNode(iterator.next(), Opcodes.RETURN);
        } else {

            // INVOKESPECIAL stubInternalName _syncSend
            // (Lcom/liferay/portal/kernel/io/Serializer;)Ljava/io/Serializable;

            _assertMethodInsnNode(iterator.next(), Opcodes.INVOKESPECIAL, stubInternalName, "_syncSend",
                    Type.getType(Serializable.class), Type.getType(Serializer.class));

            if (returnClass.isPrimitive()) {

                // ASTORE argumentsSize + 1

                _assertVarInsnNode(iterator.next(), Opcodes.ASTORE, argumentsSize + 1);

                // ALOAD argumentsSize + 1

                _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize + 1);

                // IFNULL nullCheckLabel

                LabelNode nullCheckLabelNode = _assertJumpInsnNode(iterator.next(), Opcodes.IFNULL);

                // ALOAD argumentsSize + 1

                _assertVarInsnNode(iterator.next(), Opcodes.ALOAD, argumentsSize + 1);

                // CHECKCAST returnType

                _assertTypeInsnNode(iterator.next(), Opcodes.CHECKCAST, _autoboxingMap.get(returnClass));

                if (returnClass == boolean.class) {

                    // INVOKEVIRTUAL java/lang/Boolean booleanValue ()Z

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Boolean.class), "booleanValue", Type.BOOLEAN_TYPE);
                } else if (returnClass == byte.class) {

                    // INVOKEVIRTUAL java/lang/Number intValue ()I

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "intValue", Type.INT_TYPE);
                } else if (returnClass == char.class) {

                    // INVOKEVIRTUAL java/lang/Character charValue ()C

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Character.class), "charValue", Type.CHAR_TYPE);
                } else if (returnClass == double.class) {

                    // INVOKEVIRTUAL java/lang/Number doubleValue ()D

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "doubleValue", Type.DOUBLE_TYPE);
                } else if (returnClass == float.class) {

                    // INVOKEVIRTUAL java/lang/Number floatValue ()F

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "floatValue", Type.FLOAT_TYPE);
                } else if (returnClass == int.class) {

                    // INVOKEVIRTUAL java/lang/Number intValue ()I

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "intValue", Type.INT_TYPE);
                } else if (returnClass == long.class) {

                    // INVOKEVIRTUAL java/lang/Number longValue ()J

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "longValue", Type.LONG_TYPE);
                } else if (returnClass == short.class) {

                    // INVOKEVIRTUAL java/lang/Number intValue ()I

                    _assertMethodInsnNode(iterator.next(), Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(Number.class), "intValue", Type.INT_TYPE);
                }

                // xRETURN

                _assertInsnNode(iterator.next(), returnType.getOpcode(Opcodes.IRETURN));

                // nullCheckLabel

                Assert.assertSame(nullCheckLabelNode, iterator.next());

                // xRETURN null/0

                if (!returnClass.isPrimitive()) {
                    _assertInsnNode(iterator.next(), Opcodes.ACONST_NULL);
                    _assertInsnNode(iterator.next(), Opcodes.ARETURN);
                } else if (returnClass == void.class) {
                    _assertInsnNode(iterator.next(), Opcodes.RETURN);
                } else if (returnClass == float.class) {
                    _assertInsnNode(iterator.next(), Opcodes.FCONST_0);
                    _assertInsnNode(iterator.next(), Opcodes.FRETURN);
                } else if (returnClass == double.class) {
                    _assertInsnNode(iterator.next(), Opcodes.DCONST_0);
                    _assertInsnNode(iterator.next(), Opcodes.DRETURN);
                } else if (returnClass == long.class) {
                    _assertInsnNode(iterator.next(), Opcodes.LCONST_0);
                    _assertInsnNode(iterator.next(), Opcodes.LRETURN);
                } else {
                    _assertInsnNode(iterator.next(), Opcodes.ICONST_0);
                    _assertInsnNode(iterator.next(), Opcodes.IRETURN);
                }
            } else {
                if (returnClass != Object.class) {

                    // CHECKCAST

                    _assertTypeInsnNode(iterator.next(), Opcodes.CHECKCAST, returnClass);
                }

                // ARETURN

                _assertInsnNode(iterator.next(), Opcodes.ARETURN);
            }
        }

        Assert.assertFalse(iterator.hasNext());
    }

    private void _doTestGenerateSkeletonClassFunction(Class<?> clazz) throws Exception {

        Class<? extends IntrabandProxySkeleton> skeletonClass = IntrabandProxyUtil
                .generateSkeletonClass(_classLoader, clazz);

        Constructor<? extends IntrabandProxySkeleton> constructor = skeletonClass
                .getConstructor(TargetLocator.class);

        TestGenerateTargetLocator testGenerateTargetLocator = new TestGenerateTargetLocator(clazz);

        IntrabandProxySkeleton intrabandProxySkeleton = constructor.newInstance(testGenerateTargetLocator);

        Assert.assertSame(testGenerateTargetLocator,
                ReflectionTestUtil.getFieldValue(intrabandProxySkeleton, "_targetLocator"));

        MockIntraband mockIntraband = new MockIntraband();

        MockRegistrationReference mockRegistrationReference = new MockRegistrationReference(mockIntraband);

        Datagram datagram = Datagram.createRequestDatagram(SystemDataType.PROXY.getValue(), new byte[0]);

        String targetId = "targetId";

        List<Method> proxyMethods = _getProxyMethods(clazz);

        for (int i = 0; i < proxyMethods.size() + 1; i++) {
            Serializer serializer = new Serializer();

            serializer.writeString(targetId);
            serializer.writeInt(i);

            if (i == proxyMethods.size()) {
                try (CaptureHandler captureHandler = JDKLoggerTestUtil.configureJDKLogger(skeletonClass.getName(),
                        Level.SEVERE)) {

                    intrabandProxySkeleton.dispatch(mockRegistrationReference, datagram,
                            new Deserializer(serializer.toByteBuffer()));

                    List<LogRecord> logRecords = captureHandler.getLogRecords();

                    Assert.assertEquals(1, logRecords.size());

                    LogRecord logRecord = logRecords.get(0);

                    Assert.assertEquals("Unable to dispatch", logRecord.getMessage());

                    Throwable throwable = logRecord.getThrown();

                    Assert.assertSame(IllegalArgumentException.class, throwable.getClass());
                    Assert.assertEquals(
                            "Unknow method index " + i + " for proxy methods mappings "
                                    + ReflectionTestUtil.getFieldValue(skeletonClass, "_PROXY_METHODS_MAPPING"),
                            throwable.getMessage());
                }

                break;
            }

            Method proxyMethod = proxyMethods.get(i);

            for (Class<?> parameterType : proxyMethod.getParameterTypes()) {
                _writeToSerializer(serializer, parameterType);
            }

            Deserializer deserializer = new Deserializer(serializer.toByteBuffer());

            intrabandProxySkeleton.dispatch(mockRegistrationReference, datagram, deserializer);

            Class<?> returnType = proxyMethod.getReturnType();

            if (returnType == void.class) {
                Assert.assertNull(mockIntraband.getDatagram());
                Assert.assertNull(mockIntraband.getRegistrationReference());
            } else {
                Datagram responseDatagram = mockIntraband.getDatagram();

                deserializer = new Deserializer(responseDatagram.getDataByteBuffer());

                RPCResponse rpcResponse = deserializer.readObject();

                Assert.assertEquals(_sampleValueMap.get(returnType), rpcResponse.getResult());
                Assert.assertSame(mockRegistrationReference, mockIntraband.getRegistrationReference());
            }
        }
    }

    private void _doTestGenerateSkeletonClassStructure(Class<?> clazz) throws Exception {

        Class<?> skeletonClass = IntrabandProxyUtil.generateSkeletonClass(_classLoader, clazz);

        // Class signature

        Assert.assertEquals(Modifier.PUBLIC, skeletonClass.getModifiers());
        Assert.assertArrayEquals(new Class<?>[] { IntrabandProxySkeleton.class }, skeletonClass.getInterfaces());

        // Fields

        _assertDeclaredField(skeletonClass, "PROXY_METHOD_SIGNATURES",
                Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, String[].class);

        String[] proxyMethodSignatures = IntrabandProxyUtil.getProxyMethodSignatures(skeletonClass);

        Assert.assertArrayEquals(_buildProxyMethodSignatures(clazz), proxyMethodSignatures);

        StringBundler sb = new StringBundler(proxyMethodSignatures.length * 4 + 1);

        sb.append(StringPool.OPEN_CURLY_BRACE);

        for (int i = 0; i < proxyMethodSignatures.length; i++) {
            sb.append(i);
            sb.append(" -> ");
            sb.append(proxyMethodSignatures[i]);
            sb.append(StringPool.COMMA_AND_SPACE);
        }

        if (proxyMethodSignatures.length > 0) {
            sb.setIndex(sb.index() - 1);
        }

        sb.append(StringPool.CLOSE_CURLY_BRACE);

        Field proxyMethodsMappingField = _assertDeclaredField(skeletonClass, "_PROXY_METHODS_MAPPING",
                Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, String.class);

        Assert.assertEquals(sb.toString(), proxyMethodsMappingField.get(null));

        Field logField = _assertDeclaredField(skeletonClass, "_log",
                Modifier.FINAL | Modifier.PRIVATE | Modifier.STATIC, Log.class);

        LogWrapper logWrapper = (LogWrapper) logField.get(null);

        Jdk14LogImpl jdk14LogImpl = (Jdk14LogImpl) logWrapper.getWrappedLog();

        Logger logger = jdk14LogImpl.getWrappedLogger();

        Assert.assertEquals(skeletonClass.getName(), logger.getName());

        _assertDeclaredField(skeletonClass, "_targetLocator", Modifier.PRIVATE | Modifier.FINAL,
                TargetLocator.class);

        // Constructors

        Constructor<?>[] constructors = skeletonClass.getConstructors();

        Assert.assertEquals(1, constructors.length);

        Constructor<?> constructor = constructors[0];

        Assert.assertArrayEquals(new Class<?>[] { TargetLocator.class }, constructor.getParameterTypes());

        // Methods

        _assertDeclaredMethod(skeletonClass, "dispatch",
                new Class<?>[] { RegistrationReference.class, Datagram.class, Deserializer.class }, Modifier.PUBLIC,
                void.class);
        _assertDeclaredMethod(skeletonClass, "doDispatch",
                new Class<?>[] { RegistrationReference.class, Datagram.class, Deserializer.class },
                Modifier.PROTECTED, void.class, Exception.class);
        _assertDeclaredMethod(skeletonClass, "_getProxyMethodSignatures", new Class<?>[0],
                Modifier.STATIC | Modifier.PRIVATE, String[].class);
        _assertDeclaredMethod(skeletonClass, "_getProxyMethodsMapping", new Class<?>[] { String[].class },
                Modifier.STATIC | Modifier.PRIVATE, String.class);
        _assertDeclaredMethod(skeletonClass, "_sendResponse",
                new Class<?>[] { RegistrationReference.class, Datagram.class, RPCResponse.class }, Modifier.PRIVATE,
                void.class);
        _assertDeclaredMethod(skeletonClass, "_unknownMethodIndex", new Class<?>[] { int.class }, Modifier.PRIVATE,
                void.class);

        Method[] declaredMethods = skeletonClass.getDeclaredMethods();

        Assert.assertEquals(6, declaredMethods.length);
    }

    private void _doTestGenerateStubClassStructure(Class<?> clazz, String skeletonId) throws Exception {

        Class<?> stubClass = IntrabandProxyUtil.generateStubClass(_classLoader, clazz, skeletonId);

        // Class signature

        Assert.assertEquals(Modifier.PUBLIC, stubClass.getModifiers());

        if (clazz.isInterface()) {
            Assert.assertArrayEquals(new Class<?>[] { clazz }, stubClass.getInterfaces());
        } else {
            Assert.assertArrayEquals(clazz.getInterfaces(), stubClass.getInterfaces());
        }

        // Fields

        _assertDeclaredField(stubClass, "PROXY_METHOD_SIGNATURES",
                Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, String[].class);

        Assert.assertArrayEquals(_buildProxyMethodSignatures(clazz),
                IntrabandProxyUtil.getProxyMethodSignatures(stubClass));

        _assertDeclaredField(stubClass, "_id", Modifier.PRIVATE | Modifier.FINAL, String.class);

        Field proxyTypeField = _assertDeclaredField(stubClass, "_PROXY_TYPE",
                Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, byte.class);

        Assert.assertEquals(SystemDataType.PROXY.getValue(), proxyTypeField.getByte(null));

        _assertDeclaredField(stubClass, "_intraband", Modifier.PRIVATE | Modifier.FINAL, Intraband.class);

        _assertDeclaredField(stubClass, "_registrationReference", Modifier.PRIVATE | Modifier.FINAL,
                RegistrationReference.class);

        _assertDeclaredField(stubClass, "_exceptionHandler", Modifier.PRIVATE | Modifier.FINAL,
                ExceptionHandler.class);

        Field[] fields = stubClass.getDeclaredFields();

        Assert.assertEquals(6, fields.length);

        // Constructors

        Constructor<?>[] constructors = stubClass.getConstructors();

        Assert.assertEquals(1, constructors.length);

        Constructor<?> constructor = constructors[0];

        Assert.assertArrayEquals(
                new Class<?>[] { String.class, RegistrationReference.class, ExceptionHandler.class },
                constructor.getParameterTypes());

        // Methods

        _assertDeclaredMethod(stubClass, "_getProxyMethodSignatures", new Class<?>[0],
                Modifier.STATIC | Modifier.PRIVATE, String[].class);
        _assertDeclaredMethod(stubClass, "_syncSend", new Class<?>[] { Serializer.class }, Modifier.PRIVATE,
                Serializable.class);
        _assertDeclaredMethod(stubClass, "_send", new Class<?>[] { Serializer.class }, Modifier.PRIVATE,
                void.class);

        List<Method> idMethods = _getIdMethods(clazz);

        for (Method idMethod : idMethods) {
            _assertDeclaredMethod(stubClass, idMethod.getName(), idMethod.getParameterTypes(), Modifier.PUBLIC,
                    idMethod.getReturnType(), idMethod.getExceptionTypes());
        }

        List<Method> proxyMethods = _getProxyMethods(clazz);

        for (Method proxyMethod : proxyMethods) {
            _assertDeclaredMethod(stubClass, proxyMethod.getName(), proxyMethod.getParameterTypes(),
                    (proxyMethod.getModifiers() & ~Modifier.ABSTRACT), proxyMethod.getReturnType(),
                    proxyMethod.getExceptionTypes());
        }

        List<Method> emptyMethods = _getEmptyMethods(clazz);

        for (Method emptyMethod : emptyMethods) {
            _assertDeclaredMethod(stubClass, emptyMethod.getName(), emptyMethod.getParameterTypes(),
                    Modifier.PUBLIC, emptyMethod.getReturnType(), emptyMethod.getExceptionTypes());
        }

        Method[] declaredMethods = stubClass.getDeclaredMethods();

        Assert.assertEquals(3 + idMethods.size() + proxyMethods.size() + emptyMethods.size(),
                declaredMethods.length);
    }

    private void _doTestGetClass(ClassLoader classLoader, final MethodHandler methodHandler) throws Exception {

        FutureTask<Class<?>> futureTask = new FutureTask<Class<?>>(new Callable<Class<?>>() {

            @Override
            public Class<?> call() throws Exception {
                return (Class<?>) methodHandler.invoke();
            }

        });

        Thread thread = new Thread(futureTask);

        Class<?> stubClass = null;

        synchronized (classLoader) {
            thread.start();

            while (thread.getState() != Thread.State.BLOCKED)
                ;

            stubClass = (Class<?>) methodHandler.invoke();
        }

        Assert.assertSame(stubClass, futureTask.get());

        // Load from ClassLoader cache

        Assert.assertSame(stubClass, methodHandler.invoke());
    }

    private void _doTestToClass(boolean proxyClassesDumpEnabled, boolean logEnabled) throws FileNotFoundException {

        class TestClass {
        }

        ClassNode classNode = _loadClass(TestClass.class);

        MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, "<clinit>", "()V", null, null);

        methodNode.visitCode();
        methodNode.visitInsn(Opcodes.RETURN);
        methodNode.visitEnd();

        List<MethodNode> methodNodes = classNode.methods;

        methodNodes.add(methodNode);

        ClassLoader classLoader = new URLClassLoader(new URL[0], null);

        Level level = Level.WARNING;

        if (logEnabled) {
            level = Level.INFO;
        }

        try (CaptureHandler captureHandler = JDKLoggerTestUtil
                .configureJDKLogger(IntrabandProxyUtil.class.getName(), level)) {

            List<LogRecord> logRecords = captureHandler.getLogRecords();

            IntrabandProxyUtil.toClass(classNode, classLoader);

            if (proxyClassesDumpEnabled) {
                StringBundler sb = new StringBundler(6);

                sb.append(SystemProperties.get(SystemProperties.TMP_DIR));
                sb.append(StringPool.SLASH);
                sb.append(PropsValues.INTRABAND_PROXY_DUMP_CLASSES_DIR);
                sb.append(StringPool.SLASH);
                sb.append(classNode.name);
                sb.append(".class");

                String filePath = sb.toString();

                File classFile = new File(filePath);

                Assert.assertTrue(classFile.exists());

                ClassNode reloadedClassNode = _loadClass(new FileInputStream(classFile));

                MethodNode clinitMethodNode = ASMUtil.findMethodNode(reloadedClassNode.methods, "<clinit>",
                        Type.VOID_TYPE);

                InsnList insnList = clinitMethodNode.instructions;

                Assert.assertEquals(1, insnList.size());

                _assertInsnNode(insnList.getFirst(), Opcodes.RETURN);

                if (logEnabled) {
                    Assert.assertEquals(1, logRecords.size());

                    LogRecord logRecord = logRecords.get(0);

                    Assert.assertEquals(logRecord.getMessage(), "Dumpped class ".concat(filePath));
                }
            }

            if (!proxyClassesDumpEnabled || !logEnabled) {
                Assert.assertTrue(logRecords.isEmpty());
            }
        }

        try {
            IntrabandProxyUtil.toClass(classNode, classLoader);

            Assert.fail();
        } catch (RuntimeException re) {
            Throwable throwable = re.getCause();

            Assert.assertSame(InvocationTargetException.class, throwable.getClass());

            throwable = throwable.getCause();

            Assert.assertSame(LinkageError.class, throwable.getClass());

            String message = throwable.getMessage();

            Assert.assertTrue(message.contains(
                    "duplicate class definition for name: \"" + Type.getInternalName(TestClass.class) + "\""));
        }
    }

    private void _doTestValidate(boolean skeletonOrStub) throws Exception {
        try {
            IntrabandProxyUtil.validate(_classLoader, Id.class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(Id.class + " is an annotation", iae.getMessage());
        }

        try {
            IntrabandProxyUtil.validate(_classLoader, int[].class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(int[].class + " is an array", iae.getMessage());
        }

        try {
            IntrabandProxyUtil.validate(_classLoader, SystemDataType.class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(SystemDataType.class + " is an enum", iae.getMessage());
        }

        try {
            IntrabandProxyUtil.validate(_classLoader, int.class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(int.class + " is a primitive", iae.getMessage());
        }

        ClassLoader classLoader = new URLClassLoader(new URL[0], null);

        try {
            IntrabandProxyUtil.validate(classLoader, IntrabandProxyUtilTest.class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals(IntrabandProxyUtilTest.class + " is not visible from class loader " + classLoader,
                    iae.getMessage());
        }

        class TestValidateClass1 {

            @SuppressWarnings("unused")
            private String[] PROXY_METHOD_SIGNATURES;

        }

        try {
            IntrabandProxyUtil.validate(_classLoader, TestValidateClass1.class, skeletonOrStub);

            Assert.fail();
        } catch (IllegalArgumentException iae) {
            Assert.assertEquals("Field " + TestValidateClass1.class.getDeclaredField("PROXY_METHOD_SIGNATURES")
                    + " is expected to be of type " + String[].class + " and static", iae.getMessage());
        }

        if (skeletonOrStub) {
            class TestValidateClass2 {

                @SuppressWarnings("unused")
                private String _PROXY_METHODS_MAPPING;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass2.class, true);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals("Field " + TestValidateClass2.class.getDeclaredField("_PROXY_METHODS_MAPPING")
                        + " is expected to be of type " + String.class + " and static", iae.getMessage());
            }

            class TestValidateClass3 {

                @SuppressWarnings("unused")
                private String _log;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass3.class, true);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals("Field " + TestValidateClass3.class.getDeclaredField("_log")
                        + " is expected to be of type " + Log.class + " and static", iae.getMessage());
            }

            class TestValidateClass4 {

                @SuppressWarnings("unused")
                private Object _targetLocator;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass4.class, true);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals(
                        "Field " + TestValidateClass4.class.getDeclaredField("_targetLocator")
                                + " is expected to be of type " + TargetLocator.class + " and not static",
                        iae.getMessage());
            }
        } else {
            class TestValidateClass5 {

                @SuppressWarnings("unused")
                int _proxyType;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass5.class, false);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals("Field " + TestValidateClass5.class.getDeclaredField("_proxyType")
                        + " is expected to be of type " + byte.class + " and static", iae.getMessage());
            }

            class TestValidateClass6 {

                @SuppressWarnings("unused")
                private Object _id;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass6.class, false);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals("Field " + TestValidateClass6.class.getDeclaredField("_id")
                        + " is expected to be of type " + String.class + " and not static", iae.getMessage());
            }

            class TestValidateClass7 {

                @SuppressWarnings("unused")
                private Object _intraband;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass7.class, false);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals(
                        "Field " + TestValidateClass7.class.getDeclaredField("_intraband")
                                + " is expected to be of type " + Intraband.class + " and not static",
                        iae.getMessage());
            }

            class TestValidateClass8 {

                @SuppressWarnings("unused")
                private Object _registrationReference;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass8.class, false);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals(
                        "Field " + TestValidateClass8.class.getDeclaredField("_registrationReference")
                                + " is expected to be of type " + RegistrationReference.class + " and not static",
                        iae.getMessage());
            }

            class TestValidateClass9 {

                @SuppressWarnings("unused")
                private Object _exceptionHandler;
            }

            try {
                IntrabandProxyUtil.validate(_classLoader, TestValidateClass9.class, false);

                Assert.fail();
            } catch (IllegalArgumentException iae) {
                Assert.assertEquals(
                        "Field " + TestValidateClass9.class.getDeclaredField("_exceptionHandler")
                                + " is expected to be of type " + ExceptionHandler.class + " and not static",
                        iae.getMessage());
            }
        }

        IntrabandProxyUtil.validate(_classLoader, TestValidateClass.class, skeletonOrStub);
    }

    private List<Method> _getCopiedMethods(Class<?> clazz) {
        List<Method> emptyMethods = new ArrayList<>();

        for (Method method : ReflectionUtil.getVisibleMethods(clazz)) {
            String name = method.getName();

            if (!Modifier.isAbstract(method.getModifiers()) && name.startsWith("copy")
                    && (method.getAnnotation(Id.class) == null) && (method.getAnnotation(Proxy.class) == null)) {

                emptyMethods.add(method);
            }
        }

        return emptyMethods;
    }

    private List<Method> _getEmptyMethods(Class<?> clazz) {
        List<Method> emptyMethods = new ArrayList<>();

        for (Method method : ReflectionUtil.getVisibleMethods(clazz)) {
            if (Modifier.isAbstract(method.getModifiers()) && (method.getAnnotation(Id.class) == null)
                    && (method.getAnnotation(Proxy.class) == null)) {

                emptyMethods.add(method);
            }
        }

        return emptyMethods;
    }

    private List<Method> _getIdMethods(Class<?> clazz) {
        List<Method> idMethods = new ArrayList<>();

        for (Method method : ReflectionUtil.getVisibleMethods(clazz)) {
            if (method.getAnnotation(Id.class) != null) {
                idMethods.add(method);
            }
        }

        return idMethods;
    }

    private List<Method> _getProxyMethods(Class<?> clazz) {
        List<Method> proxyMethods = new ArrayList<>();

        for (Method method : ReflectionUtil.getVisibleMethods(clazz)) {
            if (method.getAnnotation(Proxy.class) != null) {
                proxyMethods.add(method);
            }
        }

        Collections.sort(proxyMethods, new MethodComparator());

        return proxyMethods;
    }

    private ClassNode _loadClass(Class<?> clazz) {
        ClassLoader classLoader = clazz.getClassLoader();

        String name = clazz.getName();

        name = name.replace(CharPool.PERIOD, CharPool.SLASH);

        return _loadClass(classLoader.getResourceAsStream(name.concat(".class")));
    }

    private ClassNode _loadClass(InputStream is) {
        ClassReader classReader = null;

        try {
            classReader = new ClassReader(is);
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }

        ClassNode classNode = new ClassNode();

        classReader.accept(classNode, 0);

        return classNode;
    }

    private static final Map<Class<?>, Class<?>> _autoboxingMap = new HashMap<>();
    private static final ClassLoader _classLoader = IntrabandProxyUtilTest.class.getClassLoader();
    private static final Map<Class<?>, Object> _defaultValueMap = new HashMap<>();
    private static final Map<Class<?>, Object> _sampleValueMap = new HashMap<>();
    private static final Type[] _types = { Type.BOOLEAN_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE, Type.DOUBLE_TYPE,
            Type.FLOAT_TYPE, Type.INT_TYPE, Type.LONG_TYPE, Type.SHORT_TYPE, Type.getType(String.class),
            Type.getType(Object.class) };

    static {
        _autoboxingMap.put(boolean.class, Boolean.class);
        _autoboxingMap.put(byte.class, Number.class);
        _autoboxingMap.put(char.class, Character.class);
        _autoboxingMap.put(double.class, Number.class);
        _autoboxingMap.put(float.class, Number.class);
        _autoboxingMap.put(int.class, Number.class);
        _autoboxingMap.put(long.class, Number.class);
        _autoboxingMap.put(short.class, Number.class);

        _defaultValueMap.put(boolean.class, Boolean.FALSE);
        _defaultValueMap.put(byte.class, (byte) 0);
        _defaultValueMap.put(char.class, (char) 0);
        _defaultValueMap.put(double.class, (double) 0);
        _defaultValueMap.put(float.class, (float) 0);
        _defaultValueMap.put(int.class, 0);
        _defaultValueMap.put(long.class, (long) 0);
        _defaultValueMap.put(short.class, (short) 0);
        _defaultValueMap.put(String.class, null);
        _defaultValueMap.put(Date.class, null);
        _defaultValueMap.put(Object.class, null);
        _defaultValueMap.put(void.class, null);

        _sampleValueMap.put(boolean.class, Boolean.TRUE);
        _sampleValueMap.put(byte.class, (byte) 11);
        _sampleValueMap.put(char.class, 'X');
        _sampleValueMap.put(double.class, 12.345);
        _sampleValueMap.put(float.class, 5.325F);
        _sampleValueMap.put(int.class, 127);
        _sampleValueMap.put(long.class, (long) 82465);
        _sampleValueMap.put(short.class, (short) -35);
        _sampleValueMap.put(String.class, "Hello");
        _sampleValueMap.put(Date.class, new Date());
        _sampleValueMap.put(Object.class, new Locale("en"));
        _sampleValueMap.put(void.class, null);
    }

    private static class AutoReplyMockIntraband extends MockIntraband {

        public AutoReplyMockIntraband(String skeletonId, String targetId) {
            _skeletonId = skeletonId;
            _targetId = targetId;
        }

        public void setInvocation(Method method, int index) {
            _method = method;
            _index = index;
        }

        @Override
        protected Datagram processDatagram(Datagram datagram) {
            Deserializer deserializer = new Deserializer(datagram.getDataByteBuffer());

            Assert.assertEquals(_skeletonId, deserializer.readString());
            Assert.assertEquals(_targetId, deserializer.readString());
            Assert.assertEquals(_index, deserializer.readInt());

            for (Class<?> parameterType : _method.getParameterTypes()) {
                Assert.assertEquals(_sampleValueMap.get(parameterType),
                        _readFromDeserializer(deserializer, parameterType));
            }

            Class<?> returnType = _method.getReturnType();

            if (returnType == void.class) {
                return null;
            }

            Serializer serializer = new Serializer();

            serializer.writeObject(new RPCResponse((Serializable) _sampleValueMap.get(returnType)));

            return Datagram.createResponseDatagram(datagram, serializer.toByteBuffer());
        }

        private int _index;
        private Method _method;
        private final String _skeletonId;
        private final String _targetId;

    }

    private static class TestExtractMethodsClass1 {

        @Id
        public static String getId() {
            return null;
        }

    }

    private static class TestExtractMethodsClass2 {

        @Id
        public String getId(Object obj) {
            return null;
        }

    }

    private static class TestExtractMethodsClass3 {

        @Id
        public Object getId() {
            return null;
        }

    }

    private static class TestExtractMethodsClass4 {

        @Proxy
        public static void doStuff() {
        }

    }

    private static abstract class TestExtractMethodsClass5 {

        @Proxy
        public void doStuff1() {
        }

        @Proxy(name = "doStuffX")
        public void doStuff2() {
        }

        @SuppressWarnings("unused")
        public void doStuff3() {
        }

        public abstract void doStuff4();

        @Id
        public String getId1() {
            return null;
        }

        @Id
        public String getId2() {
            return null;
        }

    }

    private static abstract class TestGenerateClass1 extends TestProxyMethodsClass
            implements TestGenerateInterface1 {
    }

    private static abstract class TestGenerateClass2 extends TestProxyMethodsClass
            implements TestGenerateInterface2 {
    }

    private static class TestGenerateStubFunction1 {

        @SuppressWarnings("unused")
        public TestGenerateStubFunction1() {
            if (_log.isInfoEnabled()) {
                _log.info(TestGenerateStubFunction1.class.getName() + " in <init>");
            }
        }

        private static final Log _log = LogFactoryUtil.getLog(TestGenerateStubFunction1.class);

        static {
            if (_log.isInfoEnabled()) {
                _log.info(TestGenerateStubFunction1.class.getName() + " in <clinit>");
            }
        }

    }

    private static abstract class TestGenerateStubFunction2 extends TestProxyMethodsClass
            implements TestEmptyMethodsInterface, TestIdMethodsInterface {

        @SuppressWarnings("unused")
        public void copyMethod1() {
            if (_log.isInfoEnabled()) {
                _log.info("copyMethod1");
            }
        }

        @SuppressWarnings("unused")
        protected void copyMethod2() {
            if (_log.isInfoEnabled()) {
                _log.info("copyMethod2");
            }
        }

        @SuppressWarnings("unused")
        void copyMethod3() {
            if (_log.isInfoEnabled()) {
                _log.info("copyMethod3");
            }
        }

        @SuppressWarnings("unused")
        private void copyMethod4() {
            if (_log.isInfoEnabled()) {
                _log.info("copyMethod4");
            }
        }

        private static final Log _log = LogFactoryUtil.getLog(TestGenerateStubFunction2.class);

    }

    private static class TestGenerateTargetLocator implements TargetLocator {

        public TestGenerateTargetLocator(Class<?> clazz) {
            _clazz = clazz;
        }

        @Override
        public boolean equals(Object obj) {
            TestGenerateTargetLocator testGenerateTargetLocator = (TestGenerateTargetLocator) obj;

            return _clazz.equals(testGenerateTargetLocator._clazz);
        }

        @SuppressWarnings("unused")
        public String getId() {
            return _id;
        }

        @Override
        public Object getTarget(String id) {
            _id = id;

            return ProxyUtil.newProxyInstance(_classLoader, new Class<?>[] { _clazz }, new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) {

                    Class<?>[] parameterTypes = method.getParameterTypes();

                    for (int i = 0; i < args.length; i++) {
                        Assert.assertEquals(_sampleValueMap.get(parameterTypes[i]), args[i]);
                    }

                    return _sampleValueMap.get(method.getReturnType());
                }

            });
        }

        @Override
        public int hashCode() {
            return super.hashCode();
        }

        private final Class<?> _clazz;
        private String _id;

    }

    private static abstract class TestProxyMethodsClass implements TestProxyMethodsInterface {

        @Proxy
        protected abstract short syncCallShort(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        abstract Object syncCallObject(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        abstract String syncCallString(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

    }

    private static class TestValidateClass {

        @SuppressWarnings("unused")
        private static String _PROXY_METHODS_MAPPING;

        @SuppressWarnings("unused")
        private static String[] PROXY_METHOD_SIGNATURES;

        @SuppressWarnings("unused")
        private static Log _log;

        @SuppressWarnings("unused")
        private static byte _proxyType;

        @SuppressWarnings("unused")
        private ExceptionHandler _exceptionHandler;

        @SuppressWarnings("unused")
        private String _id;

        @SuppressWarnings("unused")
        private Intraband _intraband;

        @SuppressWarnings("unused")
        private RegistrationReference _registrationReference;

        @SuppressWarnings("unused")
        private TargetLocator _targetLocator;

    }

    private interface TestEmptyMethodsInterface {

        public boolean testBoolean();

        public byte testByte();

        public char testChar();

        public double testDouble();

        public float testFloat();

        public int testInt();

        public long testLong();

        public Object testObject();

        public short testShort();

        public void testVoid();

    }

    private interface TestGenerateInterface1 extends Comparable<String>, Callable<String>, Runnable,
            TestEmptyMethodsInterface, TestProxyMethodsInterface {
    }

    private interface TestGenerateInterface2 extends TestIdMethodsInterface, TestGenerateInterface1 {
    }

    private interface TestIdMethodsInterface {

        @Id
        public abstract String getId1();

        @Id
        public abstract String getId2();

    }

    private interface TestProxyMethodsInterface {

        @Proxy
        public void asyncCall(boolean z, byte b, char c, double d, float f, int i, long j, short s, String string,
                Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public boolean syncCallBoolean(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public byte syncCallByte(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public char syncCallChar(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public double syncCallDouble(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public float syncCallFloat(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public int syncCallInt(boolean z, byte b, char c, double d, float f, int i, long j, short s, String string,
                Date date, Object obj) throws InterruptedException, IOException;

        @Proxy
        public long syncCallLong(boolean z, byte b, char c, double d, float f, int i, long j, short s,
                String string, Date date, Object obj) throws InterruptedException, IOException;

    }

}