org.cloudata.core.common.io.CObjectWritable.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudata.core.common.io.CObjectWritable.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.cloudata.core.common.io;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudata.core.client.Cell;
import org.cloudata.core.client.Row;
import org.cloudata.core.common.conf.CConfigurable;
import org.cloudata.core.common.conf.CloudataConf;
import org.cloudata.core.common.conf.CConfigured;
import org.cloudata.core.tablet.ColumnValue;
import org.cloudata.core.tablet.TabletInfo;

/** A polymorphic Writable that writes an instance with it's class name.
 * Handles arrays, strings and primitive types without a Writable wrapper.
 */
public class CObjectWritable implements CWritable, CConfigurable {
    public static final Log LOG = LogFactory.getLog(CObjectWritable.class.getName());

    public static final short TYPE_SAME = 0;
    public static final short TYPE_DIFF = 1;

    private Class declaredClass;
    private Object instance;
    private CloudataConf conf;

    public CObjectWritable() {
    }

    public CObjectWritable(Object instance) {
        set(instance);
    }

    public CObjectWritable(Class declaredClass, Object instance) {
        this.declaredClass = declaredClass;
        this.instance = instance;
    }

    /** Return the instance, or null if none. */
    public Object get() {
        return instance;
    }

    /** Return the class this is meant to be. */
    public Class getDeclaredClass() {
        return declaredClass;
    }

    /** Reset the instance. */
    public void set(Object instance) {
        this.declaredClass = instance.getClass();
        this.instance = instance;
    }

    public String toString() {
        return "OW[class=" + declaredClass + ",value=" + instance + "]";
    }

    public void readFields(DataInput in) throws IOException {
        readObject(in, this, this.conf);
    }

    public void write(DataOutput out) throws IOException {
        writeObject(out, instance, declaredClass, conf);
    }

    private static final Map<String, Class<?>> PRIMITIVE_NAMES = new HashMap<String, Class<?>>();
    static {
        PRIMITIVE_NAMES.put("boolean", Boolean.TYPE);
        PRIMITIVE_NAMES.put("byte", Byte.TYPE);
        PRIMITIVE_NAMES.put("char", Character.TYPE);
        PRIMITIVE_NAMES.put("short", Short.TYPE);
        PRIMITIVE_NAMES.put("int", Integer.TYPE);
        PRIMITIVE_NAMES.put("long", Long.TYPE);
        PRIMITIVE_NAMES.put("float", Float.TYPE);
        PRIMITIVE_NAMES.put("double", Double.TYPE);
        PRIMITIVE_NAMES.put("void", Void.TYPE);
    }

    private static class NullInstance extends CConfigured implements CWritable {
        private Class<?> declaredClass;

        public NullInstance() {
            super(null);
        }

        public NullInstance(Class declaredClass, CloudataConf conf) {
            super(conf);
            this.declaredClass = declaredClass;
        }

        public void readFields(DataInput in) throws IOException {
            String className = CUTF8.readString(in);
            declaredClass = PRIMITIVE_NAMES.get(className);
            if (declaredClass == null) {
                try {
                    declaredClass = getConf().getClassByName(className);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e.toString());
                }
            }
        }

        public void write(DataOutput out) throws IOException {
            CUTF8.writeString(out, declaredClass.getName());
        }
    }

    public static void writeObject(DataOutput out, Object instance, Class declaredClass, CloudataConf conf)
            throws IOException {
        writeObject(out, instance, declaredClass, conf, false);
    }

    /** Write a {@link CWritable}, {@link String}, primitive type, or an array of
     * the preceding. */
    public static void writeObject(DataOutput out, Object instance, Class declaredClass, CloudataConf conf,
            boolean arrayComponent) throws IOException {

        if (instance == null) { // null
            instance = new NullInstance(declaredClass, conf);
            declaredClass = CWritable.class;
            arrayComponent = false;
        }

        if (!arrayComponent) {
            CUTF8.writeString(out, declaredClass.getName()); // always write declared
            //System.out.println("Write:declaredClass.getName():" + declaredClass.getName());
        }

        if (declaredClass.isArray()) { // array
            int length = Array.getLength(instance);
            out.writeInt(length);
            //System.out.println("Write:length:" + length);

            if (declaredClass.getComponentType() == Byte.TYPE) {
                out.write((byte[]) instance);
            } else if (declaredClass.getComponentType() == ColumnValue.class) {
                //ColumnValue?  Deserialize? ?? ?   ?? ?  .
                writeColumnValue(out, instance, declaredClass, conf, length);
            } else {
                for (int i = 0; i < length; i++) {
                    writeObject(out, Array.get(instance, i), declaredClass.getComponentType(), conf,
                            !declaredClass.getComponentType().isArray());
                }
            }
        } else if (declaredClass == String.class) { // String
            CUTF8.writeString(out, (String) instance);

        } else if (declaredClass.isPrimitive()) { // primitive type

            if (declaredClass == Boolean.TYPE) { // boolean
                out.writeBoolean(((Boolean) instance).booleanValue());
            } else if (declaredClass == Character.TYPE) { // char
                out.writeChar(((Character) instance).charValue());
            } else if (declaredClass == Byte.TYPE) { // byte
                out.writeByte(((Byte) instance).byteValue());
            } else if (declaredClass == Short.TYPE) { // short
                out.writeShort(((Short) instance).shortValue());
            } else if (declaredClass == Integer.TYPE) { // int
                out.writeInt(((Integer) instance).intValue());
            } else if (declaredClass == Long.TYPE) { // long
                out.writeLong(((Long) instance).longValue());
            } else if (declaredClass == Float.TYPE) { // float
                out.writeFloat(((Float) instance).floatValue());
            } else if (declaredClass == Double.TYPE) { // double
                out.writeDouble(((Double) instance).doubleValue());
            } else if (declaredClass == Void.TYPE) { // void
            } else {
                throw new IllegalArgumentException("Not a primitive: " + declaredClass);
            }
        } else if (declaredClass.isEnum()) { // enum
            CUTF8.writeString(out, ((Enum) instance).name());
        } else if (CWritable.class.isAssignableFrom(declaredClass)) { // Writable
            if (instance.getClass() == declaredClass) {
                out.writeShort(TYPE_SAME); // ? ?? ? ?? 
                //System.out.println("Write:TYPE_SAME:" + TYPE_SAME);

            } else {
                out.writeShort(TYPE_DIFF);
                //System.out.println("Write:TYPE_DIFF:" + TYPE_DIFF);
                CUTF8.writeString(out, instance.getClass().getName());
                //System.out.println("Write:instance.getClass().getName():" + instance.getClass().getName());
            }
            ((CWritable) instance).write(out);
            //System.out.println("Write:instance value");

        } else {
            throw new IOException("Can't write: " + instance + " as " + declaredClass);
        }
    }

    private static void writeColumnValue(DataOutput out, Object instance, Class declaredClass, CloudataConf conf,
            int length) throws IOException {
        int shortByteSize = CWritableUtils.getShortByteSize();
        int intByteSize = CWritableUtils.getIntByteSize();

        int totalByteSize = 0;

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < length; i++) {
            ColumnValue columnValue = (ColumnValue) Array.get(instance, i);
            totalByteSize += shortByteSize;
            totalByteSize += columnValue.size();
        }
        //    long endTime = System.currentTimeMillis();
        //LOG.fatal("writeColumnValue1:length=" + length + ",bytes=" + totalByteSize + ",time=" + (endTime - startTime));

        out.writeInt(totalByteSize);

        //    startTime = System.currentTimeMillis();
        for (int i = 0; i < length; i++) {
            writeObject(out, Array.get(instance, i), declaredClass.getComponentType(), conf, true);
        }
        long endTime = System.currentTimeMillis();
        //LOG.fatal("writeColumnValue2:time=" + (endTime - startTime));
    }

    private static Object readColumnValue(DataInput in, CloudataConf conf, Class<?> declaredClass, int length)
            throws IOException {
        long startTime = System.currentTimeMillis();

        int totalByteSize = in.readInt();
        byte[] buf = new byte[totalByteSize];
        in.readFully(buf);
        long endTime = System.currentTimeMillis();
        //LOG.fatal("readColumnValue1:length=" + length + ",bytes=" + totalByteSize + ",time=" + (endTime - startTime));

        DataInputStream byteDataIn = new DataInputStream(new ByteArrayInputStream(buf));

        ColumnValue[] instance = (ColumnValue[]) Array.newInstance(declaredClass.getComponentType(), length);
        //startTime = System.currentTimeMillis();
        Class componentClass = declaredClass.getComponentType();
        for (int i = 0; i < length; i++) {
            //Array.set(instance, i, readObject(byteDataIn, null, conf, true, declaredClass.getComponentType()));
            instance[i] = (ColumnValue) readObject(byteDataIn, null, conf, true, componentClass);
        }
        byteDataIn.close();
        byteDataIn = null;
        buf = null;
        //endTime = System.currentTimeMillis();
        //LOG.fatal("readColumnValue2:time=" + (endTime - startTime));
        return instance;
    }

    /** Read a {@link CWritable}, {@link String}, primitive type, or an array of
     * the preceding. */
    public static Object readObject(DataInput in, CloudataConf conf) throws IOException {
        return readObject(in, null, conf, false, null);
    }

    public static Object readObject(DataInput in, CObjectWritable objectWritable, CloudataConf conf)
            throws IOException {
        return readObject(in, objectWritable, conf, false, null);
    }

    /** Read a {@link CWritable}, {@link String}, primitive type, or an array of
     * the preceding. */
    @SuppressWarnings("unchecked")
    public static Object readObject(DataInput in, CObjectWritable objectWritable, CloudataConf conf,
            boolean arrayComponent, Class componentClass) throws IOException {
        String className;
        if (arrayComponent) {
            className = componentClass.getName();
        } else {
            className = CUTF8.readString(in);
            //SANGCHUL
            //   System.out.println("SANGCHUL] className:" + className);
        }

        Class<?> declaredClass = PRIMITIVE_NAMES.get(className);
        if (declaredClass == null) {
            try {
                declaredClass = conf.getClassByName(className);
            } catch (ClassNotFoundException e) {
                //SANGCHUL
                e.printStackTrace();
                throw new RuntimeException("readObject can't find class[className=" + className + "]", e);
            }
        }

        Object instance;

        if (declaredClass.isPrimitive()) { // primitive types

            if (declaredClass == Boolean.TYPE) { // boolean
                instance = Boolean.valueOf(in.readBoolean());
            } else if (declaredClass == Character.TYPE) { // char
                instance = Character.valueOf(in.readChar());
            } else if (declaredClass == Byte.TYPE) { // byte
                instance = Byte.valueOf(in.readByte());
            } else if (declaredClass == Short.TYPE) { // short
                instance = Short.valueOf(in.readShort());
            } else if (declaredClass == Integer.TYPE) { // int
                instance = Integer.valueOf(in.readInt());
            } else if (declaredClass == Long.TYPE) { // long
                instance = Long.valueOf(in.readLong());
            } else if (declaredClass == Float.TYPE) { // float
                instance = Float.valueOf(in.readFloat());
            } else if (declaredClass == Double.TYPE) { // double
                instance = Double.valueOf(in.readDouble());
            } else if (declaredClass == Void.TYPE) { // void
                instance = null;
            } else {
                throw new IllegalArgumentException("Not a primitive: " + declaredClass);
            }

        } else if (declaredClass.isArray()) { // array
            //System.out.println("SANGCHUL] is array");
            int length = in.readInt();
            //System.out.println("SANGCHUL] array length : " + length);
            //System.out.println("Read:in.readInt():" + length);
            if (declaredClass.getComponentType() == Byte.TYPE) {
                byte[] bytes = new byte[length];
                in.readFully(bytes);
                instance = bytes;
            } else if (declaredClass.getComponentType() == ColumnValue.class) {
                instance = readColumnValue(in, conf, declaredClass, length);
            } else {
                Class componentType = declaredClass.getComponentType();

                // SANGCHUL
                //System.out.println("SANGCHUL] componentType : " + componentType.getName());

                instance = Array.newInstance(componentType, length);
                for (int i = 0; i < length; i++) {
                    Object arrayComponentInstance = readObject(in, null, conf, !componentType.isArray(),
                            componentType);
                    Array.set(instance, i, arrayComponentInstance);
                    //Array.set(instance, i, readObject(in, conf));
                }
            }
        } else if (declaredClass == String.class) { // String
            instance = CUTF8.readString(in);
        } else if (declaredClass.isEnum()) { // enum
            instance = Enum.valueOf((Class<? extends Enum>) declaredClass, CUTF8.readString(in));
        } else if (declaredClass == ColumnValue.class) {
            //ColumnValue?  ?? ?? ?  ? ?.
            //? ?   ? ? ? ? . 
            Class instanceClass = null;
            try {
                short typeDiff = in.readShort();
                if (typeDiff == TYPE_DIFF) {
                    instanceClass = conf.getClassByName(CUTF8.readString(in));
                } else {
                    instanceClass = declaredClass;
                }
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("readObject can't find class", e);
            }
            ColumnValue columnValue = new ColumnValue();
            columnValue.readFields(in);
            instance = columnValue;
        } else { // Writable

            Class instanceClass = null;
            try {
                short typeDiff = in.readShort();
                // SANGCHUL
                //System.out.println("SANGCHUL] typeDiff : " + typeDiff);
                //System.out.println("Read:in.readShort():" + typeDiff);
                if (typeDiff == TYPE_DIFF) {
                    // SANGCHUL
                    String classNameTemp = CUTF8.readString(in);
                    //System.out.println("SANGCHUL] typeDiff : " + classNameTemp);
                    instanceClass = conf.getClassByName(classNameTemp);
                    //System.out.println("Read:UTF8.readString(in):" + instanceClass.getClass());
                } else {
                    instanceClass = declaredClass;
                }
            } catch (ClassNotFoundException e) {

                // SANGCHUL
                e.printStackTrace();
                throw new RuntimeException("readObject can't find class", e);
            }

            CWritable writable = CWritableFactories.newInstance(instanceClass, conf);
            writable.readFields(in);
            //System.out.println("Read:writable.readFields(in)");
            instance = writable;

            if (instanceClass == NullInstance.class) { // null
                declaredClass = ((NullInstance) instance).declaredClass;
                instance = null;
            }
        }

        if (objectWritable != null) { // store values
            objectWritable.declaredClass = declaredClass;
            objectWritable.instance = instance;
        }

        return instance;
    }

    public void setConf(CloudataConf conf) {
        this.conf = conf;
    }

    public CloudataConf getConf() {
        return this.conf;
    }
}