Package com.peterhi.runtime

Source Code of com.peterhi.runtime.RT

package com.peterhi.runtime;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Array;
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.lang.reflect.Proxy;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

import com.peterhi.net.Protocol;
import com.peterhi.schemata.common.LanguageString;
import com.peterhi.schemata.common.LanguageStringItem;

public class RT {
 
  public static final int VAR_INT_SHIFT = 2;
 
  public static final int INT6_SERIAL_ID = 0;
  public static final int INT14_SERIAL_ID = 1;
  public static final int INT30_SERIAL_ID = 2;
  public static final int INT62_SERIAL_ID = 3;

  public static final int INT6_FULL_LENGTH = 8;
  public static final int INT14_FULL_LENGTH = 16;
  public static final int INT30_FULL_LENGTH = 32;
  public static final int INT62_FULL_LENGTH = 64;
 
  public static final int INT6_DATA_LENGTH = INT6_FULL_LENGTH - 2;
  public static final int INT14_DATA_LENGTH = INT14_FULL_LENGTH - 2;
  public static final int INT30_DATA_LENGTH = INT30_FULL_LENGTH - 2;
  public static final int INT62_DATA_LENGTH = INT62_FULL_LENGTH - 2;

  public static final long INT6_MAX_SIGNED = (long )(Math.pow(2, INT6_DATA_LENGTH - 1) - 1);
  public static final long INT14_MAX_SIGNED = (long )(Math.pow(2, INT14_DATA_LENGTH - 1) - 1);
  public static final long INT30_MAX_SIGNED = (long )(Math.pow(2, INT30_DATA_LENGTH - 1) - 1);
  public static final long INT62_MAX_SIGNED = (long )(Math.pow(2, INT62_DATA_LENGTH - 1) - 1);
 
  public static final long INT6_MASK = INT6_MAX_SIGNED;
  public static final long INT14_MASK = INT14_MAX_SIGNED;
  public static final long INT30_MASK = INT30_MAX_SIGNED;
  public static final long INT62_MASK = INT62_MAX_SIGNED;
 
  public static final long INT6_MAX_UNSIGNED = (long )(Math.pow(2, INT6_DATA_LENGTH - 0) - 1);
  public static final long INT14_MAX_UNSIGNED = (long )(Math.pow(2, INT14_DATA_LENGTH - 0) - 1);
  public static final long INT30_MAX_UNSIGNED = (long )(Math.pow(2, INT30_DATA_LENGTH - 0) - 1);
  public static final long INT62_MAX_UNSIGNED = (long )(Math.pow(2, INT62_DATA_LENGTH - 0) - 1);
 
  public static final long INT6_MIN = (long )(-Math.pow(2, INT6_DATA_LENGTH - 1));
  public static final long INT14_MIN = (long)(-Math.pow(2, INT14_DATA_LENGTH - 1));
  public static final long INT30_MIN = (long )(-Math.pow(2, INT30_DATA_LENGTH - 1));
  public static final long INT62_MIN = (long )(-Math.pow(2, INT62_DATA_LENGTH - 1));
 
 
 
 
 
 
  public static final int RT_NULL = 0;
  public static final int RT_SINGLE = 64;
  public static final int RT_MULTI = 128;
 
  public static final int RST_BOOLEAN = 1;
  public static final int RST_BYTE = 2;
  public static final int RST_CHARACTER = 3;
  public static final int RST_SHORT = 4;
  public static final int RST_INTEGER = 5;
  public static final int RST_LONG = 6;
  public static final int RST_FLOAT = 7;
  public static final int RST_DOUBLE = 8;
  public static final int RST_STRING = 9;
  public static final int RST_PROTOCOL = 10;
  public static final int RST_BOOLEANS = 11;
  public static final int RST_BYTES = 12;
  public static final int RST_CHARS = 13;
  public static final int RST_SHORTS = 14;
  public static final int RST_INTS = 15;
  public static final int RST_LONGS = 16;
  public static final int RST_FLOATS = 17;
  public static final int RST_DOUBLES = 18;
 
  public static Field[] fields(Class<?> type, String name) {
    if (type == null) {
      throw new NullPointerException();
    }
   
    if (name == null) {
      throw new NullPointerException();
    }
   
    if (name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    List<Field> allFieldList = new ArrayList<Field>();
    Field[] fieldArray = type.getFields();
    Field[] declaredFieldArray = type.getDeclaredFields();
   
    for (Field field : fieldArray) {
      String fieldName = field.getName();
      boolean same = fieldName.equals(name);
     
      if (!same) {
        continue;
      }

      allFieldList.add(field);
    }
   
    for (Field declaredField : declaredFieldArray) {
      String declaredFieldName = declaredField.getName();
      boolean same = declaredFieldName.equals(name);
     
      if (!same) {
        continue;
      }
     
      allFieldList.add(declaredField);
    }
   
    Field[] allFieldArray = new Field[allFieldList.size()];
    allFieldArray = allFieldList.toArray(allFieldArray);
   
    Arrays.sort(allFieldArray, new Comparator<Field>() {
      @Override
      public int compare(Field field, Field otherField) {
        if (field == null && otherField == null) {
          return 0;
        }
       
        if (field == null) {
          return -1;
        }
       
        if (otherField == null) {
          return 1;
        }
       
        String fieldName = field.getName();
        String otherFieldName = otherField.getName();
        return fieldName.compareTo(otherFieldName);
      }
    });
   
    return allFieldArray;
  }
 
  public static Method[] methods(Class<?> type, String name) {
    if (type == null) {
      throw new NullPointerException();
    }
   
    if (name == null) {
      throw new NullPointerException();
    }
   
    if (name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    List<Method> allMethodList = new ArrayList<Method>();
    Method[] methodArray = type.getMethods();
    Method[] declaredMethodArray = type.getDeclaredMethods();
   
    for (Method method : methodArray) {
      String methodName = method.getName();
      boolean same = methodName.equals(name);
     
      if (!same) {
        continue;
      }
     
      allMethodList.add(method);
    }
   
    for (Method declaredMethod : declaredMethodArray) {
      String declaredMethodName = declaredMethod.getName();
      boolean same = declaredMethodName.equals(name);
     
      if (!same) {
        continue;
      }
     
      allMethodList.add(declaredMethod);
    }
   
    Method[] allMethodArray = new Method[allMethodList.size()];
    allMethodArray = allMethodList.toArray(allMethodArray);
   
    Arrays.sort(allMethodArray, new Comparator<Method>() {
      @Override
      public int compare(Method method, Method otherMethod) {
        if (method == null && otherMethod == null) {
          return 0;
        }
       
        if (method == null) {
          return -1;
        }
       
        if (otherMethod == null) {
          return 1;
        }
       
        String methodName = method.getName();
        String otherMethodName = otherMethod.getName();
        return methodName.compareTo(otherMethodName);
      }
    });
   
    return allMethodArray;
  }
 
  public static Object call(String name, Class<?> type, Object...paramTypesAndArgs)
    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    return call(type, false, name, paramTypesAndArgs);
  }
 
  public static Object call(Object target, String name, Object...paramTypesAndArgs)
    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    return call(target, true, name, paramTypesAndArgs);
  }
 
  public static Object call(Object target, boolean instance, String name, Object...paramTypesAndArgs)
    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    if (target == null) {
      throw new NullPointerException();
    }
   
    if (name == null) {
      throw new NullPointerException();
    }
   
    if (paramTypesAndArgs == null) {
      throw new NullPointerException();
    }
   
    Class<?> type;
   
    if (instance) {
      type = target.getClass();
    } else {
      if (target instanceof Class<?>) {
        type = (Class<?> )target;
      } else {
        throw new ClassCastException();
      }
    }
   
    if (name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    int quotient = paramTypesAndArgs.length / 2;
    int remainder = paramTypesAndArgs.length % 2;
   
    if (remainder != 0) {
      throw new IllegalArgumentException();
    }
   
    List<Class<?>> paramTypeList = new ArrayList<Class<?>>();
    List<Object> paramArgList = new ArrayList<Object>();
   
    for (int i = 0; i < quotient; i++) {
      Class<?> paramType = (Class<?> )paramTypesAndArgs[i * 2 + 0];
      Object paramArg = paramTypesAndArgs[i * 2 + 1];
     
      if (paramType == null) {
        throw new IllegalArgumentException();
      }
     
      paramTypeList.add(paramType);
      paramArgList.add(paramArg);
    }

    Class<?>[] paramTypeArray = new Class<?>[paramTypeList.size()];
    Object[] paramArgArray = new Object[paramArgList.size()];
    paramTypeArray = paramTypeList.toArray(paramTypeArray);
    paramArgArray = paramArgList.toArray(paramArgArray);
   
    Method[] methods = methods(type, name);
    Method method = null;
   
    for (int i = 0; i < methods.length; i++) {
      int modifiers = methods[i].getModifiers();
      boolean classifier = Modifier.isStatic(modifiers);
      boolean valid = instance != classifier;
     
      if (!valid) {
        continue;
      }
     
      Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
      boolean signature = Arrays.equals(methodParamTypeArray, paramTypeArray);
     
      if (!signature) {
        continue;
      }
     
      method = methods[i];
      break;
    }
   
    if (method == null) {
      throw new NoSuchMethodException();
    }
   
    Object param;
   
    if (instance) {
      param = target;
    } else {
      param = null;
    }
   
    Object value = method.invoke(param, paramArgArray);
    return value;
  }
 
  public static Object get(Object target, String name)
    throws IllegalAccessException, InvocationTargetException {
    return get(target, true, name);
  }
 
  public static Object get(String name, Class<?> type)
    throws IllegalAccessException, InvocationTargetException {
    return get(type, false, name);
  }
 
  public static Object get(Object target, boolean instance, String name)
    throws IllegalAccessException, InvocationTargetException {
    if (target == null) {
      throw new NullPointerException();
    }

    if (name == null) {
      throw new NullPointerException();
    }
   
    Class<?> type;
   
    if (instance) {
      type = target.getClass();
    } else {
      if (target instanceof Class<?>) {
        type = (Class<?> )target;
      } else {
        throw new ClassCastException();
      }
    }
   
    if (name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    Method method = null;
   
    {
      StringBuilder builder = new StringBuilder();
      builder.append("is");
      builder.append(Character.toUpperCase(name.charAt(0)));
      builder.append(name, 1, name.length());
      Method[] methods = methods(type, builder.toString());
     
      for (int i = 0; i < methods.length; i++) {
        int modifiers = methods[i].getModifiers();
        boolean classifier = Modifier.isStatic(modifiers);
        boolean valid = instance != classifier;
       
        if (!valid) {
          continue;
        }

        Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
        Class<?> methodReturnType = methods[i].getReturnType();
       
        if (methodParamTypeArray.length != 0) {
          continue;
        }
       
        if (methodReturnType == void.class) {
          continue;
        }
       
        if (methodReturnType == Void.class) {
          continue;
        }
       
        method = methods[i];
        break;
      }
    }
   
    if (method == null) {
      StringBuilder builder = new StringBuilder();
      builder.append("get");
      builder.append(Character.toUpperCase(name.charAt(0)));
      builder.append(name, 1, name.length());
      Method[] methods = methods(type, builder.toString());
     
      for (int i = 0; i < methods.length; i++) {
        int modifiers = methods[i].getModifiers();
        boolean classifier = Modifier.isStatic(modifiers);
        boolean valid = instance != classifier;
       
        if (!valid) {
          continue;
        }
       
        Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
        Class<?> methodReturnType = methods[i].getReturnType();
       
        if (methodParamTypeArray.length != 0) {
          continue;
        }
       
        if (methodReturnType == void.class) {
          continue;
        }
       
        if (methodReturnType == Void.class) {
          continue;
        }
       
        method = methods[i];
        break;
      }
    }
   
    if (method == null) {
      Method[] methods = methods(type, name);
     
      for (int i = 0; i < methods.length; i++) {
        int modifiers = methods[i].getModifiers();
        boolean classifier = Modifier.isStatic(modifiers);
        boolean valid = instance != classifier;
       
        if (!valid) {
          continue;
        }
       
        Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
        Class<?> methodReturnType = methods[i].getReturnType();
       
        if (methodParamTypeArray.length != 0) {
          continue;
        }
       
        if (methodReturnType == void.class) {
          continue;
        }
       
        if (methodReturnType == Void.class) {
          continue;
        }
       
        method = methods[i];
        break;
      }
    }
   
    Object param;
   
    if (instance) {
      param = target;
    } else {
      param = null;
    }

    Object value = null;
    boolean direct = (method == null);
   
    if (!direct) {
      try {
        value = method.invoke(param);
      } catch (IllegalAccessException ex) {
        direct = true;
      }
    }
   
    if (direct) {
      Field[] fields = fields(type, name);
      boolean accessed = false;
     
      for (Field field : fields) {
        try {
          value = field.get(param);
          accessed = true;
          break;
        } catch (IllegalAccessException innerEx) {
          continue;
        }
      }
     
      if (!accessed) {
        throw new IllegalAccessException();
      }
    }
   
    return value;
  }
 
  public static void set(Object target, String name, Object value)
    throws IllegalAccessException, InvocationTargetException {
    set(target, true, name, value);
  }
 
  public static void set(String name, Class<?> type, Object value)
    throws IllegalAccessException, InvocationTargetException {
    set(type, false, name, value);
  }
 
  public static void set(Object target, boolean instance, String name, Object value)
    throws IllegalAccessException, InvocationTargetException {
    if (target == null) {
      throw new NullPointerException();
    }
   
    if (name == null) {
      throw new NullPointerException();
    }
   
    Class<?> type;
   
    if (instance) {
      type = target.getClass();
    } else {
      if (target instanceof Class<?>) {
        type = (Class<?> )target;
      } else {
        throw new ClassCastException();
      }
    }
   
    if (name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    Method method = null;
   
    {
      StringBuilder builder = new StringBuilder();
      builder.append("set");
      builder.append(Character.toUpperCase(name.charAt(0)));
      builder.append(name, 1, name.length());
      Method[] methods = methods(type, builder.toString());
     
      for (int i = 0; i < methods.length; i++) {
        int modifiers = methods[i].getModifiers();
        boolean classifier = Modifier.isStatic(modifiers);
        boolean valid = instance != classifier;
       
        if (!valid) {
          continue;
        }
       
        Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
        Class<?> methodReturnType = methods[i].getReturnType();
       
        if (methodParamTypeArray.length != 1) {
          continue;
        }
       
        if (methodReturnType != void.class) {
          if (methodReturnType != Void.class) {
            continue;
          }
        }
       
        method = methods[i];
        break;
      }
    }
   
    if (method == null) {
      Method[] methods = methods(type, name);
     
      for (int i = 0; i < methods.length; i++) {
        int modifiers = methods[i].getModifiers();
        boolean classifier = Modifier.isStatic(modifiers);
        boolean valid = instance != classifier;
       
        if (!valid) {
          continue;
        }
       
        Class<?>[] methodParamTypeArray = methods[i].getParameterTypes();
        Class<?> methodReturnType = methods[i].getReturnType();
       
        if (methodParamTypeArray.length != 0) {
          continue;
        }
       
        if (methodReturnType != void.class) {
          if (methodReturnType != Void.class) {
            continue;
          }
        }
       
        method = methods[i];
        break;
      }
    }
   
    Object param;
   
    if (instance) {
      param = target;
    } else {
      param = null;
    }
   
    boolean direct = (method == null);
   
    if (!direct) {
      try {
        method.invoke(param, value);
      } catch (IllegalAccessException ex) {
        direct = true;
      }
    }
   
    if (direct) {
      Field[] fields = fields(type, name);
      boolean modified = false;
     
      for (Field field : fields) {
        try {
          field.set(param, value);
          modified = true;
          break;
        } catch (IllegalAccessException innerEx) {
          continue;
        }
      }
     
      if (!modified) {
        throw new IllegalAccessException();
      }
    }
  }
 
  public static Object defaultInvoke(Class<?> type, Object proxy, Method method, Object[] args) throws Exception {
    if (method.getDeclaringClass() == Object.class) {
      if (method.getReturnType() == int.class &&
        method.getName().equals("hashCode") &&
        method.getParameterTypes().length == 0) {
        return System.identityHashCode(proxy);
      } else if (method.getReturnType() == boolean.class &&
             method.getName().equals("equals") &&
             method.getParameterTypes().length == 1 &&
             method.getParameterTypes()[0] == Object.class) {
        int hashCode = proxy.hashCode();
        int otherHashCode = args[0] == null ? 0 : args[0].hashCode();
        return hashCode == otherHashCode;
      } else if (method.getReturnType() == String.class &&
             method.getName().equals("toString") &&
             method.getParameterTypes().length == 0) {
        int hashCode = proxy.hashCode();
        String hexHashCode = Integer.toHexString(hashCode);
        return MessageFormat.format(Constants.PATTERN_TO_STRING, type.getName(), hexHashCode);
      }
    }
   
    throw new UnsupportedOperationException();
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  public static URL getClassResource(Class<?> type, String suffix) {
    if (type == null) {
      throw new NullPointerException();
    }
   
    if (suffix == null) {
      suffix = "";
    }
   
    StringBuilder builder = new StringBuilder();
    builder.append('/');
   
    String name = type.getName();
    name = name.replaceAll("\\.", "/");
    builder.append(name);
   
    if (!suffix.startsWith(".")) {
      builder.append(".");
    }
   
    builder.append(suffix);
 
    String path = builder.toString();
    return type.getResource(path);
  }
 
  public static void checkForNull(Object object) throws NullPointerException {
    if (object == null) {
      throw new NullPointerException("Object is null.");
    }
  }
 
  public static void checkForEmpty(Object array) throws NullPointerException, IllegalArgumentException {
    checkForNull(array);
   
    int length = Array.getLength(array);
   
    if (length <= 0) {
      throw new IllegalArgumentException("Array length is zero or less.");
    }
  }
 
  public static void checkForInvalid(int index, int length) throws IllegalArgumentException {
    if (index < 0) {
      throw new IllegalArgumentException("Index is negative.");
    }
   
    if (length <= 0) {
      throw new IllegalArgumentException("Length is zero or less.");
    }
  }
 
  public static void checkBuffer(byte[] buffer, int offset, int length) throws NullPointerException, IllegalArgumentException {
    checkForEmpty(buffer);
    checkForInvalid(offset, length);
   
    if (offset + length > buffer.length) {
      throw new IllegalArgumentException("Index + length is greater than array length.");
    }
  }
 
  public static boolean equals(Object object, Object other) {
    if (object == other) {
      return true;
    }
   
    if (object != null) {
      return object.equals(other);
    } else {
      return other.equals(object);
    }
  }
 
  public static URL getSystemFile(String name) throws IOException {
    if (name == null || name.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    File dir = new File(System.getProperty("user.dir"));
   
    if (!dir.exists()) {
      try {
        dir = new File(RT.class.getProtectionDomain().getCodeSource().getLocation().toURI());
      } catch (URISyntaxException ex) {
        throw new IOException(ex);
      }
    }
   
    File file = new File(dir, name);
   
    if (!file.exists()) {
      throw new FileNotFoundException();
    }
   
    return file.toURI().toURL();
  }
 
  public static String getLanguageString(LanguageString languageString, Locale locale) {
    if (languageString == null) {
      throw new NullPointerException();
    }
   
    if (locale == null) {
      locale = Locale.getDefault();
    }
   
    LanguageStringItem[] languageStringItems = languageString.getLanguageStringItemArray();
   
    if (languageStringItems == null || languageStringItems.length == 0) {
      throw new IllegalArgumentException();
    }
   
    for (LanguageStringItem languageStringItem : languageStringItems) {
      String language = languageStringItem.getLanguage();
      String[] components = language.split("_");
     
      if (locale.equals(new Locale(components[0], components[1]))) {
        return languageStringItem.newCursor().getTextValue();
      }
    }
   
    return languageStringItems[0].newCursor().getTextValue();
  }
 
  public static String getLanguageString(LanguageString languageString) {
    return getLanguageString(languageString, Locale.getDefault());
  }
 
  public static <T extends StringResource> T getStringResource(Class<T> type) {
    if (type == null) {
      throw new NullPointerException();
    }
   
    InvocationHandler invocationHandler = new StringResourceInvocationHandler(type);
    Class<?>[] interfaces = new Class<?>[] { type };
    ClassLoader loader = type.getClassLoader();
    Object object = Proxy.newProxyInstance(loader, interfaces, invocationHandler);
    return type.cast(object);
  }
 
  public static Comparator<Class<?>> getClassNameComparator() {
    return ClassNameComparator.getInstance();
  }
 
  public static Comparator<Method> getMethodNameComparator() {
    return MethodNameComparator.getInstance();
  }
 
  public static boolean isFlagged(int[] pointer, int flags, boolean exact) {
    if (pointer == null) {
      throw new NullPointerException();
    }
   
    if (pointer.length != 1) {
      throw new IllegalArgumentException();
    }
   
    if (flags == 0) {
      throw new IllegalArgumentException();
    }
   
    if (exact) {
      return pointer[0] == flags;
    }
   
    return (pointer[0] & flags) == flags;
  }
 
  public static boolean isFlagged(int value, int flags, boolean exact) {
    int[] pointer = new int[] { value };
    return isFlagged(pointer, flags, exact);
  }
 
  public static boolean isFlagged(int[] pointer, int flags) {
    return isFlagged(pointer, flags, false);
  }
 
  public static boolean isFlagged(int value, int flags) {
    return isFlagged(value, flags, false);
  }

  public static boolean addFlags(int[] pointer, int flags) {
    if (isFlagged(pointer, flags)) {
      return false;
    }
   
    pointer[0] |= flags;
    return true;
  }
 
  public static boolean removeFlags(int[] pointer, int flags) {
    if (!isFlagged(pointer, flags)) {
      return false;
    }
   
    pointer[0] &= ~flags;
    return true;
  }
 
  public static boolean flipFlags(int[] pointer, int flags) {
    if (pointer == null) {
      throw new NullPointerException();
    }
   
    if (pointer.length != 1) {
      throw new IllegalArgumentException();
    }

    int absentFlagsToAdd = (pointer[0] ^ flags);
    int presentFlagsToRemove = (pointer[0] & flags);
   
    if (absentFlagsToAdd == 0 && presentFlagsToRemove == 0) {
      return false;
    }

    if (absentFlagsToAdd != 0) {
      addFlags(pointer, absentFlagsToAdd);
    }
   
    if (presentFlagsToRemove != 0) {
      removeFlags(pointer, presentFlagsToRemove);
    }
   
    return true;
  }
 
  public static <T> T newLocalProtocol(Class<T> protocolType) throws InstantiationException {
    if (protocolType == null) {
      throw new NullPointerException();
    }
   
    if (!Protocol.class.isAssignableFrom(protocolType)) {
      throw new IllegalArgumentException();
    }
   
    Abstract annotation = protocolType.getAnnotation(Abstract.class);
   
    if (annotation != null) {
      throw new InstantiationException(MessageFormat.format("{0} is annotated as \"abstract\"", protocolType));
     
    }
   
    InvocationHandler invocationHandler = new ProtocolInvocationHandler(protocolType);
    Object protocol = Proxy.newProxyInstance(protocolType.getClassLoader(), new Class<?>[] { protocolType }, invocationHandler);
    return protocolType.cast(protocol);
  }
 
  public static byte[] serializeProtocol(Protocol protocol) throws IOException {
    if (protocol == null) {
      throw new NullPointerException();
    }
   
    ProtocolInvocationHandler pih = (ProtocolInvocationHandler )Proxy.getInvocationHandler(protocol);
    final Class<?> protocolType = pih.getProtocolType();
    String protocolTypeName = protocolType.getName();
    final String protocolTypeSimpleName = protocolType.getSimpleName();
    final String protocolTypePrefix = protocolTypeName.substring(0, protocolTypeName.length() - protocolTypeSimpleName.length());
   
//    Comparator<Class<?>> keyComparator = new Comparator<Class<?>>() {
//      @Override
//      public int compare(Class<?> class0, Class<?> class1) {
//        String className0 = class0.getName();
//        String className1 = class1.getName();
//        return className0.compareTo(className1);
//      }
//    };
   
    Comparator<Class<?>> classComparator = new Comparator<Class<?>>() {
      @Override
      public int compare(Class<?> class0, Class<?> class1) {
        if (class0 == class1) {
          return 0;
        }
       
        if (class0 == protocolType) {
          return -1;
        }
       
        if (class1 == protocolType) {
          return 1;
        }
       
        String name0 = class0.getName();
        String simple0 = class0.getSimpleName();
        String prefix0 = name0.substring(0, name0.length() - simple0.length());
       
        String name1 = class1.getName();
        String simple1 = class1.getSimpleName();
        String prefix1 = name1.substring(0, name1.length() - simple1.length());
       
        if (prefix0.equals(prefix1)) {
          if (simple0.equals(protocolTypeSimpleName)) {
            return -1;
          } else if (simple1.equals(protocolTypeSimpleName)) {
            return 1;
          } else {
            return name0.compareTo(name1);
          }
        } else {
          if (prefix0.equals(protocolTypePrefix)) {
            return -1;
          } else if (prefix1.equals(protocolTypePrefix)) {
            return 1;
          } else {
            return name0.compareTo(name1);
          }
        }
      }
    };
   
//    SortedMap<Class<?>, SortedSet<Protocol>> protocolObjectMap = new TreeMap<Class<?>, SortedSet<Protocol>>(keyComparator);
//    fillProtocolObjectMap(protocol, protocolObjectMap);
   
    SortedMap<Class<?>, SortedSet<Protocol>> protocolObjectMap2 = new TreeMap<Class<?>, SortedSet<Protocol>>(classComparator);
    fillProtocolObjectMap(protocol, protocolObjectMap2);
   
    StringBuilder expr = new StringBuilder();
    String lastExpr = null;
   
    for (Class<?> type : protocolObjectMap2.keySet()) {
      String name = type.getName();
      String simpleName = type.getSimpleName();
      String prefix = name.substring(0, name.length() - simpleName.length());
     
      if (prefix.equals(lastExpr)) {
        expr.append(',');
        expr.append(simpleName);
      } else {
        if (lastExpr != null) {
          expr.append(';');
        }
       
        expr.append(name);
        lastExpr = prefix;
      }
    }
   
    System.out.println(expr);
 
//    SortedMap<String, SortedSet<String>> typeNameMap = new TreeMap<String, SortedSet<String>>();
//   
//    for (Class<?> type : protocolObjectMap.keySet()) {
//      String typeName = type.getName();
//      String simpleTypeName = type.getSimpleName();
//      String commonTypeNamePrefix = typeName.substring(0, typeName.length() - simpleTypeName.length());
//      SortedSet<String> simpleTypeNameSet = getSimpleTypeNameSet(typeNameMap, commonTypeNamePrefix);
//      simpleTypeNameSet.add(simpleTypeName);
//    }
   
    MemoryStream ms = new MemoryStream();
   
//    StringBuilder typeNameExpr = new StringBuilder();
//    boolean key1st = true;
//    List<Class<?>> typeList = new ArrayList<Class<?>>();
//   
//    for (String commonTypeNamePrefix : typeNameMap.keySet()) {
//      if (key1st) {
//        key1st = false;
//      } else {
//        typeNameExpr.append(';');
//      }
//     
//      SortedSet<String> simpleTypeNameSet = typeNameMap.get(commonTypeNamePrefix);
//      boolean val1st = true;
//     
//      for (String simpleTypeName : simpleTypeNameSet) {
//        if (val1st) {
//          val1st = false;
//          typeNameExpr.append(commonTypeNamePrefix);
//          typeNameExpr.append(simpleTypeName);
//        } else {
//          typeNameExpr.append(',');
//          typeNameExpr.append(simpleTypeName);
//        }
//       
//        try {
//          typeList.add(Class.forName(commonTypeNamePrefix + simpleTypeName));
//        } catch (ClassNotFoundException ex) {
//          throw new RuntimeException(ex);
//        }
//      }
//    }
//   
//    ms.writeLength(new Length(typeNameExpr.length()));
//    ms.writeBytes(typeNameExpr.toString());
   
    ms.writeLength(new Length(expr.length()));
    ms.writeBytes(expr.toString());
   
    for (Class<?> type : protocolObjectMap2.keySet()) {
      ms.writeLength(new Length(protocolObjectMap2.get(type).size()));
    }
   
//    for (Class<?> type : typeList) {
//      ms.writeLength(new Length(protocolObjectMap.get(type).size()));
//    }
   
    List<Protocol> protocolsInOrder = new ArrayList<Protocol>();
    Set<Protocol> serializedProtocols = new HashSet<Protocol>();
   
//    for (Class<?> type : typeList) {
//      SortedSet<Protocol> protocolObjectSet = protocolObjectMap.get(type);
//     
//      for (Protocol protocolObject : protocolObjectSet) {
//        protocolsInOrder.add(protocolObject);
//      }
//    }
   
//    protocolsInOrder.remove(protocol);
//    protocolsInOrder.add(0, protocol);
   
    for (Class<?> type : protocolObjectMap2.keySet()) {
      SortedSet<Protocol> values = protocolObjectMap2.get(type);
     
      for (Protocol value : values) {
        protocolsInOrder.add(value);
      }
    }
   
    for (Class<?> type : protocolObjectMap2.keySet()) {
      SortedSet<Protocol> values = protocolObjectMap2.get(type);
     
      for (Protocol value : values) {
        writeObject(ms, type, value, protocolsInOrder, serializedProtocols, false);
      }
    }
   
    protocolsInOrder.remove(protocol);
    protocolsInOrder.add(0, protocol);
   
    for (Protocol protocolInOrder : protocolsInOrder) {
      ProtocolInvocationHandler h = (ProtocolInvocationHandler )Proxy.getInvocationHandler(protocolInOrder);
      writeObject(ms, h.getProtocolType(), protocolInOrder, protocolsInOrder, serializedProtocols, false);
    }
   
//    ms.writeLength(new Length(protocolsInOrder.indexOf(protocol)));
   
    byte[] bytes = new byte[ms.available()];
    ms.readFully(bytes);
    return bytes;
  }
 
  private static void writeObject(MemoryStream ms, Class<?> type, Object object, List<Protocol> protocolsInOrder, Set<Protocol> serializedProtocols, boolean writeRefOnly) throws IOException {
    if (Protocol.class.isAssignableFrom(type)) {
      if (writeRefOnly) {
        int index = protocolsInOrder.indexOf(object);
       
        if (object == null || index < 0) {
          ms.writeLength(new Length(0));
        } else {
          ms.writeLength(new Length(index + 1));
        }
      } else {
        Protocol protocol = (Protocol )object;
       
        serializedProtocols.add(protocol);
       
        ProtocolInvocationHandler pih = (ProtocolInvocationHandler )Proxy.getInvocationHandler(object);
        Map<String, Object> propertyMap = pih.getPropertyMap();
       
        for (String key : propertyMap.keySet()) {
          Method[] methods = type.getMethods();
         
          String get = "get" + Character.toUpperCase(key.charAt(0)) + key.substring(1);
          String is = "is" + Character.toUpperCase(key.charAt(0)) + key.substring(1);
          String coll = key;

          Method theMethod = null;
         
          for (Method method : methods) {
            if (method.getName().equals(get) || method.getName().equals(is)) {
              theMethod = method;
            } else if (method.getName().equals(coll) && (method.getReturnType() == ProtocolSet.class ||
              method.getReturnType() == ProtocolList.class || method.getReturnType() == ProtocolMap.class)) {
              theMethod = method;
            }
          }
         
          if (theMethod == null) {
            throw new IOException("Object is corrupted: unknown method for property '" + key + "'");
          }
         
          Class<?> theType = theMethod.getReturnType();
         
          try {
            Object theValue = theMethod.invoke(protocol);
            writeObject(ms, theType, theValue, protocolsInOrder, serializedProtocols, true);
          } catch (Exception ex) {
            throw new IOException(ex);
          }
        }
      }
    } else if (type == boolean.class) {
      ms.writeBoolean(object == null ? false : (Boolean )object);
    } else if (type == byte.class) {
      ms.writeByte(object == null ? (byte )0 : (Byte )object);
    } else if (type == char.class) {
      ms.writeChar(object == null ? '\0' : (Character )object);
    } else if (type == short.class) {
      ms.writeShort(object == null ? (short )0 : (Short )object);
    } else if (type == int.class) {
      ms.writeInt(object == null ? 0 : (Integer )object);
    } else if (type == long.class) {
      ms.writeLong(object == null ? 0L : (Long )object);
    } else if (type == float.class) {
      ms.writeFloat(object == null ? 0.0f : (Float )object);
    } else if (type == double.class) {
      ms.writeDouble(object == null ? 0.0 : (Double )object);
    } else if (type == Boolean.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeBoolean((Boolean )object);
      }
    } else if (type == Byte.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeByte((Byte )object);
      }
    } else if (type == Character.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeChar((Character )object);
      }
    } else if (type == Short.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeShort((Short )object);
      }
    } else if (type == Integer.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeInt((Integer )object);
      }
    } else if (type == Long.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeLong((Long )object);
      }
    } else if (type == Float.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeFloat((Float )object);
      }
    } else if (type == Double.class) {
      ms.writeBoolean(object != null);
     
      if (object != null) {
        ms.writeDouble((Double )object);
      }
    } else if (type == boolean[].class) {
      if (object == null) {
        ms.writeLength(new Length(0));
      } else {
        boolean[] array = (boolean[] )object;
        ms.writeLength(new Length(array.length + 1));
        ms.writeBooleans(array);
      }
    } else if (type == byte[].class) {
      if (object == null) {
        ms.writeLength(new Length(0));
      } else {
        byte[] array = (byte[] )object;
        ms.writeLength(new Length(array.length + 1));
        ms.write(array);
      }
    } else if (type.isArray()) {
      if (object == null) {
        ms.writeLength(new Length(0));
      } else {
        int length = Array.getLength(object);
        ms.writeLength(new Length(length + 1));
       
        for (int i = 0; i < length; i++) {
          writeObject(ms, type.getComponentType(), Array.get(object, i), protocolsInOrder, serializedProtocols, true);
        }
      }
    } else if (type == String.class) {
      if (object == null) {
        ms.writeLength(new Length(0));
      } else {
        String string = (String )object;
        ms.writeLength(new Length(string.length() + 1));
        ms.writeUTFBase(string, string.length());
      }
    } else if (type == ProtocolSet.class || type == ProtocolList.class) {
      ProtocolSet set = (ProtocolSet )object;
      ms.writeLength(new Length(set.size()));
     
      Object[] array = set.toArray();
     
      for (Object item : array) {
        writeObject(ms, Object.class, item, protocolsInOrder, serializedProtocols, true);
      }
    } else if (type == ProtocolMap.class) {
      ProtocolMap map = (ProtocolMap )object;
      ms.writeLength(new Length(map.size()));
     
      Object[] keys = map.keys();
     
      for (Object key : keys) {
        writeObject(ms, Object.class, key, protocolsInOrder, serializedProtocols, true);
        writeObject(ms, Object.class, map.get(key), protocolsInOrder, serializedProtocols, true);
      }
    }
    else if (type == Object.class) {
      int rttype = determineRuntimeType(object);
      int rt = rttype & (RT_SINGLE | RT_MULTI);
      int rst = rttype & 0x3f;
     
      ms.write(rttype);
     
      if (rt == RT_SINGLE) {
        if (rst == RST_BOOLEAN) {
          ms.writeBoolean((Boolean )object);
        } else if (rst == RST_BYTE) {
          ms.writeByte((Byte )object);
        } else if (rst == RST_CHARACTER) {
          ms.writeChar((Character )object);
        } else if (rst == RST_SHORT) {
          ms.writeShort((Short )object);
        } else if (rst == RST_INTEGER) {
          ms.writeInt((Integer )object);
        } else if (rst == RST_LONG) {
          ms.writeLong((Long )object);
        } else if (rst == RST_FLOAT) {
          ms.writeFloat((Float )object);
        } else if (rst == RST_DOUBLE) {
          ms.writeDouble((Double )object);
        } else if (rst == RST_STRING) {
          String string = (String )object;
          ms.writeLength(new Length(string.length()));
          ms.writeUTFBase(string, string.length());
        } else if (rst == RST_BOOLEANS) {
          boolean[] array = (boolean[] )object;
          ms.writeLength(new Length(array.length));
          ms.writeBooleans(array);
        } else if (rst == RST_BYTES) {
          byte[] array = (byte[] )object;
          ms.writeLength(new Length(array.length));
          ms.write(array);
        } else if (rst == RST_CHARS) {
          char[] array = (char[] )object;
          ms.writeLength(new Length(array.length));
         
          for (char item : array) {
            ms.writeChar(item);
          }
        } else if (rst == RST_SHORTS) {
          short[] array = (short[] )object;
          ms.writeLength(new Length(array.length));
         
          for (short item : array) {
            ms.writeShort(item);
          }
        } else if (rst == RST_INTS) {
          int[] array = (int[] )object;
          ms.writeLength(new Length(array.length));
         
          for (int item : array) {
            ms.writeInt(item);
          }
        } else if (rst == RST_LONGS) {
          long[] array = (long[] )object;
          ms.writeLength(new Length(array.length));
         
          for (long item : array) {
            ms.writeLong(item);
          }
        } else if (rst == RST_FLOATS) {
          float[] array = (float[] )object;
          ms.writeLength(new Length(array.length));
         
          for (float item : array) {
            ms.writeFloat(item);
          }
        } else if (rst == RST_DOUBLES) {
          double[] array = (double[] )object;
          ms.writeLength(new Length(array.length));
         
          for (double item : array) {
            ms.writeDouble(item);
          }
        } else if (rst == RST_PROTOCOL) {
          int index = protocolsInOrder.indexOf(object);
         
          if (object != null || index >= 0) {
            ms.writeLength(new Length(index));
          }
        } else {
          writeObject(ms, object.getClass(), object, protocolsInOrder, serializedProtocols, true);
        }
      } else if (rt == RT_MULTI) {
        type = object.getClass();
           
        int length = Array.getLength(object);
        ms.writeLength(new Length(length));
       
        for (int i = 0; i < length; i++) {
          Object component = Array.get(object, i);
          writeObject(ms, Object.class, component, protocolsInOrder, serializedProtocols, true);
        }
      }
    }
  }
 
  private static Object readSingleValue(MemoryStream ms, Class<?> type, List<Protocol> protocolsInOrder) throws IOException {
    if (type == boolean.class) {
      return ms.readBoolean();
    } else if (type == byte.class) {
      return ms.readByte();
    } else if (type == char.class) {
      return ms.readChar();
    } else if (type == short.class) {
      return ms.readShort();
    } else if (type == int.class) {
      return ms.readInt();
    } else if (type == long.class) {
      return ms.readLong();
    } else if (type == float.class) {
      return ms.readFloat();
    } else if (type == double.class) {
      return ms.readDouble();
    } else if (type == Boolean.class) {
      if (ms.readBoolean()) {
        return ms.readBoolean();
      }
    } else if (type == Byte.class) {
      if (ms.readBoolean()) {
        return ms.readByte();
      }
    } else if (type == Character.class) {
      if (ms.readBoolean()) {
        return ms.readChar();
      }
    } else if (type == Short.class) {
      if (ms.readBoolean()) {
        return ms.readShort();
      }
    } else if (type == Integer.class) {
      if (ms.readBoolean()) {
        return ms.readInt();
      }
    } else if (type == Long.class) {
      if (ms.readBoolean()) {
        return ms.readLong();
      }
    } else if (type == Float.class) {
      if (ms.readBoolean()) {
        return ms.readFloat();
      }
    } else if (type == Double.class) {
      if (ms.readBoolean()) {
        return ms.readDouble();
      }
    }  else if (type == boolean[].class) {
      Length length = ms.readLength();
     
      if (length.booleanValue()) {
        int intLength = length.intValue() - 1;
        boolean[] array = new boolean[intLength];
        ms.readBooleans(array);
        return array;
      }
    } else if (type == byte[].class) {
      Length length = ms.readLength();
     
      if (length.booleanValue()) {
        int intLength = length.intValue() - 1;
        byte[] array = new byte[intLength];
        ms.readFully(array);
        return array;
      }
    } else if (type.isArray()) {
      Length length = ms.readLength();
     
      if (length.booleanValue()) {
        int intLength = length.intValue() - 1;
        Object array = Array.newInstance(type.getComponentType(), intLength);
       
        for (int i = 0; i < intLength; i++) {
          Array.set(array, i, readSingleValue(ms, type.getComponentType(), protocolsInOrder));
        }
       
        return array;
      }
    } else if (type == String.class) {
      Length length = ms.readLength();
     
      if (length.booleanValue()) {
        int intLength = length.intValue() - 1;
        return ms.readUTFBase(intLength);
      }
    } else if (Protocol.class.isAssignableFrom(type)) {
      Length length = ms.readLength();
     
      if (length.booleanValue()) {
        int index = length.intValue() - 1;
        return protocolsInOrder.get(index);
      }
    } else if (type == Object.class) {
      int rttype = ms.readUnsignedByte();
      Class<?> klass = determineRuntimeType(rttype);
     
      if (klass != null) {
        if (klass == Boolean.class) {
          return ms.readBoolean();
        } else if (klass == Byte.class) {
          return ms.readByte();
        } else if (klass == Character.class) {
          return ms.readChar();
        } else if (klass == Short.class) {
          return ms.readShort();
        } else if (klass == Integer.class) {
          return ms.readInt();
        } else if (klass == Long.class) {
          return ms.readLong();
        } else if (klass == Float.class) {
          return ms.readFloat();
        } else if (klass == Double.class) {
          return ms.readDouble();
        } else if (klass == String.class) {
          Length length = ms.readLength();
          return ms.readUTFBase(length.intValue());
        } else if (klass == boolean[].class) {
          Length length = ms.readLength();
          boolean[] array = new boolean[length.intValue()];
          ms.readBooleans(array);
          return array;
        } else if (klass == byte[].class) {
          Length length = ms.readLength();
          byte[] array = new byte[length.intValue()];
          ms.readFully(array);
          return array;
        } else if (klass == char[].class) {
          Length length = ms.readLength();
          char[] array = new char[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readChar();
          }
          return array;
        } else if (klass == short[].class) {
          Length length = ms.readLength();
          short[] array = new short[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readShort();
          }
          return array;
        } else if (klass == int[].class) {
          Length length = ms.readLength();
          int[] array = new int[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readInt();
          }
          return array;
        } else if (klass == long[].class) {
          Length length = ms.readLength();
          long[] array = new long[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readLong();
          }
          return array;
        } else if (klass == float[].class) {
          Length length = ms.readLength();
          float[] array = new float[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readFloat();
          }
          return array;
        } else if (klass == double[].class) {
          Length length = ms.readLength();
          double[] array = new double[length.intValue()];
         
          for (int i = 0; i < array.length; i++) {
            array[i] = ms.readDouble();
          }
          return array;
        } else if (klass == Protocol.class) {
          Length index = ms.readLength();
          return protocolsInOrder.get(index.intValue());
        }
        else if (klass.isArray()) {
          Length length = ms.readLength();
          Object array = Array.newInstance(klass.getComponentType(), length.intValue());
         
          for (int i = 0; i < length.intValue(); i++) {
            Array.set(array, i, readSingleValue(ms, klass.getComponentType(), protocolsInOrder));
          }
         
          return array;
        }
      }
    }
   
    return null;
  }
 
  private static int determineRuntimeSubtype(Class<?> runtimeClass) {
    if (runtimeClass == Boolean.class) {
      return RST_BOOLEAN;
    } else if (runtimeClass == Byte.class) {
      return RST_BYTE;
    } else if (runtimeClass == Character.class) {
      return RST_CHARACTER;
    } else if (runtimeClass == Short.class) {
      return RST_SHORT;
    } else if (runtimeClass == Integer.class) {
      return RST_INTEGER;
    } else if (runtimeClass == Long.class) {
      return RST_LONG;
    } else if (runtimeClass == Float.class) {
      return RST_FLOAT;
    } else if (runtimeClass == Double.class) {
      return RST_DOUBLE;
    } else if (runtimeClass == String.class) {
      return RST_STRING;
    } else if (runtimeClass == boolean[].class) {
      return RST_BOOLEANS;
    } else if (runtimeClass == byte[].class) {
      return RST_BYTES;
    } else if (runtimeClass == char[].class) {
      return RST_CHARS;
    } else if (runtimeClass == short[].class) {
      return RST_SHORTS;
    } else if (runtimeClass == int[].class) {
      return RST_INTS;
    } else if (runtimeClass == long[].class) {
      return RST_LONGS;
    } else if (runtimeClass == float[].class) {
      return RST_FLOATS;
    } else if (runtimeClass == double[].class) {
      return RST_DOUBLES;
    } else if (Protocol.class.isAssignableFrom(runtimeClass)) {
      return RST_PROTOCOL;
    }
   
    return 0;
  }
 
  private static int determineRuntimeType(Object object) {
    int rttype = 0;
   
    if (object == null) {
      rttype |= RT_NULL;
    } else {
      Class<?> runtimeClass = object.getClass();
     
      if (runtimeClass.isArray() && !runtimeClass.getComponentType().isPrimitive()) {
        rttype |= RT_MULTI;
        rttype |= determineRuntimeSubtype(runtimeClass.getComponentType());
      }
      else {
        rttype |= RT_SINGLE;
        rttype |= determineRuntimeSubtype(runtimeClass);
      }
    }
   
    return rttype;
  }
 
  private static Class<?> determineRuntimeType(int rttype) {
    int rt = rttype & (RT_SINGLE | RT_MULTI);
    int rst = rttype & 0x3f;
   
    if (rt == RT_NULL) {
      return null;
    } else {
      if (rt == RT_SINGLE) {
        if (rst == RST_BOOLEAN) {
          return Boolean.class;
        } else if (rst == RST_BYTE) {
          return Byte.class;
        } else if (rst == RST_CHARACTER) {
          return Character.class;
        } else if (rst == RST_SHORT) {
          return Short.class;
        } else if (rst == RST_INTEGER) {
          return Integer.class;
        } else if (rst == RST_LONG) {
          return Long.class;
        } else if (rst == RST_FLOAT) {
          return Float.class;
        } else if (rst == RST_DOUBLE) {
          return Double.class;
        } else if (rst == RST_STRING) {
          return String.class;
        } else if (rst == RST_BOOLEANS) {
          return boolean[].class;
        } else if (rst == RST_BYTES) {
          return byte[].class;
        } else if (rst == RST_CHARS) {
          return char[].class;
        } else if (rst == RST_SHORTS) {
          return short[].class;
        } else if (rst == RST_INTS) {
          return int[].class;
        } else if (rst == RST_LONGS) {
          return long[].class;
        } else if (rst == RST_FLOATS) {
          return float[].class;
        } else if (rst == RST_DOUBLES) {
          return double[].class;
        } else if (rst == RST_PROTOCOL) {
          return Protocol.class;
        }
      } else if (rt == RT_MULTI) {
        if (rst == RST_BOOLEAN) {
          return Boolean[].class;
        } else if (rst == RST_BYTE) {
          return Byte[].class;
        } else if (rst == RST_CHARACTER) {
          return Character[].class;
        } else if (rst == RST_SHORT) {
          return Short[].class;
        } else if (rst == RST_INTEGER) {
          return Integer[].class;
        } else if (rst == RST_LONG) {
          return Long[].class;
        } else if (rst == RST_FLOAT) {
          return Float[].class;
        } else if (rst == RST_DOUBLE) {
          return Double[].class;
        } else if (rst == RST_STRING) {
          return String[].class;
        } else if (rst == RST_BOOLEANS) {
          return boolean[][].class;
        } else if (rst == RST_BYTES) {
          return byte[][].class;
        } else if (rst == RST_CHARS) {
          return char[][].class;
        } else if (rst == RST_SHORTS) {
          return short[][].class;
        } else if (rst == RST_INTS) {
          return int[][].class;
        } else if (rst == RST_LONGS) {
          return long[][].class;
        } else if (rst == RST_FLOATS) {
          return float[][].class;
        } else if (rst == RST_DOUBLES) {
          return double[][].class;
        } else if (rst == RST_PROTOCOL) {
          return Protocol[].class;
        } else {
          return Object[].class;
        }
      }
    }
   
    return null;
  }
 
  public static Protocol deserializeProtocol(byte[] b, int off, int[] outLen) throws IOException, InstantiationException, ClassNotFoundException {
    if (b == null) {
      throw new NullPointerException();
    }
   
    if (off < 0) {
      throw new IllegalArgumentException();
    }
   
    if (off >= b.length) {
      throw new IllegalArgumentException();
    }
   
    MemoryStream ms = new MemoryStream();
    ms.write(b, off, b.length - off);
   
    Length length = ms.readLength();
    String typeNameExpr = ms.readBytes(length.intValue());
    String[] typeNameExprEntries = typeNameExpr.split(";");
    List<Class<?>> typeList = new ArrayList<Class<?>>();
    List<Length> objectCounts = new ArrayList<Length>();
   
    for (String typeNameExprEntry : typeNameExprEntries) {
      int index = typeNameExprEntry.lastIndexOf('$');
     
      if (index < 0) {
        index = typeNameExprEntry.lastIndexOf('.');
      }
     
      index += 1;
     
      String commonTypeNamePrefix = typeNameExprEntry.substring(0, index);
      String simpleTypeNameExpr = typeNameExprEntry.substring(index);
      String[] simpleTypeNames = simpleTypeNameExpr.split(",");
     
      for (String simpleTypeName : simpleTypeNames) {
        typeList.add(Class.forName(commonTypeNamePrefix + simpleTypeName));
      }
    }
   
    for (Class<?> type : typeList) {
      Length objCount = ms.readLength();
      objectCounts.add(objCount);
    }
   
    List<Protocol> protocolsInOrder = new ArrayList<Protocol>();
   
    for (int i = 0; i < typeList.size(); i++) {
      Class<?> type = typeList.get(i);
      Length objCount = objectCounts.get(i);
     
      for (int j = 0; j < objCount.intValue(); j++) {
        Protocol protocolInOrder = (Protocol )newLocalProtocol(type);
        protocolsInOrder.add(protocolInOrder);
      }
    }
   
    for (Protocol protocolInOrder : protocolsInOrder) {
      ProtocolInvocationHandler pih = (ProtocolInvocationHandler )Proxy.getInvocationHandler(protocolInOrder);
      readSingleObject(ms, protocolInOrder, pih.getProtocolType(), protocolsInOrder);
    }
   
//    Protocol finalProtocol = protocolsInOrder.get(ms.readLength().intValue());
   
    System.out.println("AVAILABLE = " + ms.available());
   
//    return finalProtocol;
    return protocolsInOrder.get(0);
  }
 
  private static Protocol readSingleObject(MemoryStream ms, Protocol protocol, Class<?> type, List<Protocol> protocolsInOrder) throws InstantiationException, IOException {
    ProtocolInvocationHandler pih = (ProtocolInvocationHandler )Proxy.getInvocationHandler(protocol);
    Map<String, Object> propertyMap = pih.getPropertyMap();
   
    for (String key : propertyMap.keySet()) {
      Method[] methods = type.getMethods();
     
      String set = "set" + Character.toUpperCase(key.charAt(0)) + key.substring(1);
      String coll = key;

      boolean isColl = false;
      Method theMethod = null;
      Class<?> theType = null;
     
      for (Method method : methods) {
        if (method.getName().equals(set)) {
          theMethod = method;
          theType = theMethod.getParameterTypes()[0];
        } else if (method.getName().equals(coll)) {
          theMethod = method;
          theType = method.getReturnType();
          isColl = true;
        }
      }
     
      if (theMethod == null || theType == null) {
        throw new IOException("Object is corrupted.");
      }
     
      try {
        if (isColl) {
          ProtocolCollection pc = (ProtocolCollection )theMethod.invoke(protocol);
         
          if (pc instanceof ProtocolSet) {
            ProtocolSet ps = (ProtocolSet )pc;
           
            Length length = ms.readLength();
           
            for (int i = 0; i < length.intValue(); i++) {
              ps.add(readSingleValue(ms, Object.class, protocolsInOrder));
            }
          } else if (pc instanceof ProtocolMap) {
            ProtocolMap pm = (ProtocolMap )pc;
           
            Length length = ms.readLength();
           
            for (int i = 0; i < length.intValue(); i++) {
              Object k = readSingleValue(ms, Object.class, protocolsInOrder);
              Object v = readSingleValue(ms, Object.class, protocolsInOrder);
              pm.put(k, v);
            }
          }
        } else {
          try {
            theMethod.invoke(protocol, readSingleValue(ms, theType, protocolsInOrder));
          } catch (Exception ex) {
            throw new IOException(ex);
          }
        }
      } catch (Exception ex) {
        throw new IOException(ex);
      }
    }
   
    return protocol;
  }
 
  private static void fillProtocolObjectMap(Object current, SortedMap<Class<?>, SortedSet<Protocol>> protocolObjectMap) {
    if (protocolObjectMap == null) {
      throw new NullPointerException();
    }
   
    if (current == null) {
      return;
    }
   
    if (current instanceof Protocol) {
      Protocol protocol = (Protocol )current;
      ProtocolInvocationHandler pih = (ProtocolInvocationHandler )Proxy.getInvocationHandler(protocol);
     
      if (pih == null) {
        throw new IllegalArgumentException();
      }
     
      Class<?> protocolType = pih.getProtocolType();
      SortedSet<Protocol> protocolObjectSet = getProtocolObjectSet(protocolObjectMap, protocolType);
     
      if (protocolObjectSet.add(protocol)) {
        Map<String, Object> propertyMap = pih.getPropertyMap();
       
        for (Object value : propertyMap.values()) {
          fillProtocolObjectMap(value, protocolObjectMap);
        }
      }
    } else if (current instanceof ProtocolSet) {
      ProtocolSet<?> protocolSet = (ProtocolSet<?> )current;
      Object[] array = protocolSet.toArray();
     
      for (Object item : array) {
        fillProtocolObjectMap(item, protocolObjectMap);
      }
    } else if (current instanceof ProtocolMap) {
      ProtocolMap<?, ?> protocolMap = (ProtocolMap<?, ?> )current;
      Object[] keys = protocolMap.keys();
     
      for (Object key : keys) {
        fillProtocolObjectMap(key, protocolObjectMap);
        fillProtocolObjectMap(protocolMap.get(key), protocolObjectMap);
      }
    } else {
      Class<?> type = current.getClass();
     
      if (type.isArray()) {
        for (int i = 0; i < Array.getLength(current); i++) {
          Object item = Array.get(current, i);
          fillProtocolObjectMap(item, protocolObjectMap);
        }
      }
    }
  }
 
  private static SortedSet<Protocol> getProtocolObjectSet(SortedMap<Class<?>, SortedSet<Protocol>> protocolObjectMap, Class<?> type) {
    if (protocolObjectMap == null) {
      throw new NullPointerException();
    }
   
    if (type == null) {
      throw new NullPointerException();
    }
   
    SortedSet<Protocol> protocolObjectSet = protocolObjectMap.get(type);
   
    if (protocolObjectSet == null) {
      Comparator<Protocol> protocolComparator = new Comparator<Protocol>() {
        @Override
        public int compare(Protocol protocol0, Protocol protocol1) {
          int hashCode0 = protocol0.hashCode();
          int hashCode1 = protocol1.hashCode();
          return hashCode0 - hashCode1;
        }
      };
     
      protocolObjectSet = new TreeSet<Protocol>(protocolComparator);
      protocolObjectMap.put(type, protocolObjectSet);
    }
   
    return protocolObjectSet;
  }
 
  private static SortedSet<String> getSimpleTypeNameSet(SortedMap<String, SortedSet<String>> typeNameMap, String commonTypeNamePrefix) {
    if (typeNameMap == null) {
      throw new NullPointerException();
    }
   
    if (commonTypeNamePrefix == null) {
      throw new NullPointerException();
    }
   
    if (commonTypeNamePrefix.isEmpty()) {
      throw new IllegalArgumentException();
    }
   
    SortedSet<String> simpleTypeNameSet = typeNameMap.get(commonTypeNamePrefix);
   
    if (simpleTypeNameSet == null) {
      simpleTypeNameSet = new TreeSet<String>();
      typeNameMap.put(commonTypeNamePrefix, simpleTypeNameSet);
    }
   
    return simpleTypeNameSet;
  }
 
  public static boolean isEmpty(String str) {
    if (str == null) {
      return true;
    }
   
    return str.isEmpty();
  }
 
  public static interface WhiteboardDocument extends Protocol {
    String getId();
    void setId(String value);
    String getName();
    void setName(String value);
    ProtocolMap<String, Object> authorProperties();
    ProtocolList<WhiteboardWorksheet> worksheets();
  }
 
  public static interface WhiteboardWorksheet extends Protocol {
    String getName();
    void setName(String value);
    ProtocolList<WhiteboardObject> objects();
  }
 
  @Abstract
  public static interface WhiteboardObject extends Protocol {
    String getId();
    void setId(String value);
    String getName();
    void setName(String value);
    String[] getDescLines();
    void setDescLines(String[] value);
  }
 
  @Abstract
  public static interface WhiteboardVisualObject extends WhiteboardObject {
    WhiteboardPen getPen();
    void setPen(WhiteboardPen value);
    WhiteboardBrush[] getBrushes();
    void setBrushes(WhiteboardBrush[] values);
  }
 
  public static interface WhiteboardRectangle extends WhiteboardVisualObject {
    int getX();
    void setX(int value);
    int getY();
    void setY(int value);
    int getWidth();
    void setWidth(int value);
    int getHeight();
    void setHeight(int value);
  }
 
  public static interface WhiteboardPen extends Protocol {
    int getWidth();
    void setWidth(int value);
    WhiteboardColor getColor();
    void setColor(WhiteboardColor value);
  }
 
  public static interface WhiteboardBrush extends Protocol {
    WhiteboardColor getColor();
    void setColor(WhiteboardColor value);
  }
 
  public static interface WhiteboardColor extends Protocol {
    int[] getRgb();
    void setRgb(int[] value);
  }
 
  public static interface Data extends Protocol {
    boolean isBoolean();
    void setBoolean(boolean value);
    byte getByte();
    void setByte(byte value);
    char getChar();
    void setChar(char value);
    short getShort();
    void setShort(short value);
    int getInt();
    void setInt(int value);
    long getLong();
    void setLong(long value);
    float getFloat();
    void setFloat(float value);
    double getDouble();
    void setDouble(double value);
   
    Boolean getBooleanObject();
    void setBooleanObject(Boolean value);
    Byte getByteObject();
    void setByteObject(Byte value);
    Character getCharacterObject();
    void setCharacterObject(Character value);
    Short getShortObject();
    void setShortObject(Short value);
    Integer getIntegerObject();
    void setIntegerObject(Integer value);
    Long getLongObject();
    void setLongObject(Long value);
    Float getFloatObject();
    void setFloatObject(Float value);
    Double getDoubleObject();
    void setDoubleObject(Double value);
   
    Boolean getNullBooleanObject();
    void setNullBooleanObject(Boolean value);
    Byte getNullByteObject();
    void setNullByteObject(Byte value);
    Character getNullCharacterObject();
    void setNullCharacterObject(Character value);
    Short getNullShortObject();
    void setNullShortObject(Short value);
    Integer getNullIntegerObject();
    void setNullIntegerObject(Integer value);
    Long getNullLongObject();
    void setNullLongObject(Long value);
    Float getNullFloatObject();
    void setNullFloatObject(Float value);
    Double getNullDoubleObject();
    void setNullDoubleObject(Double value);
   
    boolean[] getBooleanArray();
    void setBooleanArray(boolean[] value);
    byte[] getByteArray();
    void setByteArray(byte[] value);
    String[] getStringArray();
    void setStringArray(String[] value);
    Double[][] getDoubleArray();
    void setDoubleArray(Double[][] value);
   
    boolean[] getNullBooleanArray();
    void setNullBooleanArray(boolean[] value);
    byte[] getNullByteArray();
    void setNullByteArray(byte[] value);
    String[] getNullStringArray();
    void setNullStringArray(String[] value);
    Double[][] getNullDoubleArray();
    void setNullDoubleArray(Double[][] value);
   
    boolean[] getEmptyBooleanArray();
    void setEmptyBooleanArray(boolean[] value);
    byte[] getEmptyByteArray();
    void setEmptyByteArray(byte[] value);
    String[] getEmptyStringArray();
    void setEmptyStringArray(String[] value);
    Double[][] getPartialEmptyDoubleArray();
    void setPartialEmptyDoubleArray(Double[][] value);
    Double[][] getEmptyDoubleArray();
    void setEmptyDoubleArray(Double[][] value);
   
    Object getSingleObject();
    void setSingleObject(Object value);
    Object getMultiObject();
    void setMultiObject(Object value);
   
    ProtocolSet<Object> set();
    ProtocolList<Object> list();
   
    Data getSelf();
    void setSelf(Data value);
  }
 
  interface Foo extends Protocol {
    Object getA();
    void setA(Object value);
  }
 
  interface Bar extends Protocol {
    Object getA();
    void setA(Object value);
  }
 
  interface FooBar extends Protocol {
    FooBar getSelf();
    void setSelf(FooBar value);
    Object getSelf2();
    void setSelf2(Object value);
    FooBar[] getSelves();
    void setSelves(FooBar[] value);
    Object[] getSelves2();
    void setSelves2(Object[] value);
    FooBar[][] getDeep();
    void setDeep(FooBar[][] value);
    Object[][] getDeepObj();
    void setDeepObj(Object[][] value);
    ProtocolSet<Object> selfSet();
    ProtocolList<Object> selfList();
    ProtocolMap<Object, Object> selfMap();
  }
 
  interface Person extends Protocol {
    String getName();
    void setName(String value);
    Person getSpouse();
    void setSpouse(Person value);
  }
 
  public static void main(String[] args) throws Exception {
//    test1();
   
//    Person a0 = newLocalProtocol(Person.class);
//    Person b0 = newLocalProtocol(Person.class);
//   
//    a0.setName("John");
//    b0.setName("Lisa");
//   
//    a0.setSpouse(b0);
//    b0.setSpouse(a0);
//   
//    byte[] data = serializeProtocol(a0);
//   
//    Person x = (Person )deserializeProtocol(data, 0, null);
//   
//    System.out.println(a0 + ", " + b0 + ", " + x.getName() + ", " + x.getSpouse().getName());
   
//    FooBar fb0 = newLocalProtocol(FooBar.class);
//    fb0.setSelf(fb0);
//    fb0.setSelf2(fb0);
//    fb0.setSelves(new FooBar[] { fb0 });
//    fb0.setSelves2(new Object[] { fb0 });
//    fb0.setDeep(new FooBar[][] { null, new FooBar[0], new FooBar[] { fb0 } });
//    fb0.setDeepObj(new Object[][] { null, new Object[0], new Object[] { fb0 } });
//    fb0.selfSet().add(fb0);
//    fb0.selfList().add(fb0);
//    fb0.selfMap().put("Hello World!", fb0);
//    byte[] bytes = serializeProtocol(fb0);
//    FooBar fb1 = (FooBar )deserializeProtocol(bytes, 0, null);
//    System.out.println(fb1 + " == " + fb1.getSelf() + " == " + fb1.getSelf2() + " == " +
//      Arrays.deepToString((Object[] )fb1.getSelves()) + " == " + Arrays.deepToString((Object[] )fb1.getSelves2()) + " == " +
//      fb1.selfSet() + " == " + fb1.selfList() + " == " + Arrays.deepToString((Object[] )fb1.getDeep()) + " == " +
//      Arrays.deepToString((Object[] )fb1.getDeepObj()) + " == " + Arrays.toString(fb0.selfMap().keys()) + " == " +
//      Arrays.toString(fb1.selfMap().values()));
   
//    Bar bar0 = newLocalProtocol(Bar.class);
//    bar0.setA(new Object[][] { null, new Object[] { 1.0, 2.0 }, new Object[0], new Object[] { 3.0 } });
//    byte[] bytes = serializeProtocol(bar0);
//    Bar bar1 = (Bar )deserializeProtocol(bytes, 0, null);
//    System.out.println(Arrays.deepToString((Object[] )bar1.getA()));
   
//    Foo foo0 = newLocalProtocol(Foo.class);
//    foo0.setA(new Integer[] { 1, 2, 3 });
//    byte[] bytes = serializeProtocol(foo0);
//    Foo foo1 = (Foo )deserializeProtocol(bytes, 0, null);
//    System.out.println(Arrays.deepToString((Object[] )foo1.getA()));
   
//    WhiteboardDocument doc0 = initializeWhiteboardDocument();
//    byte[] bytes = serializeProtocol(doc0);
//    WhiteboardDocument doc = (WhiteboardDocument )deserializeProtocol(bytes, 0, null);
//    System.out.println(doc);
  }
 
  private static void test1() throws Exception {
    Data data0 = newLocalProtocol(Data.class);
   
    data0.setBoolean(true);
    data0.setByte(Byte.MAX_VALUE);
    data0.setChar('A');
    data0.setShort(Short.MAX_VALUE);
    data0.setInt(Integer.MAX_VALUE);
    data0.setLong(Long.MAX_VALUE);
    data0.setFloat(Float.MAX_VALUE);
    data0.setDouble(Double.MAX_VALUE);
   
    data0.setBooleanObject(Boolean.TRUE);
    data0.setByteObject(Byte.MAX_VALUE);
    data0.setCharacterObject('A');
    data0.setShortObject(Short.MAX_VALUE);
    data0.setIntegerObject(Integer.MAX_VALUE);
    data0.setLongObject(Long.MAX_VALUE);
    data0.setFloatObject(Float.MAX_VALUE);
    data0.setDoubleObject(Double.MAX_VALUE);
   
    data0.setBooleanArray(new boolean[] { true, false, true, false, true, false, true, false, true });
    data0.setByteArray(new byte[] { 1, 2, 3, 4, 5 });
    data0.setStringArray(new String[] { "Hello", "World", "!", "Hello World!" });
    data0.setDoubleArray(new Double[][] { new Double[] { 1.0, 2.0, 3.0 }, new Double[] { 4.0, 5.0 }, new Double[] { 6.0 } });

    data0.setEmptyBooleanArray(new boolean[0]);
    data0.setEmptyByteArray(new byte[0]);
    data0.setEmptyStringArray(new String[0]);
    data0.setPartialEmptyDoubleArray(new Double[][] { new Double[] { 1.0 }, new Double[0], null, new Double[] { 2.0, 3.0 } });
    data0.setEmptyDoubleArray(new Double[0][]);
   
    data0.set().add(true);
    data0.set().add('A');
    data0.set().add(Integer.MAX_VALUE);
    data0.set().add(Double.MAX_VALUE);
    data0.set().add(new boolean[] { true, false, true, false, true, false, true, false, false, true });
   
    data0.list().add(Byte.MAX_VALUE);
    data0.list().add(Short.MAX_VALUE);
    data0.list().add(Float.MAX_VALUE);
    data0.list().add("Hello World!");
    data0.list().add(new Object[][] { null, new Object[] { 3.0, 8.0 }, new Object[0], new Object[] { 1.0 } });
    data0.list().add(new Double[] { null, 2.0, 3.0 });
   
    data0.setSelf(data0);
   
//    data0.setSingleObject(true);
//    data0.setSingleObject(Byte.MAX_VALUE);
//    data0.setSingleObject('A');
//    data0.setSingleObject(Short.MAX_VALUE);
//    data0.setSingleObject(Integer.MAX_VALUE);
//    data0.setSingleObject(Long.MAX_VALUE);
//    data0.setSingleObject(Float.MAX_VALUE);
//    data0.setSingleObject(Double.MAX_VALUE);
//    data0.setSingleObject("Hello World!");
//    data0.setSingleObject(new boolean[] { true, false, true });
    data0.setSingleObject(new double[] { 1.0, 2.0, 3.0 });
    data0.setMultiObject(new Integer[] { 1, 2, 3 });
    byte[] bytes = serializeProtocol(data0);
   
    Data data1 = (Data )deserializeProtocol(bytes, 0, null);
   
    System.out.println("boolean = " + data1.isBoolean());
    System.out.println("byte = " + data1.getByte());
    System.out.println("char = " + data1.getChar());
    System.out.println("short = " + data1.getShort());
    System.out.println("int = " + data1.getInt());
    System.out.println("long = " + data1.getLong());
    System.out.println("float = " + data1.getFloat());
    System.out.println("double = " + data1.getDouble());
   
    System.out.println("Boolean = " + data1.getBooleanObject());
    System.out.println("Byte = " + data1.getByteObject());
    System.out.println("Character = " + data1.getCharacterObject());
    System.out.println("Short = " + data1.getShortObject());
    System.out.println("Integer = " + data1.getIntegerObject());
    System.out.println("Long = " + data1.getLongObject());
    System.out.println("Float = " + data1.getFloatObject());
    System.out.println("Double = " + data1.getDoubleObject());
   
    System.out.println("NullBoolean = " + data1.getNullBooleanObject());
    System.out.println("NullByte = " + data1.getNullByteObject());
    System.out.println("NullCharacter = " + data1.getNullCharacterObject());
    System.out.println("NullShort = " + data1.getNullShortObject());
    System.out.println("NullInteger = " + data1.getNullIntegerObject());
    System.out.println("NullLong = " + data1.getNullLongObject());
    System.out.println("NullFloat = " + data1.getNullFloatObject());
    System.out.println("NullDouble = " + data1.getNullDoubleObject());
   
    System.out.println("boolean array = " + Arrays.toString(data1.getBooleanArray()));
    System.out.println("byte array = " + Arrays.toString(data1.getByteArray()));
    System.out.println("String array = " + Arrays.toString(data1.getStringArray()));
    System.out.println("Double array = " + Arrays.deepToString(data1.getDoubleArray()));
   
    System.out.println("null boolean array = " + data1.getNullBooleanArray());
    System.out.println("null byte array = " + data1.getNullByteArray());
    System.out.println("null String array = " + data1.getNullStringArray());
    System.out.println("null Double array = " + data1.getNullDoubleArray());
   
    System.out.println("empty boolean array = " + Arrays.toString(data1.getEmptyBooleanArray()));
    System.out.println("empty byte array = " + Arrays.toString(data1.getEmptyByteArray()));
    System.out.println("empty String array = " + Arrays.toString(data1.getEmptyStringArray()));
    System.out.println("parital empty Double array = " + Arrays.deepToString(data1.getPartialEmptyDoubleArray()));
    System.out.println("empty Double array = " + Arrays.deepToString(data1.getEmptyDoubleArray()));
   
//    System.out.println("single object = " + data1.getSingleObject());
//    System.out.println("single object = " + Arrays.toString((boolean[] )data1.getSingleObject()));
    System.out.println("single object = " + Arrays.toString((double[] )data1.getSingleObject()));
    System.out.println("multi object = " + Arrays.deepToString((Object[] )data1.getMultiObject()));
   
    System.out.println("set count = " + data1.set().size());
    System.out.println("set values = " + Arrays.deepToString(data1.set().toArray()));
    System.out.println("list count = " + data1.list().size());
    System.out.println("list values = " + Arrays.deepToString(data1.list().toArray()));
    System.out.println("runtime dynamically typed type = " + Arrays.toString((Object[] )data1.list().get(5)));
  }
 
  private static WhiteboardDocument initializeWhiteboardDocument() throws Exception {
    WhiteboardDocument doc = newLocalProtocol(WhiteboardDocument.class);
    {
      doc.setId("document1");
      doc.setName("Document One");
     
      WhiteboardPen defaultPen = newLocalProtocol(WhiteboardPen.class);
      {
        defaultPen.setWidth(5);
       
        WhiteboardColor defaultPenColor = newLocalProtocol(WhiteboardColor.class);
        {
          defaultPenColor.setRgb(new int[] { 1, 0, 0 });
        }
        defaultPen.setColor(defaultPenColor);
       
      }
      doc.authorProperties().put("defaultPen", defaultPen);
     
      WhiteboardBrush defaultBrush0 = newLocalProtocol(WhiteboardBrush.class);
      {
        WhiteboardColor defaultBrushColor0 = newLocalProtocol(WhiteboardColor.class);
        {
          defaultBrushColor0.setRgb(new int[] { 255, 255, 255 });
        }
        defaultBrush0.setColor(defaultBrushColor0);
      }
      WhiteboardBrush defaultBrush1 = newLocalProtocol(WhiteboardBrush.class);
      {
        WhiteboardColor defaultBrushColor1 = newLocalProtocol(WhiteboardColor.class);
        {
          defaultBrushColor1.setRgb(new int[] { 128, 128, 128 });
        }
        defaultBrush1.setColor(defaultBrushColor1);
      }
      doc.authorProperties().put("defaultBrushes", new Object[] { defaultBrush0, defaultBrush1 });
      Sample sample = newLocalProtocol(Sample.class);
      Sample.Foo foo = newLocalProtocol(Sample.Foo.class);
      doc.authorProperties().put("objects", new Object[] { defaultBrush0, defaultPen, doc, sample, foo });
      doc.authorProperties().put("author", "hytparadisee");
      doc.authorProperties().put("pointback", doc);
     
      WhiteboardWorksheet sheet0 = newLocalProtocol(WhiteboardWorksheet.class);
      {
        sheet0.setName("Sheet 1");
       
        WhiteboardRectangle rect0 = newLocalProtocol(WhiteboardRectangle.class);
        {
          rect0.setId("rect0");
          rect0.setName("Rectangle 0");
          rect0.setDescLines(new String[] { "A small rectangle", "Nothing special", "Yet important" });
          rect0.setX(0);
          rect0.setY(0);
          rect0.setWidth(200);
          rect0.setHeight(100);
        }
        sheet0.objects().add(rect0);
       
        WhiteboardRectangle rect1 = newLocalProtocol(WhiteboardRectangle.class);
        {
          rect1.setId("rect1");
          rect1.setName("Another beautiful rectangle");
          rect1.setDescLines(new String[] { null, null, "Haha!" });
          rect1.setX(300);
          rect1.setY(45);
          rect1.setWidth(200);
          rect1.setHeight(40);
         
          WhiteboardBrush rectBrush0 = newLocalProtocol(WhiteboardBrush.class);
          {
            WhiteboardColor rectBrushColor0 = newLocalProtocol(WhiteboardColor.class);
            {
              rectBrushColor0.setRgb(new int[] { 255, 0, 0 });
            }
            rectBrush0.setColor(rectBrushColor0);
          }
          rect1.setBrushes(new WhiteboardBrush[] { rectBrush0 });
        }
        sheet0.objects().add(rect1);
      }
      doc.worksheets().add(sheet0);
     
      WhiteboardWorksheet sheet1 = newLocalProtocol(WhiteboardWorksheet.class);
      {
        sheet1.setName("My Sheet");
      }
      doc.worksheets().add(sheet1);
     
      WhiteboardWorksheet sheet2 = newLocalProtocol(WhiteboardWorksheet.class);
      {
        sheet2.setName("Custom Sheet");
       
        WhiteboardRectangle rect0 = newLocalProtocol(WhiteboardRectangle.class);
        {
          rect0.setId("rect1");
          rect0.setName("A rect in sheet 2");
          rect0.setDescLines(new String[] { "Some description" });
          rect0.setX(50);
          rect0.setY(50);
          rect0.setWidth(50);
          rect0.setHeight(50);
         
          WhiteboardPen rectPen = newLocalProtocol(WhiteboardPen.class);
          {
            WhiteboardColor rectPenColor = newLocalProtocol(WhiteboardColor.class);
            {
              rectPenColor.setRgb(new int[] { 0, 255, 0 });
            }
            rectPen.setColor(rectPenColor);
          }
          rect0.setPen(rectPen);
        }
        sheet2.objects().add(rect0);
      }
      doc.worksheets().add(sheet2);
    }
    return doc;
  }
}
TOP

Related Classes of com.peterhi.runtime.RT

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.