com.jaspersoft.studio.data.querydesigner.json.JsonDataManager.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.data.querydesigner.json.JsonDataManager.java

Source

/*******************************************************************************
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 * 
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 * 
 * 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
 ******************************************************************************/
package com.jaspersoft.studio.data.querydesigner.json;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.data.DataFile;
import net.sf.jasperreports.data.DataFileStream;
import net.sf.jasperreports.data.DataFileUtils;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.design.JRDesignField;

import org.apache.commons.io.IOUtils;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jaspersoft.studio.data.designer.tree.ISelectableNodes;
import com.jaspersoft.studio.model.MRoot;
import com.jaspersoft.studio.model.datasource.json.JsonSupportNode;
import com.jaspersoft.studio.utils.ModelUtils;
import com.jaspersoft.studio.utils.jasper.JasperReportsConfiguration;

/**
 * This class works with the specified Json data information.
 * Usually this will be read from an input file or an existing string.
 * 
 * @author Massimo Rabbi (mrabbi@users.sourceforge.net)
 *
 */
public class JsonDataManager implements ISelectableNodes<JsonSupportNode> {
    private ObjectMapper mapper;
    private JsonNode jsonRoot;
    private MRoot jsonSupportModel;
    private Map<JsonSupportNode, JsonNode> jsonNodesMap;

    /**
     * Tries to load a JSON tree structure using the specified data file and context.
     * 
     * @param dataFile the resource information to get the JSON
     * @param jconfig the context
     * @throws IOException
     * @throws JRException
     */
    public void loadJsonDataFile(DataFile dataFile, JasperReportsConfiguration jconfig)
            throws IOException, JRException {
        getJsonNodesMap().clear();
        DataFileStream ins = null;
        try {
            Map<String, Object> parameters = new HashMap<String, Object>();
            // FIXME - We need to proper populate the map!!!
            ins = DataFileUtils.instance(jconfig).getDataStream(dataFile, parameters);
            jsonRoot = getJsonMapper().readTree(ins);
            buildJsonSupportTree();
        } catch (IOException e) {
            throw e;
        } catch (JRException e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(ins);
        }
    }

    /**
     * Tries to load a Json tree structure using the 
     * specified string content as input source.
     * 
     * @param jsonData the string containing json data
     * @throws IOException 
     * @throws JsonProcessingException 
     */
    public void loadJsonDataString(String jsonData) throws JsonProcessingException, IOException {
        jsonRoot = getJsonMapper().readTree(jsonData);
        buildJsonSupportTree();
    }

    /*
     * Returns the Json object mapper.
     */
    private ObjectMapper getJsonMapper() {
        if (mapper == null) {
            mapper = new ObjectMapper();
            mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
            mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        }
        return mapper;
    }

    /**
     * @return the current json root node
     */
    public JsonNode getJsonTreeRoot() {
        return jsonRoot;
    }

    /**
     * @return the current support model root
     */
    public MRoot getJsonSupportModel() {
        return jsonSupportModel;
    }

    /*
     * Creates the support tree that uses ANodes.
     */
    private void buildJsonSupportTree() {
        jsonSupportModel = new MRoot(null, null);
        List<JsonSupportNode> children = getChildrenJsonNodes(getJsonTreeRoot());
        for (JsonSupportNode c : children) {
            c.setParent(jsonSupportModel, -1);
        }
    }

    /*
     * Extract the children ANodes for a specified Json node.
     */
    private List<JsonSupportNode> getChildrenJsonNodes(JsonNode jsonNode) {
        List<JsonSupportNode> children = new ArrayList<JsonSupportNode>();
        if (jsonNode.isArray() && jsonNode.equals(jsonRoot)) {
            // Assumption: consider the first element as a template
            jsonNode = jsonNode.get(0);
        }
        Iterator<String> fieldNames = jsonNode.fieldNames();
        while (fieldNames.hasNext()) {
            String name = fieldNames.next();
            JsonNode tmpNode = jsonNode.get(name);
            if (tmpNode.isObject()) {
                JsonSupportNode child = new JsonSupportNode();
                child.setNodeText(name);
                List<JsonSupportNode> innerChildren = getChildrenJsonNodes(tmpNode);
                for (JsonSupportNode innerChild : innerChildren) {
                    innerChild.setParent(child, -1);
                }
                getJsonNodesMap().put(child, tmpNode);
                children.add(child);
            } else if (tmpNode.isArray()) {
                Iterator<JsonNode> elements = tmpNode.elements();
                while (elements.hasNext()) {
                    JsonNode el = elements.next();
                    JsonSupportNode child = new JsonSupportNode();
                    child.setNodeText(name);
                    List<JsonSupportNode> innerChildren = getChildrenJsonNodes(el);
                    for (JsonSupportNode innerChild : innerChildren) {
                        innerChild.setParent(child, -1);
                    }
                    getJsonNodesMap().put(child, el);
                    children.add(child);
                }
            } else if (tmpNode.isValueNode()) {
                JsonSupportNode child = new JsonSupportNode();
                child.setNodeText(name);
                getJsonNodesMap().put(child, tmpNode);
                children.add(child);
            }
        }
        return children;
    }

    /*
     * (non-Javadoc)
     * @see com.jaspersoft.studio.data.querydesigner.ISelectableNodes#getSelectableNodes(java.lang.String)
     */
    public List<JsonSupportNode> getSelectableNodes(String query) {
        List<JsonSupportNode> selectedList = new ArrayList<JsonSupportNode>();
        JsonQueryHelper jsonQueryHelper = new JsonQueryHelper(mapper);
        try {
            JsonNode jsonData = jsonQueryHelper.getJsonData(jsonRoot, query);
            if (jsonData != null) {
                List<JsonNode> elementsList = new ArrayList<JsonNode>();
                if (jsonData.isArray()) {
                    Iterator<JsonNode> elements = jsonData.elements();
                    while (elements.hasNext()) {
                        elementsList.add(elements.next());
                    }
                } else if (jsonData.isObject()) {
                    elementsList.add(jsonData);
                }

                for (JsonSupportNode sn : getJsonNodesMap().keySet()) {
                    if (elementsList.contains(getJsonNodesMap().get(sn))) {
                        selectedList.add(sn);
                    }
                }
            }
        } catch (JRException e) {
            // Do not care about error in node selection
        }

        return selectedList;
    }

    /**
     * Given a JSON selection query, extracts from the result set 
     * the list of possible fields that can be used in a report.
     * 
     * @param query the JSON query text
     * @return a list of fields
     */
    public List<JRDesignField> extractFields(String query) {
        JsonQueryHelper jsonQueryHelper = new JsonQueryHelper(mapper);
        try {
            JsonNode jsonData = jsonQueryHelper.getJsonData(jsonRoot, query);
            if (jsonData != null) {
                if (jsonData.isArray()) {
                    return getFieldsFromArrayNode((ArrayNode) jsonData);
                } else if (jsonData.isObject()) {
                    return getFieldsFromObjectNode((ObjectNode) jsonData);
                }
            }
        } catch (JRException e) {
            // Do not care about error in node selection
        }
        return new ArrayList<JRDesignField>();
    }

    /*
     * Gets the fields from a JSON node of type object.
     */
    private List<JRDesignField> getFieldsFromObjectNode(ObjectNode node) {
        List<JRDesignField> fields = new ArrayList<JRDesignField>();
        Iterator<String> fieldNames = node.fieldNames();
        while (fieldNames.hasNext()) {
            String name = fieldNames.next();
            JRDesignField f = new JRDesignField();
            f.setName(ModelUtils.getNameForField(fields, name));
            f.setDescription(name);
            f.setValueClass(String.class);
            fields.add(f);
        }
        return fields;
    }

    /*
     * Gets the fields from a JSON node of type array.
     */
    private List<JRDesignField> getFieldsFromArrayNode(ArrayNode node) {
        // Assumption: consider the first element as template 
        JsonNode firstEl = node.get(0);
        if (firstEl instanceof ObjectNode) {
            return getFieldsFromObjectNode((ObjectNode) firstEl);
        } else if (firstEl instanceof ArrayNode) {
            return getFieldsFromArrayNode((ArrayNode) firstEl);
        }
        return new ArrayList<JRDesignField>();
    }

    public Map<JsonSupportNode, JsonNode> getJsonNodesMap() {
        if (this.jsonNodesMap == null) {
            this.jsonNodesMap = new HashMap<JsonSupportNode, JsonNode>();
        }
        return jsonNodesMap;
    }

    public String getQueryExpression(String existingQuery, JsonSupportNode selectedNode) {
        String absoluteQuery = getAbsoluteQueryExpression(selectedNode);
        if (existingQuery != null && absoluteQuery.startsWith(existingQuery)
                && absoluteQuery.length() > existingQuery.length()) {
            // consider also an additional . selector
            int qLength = existingQuery.length();
            return absoluteQuery.substring(qLength + Math.min(qLength, 1));
        }
        return absoluteQuery;
    }

    private String getAbsoluteQueryExpression(JsonSupportNode selectedNode) {
        StringBuffer queryBuff = new StringBuffer();
        queryBuff.insert(0, selectedNode.getNodeText());
        JsonSupportNode tmpNode = selectedNode;
        while (tmpNode.getParent() != null && !(tmpNode.getParent() instanceof MRoot)) {
            tmpNode = (JsonSupportNode) tmpNode.getParent();
            queryBuff.insert(0, tmpNode.getNodeText() + ".");
        }
        return queryBuff.toString();
    }
}