Package com.dyuproject.protostuff.runtime

Source Code of com.dyuproject.protostuff.runtime.PolymorphicCollectionSchema

//================================================================================
//Copyright (c) 2012, David Yu
//All rights reserved.
//--------------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
// 3. Neither the name of protostuff nor the names of its contributors may be used
//    to endorse or promote products derived from this software without
//    specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//================================================================================


package com.dyuproject.protostuff.runtime;

import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.ID_COLLECTION;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.ID_ENUM;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.ID_ENUM_SET;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.STR_COLLECTION;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.STR_ENUM;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.STR_ENUM_SET;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;

import com.dyuproject.protostuff.GraphInput;
import com.dyuproject.protostuff.Input;
import com.dyuproject.protostuff.Output;
import com.dyuproject.protostuff.Pipe;
import com.dyuproject.protostuff.ProtostuffException;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.StatefulOutput;
import com.dyuproject.protostuff.runtime.IdStrategy.Wrapper;
import com.dyuproject.protostuff.runtime.RuntimeEnv.Instantiator;


/**
* Used when the type is an interface (Collection/List/Set/SortedSet).
*
* @author David Yu
* @created Apr 24, 2012
*/
public abstract class PolymorphicCollectionSchema extends PolymorphicSchema
{
   
    static final int ID_EMPTY_SET = 1,
            ID_EMPTY_LIST = 2,
           
            ID_SINGLETON_SET = 3,
            ID_SINGLETON_LIST = 4,
           
            ID_SET_FROM_MAP = 5,
            ID_COPIES_LIST = 6,
           
            ID_UNMODIFIABLE_COLLECTION = 7,
            ID_UNMODIFIABLE_SET = 8,
            ID_UNMODIFIABLE_SORTED_SET = 9,
            ID_UNMODIFIABLE_LIST = 10,
            ID_UNMODIFIABLE_RANDOM_ACCESS_LIST =11,
           
            ID_SYNCHRONIZED_COLLECTION = 12,
            ID_SYNCHRONIZED_SET = 13,
            ID_SYNCHRONIZED_SORTED_SET = 14,
            ID_SYNCHRONIZED_LIST = 15,
            ID_SYNCHRONIZED_RANDOM_ACCESS_LIST = 16,

            ID_CHECKED_COLLECTION = 17,
            ID_CHECKED_SET = 18,
            ID_CHECKED_SORTED_SET = 19,
            ID_CHECKED_LIST = 20,
            ID_CHECKED_RANDOM_ACCESS_LIST = 21;
            
   
    static final String STR_EMPTY_SET = "a",
            STR_EMPTY_LIST = "b",
           
            STR_SINGLETON_SET = "c",
            STR_SINGLETON_LIST = "d",
           
            STR_SET_FROM_MAP = "e",
            STR_COPIES_LIST = "f",
           
            STR_UNMODIFIABLE_COLLECTION = "g",
            STR_UNMODIFIABLE_SET = "h",
            STR_UNMODIFIABLE_SORTED_SET = "i",
            STR_UNMODIFIABLE_LIST = "j",
            STR_UNMODIFIABLE_RANDOM_ACCESS_LIST = "k",
           
            STR_SYNCHRONIZED_COLLECTION = "l",
            STR_SYNCHRONIZED_SET = "m",
            STR_SYNCHRONIZED_SORTED_SET = "n",
            STR_SYNCHRONIZED_LIST = "o",
            STR_SYNCHRONIZED_RANDOM_ACCESS_LIST = "p",

            STR_CHECKED_COLLECTION = "q",
            STR_CHECKED_SET = "r",
            STR_CHECKED_SORTED_SET = "s",
            STR_CHECKED_LIST = "t",
            STR_CHECKED_RANDOM_ACCESS_LIST = "u";
   
    static final IdentityHashMap<Class<?>,Integer> __nonPublicCollections =
            new IdentityHashMap<Class<?>, Integer>();
   
    static final Field fSingletonSet_element,
            fSingletonList_element,
           
            fUnmodifiableCollection_c,
            fUnmodifiableSortedSet_ss,
            fUnmodifiableList_list,
           
            fSynchronizedCollection_c,
            fSynchronizedSortedSet_ss,
            fSynchronizedList_list,
            fSynchronizedCollection_mutex,
           
            fCheckedCollection_c,
            fCheckedSortedSet_ss,
            fCheckedList_list,
            fCheckedCollection_type,
           
            fSetFromMap_m,
            fSetFromMap_s,
           
            fCopiesList_n,
            fCopiesList_element;
       
   
    static final Instantiator<?> iSingletonSet,
            iSingletonList,
           
            iUnmodifiableCollection,
            iUnmodifiableSet,
            iUnmodifiableSortedSet,
            iUnmodifiableList,
            iUnmodifiableRandomAccessList,
           
            iSynchronizedCollection,
            iSynchronizedSet,
            iSynchronizedSortedSet,
            iSynchronizedList,
            iSynchronizedRandomAccessList,
           
            iCheckedCollection,
            iCheckedSet,
            iCheckedSortedSet,
            iCheckedList,
            iCheckedRandomAccessList,
           
            iSetFromMap,
           
            iCopiesList;
       
   
    static
    {
        map("java.util.Collections$EmptySet", ID_EMPTY_SET);
        map("java.util.Collections$EmptyList", ID_EMPTY_LIST);
       
        Class<?> cSingletonSet =
                map("java.util.Collections$SingletonSet", ID_SINGLETON_SET);
       
        Class<?> cSingletonList =
                map("java.util.Collections$SingletonList", ID_SINGLETON_LIST);
       
        Class<?> cSetFromMap =
                map("java.util.Collections$SetFromMap", ID_SET_FROM_MAP);
       
        Class<?> cCopiesList =
                map("java.util.Collections$CopiesList", ID_COPIES_LIST);
       
        Class<?> cUnmodifiableCollection =
                map("java.util.Collections$UnmodifiableCollection", ID_UNMODIFIABLE_COLLECTION);
        Class<?> cUnmodifiableSet =
                map("java.util.Collections$UnmodifiableSet", ID_UNMODIFIABLE_SET);
        Class<?> cUnmodifiableSortedSet =
                map("java.util.Collections$UnmodifiableSortedSet", ID_UNMODIFIABLE_SORTED_SET);
        Class<?> cUnmodifiableList =
                map("java.util.Collections$UnmodifiableList", ID_UNMODIFIABLE_LIST);
        Class<?> cUnmodifiableRandomAccessList =
                map("java.util.Collections$UnmodifiableRandomAccessList", ID_UNMODIFIABLE_RANDOM_ACCESS_LIST);
       
        Class<?> cSynchronizedCollection =
                map("java.util.Collections$SynchronizedCollection", ID_SYNCHRONIZED_COLLECTION);
        Class<?> cSynchronizedSet =
                map("java.util.Collections$SynchronizedSet", ID_SYNCHRONIZED_SET);
        Class<?> cSynchronizedSortedSet =
                map("java.util.Collections$SynchronizedSortedSet", ID_SYNCHRONIZED_SORTED_SET);
        Class<?> cSynchronizedList =
                map("java.util.Collections$SynchronizedList", ID_SYNCHRONIZED_LIST);
        Class<?> cSynchronizedRandomAccessList =
                map("java.util.Collections$SynchronizedRandomAccessList", ID_SYNCHRONIZED_RANDOM_ACCESS_LIST);
       
        Class<?> cCheckedCollection =
                map("java.util.Collections$CheckedCollection", ID_CHECKED_COLLECTION);
        Class<?> cCheckedSet =
                map("java.util.Collections$CheckedSet", ID_CHECKED_SET);
        Class<?> cCheckedSortedSet =
                map("java.util.Collections$CheckedSortedSet", ID_CHECKED_SORTED_SET);
        Class<?> cCheckedList =
                map("java.util.Collections$CheckedList", ID_CHECKED_LIST);
        Class<?> cCheckedRandomAccessList =
                map("java.util.Collections$CheckedRandomAccessList", ID_CHECKED_RANDOM_ACCESS_LIST);
       
        try
        {
            fSingletonSet_element = cSingletonSet.getDeclaredField("element");
           
            fSingletonList_element = cSingletonList.getDeclaredField("element");
           
            fSetFromMap_m = cSetFromMap.getDeclaredField("m");
            fSetFromMap_s = cSetFromMap.getDeclaredField("s");
           
            fCopiesList_n = cCopiesList.getDeclaredField("n");
            fCopiesList_element = cCopiesList.getDeclaredField("element");
           
            fUnmodifiableCollection_c = cUnmodifiableCollection.getDeclaredField("c");
            fUnmodifiableSortedSet_ss = cUnmodifiableSortedSet.getDeclaredField("ss");
            fUnmodifiableList_list = cUnmodifiableList.getDeclaredField("list");
           
            fSynchronizedCollection_c = cSynchronizedCollection.getDeclaredField("c");
            fSynchronizedCollection_mutex = cSynchronizedCollection.getDeclaredField("mutex");
            fSynchronizedSortedSet_ss = cSynchronizedSortedSet.getDeclaredField("ss");
            fSynchronizedList_list = cSynchronizedList.getDeclaredField("list");
           
            fCheckedCollection_c = cCheckedCollection.getDeclaredField("c");
            fCheckedCollection_type = cCheckedCollection.getDeclaredField("type");
            fCheckedSortedSet_ss = cCheckedSortedSet.getDeclaredField("ss");
            fCheckedList_list = cCheckedList.getDeclaredField("list");
        }
        catch(Exception e)
        {
            throw new RuntimeException(e);
        }
       
        // field accessors
       
        fSingletonSet_element.setAccessible(true);
       
        fSingletonList_element.setAccessible(true);
       
        fSetFromMap_m.setAccessible(true);
        fSetFromMap_s.setAccessible(true);
       
        fCopiesList_n.setAccessible(true);
        fCopiesList_element.setAccessible(true);
       
        fUnmodifiableCollection_c.setAccessible(true);
        fUnmodifiableSortedSet_ss.setAccessible(true);
        fUnmodifiableList_list.setAccessible(true);
       
        fSynchronizedCollection_c.setAccessible(true);
        fSynchronizedCollection_mutex.setAccessible(true);
        fSynchronizedSortedSet_ss.setAccessible(true);
        fSynchronizedList_list.setAccessible(true);
       
        fCheckedCollection_c.setAccessible(true);
        fCheckedCollection_type.setAccessible(true);
        fCheckedSortedSet_ss.setAccessible(true);
        fCheckedList_list.setAccessible(true);
       
        // instantiators
       
        iSingletonSet = RuntimeEnv.newInstantiator(cSingletonSet);
       
        iSingletonList = RuntimeEnv.newInstantiator(cSingletonList);
       
        iSetFromMap = RuntimeEnv.newInstantiator(cSetFromMap);
       
        iCopiesList = RuntimeEnv.newInstantiator(cCopiesList);
       
        iUnmodifiableCollection = RuntimeEnv.newInstantiator(cUnmodifiableCollection);
        iUnmodifiableSet = RuntimeEnv.newInstantiator(cUnmodifiableSet);
        iUnmodifiableSortedSet = RuntimeEnv.newInstantiator(cUnmodifiableSortedSet);
        iUnmodifiableList = RuntimeEnv.newInstantiator(cUnmodifiableList);
        iUnmodifiableRandomAccessList = RuntimeEnv.newInstantiator(cUnmodifiableRandomAccessList);
       
        iSynchronizedCollection = RuntimeEnv.newInstantiator(cSynchronizedCollection);
        iSynchronizedSet = RuntimeEnv.newInstantiator(cSynchronizedSet);
        iSynchronizedSortedSet = RuntimeEnv.newInstantiator(cSynchronizedSortedSet);
        iSynchronizedList = RuntimeEnv.newInstantiator(cSynchronizedList);
        iSynchronizedRandomAccessList = RuntimeEnv.newInstantiator(cSynchronizedRandomAccessList);
       
        iCheckedCollection = RuntimeEnv.newInstantiator(cCheckedCollection);
        iCheckedSet = RuntimeEnv.newInstantiator(cCheckedSet);
        iCheckedSortedSet = RuntimeEnv.newInstantiator(cCheckedSortedSet);
        iCheckedList = RuntimeEnv.newInstantiator(cCheckedList);
        iCheckedRandomAccessList = RuntimeEnv.newInstantiator(cCheckedRandomAccessList);
    }
   
    private static Class<?> map(String className, int id)
    {
        Class<?> clazz = RuntimeEnv.loadClass(className);
        __nonPublicCollections.put(clazz, id);
        return clazz;
    }
   
    static String name(int number)
    {
        switch(number)
        {
            case ID_EMPTY_SET: return STR_EMPTY_SET;
            case ID_EMPTY_LIST: return STR_EMPTY_LIST;
            case ID_SINGLETON_SET: return STR_SINGLETON_SET;
            case ID_SINGLETON_LIST: return STR_SINGLETON_LIST;
            case ID_SET_FROM_MAP: return STR_SET_FROM_MAP;
            case ID_COPIES_LIST: return STR_COPIES_LIST;
            case ID_UNMODIFIABLE_COLLECTION: return STR_UNMODIFIABLE_COLLECTION;
            case ID_UNMODIFIABLE_SET: return STR_UNMODIFIABLE_SET;
            case ID_UNMODIFIABLE_SORTED_SET: return STR_UNMODIFIABLE_SORTED_SET;
            case ID_UNMODIFIABLE_LIST: return STR_UNMODIFIABLE_LIST;
            case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST: return STR_UNMODIFIABLE_RANDOM_ACCESS_LIST;
            case ID_SYNCHRONIZED_COLLECTION: return STR_SYNCHRONIZED_COLLECTION;
            case ID_SYNCHRONIZED_SET: return STR_SYNCHRONIZED_SET;
            case ID_SYNCHRONIZED_SORTED_SET: return STR_SYNCHRONIZED_SORTED_SET;
            case ID_SYNCHRONIZED_LIST: return STR_SYNCHRONIZED_LIST;
            case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST: return STR_SYNCHRONIZED_RANDOM_ACCESS_LIST;
            case ID_CHECKED_COLLECTION: return STR_CHECKED_COLLECTION;
            case ID_CHECKED_SET: return STR_CHECKED_SET;
            case ID_CHECKED_SORTED_SET: return STR_CHECKED_SORTED_SET;
            case ID_CHECKED_LIST: return STR_CHECKED_LIST;
            case ID_CHECKED_RANDOM_ACCESS_LIST: return STR_CHECKED_RANDOM_ACCESS_LIST;
            case ID_ENUM_SET: return STR_ENUM_SET;
            case ID_ENUM: return STR_ENUM;
            case ID_COLLECTION: return STR_COLLECTION;
            default: return null;
        }
    }
   
    static int number(String name)
    {
        if(name.length() != 1)
            return 0;
       
        switch(name.charAt(0))
        {
            case 'a': return 1;
            case 'b': return 2;
            case 'c': return 3;
            case 'd': return 4;
            case 'e': return 5;
            case 'f': return 6;
            case 'g': return 7;
            case 'h': return 8;
            case 'i': return 9;
            case 'j': return 10;
            case 'k': return 11;
            case 'l': return 12;
            case 'm': return 13;
            case 'n': return 14;
            case 'o': return 15;
            case 'p': return 16;
            case 'q': return 17;
            case 'r': return 18;
            case 's': return 19;
            case 't': return 20;
            case 'u': return 21;
            case 'v': return ID_ENUM_SET;
            case 'x': return ID_ENUM;
            case 'y': return ID_COLLECTION;
            default: return 0;
        }
    }
   
    protected final Pipe.Schema<Object> pipeSchema = new Pipe.Schema<Object>(this)
    {
        protected void transfer(Pipe pipe, Input input, Output output) throws IOException
        {
            transferObject(this, pipe, input, output, strategy);
        }
    };
   
    public PolymorphicCollectionSchema(IdStrategy strategy)
    {
        super(strategy);
    }
   
    public Pipe.Schema<Object> getPipeSchema()
    {
        return pipeSchema;
    }
   
    public String getFieldName(int number)
    {
        return name(number);
    }

    public int getFieldNumber(String name)
    {
        return number(name);
    }

    public String messageFullName()
    {
        return Collection.class.getName();
    }

    public String messageName()
    {
        return Collection.class.getSimpleName();
    }

    public void mergeFrom(Input input, Object owner) throws IOException
    {
        setValue(readObjectFrom(input, this, owner, strategy), owner);
    }

    public void writeTo(Output output, Object value) throws IOException
    {
        writeObjectTo(output, value, this, strategy);
    }
   
    static int idFrom(Class<?> clazz)
    {
        final Integer id = __nonPublicCollections.get(clazz);
        if(id == null)
            throw new RuntimeException("Unknown collection: " + clazz);
       
        return id.intValue();
    }
   
    static Object instanceFrom(final int id)
    {
        switch(id)
        {
            case ID_EMPTY_SET:
                return Collections.EMPTY_SET;
            case ID_EMPTY_LIST:
                return Collections.EMPTY_LIST;
           
            case ID_SINGLETON_SET:
                return iSingletonSet.newInstance();
            case ID_SINGLETON_LIST:
                return iSingletonList.newInstance();
               
            case ID_SET_FROM_MAP:
                return iSetFromMap.newInstance();
            case ID_COPIES_LIST:
                return iCopiesList.newInstance();
               
            case ID_UNMODIFIABLE_COLLECTION:
                return iUnmodifiableCollection.newInstance();
            case ID_UNMODIFIABLE_SET:
                return iUnmodifiableSet.newInstance();
            case ID_UNMODIFIABLE_SORTED_SET:
                return iUnmodifiableSortedSet.newInstance();
            case ID_UNMODIFIABLE_LIST:
                return iUnmodifiableList.newInstance();
            case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST:
                return iUnmodifiableRandomAccessList.newInstance();
               
            case ID_SYNCHRONIZED_COLLECTION:
                return iSynchronizedCollection.newInstance();
            case ID_SYNCHRONIZED_SET:
                return iSynchronizedSet.newInstance();
            case ID_SYNCHRONIZED_SORTED_SET:
                return iSynchronizedSortedSet.newInstance();
            case ID_SYNCHRONIZED_LIST:
                return iSynchronizedList.newInstance();
            case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST:
                return iSynchronizedRandomAccessList.newInstance();
               
            case ID_CHECKED_COLLECTION:
                return iCheckedCollection.newInstance();
            case ID_CHECKED_SET:
                return iCheckedSet.newInstance();
            case ID_CHECKED_SORTED_SET:
                return iCheckedSortedSet.newInstance();
            case ID_CHECKED_LIST:
                return iCheckedList.newInstance();
            case ID_CHECKED_RANDOM_ACCESS_LIST:
                return iCheckedRandomAccessList.newInstance();
               
            default:
                throw new RuntimeException("Unknown id: " + id);
        }
    }
   
    @SuppressWarnings("unchecked")
    static void writeObjectTo(Output output, Object value, Schema<?> currentSchema,
            IdStrategy strategy) throws IOException
    {
        if(Collections.class == value.getClass().getDeclaringClass())
        {
            writeNonPublicCollectionTo(output, value, currentSchema, strategy);
            return;
        }
       
        if(EnumSet.class.isAssignableFrom(value.getClass()))
        {
            strategy.writeEnumIdTo(output, ID_ENUM_SET,
                    EnumIO.getElementTypeFromEnumSet(value));
           
            // TODO optimize
        }
        else
        {
            strategy.writeCollectionIdTo(output, ID_COLLECTION, value.getClass());
        }
       
        if(output instanceof StatefulOutput)
        {
            // update using the derived schema.
            ((StatefulOutput)output).updateLast(strategy.COLLECTION_SCHEMA, currentSchema);
        }
       
        strategy.COLLECTION_SCHEMA.writeTo(output, (Collection<Object>)value);
    }
   
    static void writeNonPublicCollectionTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy) throws IOException
    {
        final Integer num = __nonPublicCollections.get(value.getClass());
        if(num == null)
            throw new RuntimeException("Unknown collection: " + value.getClass());
        final int id = num.intValue();
        switch(id)
        {
            case ID_EMPTY_SET:
                output.writeUInt32(id, 0, false);
                break;
               
            case ID_EMPTY_LIST:
                output.writeUInt32(id, 0, false);
                break;
               
            case ID_SINGLETON_SET:
            {
                output.writeUInt32(id, 0, false);
               
                final Object element;
                try
                {
                    element = fSingletonSet_element.get(value);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                if(element != null)
                    output.writeObject(1, element, strategy.OBJECT_SCHEMA, false);
               
                break;
            }
               
            case ID_SINGLETON_LIST:
            {
                output.writeUInt32(id, 0, false);
               
                // faster path (reflection not needed to get the single element).
                final Object element = ((List<?>)value).get(0);
               
                if(element != null)
                    output.writeObject(1, element, strategy.OBJECT_SCHEMA, false);
               
                break;
            }
               
            case ID_SET_FROM_MAP:
            {
                final Object m;
                try
                {
                    m = fSetFromMap_m.get(value);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                output.writeObject(id, m, strategy.POLYMORPHIC_MAP_SCHEMA, false);
               
                break;
            }
               
            case ID_COPIES_LIST:
            {
                output.writeUInt32(id, 0, false);
               
                final int n = ((List<?>)value).size();
                final Object element;
                try
                {
                    element = fCopiesList_element.get(value);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                output.writeUInt32(1, n, false);
               
                if(element != null)
                    output.writeObject(2, element, strategy.OBJECT_SCHEMA, false);
               
                break;
            }  
            case ID_UNMODIFIABLE_COLLECTION:
                writeUnmodifiableCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_UNMODIFIABLE_SET:
                writeUnmodifiableCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_UNMODIFIABLE_SORTED_SET:
                writeUnmodifiableCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_UNMODIFIABLE_LIST:
                writeUnmodifiableCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST:
                writeUnmodifiableCollectionTo(output, value, currentSchema, strategy, id);
                break;
           
            case ID_SYNCHRONIZED_COLLECTION:
                writeSynchronizedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_SYNCHRONIZED_SET:
                writeSynchronizedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_SYNCHRONIZED_SORTED_SET:
                writeSynchronizedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_SYNCHRONIZED_LIST:
                writeSynchronizedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST:
                writeSynchronizedCollectionTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_CHECKED_COLLECTION:
                writeCheckedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_CHECKED_SET:
                writeCheckedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_CHECKED_SORTED_SET:
                writeCheckedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_CHECKED_LIST:
                writeCheckedCollectionTo(output, value, currentSchema, strategy, id);
                break;
            case ID_CHECKED_RANDOM_ACCESS_LIST:
                writeCheckedCollectionTo(output, value, currentSchema, strategy, id);
                break;
               
            default:
                throw new RuntimeException("Should not happen.");
        }
    }
   
    private static void writeUnmodifiableCollectionTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object c;
        try
        {
            c = fUnmodifiableCollection_c.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        output.writeObject(id, c, strategy.POLYMORPHIC_COLLECTION_SCHEMA, false);
    }
   
    private static void writeSynchronizedCollectionTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object c, mutex;
        try
        {
            c = fSynchronizedCollection_c.get(value);
            mutex = fSynchronizedCollection_mutex.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        if(mutex != value)
        {
            // TODO for future release, introduce an interface(GraphOutput) so we
            // can check whether the output can retain references.
            throw new RuntimeException(
                    "This exception is thrown to fail fast. " +
                    "Synchronized collections with a different mutex would only " +
                    "work if graph format is used, since the reference is retained.");
        }
       
        output.writeObject(id, c, strategy.POLYMORPHIC_COLLECTION_SCHEMA, false);
    }
   
    private static void writeCheckedCollectionTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object c, type;
        try
        {
            c = fCheckedCollection_c.get(value);
            type = fCheckedCollection_type.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        output.writeObject(id, c, strategy.POLYMORPHIC_COLLECTION_SCHEMA, false);
        output.writeObject(1, type, strategy.CLASS_SCHEMA, false);
    }

    @SuppressWarnings("unchecked")
    static Object readObjectFrom(Input input,  Schema<?> schema, Object owner,
            IdStrategy strategy) throws IOException // TODO pass in type (Class<?>)
    {
        final boolean graph = input instanceof GraphInput;
        Object ret = null;
        final int number = input.readFieldNumber(schema);
        switch(number)
        {
            case ID_EMPTY_SET:
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(Collections.EMPTY_SET, owner);
                }
               
                ret = Collections.EMPTY_SET;
                break;
               
            case ID_EMPTY_LIST:
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(Collections.EMPTY_LIST, owner);
                }
               
                ret = Collections.EMPTY_LIST;
                break;
               
            case ID_SINGLETON_SET:
            {
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                final Object collection = iSingletonSet.newInstance();
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(collection, owner);
                }
               
                final int next = input.readFieldNumber(schema);
                if(next == 0)
                {
                    // null element
                    return collection;
                }
               
                if(next != 1)
                    throw new ProtostuffException("Corrupt input");
               
                final Wrapper wrapper = new Wrapper();
                Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
                if(!graph || !((GraphInput)input).isCurrentMessageReference())
                    element = wrapper.value;
               
                try
                {
                    fSingletonSet_element.set(collection, element);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                ret = collection;
                break;
            }
           
            case ID_SINGLETON_LIST:
            {
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                final Object collection = iSingletonList.newInstance();
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(collection, owner);
                }
               
                final int next = input.readFieldNumber(schema);
                if(next == 0)
                {
                    // null element
                    return collection;
                }
               
                if(next != 1)
                    throw new ProtostuffException("Corrupt input.");
               
                final Wrapper wrapper = new Wrapper();
                Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
                if(!graph || !((GraphInput)input).isCurrentMessageReference())
                    element = wrapper.value;
               
                try
                {
                    fSingletonList_element.set(collection, element);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                ret = collection;
                break;
            }
           
            case ID_SET_FROM_MAP:
            {
                final Object collection = iSetFromMap.newInstance();
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(collection, owner);
                }
               
                final Wrapper wrapper = new Wrapper();
                Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA);
                if(!graph || !((GraphInput)input).isCurrentMessageReference())
                    m = wrapper.value;
               
                try
                {
                    fSetFromMap_m.set(collection, m);
                    fSetFromMap_s.set(collection, ((Map<?,?>)m).keySet());
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                ret = collection;
                break;
            }
               
            case ID_COPIES_LIST:
            {
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                final Object collection = iCopiesList.newInstance();
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(collection, owner);
                }
               
                if(1 != input.readFieldNumber(schema))
                    throw new ProtostuffException("Corrupt input.");
               
                final int n = input.readUInt32(),
                        next = input.readFieldNumber(schema);
               
                if(next == 0)
                {
                    // null element
                    try
                    {
                        fCopiesList_n.setInt(collection, n);
                    }
                    catch (IllegalArgumentException e)
                    {
                        throw new RuntimeException(e);
                    }
                    catch (IllegalAccessException e)
                    {
                        throw new RuntimeException(e);
                    }
                   
                    return collection;
                }
               
                if(next != 2)
                    throw new ProtostuffException("Corrupt input.");
               
                final Wrapper wrapper = new Wrapper();
                Object element = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
                if(!graph || !((GraphInput)input).isCurrentMessageReference())
                    element = wrapper.value;
               
                try
                {
                    fCopiesList_n.setInt(collection, n);
                    fCopiesList_element.set(collection, element);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                ret = collection;
                break;
            }
           
            case ID_UNMODIFIABLE_COLLECTION:
                ret = readUnmodifiableCollectionFrom(input, schema, owner, strategy, graph, 
                        iUnmodifiableCollection.newInstance(), false, false);
                break;
            case ID_UNMODIFIABLE_SET:
                ret = readUnmodifiableCollectionFrom(input, schema, owner, strategy, graph, 
                        iUnmodifiableSet.newInstance(), false, false);
                break;
            case ID_UNMODIFIABLE_SORTED_SET:
                ret = readUnmodifiableCollectionFrom(input, schema, owner, strategy, graph, 
                        iUnmodifiableSortedSet.newInstance(), true, false);
                break;
            case ID_UNMODIFIABLE_LIST:
                ret = readUnmodifiableCollectionFrom(input, schema, owner, strategy, graph, 
                        iUnmodifiableList.newInstance(), false, true);
                break;
            case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST:
                ret = readUnmodifiableCollectionFrom(input, schema, owner, strategy, graph, 
                        iUnmodifiableRandomAccessList.newInstance(), false, true);
                break;
               
            case ID_SYNCHRONIZED_COLLECTION:
                ret = readSynchronizedCollectionFrom(input, schema, owner, strategy, graph, 
                        iSynchronizedCollection.newInstance(), false, false);
                break;
            case ID_SYNCHRONIZED_SET:
                ret = readSynchronizedCollectionFrom(input, schema, owner, strategy, graph, 
                        iSynchronizedSet.newInstance(), false, false);
                break;
            case ID_SYNCHRONIZED_SORTED_SET:
                ret = readSynchronizedCollectionFrom(input, schema, owner, strategy, graph, 
                        iSynchronizedSortedSet.newInstance(), true, false);
                break;
            case ID_SYNCHRONIZED_LIST:
                ret = readSynchronizedCollectionFrom(input, schema, owner, strategy, graph, 
                        iSynchronizedList.newInstance(), false, true);
                break;
            case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST:
                ret = readSynchronizedCollectionFrom(input, schema, owner, strategy, graph, 
                        iSynchronizedRandomAccessList.newInstance(), false, true);
                break;
               
            case ID_CHECKED_COLLECTION:
                ret = readCheckedCollectionFrom(input, schema, owner, strategy, graph, 
                        iCheckedCollection.newInstance(), false, false);
                break;
            case ID_CHECKED_SET:
                ret = readCheckedCollectionFrom(input, schema, owner, strategy, graph, 
                        iCheckedSet.newInstance(), false, false);
                break;
            case ID_CHECKED_SORTED_SET:
                ret = readCheckedCollectionFrom(input, schema, owner, strategy, graph, 
                        iCheckedSortedSet.newInstance(), true, false);
                break;
            case ID_CHECKED_LIST:
                ret = readCheckedCollectionFrom(input, schema, owner, strategy, graph, 
                        iCheckedList.newInstance(), false, true);
                break;
            case ID_CHECKED_RANDOM_ACCESS_LIST:
                ret = readCheckedCollectionFrom(input, schema, owner, strategy, graph, 
                        iCheckedRandomAccessList.newInstance(), false, true);
                break;
               
            case ID_ENUM_SET:
            {
                final Collection<?> es = strategy.resolveEnumFrom(input).newEnumSet();
               
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(es, owner);
                }
               
                // TODO enum schema
                strategy.COLLECTION_SCHEMA.mergeFrom(input, (Collection<Object>)es);
                return es;
            }
               
            case ID_COLLECTION:
            {
                final Collection<Object> collection = strategy.resolveCollectionFrom(
                        input).newMessage();
               
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(collection, owner);
                }
               
                strategy.COLLECTION_SCHEMA.mergeFrom(input, collection);
               
                return collection;
            }
               
            default: throw new ProtostuffException("Corrupt input.");
        }
       
        if(0 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        return ret;
    }
   
    private static Object readUnmodifiableCollectionFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object collection, boolean ss, boolean list) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(collection, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object c = input.mergeObject(wrapper, strategy.POLYMORPHIC_COLLECTION_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            c = wrapper.value;
        try
        {
            fUnmodifiableCollection_c.set(collection, c);
           
            if(ss)
                fUnmodifiableSortedSet_ss.set(collection, c);
           
            if(list)
                fUnmodifiableList_list.set(collection, c);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return collection;
    }
   
    private static Object readSynchronizedCollectionFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object collection, boolean ss, boolean list) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(collection, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object c = input.mergeObject(wrapper, strategy.POLYMORPHIC_COLLECTION_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            c = wrapper.value;
        try
        {
            fSynchronizedCollection_c.set(collection, c);
            // mutex is the object itself.
            fSynchronizedCollection_mutex.set(collection, collection);
           
            if(ss)
                fSynchronizedSortedSet_ss.set(collection, c);
           
            if(list)
                fSynchronizedList_list.set(collection, c);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return collection;
    }
   
    private static Object readCheckedCollectionFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object collection, boolean ss, boolean list) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(collection, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object c = input.mergeObject(wrapper, strategy.POLYMORPHIC_COLLECTION_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            c = wrapper.value;
       
        if(1 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        Object type = input.mergeObject(wrapper, strategy.CLASS_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            type = wrapper.value;
        try
        {
            fCheckedCollection_c.set(collection, c);
            fCheckedCollection_type.set(collection, type);
           
            if(ss)
                fCheckedSortedSet_ss.set(collection, c);
           
            if(list)
                fCheckedList_list.set(collection, c);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return collection;
    }

    static void transferObject(Pipe.Schema<Object> pipeSchema, Pipe pipe,
            Input input, Output output, IdStrategy strategy) throws IOException
    {
        final int number = input.readFieldNumber(pipeSchema.wrappedSchema);
        switch(number)
        {
            case ID_EMPTY_SET:
                output.writeUInt32(number, input.readUInt32(), false);
                break;
               
            case ID_EMPTY_LIST:
                output.writeUInt32(number, input.readUInt32(), false);
                break;
               
            case ID_SINGLETON_SET:
            case ID_SINGLETON_LIST:
            {
                output.writeUInt32(number, input.readUInt32(), false);
               
                final int next = input.readFieldNumber(pipeSchema.wrappedSchema);
                if(next == 0)
                {
                    // null element
                    return;
                }
               
                if(next != 1)
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(1, pipe, strategy.OBJECT_PIPE_SCHEMA, false);
                break;
            }  
            case ID_SET_FROM_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
                break;
               
            case ID_COPIES_LIST:
            {
                output.writeUInt32(number, input.readUInt32(), false);
               
                if(1 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                // size
                output.writeUInt32(1, input.readUInt32(), false);
               
                final int next = input.readFieldNumber(pipeSchema.wrappedSchema);
                if(next == 0)
                {
                    // null element
                    return;
                }
               
                if(next != 2)
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(2, pipe, strategy.OBJECT_PIPE_SCHEMA, false);
                break;
            }  
            case ID_UNMODIFIABLE_COLLECTION:
            case ID_UNMODIFIABLE_SET:
            case ID_UNMODIFIABLE_SORTED_SET:
            case ID_UNMODIFIABLE_LIST:
            case ID_UNMODIFIABLE_RANDOM_ACCESS_LIST:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA,
                        false);
                break;
               
            case ID_SYNCHRONIZED_COLLECTION:
            case ID_SYNCHRONIZED_SET:
            case ID_SYNCHRONIZED_SORTED_SET:
            case ID_SYNCHRONIZED_LIST:
            case ID_SYNCHRONIZED_RANDOM_ACCESS_LIST:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA,
                        false);
                break;
               
            case ID_CHECKED_COLLECTION:
            case ID_CHECKED_SET:
            case ID_CHECKED_SORTED_SET:
            case ID_CHECKED_LIST:
            case ID_CHECKED_RANDOM_ACCESS_LIST:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_COLLECTION_PIPE_SCHEMA,
                        false);
               
                if(1 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(1, pipe, strategy.CLASS_PIPE_SCHEMA,
                        false);
                break;
               
            case ID_ENUM_SET:
                strategy.transferEnumId(input, output, number);
               
                if(output instanceof StatefulOutput)
                {
                    // update using the derived schema.
                    ((StatefulOutput)output).updateLast(strategy.COLLECTION_PIPE_SCHEMA, pipeSchema);
                }
               
                // TODO use enum schema
                Pipe.transferDirect(strategy.COLLECTION_PIPE_SCHEMA, pipe, input, output);
                return;
            case ID_COLLECTION:
                strategy.transferCollectionId(input, output, number);
               
                if(output instanceof StatefulOutput)
                {
                    // update using the derived schema.
                    ((StatefulOutput)output).updateLast(strategy.COLLECTION_PIPE_SCHEMA, pipeSchema);
                }
               
                Pipe.transferDirect(strategy.COLLECTION_PIPE_SCHEMA, pipe, input, output);
                return;
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        if(0 != input.readFieldNumber(pipeSchema.wrappedSchema))
            throw new ProtostuffException("Corrupt input.");
    }
}
TOP

Related Classes of com.dyuproject.protostuff.runtime.PolymorphicCollectionSchema

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.