foam.lib.json.Outputter.java Source code

Java tutorial

Introduction

Here is the source code for foam.lib.json.Outputter.java

Source

/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.lib.json;

import foam.core.ClassInfo;
import foam.core.Detachable;
import foam.core.FObject;
import foam.core.PropertyInfo;
import foam.dao.AbstractSink;
import foam.util.SafetyUtil;
import java.io.*;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.IOUtils;

public class Outputter extends AbstractSink implements foam.lib.Outputter {
    protected static ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            df.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
            return df;
        }
    };

    protected PrintWriter writer_;
    protected OutputterMode mode_;
    protected StringWriter stringWriter_ = null;
    protected boolean outputShortNames_ = false;
    protected boolean outputDefaultValues_ = false;
    protected boolean outputClassNames_ = true;

    public Outputter() {
        this(OutputterMode.FULL);
    }

    public Outputter(OutputterMode mode) {
        this((PrintWriter) null, mode);
    }

    public Outputter(File file, OutputterMode mode) throws FileNotFoundException {
        this(new PrintWriter(file), mode);
    }

    public Outputter(PrintWriter writer, OutputterMode mode) {
        if (writer == null) {
            stringWriter_ = new StringWriter();
            writer = new PrintWriter(stringWriter_);
        }

        this.mode_ = mode;
        this.writer_ = writer;
    }

    public String stringify(FObject obj) {
        initWriter();
        outputFObject(obj);
        return this.toString();
    }

    public String stringifyDelta(FObject oldFObject, FObject newFObject) {
        initWriter();
        outputFObjectDelta(oldFObject, newFObject);
        return this.toString();
    }

    protected void initWriter() {
        if (stringWriter_ == null) {
            stringWriter_ = new StringWriter();
            writer_ = new PrintWriter(stringWriter_);
        }
        stringWriter_.getBuffer().setLength(0);
    }

    public void setWriter(PrintWriter writer) {
        writer_ = writer;
    }

    protected void outputUndefined() {
    }

    protected void outputNull() {
    }

    protected void outputString(String s) {
        writer_.append("\"");
        writer_.append(escape(s));
        writer_.append("\"");
    }

    public String escape(String s) {
        return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\t", "\\t").replace("\n", "\\n");
    }

    protected void outputNumber(Number value) {
        writer_.append(value.toString());
    }

    protected void outputBoolean(Boolean value) {
        writer_.append(value ? "true" : "false");
    }

    protected void outputArray(Object[] array) {
        writer_.append("[");
        for (int i = 0; i < array.length; i++) {
            output(array[i]);
            if (i < array.length - 1)
                writer_.append(",");
        }
        writer_.append("]");
    }

    protected void outputByteArray(byte[][] array) {
        writer_.append("[");
        for (int i = 0; i < array.length; i++) {
            output(array[i]);
            if (i < array.length - 1)
                writer_.append(",");
        }
        writer_.append("]");
    }

    protected void outputByteArray(byte[] array) {
        output(foam.util.SecurityUtil.ByteArrayToHexString(array));
    }

    protected void outputMap(java.util.Map map) {
        writer_.append("{");
        java.util.Iterator keys = map.keySet().iterator();
        while (keys.hasNext()) {
            Object key = keys.next();
            Object value = map.get(key);
            outputString(key == null ? "" : key.toString());
            writer_.append(":");
            output(value);
            if (keys.hasNext())
                writer_.append(",");
        }
        writer_.append("}");
    }

    protected void outputList(java.util.List list) {
        writer_.append("[");
        java.util.Iterator iter = list.iterator();
        while (iter.hasNext()) {
            output(iter.next());
            if (iter.hasNext())
                writer_.append(",");
        }
        writer_.append("]");
    }

    protected void outputProperty(FObject o, PropertyInfo p) {
        writer_.append(beforeKey_());
        writer_.append(getPropertyName(p));
        writer_.append(afterKey_());
        writer_.append(":");
        p.toJSON(this, p.get(o));
    }

    public void outputMap(Object... values) {
        if (values.length % 2 != 0) {
            throw new RuntimeException("Need even number of arguments for outputMap");
        }

        writer_.append("{");
        int i = 0;
        while (i < values.length) {
            writer_.append(beforeKey_());
            writer_.append(values[i++].toString());
            writer_.append(afterKey_());
            writer_.append(":");
            output(values[i++]);
            if (i < values.length)
                writer_.append(",");
        }
        writer_.append("}");
    }

    public void outputEnum(Enum<?> value) {
        //    outputNumber(value.ordinal());

        writer_.append("{");
        writer_.append(beforeKey_());
        writer_.append("class");
        writer_.append(afterKey_());
        writer_.append(":");
        outputString(value.getClass().getName());
        writer_.append(",");
        writer_.append(beforeKey_());
        writer_.append("ordinal");
        writer_.append(afterKey_());
        writer_.append(":");
        outputNumber(value.ordinal());
        writer_.append("}");
    }

    public void output(Object value) {
        if (value instanceof OutputJSON) {
            ((OutputJSON) value).outputJSON(this);
        } else if (value instanceof String) {
            outputString((String) value);
        } else if (value instanceof FObject) {
            outputFObject((FObject) value);
        } else if (value instanceof PropertyInfo) {
            outputPropertyInfo((PropertyInfo) value);
        } else if (value instanceof ClassInfo) {
            outputClassInfo((ClassInfo) value);
        } else if (value instanceof Number) {
            outputNumber((Number) value);
        } else if (isArray(value)) {
            if (value.getClass().equals(byte[][].class)) {
                outputByteArray((byte[][]) value);
            } else if (value instanceof byte[]) {
                outputByteArray((byte[]) value);
            } else {
                outputArray((Object[]) value);
            }
        } else if (value instanceof Boolean) {
            outputBoolean((Boolean) value);
        } else if (value instanceof java.util.Date) {
            outputDate((java.util.Date) value);
        } else if (value instanceof java.util.Map) {
            outputMap((java.util.Map) value);
        } else if (value instanceof java.util.List) {
            outputList((java.util.List) value);
        } else if (value instanceof Enum<?>) {
            outputEnum((Enum<?>) value);
        } else /*if ( value == null )*/ {
            writer_.append("null");
        }
    }

    protected boolean isArray(Object value) {
        return (value != null) && (value.getClass() != null) && value.getClass().isArray();
    }

    protected void outputDate(java.util.Date date) {
        outputString(sdf.get().format(date));
    }

    protected Boolean maybeOutputProperty(FObject fo, PropertyInfo prop, boolean includeComma) {
        if (mode_ == OutputterMode.NETWORK && prop.getNetworkTransient())
            return false;
        if (mode_ == OutputterMode.STORAGE && prop.getStorageTransient())
            return false;
        if (!outputDefaultValues_ && !prop.isSet(fo))
            return false;

        Object value = prop.get(fo);
        if (value == null || (isArray(value) && Array.getLength(value) == 0)) {
            return false;
        }

        if (includeComma)
            writer_.append(",");
        outputProperty(fo, prop);
        return true;
    }

    protected void outputFObjectDelta(FObject oldFObject, FObject newFObject) {
        ClassInfo info = oldFObject.getClassInfo();
        boolean outputComma = true;
        boolean isDiff = false;
        boolean isPropertyDiff = false;
        if (!oldFObject.equals(newFObject)) {
            List axioms = info.getAxiomsByClass(PropertyInfo.class);
            Iterator i = axioms.iterator();

            while (i.hasNext()) {
                PropertyInfo prop = (PropertyInfo) i.next();
                isPropertyDiff = maybeOutputPropertyDelta(oldFObject, newFObject, prop);
                if (isPropertyDiff) {
                    if (!isDiff) {
                        writer_.append("{");
                        if (outputClassNames_) {
                            //output Class name
                            writer_.append(beforeKey_());
                            writer_.append("class");
                            writer_.append(afterKey_());
                            writer_.append(":");
                            outputString(info.getId());
                        }
                        if (outputClassNames_)
                            writer_.append(",");
                        PropertyInfo id = (PropertyInfo) info.getAxiomByName("id");
                        outputProperty(newFObject, id);
                        isDiff = true;
                    }

                    writer_.append(",");
                    outputProperty(newFObject, prop);
                }
            }

            if (isDiff) {
                writer_.append("}");
            }
        }
    }

    protected boolean maybeOutputPropertyDelta(FObject oldFObject, FObject newFObject, PropertyInfo prop) {
        if (mode_ == OutputterMode.NETWORK && prop.getNetworkTransient())
            return false;
        if (mode_ == OutputterMode.STORAGE && prop.getStorageTransient())
            return false;

        if (prop.compare(oldFObject, newFObject) != 0) {
            return true;
        }
        return false;
    }

    public void outputJSONJFObject(FObject o) {
        writer_.append("p(");
        outputFObject(o);
        writer_.append(")\r\n");
    }

    protected void outputFObject(FObject o) {
        ClassInfo info = o.getClassInfo();

        writer_.append("{");
        if (outputClassNames_) {
            writer_.append(beforeKey_());
            writer_.append("class");
            writer_.append(afterKey_());
            writer_.append(":");
            outputString(info.getId());
        }
        List axioms = info.getAxiomsByClass(PropertyInfo.class);
        Iterator i = axioms.iterator();
        boolean outputComma = outputClassNames_;
        while (i.hasNext()) {
            PropertyInfo prop = (PropertyInfo) i.next();
            outputComma = maybeOutputProperty(o, prop, outputComma) || outputComma;
        }

        writer_.append("}");
    }

    protected void outputPropertyInfo(PropertyInfo prop) {
        writer_.append("{");
        outputString("class");
        writer_.append(":");
        outputString("__Property__");
        writer_.append(",");
        outputString("forClass_");
        writer_.append(":");
        outputString(prop.getClassInfo().getId());
        writer_.append(",");
        outputString("name");
        writer_.append(":");
        outputString(getPropertyName(prop));
        writer_.append("}");
    }

    protected void outputClassInfo(ClassInfo info) {
        writer_.append("{");
        outputString("class");
        writer_.append(":");
        outputString("__Class__");
        writer_.append(",");
        outputString("forClass_");
        writer_.append(":");
        outputString(info.getId());
        writer_.append("}");
    }

    protected String beforeKey_() {
        return "\"";
    }

    protected String afterKey_() {
        return "\"";
    }

    public FObject parse(String str) {
        return null;
    }

    public String getPropertyName(PropertyInfo p) {
        return outputShortNames_ && !SafetyUtil.isEmpty(p.getShortName()) ? p.getShortName() : p.getName();
    }

    @Override
    public String toString() {
        return (stringWriter_ != null) ? stringWriter_.toString() : null;
    }

    @Override
    public void put(Object obj, Detachable sub) {
        outputFObject((FObject) obj);
    }

    public void outputRawString(String str) {
        writer_.append(str);
    }

    public Outputter setOutputShortNames(boolean outputShortNames) {
        outputShortNames_ = outputShortNames;
        return this;
    }

    public Outputter setOutputDefaultValues(boolean outputDefaultValues) {
        outputDefaultValues_ = outputDefaultValues;
        return this;
    }

    public Outputter setOutputClassNames(boolean outputClassNames) {
        outputClassNames_ = outputClassNames;
        return this;
    }

    @Override
    public void close() throws IOException {
        IOUtils.closeQuietly(stringWriter_);
        IOUtils.closeQuietly(writer_);
    }

    @Override
    public void flush() throws IOException {
        if (stringWriter_ != null)
            stringWriter_.flush();
        if (writer_ != null)
            writer_.flush();
    }
}