/** * Copyright 2014 National University of Ireland, Galway. * * This file is part of the SIREn project. Project and contact information: * * https://github.com/rdelbru/SIREn * * 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 org.sindice.siren.qparser.json.parser; import java.io.IOException; import java.util.Iterator; import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException; import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; import org.apache.lucene.queryparser.flexible.core.parser.SyntaxParser; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import org.sindice.siren.qparser.json.ParseException; import org.sindice.siren.qparser.json.nodes.TopLevelQueryNode; /** * Parser for the SIREN's JSON query syntax * * <p> * * This parser is based on the Jackson's JSON parser and uses internally * an {@link ObjectMapper} to create a tree model of the JSON data. The * tree model is then traversed using a property-centric visitor model. * The parser works as follows: * <ol> * <li> The JSON data is parsed and a JSON tree model is created. * <li> The tree model is then traversed using {@link JsonPropertyParser}s. * For each property found in the tree model, the corresponding * {@link JsonPropertyParser} is applied. * </ol> */ public class JsonSyntaxParser implements SyntaxParser { private final ObjectMapper mapper; public JsonSyntaxParser() { this.mapper = new ObjectMapper(); } @Override public QueryNode parse(final CharSequence query, final CharSequence field) throws QueryNodeParseException { try { final JsonNode node = mapper.readTree(query.toString()); final String fieldname = this.getFirstFieldName(node); final TopLevelQueryNode topNode = new TopLevelQueryNode(); // check for node property if (fieldname.equals(NodePropertyParser.NODE_PROPERTY)) { final NodePropertyParser nodeParser = new NodePropertyParser(node, field); topNode.add(nodeParser.parse()); return topNode; } // check for twig property if (fieldname.equals(TwigPropertyParser.TWIG_PROPERTY)) { final TwigPropertyParser twigParser = new TwigPropertyParser(node, field); topNode.add(twigParser.parse()); return topNode; } // check for boolean property if (fieldname.equals(BooleanPropertyParser.BOOLEAN_PROPERTY)) { final BooleanPropertyParser booleanParser = new BooleanPropertyParser(node, field); topNode.add(booleanParser.parse()); return topNode; } throw new ParseException("Invalid JSON query: unknown property '" + fieldname + "'"); } catch (final IOException e) { throw new ParseException("Invalid JSON query", e); } } private String getFirstFieldName(final JsonNode node) throws ParseException { final Iterator<String> fieldNames = node.getFieldNames(); if (fieldNames.hasNext()) { return fieldNames.next(); } throw new ParseException("Invalid JSON query: either a node, boolean or twig query must be defined"); } }