jsondiscoverer.JsonSource.java Source code

Java tutorial

Introduction

Here is the source code for jsondiscoverer.JsonSource.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2015
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Javier Canovas (me@jlcanovas.es) 
 *******************************************************************************/

package jsondiscoverer;

import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;

/**
 * This class represents a JSON source. A JSON source is represented by
 * a set of JSON documents with the same meaning (i.e., set of JSON documents 
 * returned by the same JSON-based Web API). 
 * <p>
 * In the context of JSON Discoverer, it is used to model a single JSON-based Web service.
 * <p>
 * JSON documents are represented as {@link JsonData} elements. 
 * <p>
 * The set of JSON documents can be retrieved by calling the method {@link JsonSource#getJsonData()}.
 * <p>
 * As {@link JsonData} elements can include input elements (to represent which JSON data
 * has triggered such JSON document), a {@link JsonSource} can include {@link JsonData} elements with
 * or without input. To know whether the {@link JsonData} elements included in the {@link JsonSource}
 * have input elements, you have to call the method {@link JsonSource#withInput}.
 * <p>
 * Note that all the {@link JsonData} elements included in a {@link JsonSource} have to include (or 
 * not include) inputs.
 * <p>
 * 
 * @author Javier Canovas (me@jlcanovas.es)
 *
 */
public class JsonSource extends AbstractJsonSource {
    /**
     * List of JSON documents
     */
    protected List<JsonData> jsonData;

    /**
     * Sets if the set of JSON documents are the result of computing an input
     * JSON document (to support JSON-based Web APIs)
     */
    public boolean withInput;

    /**
     * Builds a new JsonSource with a name. Once created, the JsonSource has to 
     * be populated by calling {@link JsonSource#addJsonData(Reader, Reader)}.
     * 
     * @param name The name of the JsonSource
     */
    public JsonSource(String name) {
        super(name);
        this.jsonData = new ArrayList<JsonData>();
        this.withInput = false;
    }

    /**
     * Gets the set of {@link JsonData} elements linked to this source. 
     * Warning: the returned list is mutable
     * 
     * @return The set of JSON documents (as {@link JsonData}
     */
    protected List<JsonData> getJsonData() {
        return jsonData;
    }

    /**
     * Indicates if the JsonSource includes input elements. 
     * <p>
     * Note that all of them have to include (or not include) input elements
     * 
     * @return Boolean indicating the status
     */
    public boolean includesInput() {
        return this.withInput;
    }

    /**
     * Builds a {@link JsonData} element out of a JSON document representing the input and another
     * JSON document representing the output. 
     * <p>
     * The input/output must be provided as a valid JSON objects.
     * 
     * @param input The {@link Reader} from which obtain JSON document used as input (optional)
     * @param output The {@link Reader} from which obtain the JSON document
     * @throws IllegalArgumentException If any reader is null 
     * @return The {@link JsonData} with the JSON document and the input
     */
    private JsonData buildJsonData(Reader input, Reader output) {
        if (output == null)
            throw new IllegalArgumentException("The JSON document cannot be null and must exist");

        JsonObject inputJsonObject = null;
        if (input != null) {
            JsonElement inputElement = (new JsonParser()).parse(new JsonReader(input));
            if (!inputElement.isJsonObject())
                throw new JsonParseException("The input value must be a valid JSON object. Received " + input);
            inputJsonObject = inputElement.getAsJsonObject();
        }

        JsonElement rootElement = (new JsonParser()).parse(new JsonReader(output));
        JsonData data = new JsonData(inputJsonObject, rootElement);
        return data;
    }

    /**
     * Adds a new JSON document as well as the input JSON document (optional) to get such a document. 
     * <p>
     * The input/output must be provided as a valid JSON objects.
     * <p>
     * Warning: Once the source has been created with input (or without), subsequent 
     * calls must also include (or not) inputs
     * 
     * @param input The {@link Reader} from which obtain the JSON document used as input (optional)
     * @param output The {@link Reader} from which obtain the JSON document
     * @throws IllegalArgumentException If input is null
     * @throws IllegalStateException If the JSON source was initially created to not hold input data
     */
    public void addJsonData(Reader input, Reader output) {
        if (output == null)
            throw new IllegalArgumentException("output cannot be null");

        if (this.jsonData.size() > 0 && this.withInput == false && input != null)
            throw new IllegalStateException(
                    "This JSON source was initially created to hold JSON data *without* input");
        if (this.jsonData.size() > 0 && this.withInput == true && input == null)
            throw new IllegalStateException(
                    "This JSON source was initially created to hold JSON data *with* input");
        if (this.jsonData.size() == 0)
            this.withInput = (input == null) ? false : true;

        JsonData data = buildJsonData(input, output);
        getJsonData().add(data);
    }

    /**
     * Generates a list of JSON objects according to the {@link JsonData} of this source.
     * <ul>
     * <li>If the source DOES include inputs, the list will include the set of input elements as roots for the
     * {@link JsonData}. For instance:</li> 
     * </ul>
     * 
     * <pre>
     * - [input JSON element 1]
     *   +-- Output
     *       +-- [output JSON element 1]  
     * - [input JSON element 2]
     *   +-- Output
     *       +-- [output JSON element 2]  
     * -...
     * </pre>
     * <ul>
     * <li>If the source DOES NOT include inputs, the list will include all the objects from {@link JsonData}. For instance</li>
     * </ul>
     * <pre>
     * - [output JSON element 1]  
     * - [output JSON element 2] 
     * - [output JSON element 3] 
     * -...
     * </pre>
     * 
     * @return The list of {@link JsonObject}s
     */
    public List<JsonObject> getSourceDigested() {
        List<JsonObject> result = new ArrayList<JsonObject>();
        if (this.withInput == true) {
            for (JsonData data : this.getJsonData()) {
                JsonObject inputElement = data.getInput();
                JsonElement outputElement = data.getData();
                inputElement.getAsJsonObject().add(getName() + "Output", outputElement);
                result.add(inputElement);
            }
        } else {
            for (JsonData data : this.getJsonData()) {
                JsonElement outputElement = data.getData();
                if (outputElement.isJsonArray()) {
                    for (int i = 0; i < outputElement.getAsJsonArray().size(); i++)
                        if (outputElement.getAsJsonArray().get(i).isJsonObject())
                            result.add(outputElement.getAsJsonArray().get(i).getAsJsonObject());
                } else if (outputElement.isJsonObject()) {
                    result.add(outputElement.getAsJsonObject());
                }
            }
        }
        return result;
    }
}