innovimax.quixproc.datamodel.generator.json.AJSONGenerator.java Source code

Java tutorial

Introduction

Here is the source code for innovimax.quixproc.datamodel.generator.json.AJSONGenerator.java

Source

/*
QuiXProc: efficient evaluation of XProc Pipelines.
Copyright (C) 2011-2015 Innovimax
All rights reserved.
    
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package innovimax.quixproc.datamodel.generator.json;

import java.io.IOException;
import java.io.InputStream;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonToken;

import innovimax.quixproc.datamodel.event.AQuiXEvent;
import innovimax.quixproc.datamodel.generator.AGenerator;
import innovimax.quixproc.datamodel.generator.ATreeGenerator;
import innovimax.quixproc.datamodel.generator.annotations.TreeGenerator;
import innovimax.quixproc.datamodel.stream.IQuiXStreamReader;

public abstract class AJSONGenerator extends ATreeGenerator {

    private static byte[] initNextChar() {
        byte[] results = new byte[128];
        for (int i = 0; i < results.length; i++) {
            results[i] = (byte) nextAllowedChar(((i & 0x7F) + 1) & 0x7F);
        }
        return results;
    }

    static final byte[] nextChar = initNextChar();
    static final byte[] nextDigit = initNextDigit();

    private static byte[] initNextDigit() {
        byte[] results = new byte[10];
        for (int i = 0; i < results.length; i++) {
            results[i] = (byte) ('0' + ((i + 1) % 10));
        }
        return results;
    }

    private static int nextAllowedChar(int b) {
        if (b <= 0x20) {
            // if (b <= 0xD) {
            // if (b <= 0xa) {
            // if (b <= 0x9) {
            // return (byte) 0x9;
            // }
            // return (byte) 0xA;
            // }
            // return (byte) 0xD;
            // }
            return (byte) 0x20;

        }
        // no backslash
        if (b == '\\')
            return b + 1;
        // no quote
        if (b == '"')
            return b + 1;
        return b;
    }

    private static class BoxedArray {
        final byte[][] array;
        final int start;
        final int selector;
        final byte character;
        int end;

        BoxedArray(byte[][] array, int selector, int start) {
            this.array = array;
            this.selector = selector;
            this.start = start;
            this.end = start;
            this.character = array[selector][start];
        }

        void nextUnique() {
            int pos = this.end;
            while (pos >= this.start) {
                byte r = this.array[this.selector][pos];
                byte s = nextChar(r, 0);
                this.array[this.selector][pos] = s;
                if (s != this.character) {
                    return;
                }
                // s == this.character
                // move up
                pos--;
            }
            // if here we have to extend the buffer
            byte[] replace = new byte[this.array[this.selector].length + 1];
            System.arraycopy(this.array[this.selector], 0, replace, 0, this.start + 1);
            System.arraycopy(this.array[this.selector], this.start, replace, this.start + 1,
                    replace.length - this.start - 1);
            this.end++;
            this.array[this.selector] = replace;
        }
    }

    static byte nextChar(byte b, int incr) {
        // System.out.println("nextChar : "+Integer.toHexString(b &
        // 0xFF)+"("+Character.toString((char) (b& 0xFF))+")" );
        byte r = nextChar[(b + incr) & 0x7F];
        // System.out.println("nextChar : "+Integer.toHexString(r &
        // 0xFF)+"("+Character.toString((char) (r& 0xFF))+")" );
        return r;
    }

    static byte nextDigit(byte b, int incr) {
        byte r = nextDigit[(b + incr) % 10];
        return r;
    }

    /*
     * @Generator(ext=FileExtension.JSON, type=Type.HIGH_NODE_NAME_SIZE,
     * stype=SpecialType.STANDARD) public static class HighNodeNameSizeGenerator
     * extends ATreeGenerator.ANodeNameSizeGenerator {
     * 
     * protected HighNodeNameSizeGenerator(FileExtension ext, SpecialType
     * xmlType) { super(ext, xmlType); }
     * 
     * }
     */
    // @Generator(ext=FileExtension.JSON, type=Type.HIGH_TEXT_SIZE,
    // stype=SpecialType.STANDARD)
    public static class HighTextSizeGenerator extends AHighTextSizeGenerator {

        final byte[] start = s2b("{");
        final byte[][] end = { s2b("}"), s2b("\"}") };
        int choose_end = 0;

        @Override
        protected byte[] getEnd() {
            return this.end[this.choose_end];
        }

        @Override
        protected byte[] getStart() {
            return this.start;
        }

        final byte[][] patterns = { s2b("\"\":\""), s2b("a") };

        @Override
        protected byte[][] getPatterns() {
            return this.patterns;
        }

        @Override
        public byte[] applyVariation(Variation variation, byte[][] bs, int pos) {
            int incr = 0;
            switch (variation) {
            case NO_VARIATION:
                return bs[pos];
            case RANDOM:
                incr = this.random.nextInt(128);
                //$FALL-THROUGH$
            case SEQUENTIAL:
                switch (pos) {
                case 1:
                    bs[pos][0] = nextChar(bs[pos][0], incr);
                    break;
                default:
                }
                return bs[pos];
            default:
            }
            return null;
        }

        @Override
        protected boolean notFinished(long current_size, int current_pattern, long total) {

            return current_size < total;
        }

        @Override
        protected int updatePattern(int current_pattern) {
            return 0;
        }

        @Override
        protected long updateSize(long current_size, int current_pattern) {
            return current_size + 1;
        }

        @Override
        public IQuiXStreamReader getQuiXStreamReader() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected boolean notFinishedEvent(long current_size, int current_pattern, long total) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        protected AQuiXEvent[] getEndEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[][] getPatternsEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[] getStartEvent() {
            // TODO Auto-generated method stub
            return null;
        }

    }

    @TreeGenerator(ext = FileExtension.JSON, type = TreeType.HIGH_NODE_DENSITY, stype = SpecialType.STANDARD)
    public static class HighDensityGenerator extends AHighDensityGenerator {

        final byte[] start = s2b("{");
        final byte[][] end = { s2b("}"), s2b("]}") };

        int choose_end = 0;

        @Override
        protected byte[] getEnd() {
            return this.end[this.choose_end];
        }

        @Override
        protected byte[] getStart() {
            return this.start;
        }

        // {} => 2 smallest
        // {"A":1} => 7
        // {"A":1,"B":1} => 13
        // {"A":[1,1,1,1,1]}
        // since key must be different at some point you need bigger key
        // ..."AA":1, ...
        // more or less 7 bytes per key value looks like the densest

        private final byte[][] patterns = { // empty object is allowed
                // "\"A\":1".getBytes(), // first used only once
                // ",\"A\":1".getBytes()
                s2b("\"\":["), // first used only once
                s2b("{}"), s2b(",{}") };

        // private final BoxedArray baA = new BoxedArray(this.patterns, 1, 2);

        @Override
        protected byte[][] getPatterns() {
            return this.patterns;
        }

        @Override
        protected int updatePattern(int current_pattern) {
            if (current_pattern == 2)
                return 2;
            if (current_pattern == 1)
                return 2;
            if (current_pattern == 0)
                return 1;
            this.choose_end = 1;
            return 0;
        }

        @Override
        public byte[] applyVariation(Variation variation, byte[][] bs, int pos) {
            // int incr = 0;
            // IMPORTANT : the uniqueness is mandatory
            // it doesn't depends on applyRandom hence
            // if (pos == 1)
            // this.baA.nextUnique();
            switch (variation) {
            case NO_VARIATION:
                return bs[pos];
            case RANDOM:
                // incr = this.random.nextInt(10);
                //$FALL-THROUGH$
            case SEQUENTIAL:
                switch (pos) {
                case 0:
                case 1:
                    // no op
                    break;
                case 2:
                    // bs[pos][1] = nextDigit(bs[pos][1], incr);
                    break;
                default:
                }
                return bs[pos];
            default:
            }
            return null;
        }

        @Override
        public IQuiXStreamReader getQuiXStreamReader() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected boolean notFinishedEvent(long current_size, int current_pattern, long total) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        protected AQuiXEvent[] getEndEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[][] getPatternsEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[] getStartEvent() {
            // TODO Auto-generated method stub
            return null;
        }

    }

    // high depth
    // {} -> 2
    // {"":{}} -> 7
    // {"":{"":{}}} -> 12
    // start "{"
    // end "}"
    // '"":{' and '}'
    public abstract static class AHighDepthGenerator extends AHighNodeDepthGenerator {

        @Override
        protected int getPatternsLength() {
            return getPatterns()[0].length + getPatterns()[1].length;
        }

        @Override
        public byte[] applyVariation(Variation variation, byte[][] bs, int pos) {
            // int incr = 0;
            switch (variation) {
            case NO_VARIATION:
                return bs[pos];
            case RANDOM:
                // incr = this.random.nextInt(128);
                //$FALL-THROUGH$
            case SEQUENTIAL:
                switch (pos) {
                case 0:
                    // bs[pos][1] = nextChar(bs[pos][1], incr);
                    break;
                case 1:
                    // no op
                    break;
                default:
                }
                return bs[pos];
            default:
            }
            return null;
        }

        @Override
        public IQuiXStreamReader getQuiXStreamReader() {
            // TODO Auto-generated method stub
            return null;
        }

    }

    @TreeGenerator(ext = FileExtension.JSON, type = TreeType.HIGH_NODE_DEPTH, stype = SpecialType.STANDARD)
    public static class HighDepthGeneratorObject extends AHighDepthGenerator {

        final byte[] start = s2b("{");
        final byte[] end = s2b("}");

        @Override
        protected byte[] getEnd() {
            return this.end;
        }

        @Override
        protected byte[] getStart() {
            return this.start;
        }

        final byte[][] patterns = { s2b("\"\":{"), s2b("}") };

        @Override
        protected byte[][] getPatterns() {
            return this.patterns;
        }

        @Override
        protected boolean notFinishedEvent(long current_size, int current_pattern, long total) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        protected AQuiXEvent[] getEndEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[][] getPatternsEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[] getStartEvent() {
            // TODO Auto-generated method stub
            return null;
        }
    }

    @TreeGenerator(ext = FileExtension.JSON, type = TreeType.HIGH_NODE_DEPTH, stype = SpecialType.ARRAY)
    public static class HighDepthGeneratorArray extends AHighDepthGenerator {

        final byte[] start = s2b("{\"\":");
        final byte[] end = s2b("}");

        @Override
        protected byte[] getEnd() {
            return this.end;
        }

        @Override
        protected byte[] getStart() {
            return this.start;
        }

        final byte[][] patterns = { s2b("["), s2b("]") };

        @Override
        protected byte[][] getPatterns() {
            return this.patterns;
        }

        @Override
        protected boolean notFinishedEvent(long current_size, int current_pattern, long total) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        protected AQuiXEvent[] getEndEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[][] getPatternsEvent() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        protected AQuiXEvent[] getStartEvent() {
            // TODO Auto-generated method stub
            return null;
        }
    }

    public static void main(String[] args)
            throws JsonParseException, IOException, InstantiationException, IllegalAccessException {

        /*
         * final byte[][] patterns = { // empty object is allowed
         * 
         * "\"A\":1".getBytes(), // first used only once ",\"A\":1".getBytes()
         * }; BoxedArray baA = new BoxedArray(patterns, 1, 2); for (int i = 0; i
         * <Integer.MAX_VALUE; i++) { baA.nextUnique(); }
         * 
         * 
         * System.out.println(display(patterns[1]));
         */
        JsonFactory f = new JsonFactory();
        f.disable(Feature.ALLOW_COMMENTS);
        f.disable(Feature.ALLOW_SINGLE_QUOTES);
        // AGenerator generator = instance(ATreeGenerator.Type.HIGH_DENSITY);
        AGenerator generator = instance(FileExtension.JSON, TreeType.HIGH_NODE_DEPTH, SpecialType.STANDARD);

        InputStream is = generator.getInputStream(50, Unit.MBYTE, Variation.NO_VARIATION);
        if (false) {
            int c;
            while ((c = is.read()) != -1) {
                System.out.println(display((byte) (c & 0xFF)));
            }
        } else {
            JsonParser p = f.createParser(is);
            p.enable(Feature.STRICT_DUPLICATE_DETECTION);

            while (p.nextToken() != JsonToken.END_OBJECT) {
                //
            }
        }
    }
}