<commit_before>/**
 *
 */
package org.drools.common;

import java.io.IOException;
import java.io.InputStream;
import java.io.StreamCorruptedException;
import java.io.Externalizable;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.ObjectInput;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
import java.util.List;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.drools.base.ClassFieldExtractorCache;
import org.drools.rule.DialectDatas;
import org.drools.rule.Package;
import org.drools.rule.CompositePackageClassLoader;

public class DroolsObjectInputStream
        implements DroolsObjectInput, DroolsObjectStreamConstants {

    private final Map<Integer, Object> objectsByHandle = new HashMap<Integer, Object>();
    private DroolsObjectInput dataInput;

    private static final Map<String, Class>     primClasses = new HashMap<String, Class>( 8, 1.0F );
    static {
        primClasses.put( "boolean",
                         boolean.class );
        primClasses.put( "byte",
                         byte.class );
        primClasses.put( "char",
                         char.class );
        primClasses.put( "short",
                         short.class );
        primClasses.put( "int",
                         int.class );
        primClasses.put( "long",
                         long.class );
        primClasses.put( "float",
                         float.class );
        primClasses.put( "double",
                         double.class );
        primClasses.put( "void",
                         void.class );
    }

    private ClassLoader classLoader;
    private InternalRuleBase         ruleBase;
    private InternalWorkingMemory    workingMemory;
    private Package                  pkg;
    private DialectDatas             dialectDatas;
    private ClassFieldExtractorCache extractorFactory;

    /**
     * Created this inner class to handle un-Externalizable objects just in case.
     */
    private class DroolsInternalInputStream
            extends ObjectInputStream
            implements DroolsObjectInput {

        private DroolsInternalInputStream(InputStream in, ClassLoader classLoader) throws IOException {
            super(in);
            setClassLoader(classLoader);
        }

        public ClassLoader getClassLoader() {
            return DroolsObjectInputStream.this.getClassLoader();
        }

        public void setClassLoader(ClassLoader classLoader) {
            DroolsObjectInputStream.this.setClassLoader(classLoader);
        }

        public InternalRuleBase getRuleBase() {
            return DroolsObjectInputStream.this.getRuleBase();
        }
        public void setRuleBase(InternalRuleBase ruleBase) {
            DroolsObjectInputStream.this.setRuleBase(ruleBase);
        }

        public InternalWorkingMemory getWorkingMemory() {
            return DroolsObjectInputStream.this.getWorkingMemory();
        }
        public void setWorkingMemory(InternalWorkingMemory workingMemory) {
            DroolsObjectInputStream.this.setWorkingMemory(workingMemory);
        }

        public Package getPackage() {
            return DroolsObjectInputStream.this.getPackage();
        }
        public void setPackage(Package pkg) {
            DroolsObjectInputStream.this.setPackage(pkg);
        }

        public DialectDatas getDialectDatas() {
            return DroolsObjectInputStream.this.getDialectDatas();
        }
        public void setDialectDatas(DialectDatas dialectDatas) {
            DroolsObjectInputStream.this.setDialectDatas(dialectDatas);
        }

        public ClassFieldExtractorCache getExtractorFactory() {
            return DroolsObjectInputStream.this.getExtractorFactory();
        }

        public void setExtractorFactory(ClassFieldExtractorCache extractorFactory) {
            DroolsObjectInputStream.this.setExtractorFactory(extractorFactory);
        }

        protected Class resolveClass(ObjectStreamClass desc) throws IOException,
                                                                    ClassNotFoundException {
            if ( getClassLoader() == null ) {
                return super.resolveClass( desc );
            } else {
                try {
                    return DroolsObjectInputStream.this.resolveClass(desc.getName());
                }
                catch (ClassNotFoundException cnf) {
                    return  super.resolveClass( desc );
                }
            }
        }
    }

    public DroolsObjectInputStream(InputStream inputStream) throws IOException {
        this(inputStream, null);
    }

    public DroolsObjectInputStream(InputStream inputStream, ClassLoader classLoader) throws IOException {
        dataInput    = new DroolsInternalInputStream(inputStream, classLoader);
        extractorFactory = ClassFieldExtractorCache.getInstance();
        readStreamHeader();
    }

    public DroolsObjectInputStream(ObjectInput inputStream) throws IOException {
        this(inputStream, null);
    }

    public DroolsObjectInputStream(ObjectInput inputStream, ClassLoader classLoader) throws IOException {
        this((InputStream)inputStream, classLoader);
    }

    public InternalRuleBase getRuleBase() {
        return ruleBase;
    }
    public void setRuleBase(InternalRuleBase ruleBase) {
        this.ruleBase   = ruleBase;
    }

    public InternalWorkingMemory getWorkingMemory() {
        return workingMemory;
    }
    public void setWorkingMemory(InternalWorkingMemory workingMemory) {
        this.workingMemory  = workingMemory;
    }

    public Package getPackage() {
        return pkg;
    }
    public void setPackage(Package pkg) {
        this.pkg    = pkg;
    }

    public DialectDatas getDialectDatas() {
        return dialectDatas;
    }
    public void setDialectDatas(DialectDatas dialectDatas) {
        this.dialectDatas   = dialectDatas;
    }

    public ClassFieldExtractorCache getExtractorFactory() {
        return extractorFactory;
    }

    public void setExtractorFactory(ClassFieldExtractorCache extractorFactory) {
        this.extractorFactory   = extractorFactory;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        if (classLoader == null) {
            classLoader = Thread.currentThread().getContextClassLoader();
            if ( classLoader == null ) {
                classLoader = getClass().getClassLoader();
            }
        }
        this.classLoader    = classLoader;
    }

    protected void readStreamHeader() throws IOException {
        int magic   = readInt();
        short version = readShort();
        if (magic != STREAM_MAGIC || version != STREAM_VERSION) {
            throw new StreamCorruptedException("Invalid stream header: "+magic+'|'+version);
        }
    }

    public Object readObject() throws ClassNotFoundException, IOException {
        byte type = readRecordType();

        switch (type) {
            case RT_NULL:
                return readNull();
            case RT_EMPTY_SET:
                return readEmptySet();
            case RT_EMPTY_LIST:
                return readEmptyList();
            case RT_EMPTY_MAP:
                return readEmptyMap();
            default:
                return readObject(type);
        }
    }

    private Object readObject(byte type) throws IOException, ClassNotFoundException {
        int handle = readHandle();

        switch (type) {
            case RT_EXTERNALIZABLE:
                return readExternalizable(handle);
            case RT_STRING:
                return readString(handle);
            case RT_MAP:
                return readMap(handle);
            case RT_COLLECTION:
                return readCollection(handle);
            case RT_ARRAY:
                return readArray(handle);
            case RT_CLASS:
                return readClass(handle);
            case RT_REFERENCE:
                return readReference(handle);
            case RT_ATOMICREFERENCEARRAY:
                return readAtomicReferenceArray(handle);
            case RT_SERIALIZABLE:
                return readSerializable(handle);
            default:
                throw new StreamCorruptedException("Unsupported object type: " + type);
        }
    }

    private Object readArray(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int length = dataInput.readInt();
        Class componentType = clazz.getComponentType();
        Object array = Array.newInstance(componentType, length);
        registerObject(handle, array);
        if (componentType.isPrimitive()) {
            readPrimitiveArray(array, length, componentType);
        } else {
            readObjectArray((Object[]) array, length);
        }
        return array;
    }

    private void readPrimitiveArray(Object array, int length, Class clazz) throws IOException {
        if (clazz == Integer.TYPE) {
            readIntArray((int[]) array, length);
        } else if (clazz == Byte.TYPE) {
            readByteArray((byte[]) array, length);
        } else if (clazz == Long.TYPE) {
            readLongArray((long[]) array, length);
        } else if (clazz == Float.TYPE) {
            readFloatArray((float[]) array, length);
        } else if (clazz == Double.TYPE) {
            readDoubleArray((double[]) array, length);
        } else if (clazz == Short.TYPE) {
            readShortArray((short[]) array, length);
        } else if (clazz == Character.TYPE) {
            readCharArray((char[]) array, length);
        } else if (clazz == Boolean.TYPE) {
            readBooleanArray((boolean[]) array, length);
        } else {
            throw new StreamCorruptedException("Unsupported array type: " + clazz);
        }
    }

    private void readIntArray(int[] ints, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            ints[i] = dataInput.readInt();
        }
    }

    private void readByteArray(byte[] bytes, int length) throws IOException {
        dataInput.readFully(bytes, 0, length);
    }

    private void readLongArray(long[] longs, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            longs[i] = dataInput.readLong();
        }
    }

    private void readFloatArray(float[] floats, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            floats[i] = dataInput.readFloat();
        }
    }

    private void readDoubleArray(double[] doubles, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            doubles[i] = dataInput.readDouble();
        }
    }

    private void readShortArray(short[] shorts, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            shorts[i] = dataInput.readShort();
        }
    }

    private void readCharArray(char[] chars, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            chars[i] = dataInput.readChar();
        }
    }

    private void readBooleanArray(boolean[] booleans, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            booleans[i] = dataInput.readBoolean();
        }
    }

    private void readObjectArray(Object[] objects, int length) throws IOException, ClassNotFoundException {
        for (int i = 0; i < length; ++i) {
            objects[i] = readObject();
        }
    }

    private static Object readNull() {
        return null;
    }

    private static Set readEmptySet() {
        return Collections.EMPTY_SET;
    }

    private static List readEmptyList() {
        return Collections.EMPTY_LIST;
    }

    private static Map readEmptyMap() {
        return Collections.EMPTY_MAP;
    }

    private Object readSerializable(int handle) throws ClassNotFoundException, IOException {
        Object  object  =  dataInput.readObject();
        registerObject(handle, object);
        return object;
    }

    private Object readExternalizable(int handle) throws ClassNotFoundException, IOException {
        Class clazz = (Class) readObject();
        Externalizable externalizable;
        try {
            externalizable = (Externalizable) clazz.newInstance();
        } catch (InstantiationException e) {
            throw newInvalidClassException(clazz, e);
        } catch (IllegalAccessException e) {
            throw newInvalidClassException(clazz, e);
        }
        registerObject(handle, externalizable);
        externalizable.readExternal(this);
        return externalizable;
    }

    private String readString(int handle) throws IOException {
        String string = dataInput.readUTF();
        registerObject(handle, string);
        return string;
    }

    private AtomicReferenceArray<Object> readAtomicReferenceArray(int handle)
            throws IOException, ClassNotFoundException {
        int length  = dataInput.readInt();
        AtomicReferenceArray<Object>    array   = new AtomicReferenceArray<Object>(length);
        registerObject(handle, array);
        for (int i = 0; i < length; ++i) {
            array.set(i, readObject());
        }
        return array;
    }

    private Map readMap(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int size = dataInput.readInt();
        Map<Object, Object> map = (Map<Object, Object>) newCollection(handle, clazz, size);
        for (int i = 0; i < size; ++i) {
            Object key = readObject();
            Object value = readObject();
            map.put(key, value);
        }
        return map;
    }

    private Collection readCollection(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int size = dataInput.readInt();
        Collection<Object> collection = (Collection<Object>) newCollection(handle, clazz, size);
        for (int i = 0; i < size; ++i) {
            collection.add(readObject());
        }
        return collection;
    }

    private Object newCollection(int handle, Class clazz, int size) throws IOException {
        Object collection;
        try {
            Constructor constructor = clazz.getConstructor(Integer.TYPE);
            collection = constructor.newInstance(size);
        } catch (InstantiationException e) {
            throw newInvalidClassException(clazz, e);
        } catch (IllegalAccessException e) {
            throw newInvalidClassException(clazz, e);
        } catch (InvocationTargetException e) {
            throw newInvalidClassException(clazz, e);
        } catch (NoSuchMethodException e) {
            try {
                Constructor constructor = clazz.getConstructor();
                collection  = constructor.newInstance();
            } catch (Exception e2) {
                throw newInvalidClassException(clazz, e2);
            }
        }
        registerObject(handle, collection);
        return collection;
    }

    private int readHandle() throws IOException {
        return dataInput.readInt();
    }

    private Class readClass(int handle) throws IOException, ClassNotFoundException {
        String className = (String) readObject();
        Class clazz = resolveClass(className);
        registerObject(handle, clazz);
        return clazz;
    }

    private byte readRecordType() throws IOException {
        return dataInput.readByte();
    }

    private Object readReference(int handle) {
        return objectsByHandle.get(handle);
    }

    private void registerObject(int handle, Object object) {
        objectsByHandle.put(handle, object);
    }

    private static InvalidClassException newInvalidClassException(Class clazz, Throwable cause) {
        InvalidClassException exception = new InvalidClassException(clazz.getName());
        exception.initCause(cause);
        return exception;
    }

    /**
     * Using the ClassLoader from the top of the stack to load the class specified by the given class name.
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    protected Class resolveClass(String className) throws ClassNotFoundException{
        try {
            Class clazz = primClasses.get( className );
            if ( clazz == null ) {
                clazz = getClassLoader().loadClass( className );
                if (className.endsWith("ShadowProxy")) {
                    System.out.println();
                }
            }
            return clazz;
        }
        catch (ClassNotFoundException e) {
            return getClass().getClassLoader().loadClass(className);
        }
    }

    /*=================================================================================
    ObjectInput implementations
    =================================================================================*/
    /**
     * Reads a byte of data. This method will block if no input is
     * available.
     * @return 	the byte read, or -1 if the end of the
     *		stream is reached.
     * @exception IOException If an I/O error has occurred.
     */
    public int read() throws IOException {
        return dataInput.read();
    }

    /**
     * Reads into an array of bytes.  This method will<commit_msg>removing sysout<commit_after>/**
 *
 */
package org.drools.common;

import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceArray;

import org.drools.base.ClassFieldExtractorCache;
import org.drools.rule.DialectDatas;
import org.drools.rule.Package;

public class DroolsObjectInputStream
        implements DroolsObjectInput, DroolsObjectStreamConstants {

    private final Map<Integer, Object> objectsByHandle = new HashMap<Integer, Object>();
    private DroolsObjectInput dataInput;

    private static final Map<String, Class>     primClasses = new HashMap<String, Class>( 8, 1.0F );
    static {
        primClasses.put( "boolean",
                         boolean.class );
        primClasses.put( "byte",
                         byte.class );
        primClasses.put( "char",
                         char.class );
        primClasses.put( "short",
                         short.class );
        primClasses.put( "int",
                         int.class );
        primClasses.put( "long",
                         long.class );
        primClasses.put( "float",
                         float.class );
        primClasses.put( "double",
                         double.class );
        primClasses.put( "void",
                         void.class );
    }

    private ClassLoader classLoader;
    private InternalRuleBase         ruleBase;
    private InternalWorkingMemory    workingMemory;
    private Package                  pkg;
    private DialectDatas             dialectDatas;
    private ClassFieldExtractorCache extractorFactory;

    /**
     * Created this inner class to handle un-Externalizable objects just in case.
     */
    private class DroolsInternalInputStream
            extends ObjectInputStream
            implements DroolsObjectInput {

        private DroolsInternalInputStream(InputStream in, ClassLoader classLoader) throws IOException {
            super(in);
            setClassLoader(classLoader);
        }

        public ClassLoader getClassLoader() {
            return DroolsObjectInputStream.this.getClassLoader();
        }

        public void setClassLoader(ClassLoader classLoader) {
            DroolsObjectInputStream.this.setClassLoader(classLoader);
        }

        public InternalRuleBase getRuleBase() {
            return DroolsObjectInputStream.this.getRuleBase();
        }
        public void setRuleBase(InternalRuleBase ruleBase) {
            DroolsObjectInputStream.this.setRuleBase(ruleBase);
        }

        public InternalWorkingMemory getWorkingMemory() {
            return DroolsObjectInputStream.this.getWorkingMemory();
        }
        public void setWorkingMemory(InternalWorkingMemory workingMemory) {
            DroolsObjectInputStream.this.setWorkingMemory(workingMemory);
        }

        public Package getPackage() {
            return DroolsObjectInputStream.this.getPackage();
        }
        public void setPackage(Package pkg) {
            DroolsObjectInputStream.this.setPackage(pkg);
        }

        public DialectDatas getDialectDatas() {
            return DroolsObjectInputStream.this.getDialectDatas();
        }
        public void setDialectDatas(DialectDatas dialectDatas) {
            DroolsObjectInputStream.this.setDialectDatas(dialectDatas);
        }

        public ClassFieldExtractorCache getExtractorFactory() {
            return DroolsObjectInputStream.this.getExtractorFactory();
        }

        public void setExtractorFactory(ClassFieldExtractorCache extractorFactory) {
            DroolsObjectInputStream.this.setExtractorFactory(extractorFactory);
        }

        protected Class resolveClass(ObjectStreamClass desc) throws IOException,
                                                                    ClassNotFoundException {
            if ( getClassLoader() == null ) {
                return super.resolveClass( desc );
            } else {
                try {
                    return DroolsObjectInputStream.this.resolveClass(desc.getName());
                }
                catch (ClassNotFoundException cnf) {
                    return  super.resolveClass( desc );
                }
            }
        }
    }

    public DroolsObjectInputStream(InputStream inputStream) throws IOException {
        this(inputStream, null);
    }

    public DroolsObjectInputStream(InputStream inputStream, ClassLoader classLoader) throws IOException {
        dataInput    = new DroolsInternalInputStream(inputStream, classLoader);
        extractorFactory = ClassFieldExtractorCache.getInstance();
        readStreamHeader();
    }

    public DroolsObjectInputStream(ObjectInput inputStream) throws IOException {
        this(inputStream, null);
    }

    public DroolsObjectInputStream(ObjectInput inputStream, ClassLoader classLoader) throws IOException {
        this((InputStream)inputStream, classLoader);
    }

    public InternalRuleBase getRuleBase() {
        return ruleBase;
    }
    public void setRuleBase(InternalRuleBase ruleBase) {
        this.ruleBase   = ruleBase;
    }

    public InternalWorkingMemory getWorkingMemory() {
        return workingMemory;
    }
    public void setWorkingMemory(InternalWorkingMemory workingMemory) {
        this.workingMemory  = workingMemory;
    }

    public Package getPackage() {
        return pkg;
    }
    public void setPackage(Package pkg) {
        this.pkg    = pkg;
    }

    public DialectDatas getDialectDatas() {
        return dialectDatas;
    }
    public void setDialectDatas(DialectDatas dialectDatas) {
        this.dialectDatas   = dialectDatas;
    }

    public ClassFieldExtractorCache getExtractorFactory() {
        return extractorFactory;
    }

    public void setExtractorFactory(ClassFieldExtractorCache extractorFactory) {
        this.extractorFactory   = extractorFactory;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        if (classLoader == null) {
            classLoader = Thread.currentThread().getContextClassLoader();
            if ( classLoader == null ) {
                classLoader = getClass().getClassLoader();
            }
        }
        this.classLoader    = classLoader;
    }

    protected void readStreamHeader() throws IOException {
        int magic   = readInt();
        short version = readShort();
        if (magic != STREAM_MAGIC || version != STREAM_VERSION) {
            throw new StreamCorruptedException("Invalid stream header: "+magic+'|'+version);
        }
    }

    public Object readObject() throws ClassNotFoundException, IOException {
        byte type = readRecordType();

        switch (type) {
            case RT_NULL:
                return readNull();
            case RT_EMPTY_SET:
                return readEmptySet();
            case RT_EMPTY_LIST:
                return readEmptyList();
            case RT_EMPTY_MAP:
                return readEmptyMap();
            default:
                return readObject(type);
        }
    }

    private Object readObject(byte type) throws IOException, ClassNotFoundException {
        int handle = readHandle();

        switch (type) {
            case RT_EXTERNALIZABLE:
                return readExternalizable(handle);
            case RT_STRING:
                return readString(handle);
            case RT_MAP:
                return readMap(handle);
            case RT_COLLECTION:
                return readCollection(handle);
            case RT_ARRAY:
                return readArray(handle);
            case RT_CLASS:
                return readClass(handle);
            case RT_REFERENCE:
                return readReference(handle);
            case RT_ATOMICREFERENCEARRAY:
                return readAtomicReferenceArray(handle);
            case RT_SERIALIZABLE:
                return readSerializable(handle);
            default:
                throw new StreamCorruptedException("Unsupported object type: " + type);
        }
    }

    private Object readArray(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int length = dataInput.readInt();
        Class componentType = clazz.getComponentType();
        Object array = Array.newInstance(componentType, length);
        registerObject(handle, array);
        if (componentType.isPrimitive()) {
            readPrimitiveArray(array, length, componentType);
        } else {
            readObjectArray((Object[]) array, length);
        }
        return array;
    }

    private void readPrimitiveArray(Object array, int length, Class clazz) throws IOException {
        if (clazz == Integer.TYPE) {
            readIntArray((int[]) array, length);
        } else if (clazz == Byte.TYPE) {
            readByteArray((byte[]) array, length);
        } else if (clazz == Long.TYPE) {
            readLongArray((long[]) array, length);
        } else if (clazz == Float.TYPE) {
            readFloatArray((float[]) array, length);
        } else if (clazz == Double.TYPE) {
            readDoubleArray((double[]) array, length);
        } else if (clazz == Short.TYPE) {
            readShortArray((short[]) array, length);
        } else if (clazz == Character.TYPE) {
            readCharArray((char[]) array, length);
        } else if (clazz == Boolean.TYPE) {
            readBooleanArray((boolean[]) array, length);
        } else {
            throw new StreamCorruptedException("Unsupported array type: " + clazz);
        }
    }

    private void readIntArray(int[] ints, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            ints[i] = dataInput.readInt();
        }
    }

    private void readByteArray(byte[] bytes, int length) throws IOException {
        dataInput.readFully(bytes, 0, length);
    }

    private void readLongArray(long[] longs, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            longs[i] = dataInput.readLong();
        }
    }

    private void readFloatArray(float[] floats, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            floats[i] = dataInput.readFloat();
        }
    }

    private void readDoubleArray(double[] doubles, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            doubles[i] = dataInput.readDouble();
        }
    }

    private void readShortArray(short[] shorts, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            shorts[i] = dataInput.readShort();
        }
    }

    private void readCharArray(char[] chars, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            chars[i] = dataInput.readChar();
        }
    }

    private void readBooleanArray(boolean[] booleans, int length) throws IOException {
        for (int i = 0; i < length; ++i) {
            booleans[i] = dataInput.readBoolean();
        }
    }

    private void readObjectArray(Object[] objects, int length) throws IOException, ClassNotFoundException {
        for (int i = 0; i < length; ++i) {
            objects[i] = readObject();
        }
    }

    private static Object readNull() {
        return null;
    }

    private static Set readEmptySet() {
        return Collections.EMPTY_SET;
    }

    private static List readEmptyList() {
        return Collections.EMPTY_LIST;
    }

    private static Map readEmptyMap() {
        return Collections.EMPTY_MAP;
    }

    private Object readSerializable(int handle) throws ClassNotFoundException, IOException {
        Object  object  =  dataInput.readObject();
        registerObject(handle, object);
        return object;
    }

    private Object readExternalizable(int handle) throws ClassNotFoundException, IOException {
        Class clazz = (Class) readObject();
        Externalizable externalizable;
        try {
            externalizable = (Externalizable) clazz.newInstance();
        } catch (InstantiationException e) {
            throw newInvalidClassException(clazz, e);
        } catch (IllegalAccessException e) {
            throw newInvalidClassException(clazz, e);
        }
        registerObject(handle, externalizable);
        externalizable.readExternal(this);
        return externalizable;
    }

    private String readString(int handle) throws IOException {
        String string = dataInput.readUTF();
        registerObject(handle, string);
        return string;
    }

    private AtomicReferenceArray<Object> readAtomicReferenceArray(int handle)
            throws IOException, ClassNotFoundException {
        int length  = dataInput.readInt();
        AtomicReferenceArray<Object>    array   = new AtomicReferenceArray<Object>(length);
        registerObject(handle, array);
        for (int i = 0; i < length; ++i) {
            array.set(i, readObject());
        }
        return array;
    }

    private Map readMap(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int size = dataInput.readInt();
        Map<Object, Object> map = (Map<Object, Object>) newCollection(handle, clazz, size);
        for (int i = 0; i < size; ++i) {
            Object key = readObject();
            Object value = readObject();
            map.put(key, value);
        }
        return map;
    }

    private Collection readCollection(int handle) throws IOException, ClassNotFoundException {
        Class clazz = (Class) readObject();
        int size = dataInput.readInt();
        Collection<Object> collection = (Collection<Object>) newCollection(handle, clazz, size);
        for (int i = 0; i < size; ++i) {
            collection.add(readObject());
        }
        return collection;
    }

    private Object newCollection(int handle, Class clazz, int size) throws IOException {
        Object collection;
        try {
            Constructor constructor = clazz.getConstructor(Integer.TYPE);
            collection = constructor.newInstance(size);
        } catch (InstantiationException e) {
            throw newInvalidClassException(clazz, e);
        } catch (IllegalAccessException e) {
            throw newInvalidClassException(clazz, e);
        } catch (InvocationTargetException e) {
            throw newInvalidClassException(clazz, e);
        } catch (NoSuchMethodException e) {
            try {
                Constructor constructor = clazz.getConstructor();
                collection  = constructor.newInstance();
            } catch (Exception e2) {
                throw newInvalidClassException(clazz, e2);
            }
        }
        registerObject(handle, collection);
        return collection;
    }

    private int readHandle() throws IOException {
        return dataInput.readInt();
    }

    private Class readClass(int handle) throws IOException, ClassNotFoundException {
        String className = (String) readObject();
        Class clazz = resolveClass(className);
        registerObject(handle, clazz);
        return clazz;
    }

    private byte readRecordType() throws IOException {
        return dataInput.readByte();
    }

    private Object readReference(int handle) {
        return objectsByHandle.get(handle);
    }

    private void registerObject(int handle, Object object) {
        objectsByHandle.put(handle, object);
    }

    private static InvalidClassException newInvalidClassException(Class clazz, Throwable cause) {
        InvalidClassException exception = new InvalidClassException(clazz.getName());
        exception.initCause(cause);
        return exception;
    }

    /**
     * Using the ClassLoader from the top of the stack to load the class specified by the given class name.
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    protected Class resolveClass(String className) throws ClassNotFoundException{
        try {
            Class clazz = primClasses.get( className );
            if ( clazz == null ) {
                clazz = getClassLoader().loadClass( className );
            }
            return clazz;
        }
        catch (ClassNotFoundException e) {
            return getClass().getClassLoader().loadClass(className);
        }
    }

    /*=================================================================================
    ObjectInput implementations
    =================================================================================*/
    /**
     * Reads a byte of data. This method will block if no input is
     * available.
     * @return 	the byte read, or -1 if the end of the
     *		stream is reached.
     * @exception IOException If an I/O error has occurred.
     */
    public int read() throws IOException {
        return dataInput.read();
    }

    /**
     * Reads into an array of bytes.  This method will
{'fraction_non_alphanumeric': 0.09486900812264043, 'fraction_numerical': 0.001029630477062121, 'mean_word_length': 2.2607479250209828, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1465290', 'n_tokens_mistral': 8844, 'n_tokens_neox': 8550, 'n_words': 2209}