/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.tuplejump.stargate.lucene.json;
import com.google.common.base.Joiner;
import com.tuplejump.stargate.lucene.LuceneUtils;
import com.tuplejump.stargate.lucene.Properties;
import org.apache.lucene.document.FieldType;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import java.util.ArrayList;
import java.util.List;
/**
* User: satya
* A JsonDocument which uses a streaming json parser to construct the list of fields.
* This uses lesser memory than the regular json document which has a DOM based parser.
*/
public class StreamingJsonDocument extends JsonDocument {
public StreamingJsonDocument(String json, Properties properties, String jsonColName) {
super(properties, jsonColName);
try {
JsonParser jp = jsonFactory.createJsonParser(json);
List<String> fieldName = new ArrayList<>();
String levelFieldName = null;
JsonToken current = jp.nextToken();
JsonToken last = null;
while (current != null) {
Properties currentProps = getProps(fieldName);
FieldType fieldType = currentProps != null ? currentProps.dynamicFieldType() : null;
String currentFieldName = Joiner.on('.').join(fieldName);
switch (current) {
case START_OBJECT:
pushLevelFieldName(fieldName, levelFieldName);
break;
case END_OBJECT:
if (fieldName.size() > 0) {
levelFieldName = fieldName.remove(fieldName.size() - 1);
}
break;
case START_ARRAY:
pushLevelFieldName(fieldName, levelFieldName);
levelFieldName = null;
case END_ARRAY:
if (fieldName.size() > 0)
fieldName.remove(fieldName.size() - 1);
if (last == JsonToken.END_OBJECT)
levelFieldName = null;
break;
case FIELD_NAME:
levelFieldName = jp.getText();
fieldName.add(levelFieldName);
break;
case VALUE_STRING:
if (currentProps == null) {
fields.add(LuceneUtils.textField(currentFieldName, jp.getText()));
} else {
fields.add(LuceneUtils.field(currentFieldName, currentProps, jp.getText(), fieldType));
}
popLevelFieldName(fieldName, levelFieldName);
break;
case VALUE_NUMBER_FLOAT:
if (currentProps == null) {
fields.add(LuceneUtils.doubleField(currentFieldName, jp.getText()));
} else {
fields.add(LuceneUtils.field(currentFieldName, currentProps, jp.getText(), fieldType));
}
popLevelFieldName(fieldName, levelFieldName);
break;
case VALUE_NUMBER_INT:
if (currentProps == null) {
fields.add(LuceneUtils.longField(currentFieldName, jp.getText()));
} else {
fields.add(LuceneUtils.field(currentFieldName, currentProps, jp.getText(), fieldType));
}
popLevelFieldName(fieldName, levelFieldName);
break;
case VALUE_TRUE:
fields.add(LuceneUtils.stringField(currentFieldName, "true"));
popLevelFieldName(fieldName, levelFieldName);
break;
case VALUE_FALSE:
fields.add(LuceneUtils.stringField(currentFieldName, "false"));
popLevelFieldName(fieldName, levelFieldName);
break;
case VALUE_NULL:
fields.add(LuceneUtils.stringField(currentFieldName, "_NULL_"));
popLevelFieldName(fieldName, levelFieldName);
break;
default:
//do nothing
break;
}
last = current;
current = jp.nextToken();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void pushLevelFieldName(List<String> fieldName, String levelFieldName) {
if (levelFieldName != null) {
fieldName.add(levelFieldName);
}
}
private void popLevelFieldName(List<String> fieldName, String levelFieldName) {
fieldName.remove(levelFieldName);
}
}