com.codeasylum.bank.core.store.indigenous.JsonDisassembler.java Source code

Java tutorial

Introduction

Here is the source code for com.codeasylum.bank.core.store.indigenous.JsonDisassembler.java

Source

/*
 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 10212, 2013 David Berkman
 * 
 * This file is part of the CodeAsylum Code Project.
 * 
 * The CodeAsylum Code Project is free software, you can redistribute
 * it and/or modify it under the terms of GNU Affero General Public
 * License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 * 
 * The CodeAsylum Code Project 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 the GNU Affero General Public
 * License, along with the CodeAsylum Code Project. If not, see
 * <http://www.gnu.org/licenses/>.
 * 
 * Additional permission under the GNU Affero GPL version 3 section 7
 * ------------------------------------------------------------------
 * If you modify this Program, or any covered work, by linking or
 * combining it with other code, such other code is not for that reason
 * alone subject to any of the requirements of the GNU Affero GPL
 * version 3.
 */
package com.codeasylum.bank.core.store.indigenous;

import java.io.IOException;
import com.codeasylum.bank.core.ProcessException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.smallmind.nutsnbolts.lang.UnknownSwitchCaseException;

public class JsonDisassembler extends Disassembler {

    private static final JsonFactory JSON_FACTORY = new JsonFactory();
    private final Schema schema = new Schema();
    private final Nest nest = new Nest();
    private final JsonParser parser;
    private Record<?> nextRecord;
    private JsonToken lastToken;

    public JsonDisassembler(String json) throws IOException, ProcessException {

        try {
            parser = JSON_FACTORY.createParser(json);
        } catch (IOException ioException) {
            throw new ProcessException(ioException);
        }

        nextRecord = findNext();
    }

    @Override
    public Schema getSchema() {

        return schema;
    }

    @Override
    public boolean hasNext() {

        return nextRecord != null;
    }

    @Override
    public Record<?> next() {

        Record<?> record = nextRecord;

        try {
            nextRecord = findNext();
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }

        return record;
    }

    private Record<?> findNext() throws IOException, ProcessException {

        JsonToken token;

        while ((token = parser.nextToken()) != null) {
            try {
                switch (token) {
                case NOT_AVAILABLE:
                    throw new ProcessException("Encountered illegal token(%s)", token.name());
                case VALUE_EMBEDDED_OBJECT:
                    throw new ProcessException("Encountered illegal token(%s)", token.name());
                case FIELD_NAME:

                    String name = parser.getCurrentName();

                    if (name.indexOf('.') >= 0) {
                        throw new ProcessException("Use of reserved character '.' within field name(%s)", name);
                    }

                    nest.push(schema.addChildField(getField(name)));
                    break;
                case START_OBJECT:
                    schema.setCurrentFieldAsGroup();
                    break;
                case START_ARRAY:
                    if (schema.isCurrentlyRoot() || (lastToken.equals(JsonToken.START_ARRAY))) {
                        nest.push(schema.addChildField(getField("array").setRepeated(true)));
                    } else {
                        schema.setCurrentFieldAsRepeated();
                    }
                    break;
                case END_OBJECT:
                    closeField();
                    break;
                case END_ARRAY:
                    schema.close();
                    nest.pop();
                    break;
                case VALUE_STRING:
                    return new Record<String>(schema, nest, parser.getValueAsString());
                case VALUE_NUMBER_INT:
                    return new Record<Long>(schema, nest, parser.getValueAsLong());
                case VALUE_NUMBER_FLOAT:
                    return new Record<Double>(schema, nest, parser.getValueAsDouble());
                case VALUE_TRUE:
                    return new Record<Boolean>(schema, nest, true);
                case VALUE_FALSE:
                    return new Record<Boolean>(schema, nest, false);
                case VALUE_NULL:
                    return new Record<Void>(schema, nest, null);
                default:
                    throw new UnknownSwitchCaseException(token.name());
                }
            } finally {
                lastToken = token;
                if (token.isScalarValue()) {
                    closeField();
                }
            }
        }

        return null;
    }

    private void closeField() {

        if (schema.closeIfNotRepeated()) {
            nest.pop();
        } else {
            nest.inc();
        }
    }

    private Field getField(String name) throws ProcessException {

        Field field;

        if ((field = schema.getChildFieldWithName(name)) == null) {
            field = new Field(nextId(), name).setOptional(true);
        }

        return field;
    }
}