Package net.sf.jasperreports.engine.data

Source Code of net.sf.jasperreports.engine.data.JsonDataSource

/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2011 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRRewindableDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JsonUtil;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;

/**
* JSON data source implementation
*
* @author Narcis Marcu (narcism@users.sourceforge.net)
* @version $Id: JsonDataSource.java 4185 2011-02-16 09:59:38Z narcism $
*/
public class JsonDataSource extends JRAbstractTextDataSource implements JRRewindableDataSource {

  // the JSON select expression that gives the nodes to iterate
  private String selectExpression;

  private Iterator<JsonNode> jsonNodesIterator;

  // the current node
  private JsonNode currentJsonNode;

  private final String PROPERTY_SEPARATOR = ".";

  private final String ARRAY_LEFT = "[";

  private final String ARRAY_RIGHT = "]";
 
  private final String ATTRIBUTE_LEFT = "(";
 
  private final String ATTRIBUTE_RIGHT = ")";
 
  // the JSON tree as it is obtained from the JSON source
  private JsonNode jsonTree;
 
  private ObjectMapper mapper;
 
  private InputStream jsonStream;
 
  private boolean toClose;
 
  public JsonDataSource(InputStream stream) throws JRException {
    this(stream, null);
  }
 
  public JsonDataSource(InputStream jsonStream, String selectExpression) throws JRException {
    try {
      this.jsonStream = jsonStream;
      this.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);
     
      this.jsonTree = mapper.readTree(jsonStream);
      this.selectExpression = selectExpression;
     
      moveFirst();
    } catch (JsonProcessingException e) {
      throw new JRException(e);
    } catch (IOException e) {
      throw new JRException(e);
    }
  }


  public JsonDataSource(File file) throws FileNotFoundException, JRException {
    this(file, null);
  }
 

  public JsonDataSource(File file, String selectExpression) throws FileNotFoundException, JRException {
    this(new FileInputStream(file), selectExpression);
   
    toClose = true;
  }

  /**
   * Creates a data source instance that reads JSON data from a given location
   * @param location a String representing JSON data source
   */
  public JsonDataSource(String location, String selectExpression) throws JRException {
    this(JRLoader.getInputStreamFromLocation(location), selectExpression);
   
    toClose = true;
  }
 
  /*
   * (non-Javadoc)
   *
   * @see net.sf.jasperreports.engine.JRRewindableDataSource#moveFirst()
   */
  public void moveFirst() throws JRException {
    if (jsonTree == null || jsonTree.isMissingNode()) {
      throw new JRException("No JSON data to operate on!");
    }

    currentJsonNode = null;
    JsonNode result = getJsonData(jsonTree, selectExpression);
    if (result != null && result.isObject()) {
//      System.out.println("result is object");
      final List<JsonNode> list = new ArrayList<JsonNode>();
      list.add(result);
      jsonNodesIterator = new Iterator<JsonNode>() {
        private int count = -1;
        public void remove() {
          list.remove(count);
        }
       
        public JsonNode next() {
          count ++;
          return list.get(count);
        }
       
        public boolean hasNext() {
          return count < list.size()-1;
        }
      };
    } else if (result != null && result.isArray()) {
//      System.out.println("result is array");
      jsonNodesIterator = result.getElements();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see net.sf.jasperreports.engine.JRDataSource#next()
   */
  public boolean next() {
    if(jsonNodesIterator == null || !jsonNodesIterator.hasNext()) {
      return false;
    }
    currentJsonNode = jsonNodesIterator.next();
    return true;
  }

  /*
   * (non-Javadoc)
   *
   * @see net.sf.jasperreports.engine.JRDataSource#getFieldValue(net.sf.jasperreports.engine.JRField)
   */
  public Object getFieldValue(JRField jrField) throws JRException
  {
    if(currentJsonNode == null) {
      return null;
    }
    String expression = jrField.getDescription();
    if (expression == null || expression.length() == 0)
    {
      return null;
    }
    Object value = null;
   
    Class valueClass = jrField.getValueClass();
    JsonNode selectedObject = getJsonData(currentJsonNode, expression);
   
    if(Object.class != valueClass)
    {
      if (selectedObject != null)
      {
        try {
          if (valueClass.equals(String.class)) {
            value = selectedObject.getValueAsText();
           
          } else if (valueClass.equals(Boolean.class)) {
            value = selectedObject.getBooleanValue();
           
          } else if (Number.class.isAssignableFrom(valueClass)) {
              value = convertStringValue(selectedObject.getValueAsText(), valueClass);
             
          }
          else if (Date.class.isAssignableFrom(valueClass)) {
              value = convertStringValue(selectedObject.getValueAsText(), valueClass);
             
          } else {
            throw new JRException("Field '" + jrField.getName() + "' is of class '" + valueClass.getName() + "' and cannot be converted");
          }
        } catch (Exception e) {
          throw new JRException("Unable to get value for field '" + jrField.getName() + "' of class '" + valueClass.getName() + "'", e);
        }
      }
    }
    else
    {
      value = selectedObject;
    }
   
    return value;
  }
 
  /**
   * Extracts the JSON nodes based on the query expression
   *
   * @param rootNode
   * @param jsonExpression
   * @return
   * @throws JRException
   */
  protected JsonNode getJsonData(JsonNode rootNode, String jsonExpression) throws JRException {
    if (jsonExpression == null || jsonExpression.length() == 0) {
      return rootNode;
    }
    JsonNode tempNode = rootNode;
    StringTokenizer tokenizer = new StringTokenizer(jsonExpression, PROPERTY_SEPARATOR);
   
    while(tokenizer.hasMoreTokens()) {
      String currentToken = tokenizer.nextToken();
      int currentTokenLength = currentToken.length();
      int indexOfLeftSquareBracket = currentToken.indexOf(ARRAY_LEFT);

      // got Left Square Bracket - LSB
      if (indexOfLeftSquareBracket != -1) {
        // a Right Square Bracket must be the last character in the current token
        if(currentToken.lastIndexOf(ARRAY_RIGHT) != (currentTokenLength-1)) {
          throw new JRException("Invalid expression: " + jsonExpression + "; current token " + currentToken + " not ended properly");
        }
       
        // LSB not first character
        if (indexOfLeftSquareBracket > 0) {
          // extract nodes at property
          String property = currentToken.substring(0, indexOfLeftSquareBracket);
          tempNode = goDownPathWithAttribute(tempNode, property);
         
          String arrayOperators = currentToken.substring(indexOfLeftSquareBracket);
          StringTokenizer arrayOpsTokenizer = new StringTokenizer(arrayOperators,ARRAY_RIGHT);
          while(arrayOpsTokenizer.hasMoreTokens()) {
            if (!tempNode.isMissingNode() && tempNode.isArray()) {
              String currentArrayOperator = arrayOpsTokenizer.nextToken();
              tempNode = tempNode.path(Integer.parseInt(currentArrayOperator.substring(1)));
            }
          }
        } else { // LSB first character
          String arrayOperators = currentToken.substring(indexOfLeftSquareBracket);
          StringTokenizer arrayOpsTokenizer = new StringTokenizer(arrayOperators,ARRAY_RIGHT);
          while(arrayOpsTokenizer.hasMoreTokens()) {
            if (!tempNode.isMissingNode() && tempNode.isArray()) {
              String currentArrayOperator = arrayOpsTokenizer.nextToken();
              tempNode = tempNode.path(Integer.parseInt(currentArrayOperator.substring(1)));
            }
          }
        }
      } else {
        tempNode = goDownPathWithAttribute(tempNode, currentToken);
      }
    }
   
    return tempNode;
  }
 
 
  /**
   * Extracts the JSON nodes that match the attribute expression
   *
   * @param rootNode
   * @param pathWithAttributeExpression: e.g. Orders(CustomerId == HILAA)
   * @return
   * @throws JRException
   */
  protected JsonNode goDownPathWithAttribute(JsonNode rootNode, String pathWithAttributeExpression) throws JRException {
    // check if path has attribute selector
    int indexOfLeftRoundBracket = pathWithAttributeExpression.indexOf(ATTRIBUTE_LEFT);
    if (indexOfLeftRoundBracket != -1) {
     
      // a Right Round Bracket must be the last character in the current pathWithAttribute
      if(pathWithAttributeExpression.indexOf(ATTRIBUTE_RIGHT) != (pathWithAttributeExpression.length() - 1)) {
        throw new JRException("Invalid attribute selection expression: " + pathWithAttributeExpression);
      }
     
      if(rootNode != null && !rootNode.isMissingNode()) {
       
        String path = pathWithAttributeExpression.substring(0, indexOfLeftRoundBracket);
       
        // an expression in a form like: attribute==value
        String attributeExpression = pathWithAttributeExpression.substring(indexOfLeftRoundBracket + 1, pathWithAttributeExpression.length() - 1);
       
        JsonNode result = null;
        if (rootNode.isObject()) {
          // select only those nodes for which the attribute expression applies
          if (!rootNode.path(path).isMissingNode()) {
            if (rootNode.path(path).isObject()) {
              if (isValidExpression(rootNode.path(path), attributeExpression)) {
                result = rootNode.path(path);
              }
            } else if (rootNode.path(path).isArray()) {
              result = mapper.createArrayNode();
              for (JsonNode node: rootNode.path(path)) {
                if (isValidExpression(node, attributeExpression)) {
                  ((ArrayNode)result).add(node);
                }
              }
            }
          }
        } else if (rootNode.isArray()) {
          result = mapper.createArrayNode();
          for (JsonNode node: rootNode) {
            JsonNode deeperNode = node.path(path);
            if (!deeperNode.isMissingNode() && isValidExpression(deeperNode, attributeExpression)) {
              ((ArrayNode)result).add(deeperNode);
            }
          }
        }
        return result;
      }
     
    } else { // path has no attribute selectors
      return goDownPath(rootNode, pathWithAttributeExpression);
    }
    return rootNode;
  }
 
 
  /**
   * Extracts the JSON nodes under the simple path
   *
   * @param rootNode
   * @param simplePath - a simple field name, with no selection by attribute
   * @return
   */
  protected JsonNode goDownPath(JsonNode rootNode, String simplePath) {
    if(rootNode != null && !rootNode.isMissingNode()) {
      JsonNode result = null;
      if (rootNode.isObject()) {
        result = rootNode.path(simplePath);
      } else if (rootNode.isArray()) {
        result = mapper.createArrayNode();
        for (JsonNode node: rootNode) {
          JsonNode deeperNode = node.path(simplePath);
          if (!deeperNode.isMissingNode()) {
            ((ArrayNode)result).add(deeperNode);
          }
        }
      }
      return result;
    }
    return rootNode;
  }
 
 
  /**
   * Validates an attribute expression on a JsonNode
   *
   * @param operand
   * @param attributeExpression
   * @return
   * @throws JRException
   */
  protected boolean isValidExpression(JsonNode operand, String attributeExpression) throws JRException{
    return JsonUtil.evaluateJsonExpression(operand, attributeExpression);
  }
 
 
 
  public static void main(String[] args) throws Exception {
  }

  public void close() {
    if (toClose) {
      try  {
        jsonStream.close();
      } catch(Exception e) {
        //nothing to do
      }
    }
  }

}
TOP

Related Classes of net.sf.jasperreports.engine.data.JsonDataSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.