com.esri.gpt.framework.dcat.DcatParser.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.gpt.framework.dcat.DcatParser.java

Source

/*
 * Copyright 2013 Esri.
 *
 * Licensed 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 com.esri.gpt.framework.dcat;

import com.esri.gpt.framework.dcat.adaptors.DcatRecordAdaptor;
import com.esri.gpt.framework.dcat.dcat.DcatRecord;
import com.esri.gpt.framework.dcat.dcat.DcatRecordList;
import com.esri.gpt.framework.dcat.json.JsonArray;
import com.esri.gpt.framework.dcat.json.JsonAttribute;
import com.esri.gpt.framework.dcat.json.JsonAttributes;
import com.esri.gpt.framework.dcat.json.JsonRecord;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import java.io.IOException;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * DCAT parser.
 */
public class DcatParser {

    private static final Logger LOGGER = Logger.getLogger(DcatParser.class.getCanonicalName());

    private JsonReader jsonReader;

    /**
     * Creates instance of the parser.
     *
     * @param input input stream to parse
     */
    public DcatParser(InputStream input) throws UnsupportedEncodingException {
        this.jsonReader = new JsonReader(new InputStreamReader(input, "UTF-8"));
    }

    /**
     * Creates instance of the parser.
     *
     * @param reader data reader
     */
    public DcatParser(Reader reader) {
        this.jsonReader = new JsonReader(reader);
    }

    /**
     * Closes parser.
     */
    public void close() throws IOException {
        jsonReader.close();
    }

    /**
     * Parses data (event driven style).
     *
     * @param listener event listener
     * @throws DcatParseException if parsing fails
     */
    public void parse(final Listener listener) throws DcatParseException, IOException {
        ListenerInternal localListener = new ListenerInternal() {
            @Override
            public boolean onRecord(DcatRecord record) {
                LOGGER.log(Level.FINEST, record != null ? record.toString() : "<empty record>");
                listener.onRecord(record);
                return true;
            }
        };
        parse(localListener);
    }

    /**
     * Parses data (DOM building style).
     *
     * @param policy limit policy
     * @return list of records.
     * @throws DcatParseException if parsing fails
     */
    public DcatRecordList parse(final LimitPolicy policy) throws DcatParseException, IOException {
        final DcatRecordListImpl list = new DcatRecordListImpl();
        DcatParser.ListenerInternal listener = new DcatParser.ListenerInternal() {
            private void parse(final ListenerInternal listener) throws DcatParseException, IOException {
                if (!jsonReader.hasNext()) {
                    throw new DcatParseException("No more data available.");
                }
                JsonToken token = jsonReader.peek();
                if (token != JsonToken.BEGIN_ARRAY) {
                    throw new DcatParseException("No array found.");
                }

                parseRecords(listener);
            }

            @Override
            public boolean onRecord(DcatRecord record) {
                list.add(record);
                if (policy == null || list.size() >= policy.getLimit()) {
                    return true;
                } else {
                    policy.onLimit(list);
                    return false;
                }
            }
        };
        parse(listener);
        return list;
    }

    /**
     * Parses DCAT using internal listener.
     *
     * @param listener internal listener
     * @throws DcatParseException if parsing DCAT fails
     */
    void parse(final ListenerInternal listener) throws DcatParseException, IOException {
        if (!jsonReader.hasNext()) {
            throw new DcatParseException("No more data available.");
        }

        JsonToken token = jsonReader.peek();
        if (token != JsonToken.BEGIN_ARRAY) {
            throw new DcatParseException("No array found.");
        }
        jsonReader.beginArray();

        parseRecords(listener);
    }

    /**
     * Parses DCAT records using internal listener.
     *
     * @param listener internal listener
     * @throws DcatParseException if parsing DCAT fails
     */
    void parseRecords(ListenerInternal listener) throws DcatParseException, IOException {

        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case BEGIN_OBJECT:
                jsonReader.beginObject();
                if (!parseRecord(listener)) {
                    return;
                }
                break;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }

        jsonReader.endArray();
    }

    private boolean parseRecord(ListenerInternal listener) throws DcatParseException, IOException {
        JsonRecord record = new JsonRecord();
        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case NAME:
                parseAttribute(record);
                break;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }

        jsonReader.endObject();
        return listener.onRecord(new DcatRecordAdaptor(record));
    }

    private void parseAttribute(JsonRecord record) throws DcatParseException, IOException {
        String attrName = jsonReader.nextName();
        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case STRING:
                record.put(attrName, new JsonAttribute(jsonReader.nextString()));
                return;
            case NUMBER:
                record.put(attrName, new JsonAttribute(jsonReader.nextDouble()));
                return;
            case BOOLEAN:
                record.put(attrName, new JsonAttribute(jsonReader.nextBoolean()));
                return;
            case BEGIN_ARRAY:
                if ("distribution".equals(attrName)) {
                    jsonReader.beginArray();
                    parseDistributions(record.getDistribution());
                    jsonReader.endArray();
                } else if ("keyword".equals(attrName)) {
                    jsonReader.beginArray();
                    parseKeywords(record.getKeywords());
                    jsonReader.endArray();
                } else {
                    // skip
                    jsonReader.skipValue();
                }
                return;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }
    }

    private void parseKeywords(List<JsonAttribute> keywords) throws DcatParseException, IOException {

        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case END_ARRAY:
                jsonReader.endArray();
                break;
            case STRING:
                keywords.add(new JsonAttribute(jsonReader.nextString()));
                break;
            case NUMBER:
                keywords.add(new JsonAttribute(jsonReader.nextDouble()));
                break;
            case BOOLEAN:
                keywords.add(new JsonAttribute(jsonReader.nextBoolean()));
                break;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }
    }

    private void parseDistributions(JsonArray<JsonAttributes> distributions)
            throws DcatParseException, IOException {

        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case BEGIN_OBJECT:
                jsonReader.beginObject();
                parseDistribution(distributions);
                jsonReader.endObject();
                break;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }

    }

    private void parseDistribution(JsonArray<JsonAttributes> distributions) throws DcatParseException, IOException {
        JsonAttributes attributes = new JsonAttributes();
        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case NAME:
                parseAttribute(attributes);
                break;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }

        distributions.add(attributes);
    }

    private void parseAttribute(JsonAttributes attributes) throws DcatParseException, IOException {
        String attrName = jsonReader.nextName();
        while (jsonReader.hasNext()) {
            JsonToken token = jsonReader.peek();
            switch (token) {
            case STRING:
                attributes.put(attrName, new JsonAttribute(jsonReader.nextString()));
                return;
            case NUMBER:
                attributes.put(attrName, new JsonAttribute(jsonReader.nextDouble()));
                return;
            case BOOLEAN:
                attributes.put(attrName, new JsonAttribute(jsonReader.nextBoolean()));
                return;
            default:
                throw new DcatParseException("Unexpected token in the data: " + token);
            }
        }
    }

    /**
     * Record listener.
     */
    public static interface Listener {

        /**
         * Called upon a single record parsed.
         *
         * @param record record
         */
        void onRecord(DcatRecord record);
    }

    /**
     * Limit policy.
     */
    public static interface LimitPolicy {

        /**
         * Gets size limit.
         *
         * @return size limit
         */
        long getLimit();

        /**
         * Called when size reached limit.
         *
         * @param recordsList current list of records
         */
        void onLimit(DcatRecordList recordsList);
    }

    static interface ListenerInternal {

        boolean onRecord(DcatRecord record);
    }

    private static class DcatRecordListImpl extends ArrayList<DcatRecord> implements DcatRecordList {
    }
}