org.jvyamlb.SafeConstructorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jvyamlb.SafeConstructorImpl.java

Source

/*
 * See LICENSE file in distribution for copyright and licensing information.
 */
package org.jvyamlb;

import java.io.FileInputStream;
import java.io.InputStream;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jvyamlb.exceptions.ConstructorException;
import org.jvyamlb.exceptions.YAMLException;

import org.jvyamlb.nodes.Node;

import org.jvyamlb.util.Base64Coder;

import org.jruby.util.ByteList;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

/**
 * @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a>
 */
public class SafeConstructorImpl extends BaseConstructorImpl {
    private final static Map yamlConstructors = new HashMap();
    private final static Map yamlMultiConstructors = new HashMap();
    private final static Map yamlMultiRegexps = new HashMap();

    public YamlConstructor getYamlConstructor(final Object key) {
        YamlConstructor mine = (YamlConstructor) yamlConstructors.get(key);
        if (mine == null) {
            mine = super.getYamlConstructor(key);
        }
        return mine;
    }

    public YamlMultiConstructor getYamlMultiConstructor(final Object key) {
        YamlMultiConstructor mine = (YamlMultiConstructor) yamlMultiConstructors.get(key);
        if (mine == null) {
            mine = super.getYamlMultiConstructor(key);
        }
        return mine;
    }

    public Pattern getYamlMultiRegexp(final Object key) {
        Pattern mine = (Pattern) yamlMultiRegexps.get(key);
        if (mine == null) {
            mine = super.getYamlMultiRegexp(key);
        }
        return mine;
    }

    public Set getYamlMultiRegexps() {
        final Set all = new HashSet(super.getYamlMultiRegexps());
        all.addAll(yamlMultiRegexps.keySet());
        return all;
    }

    public static void addConstructor(final String tag, final YamlConstructor ctor) {
        yamlConstructors.put(tag, ctor);
    }

    public static void addMultiConstructor(final String tagPrefix, final YamlMultiConstructor ctor) {
        yamlMultiConstructors.put(tagPrefix, ctor);
        yamlMultiRegexps.put(tagPrefix, Pattern.compile("^" + tagPrefix));
    }

    public SafeConstructorImpl(final Composer composer) {
        super(composer);
    }

    private static ByteList into(String v) {
        return new ByteList(v.getBytes(), false);
    }

    private final static Map BOOL_VALUES = new HashMap();
    static {
        BOOL_VALUES.put(into("yes"), Boolean.TRUE);
        BOOL_VALUES.put(into("Yes"), Boolean.TRUE);
        BOOL_VALUES.put(into("YES"), Boolean.TRUE);
        BOOL_VALUES.put(into("no"), Boolean.FALSE);
        BOOL_VALUES.put(into("No"), Boolean.FALSE);
        BOOL_VALUES.put(into("NO"), Boolean.FALSE);
        BOOL_VALUES.put(into("true"), Boolean.TRUE);
        BOOL_VALUES.put(into("True"), Boolean.TRUE);
        BOOL_VALUES.put(into("TRUE"), Boolean.TRUE);
        BOOL_VALUES.put(into("false"), Boolean.FALSE);
        BOOL_VALUES.put(into("False"), Boolean.FALSE);
        BOOL_VALUES.put(into("FALSE"), Boolean.FALSE);
        BOOL_VALUES.put(into("on"), Boolean.TRUE);
        BOOL_VALUES.put(into("On"), Boolean.TRUE);
        BOOL_VALUES.put(into("ON"), Boolean.TRUE);
        BOOL_VALUES.put(into("off"), Boolean.FALSE);
        BOOL_VALUES.put(into("Off"), Boolean.FALSE);
        BOOL_VALUES.put(into("OFF"), Boolean.FALSE);
    }

    public static Object constructYamlNull(final Constructor ctor, final Node node) {
        return null;
    }

    public static Object constructYamlBool(final Constructor ctor, final Node node) {
        final Object val = ctor.constructScalar(node);
        return BOOL_VALUES.get(val);
    }

    public static Object constructYamlOmap(final Constructor ctor, final Node node) {
        return ctor.constructPairs(node);
    }

    public static Object constructYamlPairs(final Constructor ctor, final Node node) {
        return constructYamlOmap(ctor, node);
    }

    public static Object constructYamlSet(final Constructor ctor, final Node node) {
        return ((Map) ctor.constructMapping(node)).keySet();
    }

    public static Object constructYamlStr(final Constructor ctor, final Node node) {
        final ByteList value = (ByteList) ctor.constructScalar(node);
        return value.length() == 0 ? (ByteList) null : value;
    }

    public static Object constructYamlSeq(final Constructor ctor, final Node node) {
        return ctor.constructSequence(node);
    }

    public static Object constructYamlMap(final Constructor ctor, final Node node) {
        return ctor.constructMapping(node);
    }

    public static Object constructUndefined(final Constructor ctor, final Node node) {
        throw new ConstructorException(null, "could not determine a constructor for the tag " + node.getTag(),
                null);
    }

    private final static Pattern TIMESTAMP_REGEXP = Pattern.compile(
            "^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?)))?$");
    public final static Pattern YMD_REGEXP = Pattern
            .compile("^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");

    public static Object constructYamlTimestamp(final Constructor ctor, final Node node) {
        Matcher match = YMD_REGEXP.matcher(node.getValue().toString());
        if (match.matches()) {
            final String year_s = match.group(1);
            final String month_s = match.group(2);
            final String day_s = match.group(3);
            DateTime dt = new DateTime(0, 1, 1, 0, 0, 0, 0);
            if (year_s != null) {
                dt = dt.withYear(Integer.parseInt(year_s));
            }
            if (month_s != null) {
                dt = dt.withMonthOfYear(Integer.parseInt(month_s));
            }
            if (day_s != null) {
                dt = dt.withDayOfMonth(Integer.parseInt(day_s));
            }
            return new Object[] { dt };
        }
        match = TIMESTAMP_REGEXP.matcher(node.getValue().toString());
        if (!match.matches()) {
            return new Object[] { ctor.constructPrivateType(node) };
        }
        final String year_s = match.group(1);
        final String month_s = match.group(2);
        final String day_s = match.group(3);
        final String hour_s = match.group(4);
        final String min_s = match.group(5);
        final String sec_s = match.group(6);
        final String fract_s = match.group(7);
        final String utc = match.group(8);
        final String timezoneh_s = match.group(9);
        final String timezonem_s = match.group(10);

        int usec = 0;
        if (fract_s != null) {
            usec = Integer.parseInt(fract_s);
            if (usec != 0) {
                while (10 * usec < 1000) {
                    usec *= 10;
                }
            }
        }
        DateTime dt = new DateTime(0, 1, 1, 0, 0, 0, 0);
        if ("Z".equalsIgnoreCase(utc)) {
            dt = dt.withZone(DateTimeZone.forID("Etc/GMT"));
        } else {
            if (timezoneh_s != null || timezonem_s != null) {
                int zone = 0;
                int sign = +1;
                if (timezoneh_s != null) {
                    if (timezoneh_s.startsWith("-")) {
                        sign = -1;
                    }
                    zone += Integer.parseInt(timezoneh_s.substring(1)) * 3600000;
                }
                if (timezonem_s != null) {
                    zone += Integer.parseInt(timezonem_s) * 60000;
                }
                dt = dt.withZone(DateTimeZone.forOffsetMillis(sign * zone));
            }
        }
        if (year_s != null) {
            dt = dt.withYear(Integer.parseInt(year_s));
        }
        if (month_s != null) {
            dt = dt.withMonthOfYear(Integer.parseInt(month_s));
        }
        if (day_s != null) {
            dt = dt.withDayOfMonth(Integer.parseInt(day_s));
        }
        if (hour_s != null) {
            dt = dt.withHourOfDay(Integer.parseInt(hour_s));
        }
        if (min_s != null) {
            dt = dt.withMinuteOfHour(Integer.parseInt(min_s));
        }
        if (sec_s != null) {
            dt = dt.withSecondOfMinute(Integer.parseInt(sec_s));
        }
        dt = dt.withMillisOfSecond(usec / 1000);

        return new Object[] { dt, new Integer(usec % 1000) };
    }

    public static Object constructYamlInt(final Constructor ctor, final Node node) {
        String value = ctor.constructScalar(node).toString().replaceAll("_", "").replaceAll(",", "");
        ;
        int sign = +1;
        char first = value.charAt(0);
        if (first == '-') {
            sign = -1;
            value = value.substring(1);
        } else if (first == '+') {
            value = value.substring(1);
        }
        int base = 10;
        if (value.equals("0")) {
            return new Long(0);
        } else if (value.startsWith("0b")) {
            value = value.substring(2);
            base = 2;
        } else if (value.startsWith("0x")) {
            value = value.substring(2);
            base = 16;
        } else if (value.startsWith("0")) {
            value = value.substring(1);
            base = 8;
        } else if (value.indexOf(':') != -1) {
            final String[] digits = value.split(":");
            int bes = 1;
            int val = 0;
            for (int i = 0, j = digits.length; i < j; i++) {
                val += (Long.parseLong(digits[(j - i) - 1]) * bes);
                bes *= 60;
            }
            return new Integer(sign * val);
        } else {
            try {
                return new Long(sign * Long.parseLong(value));
            } catch (Exception e) {
                if (sign < 0) {
                    return new java.math.BigInteger(value).negate();
                } else {
                    return new java.math.BigInteger(value);
                }
            }
        }
        try {
            return new Long(sign * Long.parseLong(value, base));
        } catch (Exception e) {
            if (sign < 0) {
                return new java.math.BigInteger(value, base).negate();
            } else {
                return new java.math.BigInteger(value, base);
            }
        }
    }

    private final static Double INF_VALUE_POS = new Double(Double.POSITIVE_INFINITY);
    private final static Double INF_VALUE_NEG = new Double(Double.NEGATIVE_INFINITY);
    private final static Double NAN_VALUE = new Double(Double.NaN);

    public static Object constructYamlFloat(final Constructor ctor, final Node node) {
        String value = ctor.constructScalar(node).toString().replaceAll("_", "").replaceAll(",", "");
        int sign = +1;
        char first = value.charAt(0);
        if (first == '-') {
            sign = -1;
            value = value.substring(1);
        } else if (first == '+') {
            value = value.substring(1);
        }
        final String valLower = value.toLowerCase();
        if (valLower.equals(".inf")) {
            return sign == -1 ? INF_VALUE_NEG : INF_VALUE_POS;
        } else if (valLower.equals(".nan")) {
            return NAN_VALUE;
        } else if (value.indexOf(':') != -1) {
            final String[] digits = value.split(":");
            int bes = 1;
            double val = 0.0;
            for (int i = 0, j = digits.length; i < j; i++) {
                val += (Double.parseDouble(digits[(j - i) - 1]) * bes);
                bes *= 60;
            }
            return new Double(sign * val);
        } else {
            return new Double(sign * Double.parseDouble(value));
        }
    }

    public static Object constructYamlBinary(final Constructor ctor, final Node node) {
        final String[] values = ctor.constructScalar(node).toString().split("\n|(?:\r[^\n])|\\s");
        final StringBuffer vals = new StringBuffer();
        for (int i = 0, j = values.length; i < j; i++) {
            vals.append(values[i].trim());
        }
        return Base64Coder.decode(ByteList.plain(vals));
    }

    public static Object constructSpecializedSequence(final Constructor ctor, final String pref, final Node node) {
        List outp = null;
        try {
            final Class seqClass = Class.forName(pref);
            outp = (List) seqClass.newInstance();
        } catch (final Exception e) {
            throw new YAMLException("Can't construct a sequence from class " + pref + ": " + e.toString());
        }
        outp.addAll((List) ctor.constructSequence(node));
        return outp;
    }

    public static Object constructSpecializedMap(final Constructor ctor, final String pref, final Node node) {
        Map outp = null;
        try {
            final Class mapClass = Class.forName(pref);
            outp = (Map) mapClass.newInstance();
        } catch (final Exception e) {
            throw new YAMLException("Can't construct a mapping from class " + pref + ": " + e.toString());
        }
        outp.putAll((Map) ctor.constructMapping(node));
        return outp;
    }

    private static Object fixValue(final Object inp, final Class outp) {
        if (inp == null) {
            return null;
        }
        final Class inClass = inp.getClass();
        if (outp.isAssignableFrom(inClass)) {
            return inp;
        }
        if (inClass == Long.class && (outp == Integer.class || outp == Integer.TYPE)) {
            return new Integer(((Long) inp).intValue());
        }
        if (inClass == Long.class && (outp == Short.class || outp == Short.TYPE)) {
            return new Short((short) ((Long) inp).intValue());
        }
        if (inClass == Long.class && (outp == Character.class || outp == Character.TYPE)) {
            return new Character((char) ((Long) inp).intValue());
        }
        if (inClass == Double.class && (outp == Float.class || outp == Float.TYPE)) {
            return new Float(((Double) inp).floatValue());
        }
        return inp;
    }

    public static Object constructJava(final Constructor ctor, final String pref, final Node node) {
        Object outp = null;
        try {
            final Class cl = Class.forName(pref);
            outp = cl.newInstance();
            final Map values = (Map) ctor.constructMapping(node);
            java.lang.reflect.Method[] ems = cl.getMethods();
            for (final Iterator iter = values.keySet().iterator(); iter.hasNext();) {
                final Object key = iter.next();
                final Object value = values.get(key);
                final String keyName = key.toString();
                final String mName = "set" + Character.toUpperCase(keyName.charAt(0)) + keyName.substring(1);
                for (int i = 0, j = ems.length; i < j; i++) {
                    if (ems[i].getName().equals(mName) && ems[i].getParameterTypes().length == 1) {
                        ems[i].invoke(outp, new Object[] { fixValue(value, ems[i].getParameterTypes()[0]) });
                        break;
                    }
                }
            }
        } catch (final Exception e) {
            throw new YAMLException("Can't construct a java object from class " + pref + ": " + e.toString());
        }
        return outp;
    }

    static {
        BaseConstructorImpl.addConstructor("tag:yaml.org,2002:null", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlNull(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:bool", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlBool(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:omap", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlOmap(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:pairs", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlPairs(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:set", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlSet(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:int", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlInt(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:float", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlFloat(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:timestamp", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return ((Object[]) constructYamlTimestamp(self, node))[0];
            }
        });
        addConstructor("tag:yaml.org,2002:timestamp#ymd", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return ((Object[]) constructYamlTimestamp(self, node))[0];
            }
        });
        addConstructor("tag:yaml.org,2002:str", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlStr(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:binary", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlBinary(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:seq", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlSeq(self, node);
            }
        });
        addConstructor("tag:yaml.org,2002:map", new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return constructYamlMap(self, node);
            }
        });
        addConstructor(null, new YamlConstructor() {
            public Object call(final Constructor self, final Node node) {
                return self.constructPrivateType(node);
            }
        });

        addMultiConstructor("tag:yaml.org,2002:seq:", new YamlMultiConstructor() {
            public Object call(final Constructor self, final String pref, final Node node) {
                return constructSpecializedSequence(self, pref, node);
            }
        });
        addMultiConstructor("tag:yaml.org,2002:map:", new YamlMultiConstructor() {
            public Object call(final Constructor self, final String pref, final Node node) {
                return constructSpecializedMap(self, pref, node);
            }
        });
        addMultiConstructor("!java/object:", new YamlMultiConstructor() {
            public Object call(final Constructor self, final String pref, final Node node) {
                return constructJava(self, pref, node);
            }
        });
        addMultiConstructor("tag:java.yaml.org,2002:object:", new YamlMultiConstructor() {
            public Object call(final Constructor self, final String pref, final Node node) {
                return constructJava(self, pref, node);
            }
        });
    }

    public static void main(final String[] args) throws Exception {
        final String filename = args[0];
        System.out.println("Reading of file: \"" + filename + "\"");

        final ByteList input = new ByteList(1024);
        final InputStream reader = new FileInputStream(filename);
        byte[] buff = new byte[1024];
        int read = 0;
        while (true) {
            read = reader.read(buff);
            input.append(buff, 0, read);
            if (read < 1024) {
                break;
            }
        }
        reader.close();
        final long before = System.currentTimeMillis();
        for (int i = 0; i < 1; i++) {
            final Constructor ctor = new SafeConstructorImpl(
                    new ComposerImpl(new ParserImpl(new ScannerImpl(input)), new ResolverImpl()));
            for (final Iterator iter = ctor.eachDocument(); iter.hasNext();) {
                iter.next();
                //System.out.println(iter.next());
            }
        }
        final long after = System.currentTimeMillis();
        final long time = after - before;
        final double timeS = (after - before) / 1000.0;
        System.out.println("Walking through the nodes for the file: " + filename + " took " + time + "ms, or "
                + timeS + " seconds");
    }
}// SafeConstructorImpl