Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.arangodb.shaded.vertx.core.parsetools.impl.JsonParserImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2021 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.arangodb.shaded.vertx.core.parsetools.impl;
import com.arangodb.shaded.fasterxml.jackson.core.JsonFactory;
import com.arangodb.shaded.fasterxml.jackson.core.JsonLocation;
import com.arangodb.shaded.fasterxml.jackson.core.JsonToken;
import com.arangodb.shaded.fasterxml.jackson.core.ObjectCodec;
import com.arangodb.shaded.fasterxml.jackson.core.base.ParserBase;
import com.arangodb.shaded.fasterxml.jackson.core.io.IOContext;
import com.arangodb.shaded.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
import com.arangodb.shaded.vertx.core.Handler;
import com.arangodb.shaded.vertx.core.VertxException;
import com.arangodb.shaded.vertx.core.buffer.Buffer;
import com.arangodb.shaded.vertx.core.impl.Arguments;
import com.arangodb.shaded.vertx.core.json.DecodeException;
import com.arangodb.shaded.vertx.core.json.JsonArray;
import com.arangodb.shaded.vertx.core.json.JsonObject;
import com.arangodb.shaded.vertx.core.json.jackson.JacksonCodec;
import com.arangodb.shaded.vertx.core.parsetools.JsonEvent;
import com.arangodb.shaded.vertx.core.parsetools.JsonEventType;
import com.arangodb.shaded.vertx.core.parsetools.JsonParser;
import com.arangodb.shaded.vertx.core.streams.ReadStream;
import java.io.IOException;
import java.util.*;
/**
* @author Julien Viet
*/
public class JsonParserImpl implements JsonParser {
private final NonBlockingJsonParser parser;
private Handler tokenHandler = this::handleEvent;
private Handler eventHandler;
private boolean objectValueMode;
private boolean arrayValueMode;
private Handler exceptionHandler;
private String currentField;
private Handler endHandler;
private long demand = Long.MAX_VALUE;
private boolean ended;
private final ReadStream stream;
private boolean emitting;
private final Deque pending = new ArrayDeque<>();
private List collectedExceptions;
public JsonParserImpl(ReadStream stream) {
this.stream = stream;
JsonFactory factory = new JsonFactory();
try {
parser = (NonBlockingJsonParser) factory.createNonBlockingByteArrayParser();
} catch (Exception e) {
throw new VertxException(e);
}
}
@Override
public JsonParser pause() {
demand = 0L;
return this;
}
@Override
public JsonParser resume() {
return fetch(Long.MAX_VALUE);
}
@Override
public JsonParser fetch(long amount) {
Arguments.require(amount > 0L, "Fetch amount must be > 0L");
demand += amount;
if (demand < 0L) {
demand = Long.MAX_VALUE;
}
checkPending();
return this;
}
@Override
public JsonParser endHandler(Handler handler) {
if (pending.size() > 0 || !ended) {
endHandler = handler;
}
return this;
}
@Override
public JsonParser handler(Handler handler) {
eventHandler = handler;
if (stream != null) {
if (handler != null) {
stream.endHandler(v -> end());
stream.exceptionHandler(err -> {
if (exceptionHandler != null) {
exceptionHandler.handle(err);
}
});
stream.handler(this);
} else {
stream.handler(null);
stream.endHandler(null);
stream.exceptionHandler(null);
}
}
return this;
}
private void handleEvent(JsonEventImpl event) {
if (event.type() == JsonEventType.START_OBJECT && objectValueMode) {
BufferingHandler handler = new BufferingHandler();
handler.handler = buffer -> {
tokenHandler = this::handleEvent;
handleEvent(new JsonEventImpl(null, JsonEventType.VALUE, event.fieldName(), new JsonObject(handler.convert(Map.class))));
};
tokenHandler = handler;
handler.handle(new JsonEventImpl(JsonToken.START_OBJECT, JsonEventType.START_OBJECT, null, null));
} else if (event.type() == JsonEventType.START_ARRAY && arrayValueMode) {
BufferingHandler handler = new BufferingHandler();
handler.handler = buffer -> {
tokenHandler = this::handleEvent;
handleEvent(new JsonEventImpl(null, JsonEventType.VALUE, event.fieldName(), new JsonArray(handler.convert(List.class))));
};
tokenHandler = handler;
handler.handle(new JsonEventImpl(JsonToken.START_ARRAY, JsonEventType.START_ARRAY, null, null));
} else {
if (demand != Long.MAX_VALUE) {
demand--;
}
if (eventHandler != null) {
eventHandler.handle(event);
}
}
}
private void handle(IOException ioe) {
if (collectedExceptions == null) {
collectedExceptions = new ArrayList<>();
}
collectedExceptions.add(ioe);
}
@Override
public void handle(Buffer data) {
byte[] bytes = data.getBytes();
try {
parser.feedInput(bytes, 0, bytes.length);
} catch (IOException e) {
handle(e);
}
checkTokens();
checkPending();
checkExceptions();
}
@Override
public void end() {
if (ended) {
throw new IllegalStateException("Parsing already done");
}
ended = true;
parser.endOfInput();
checkTokens();
checkPending();
checkExceptions();
}
private void checkTokens() {
JsonLocation prevLocation = null;
while (true) {
JsonToken token;
try {
token = parser.nextToken();
} catch (IOException e) {
JsonLocation location = parser.currentLocation();
if (prevLocation != null) {
if (location.equals(prevLocation)) {
// If we haven't done any progress, give up
return;
}
}
prevLocation = location;
handle(e);
continue;
}
if (token == null || token == JsonToken.NOT_AVAILABLE) {
break;
}
prevLocation = null;
String field = currentField;
currentField = null;
JsonEventImpl event;
switch (token) {
case START_OBJECT: {
event = new JsonEventImpl(token, JsonEventType.START_OBJECT, field, null);
break;
}
case START_ARRAY: {
event = new JsonEventImpl(token, JsonEventType.START_ARRAY, field, null);
break;
}
case FIELD_NAME: {
try {
currentField = parser.getCurrentName();
} catch (IOException e) {
handle(e);
}
continue;
}
case VALUE_STRING: {
try {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, parser.getText());
} catch (IOException e) {
handle(e);
continue;
}
break;
}
case VALUE_TRUE: {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, Boolean.TRUE);
break;
}
case VALUE_FALSE: {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, Boolean.FALSE);
break;
}
case VALUE_NULL: {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, null);
break;
}
case VALUE_NUMBER_INT: {
try {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, parser.getLongValue());
} catch (IOException e) {
handle(e);
continue;
}
break;
}
case VALUE_NUMBER_FLOAT: {
try {
event = new JsonEventImpl(token, JsonEventType.VALUE, field, parser.getDoubleValue());
} catch (IOException e) {
handle(e);
continue;
}
break;
}
case END_OBJECT: {
event = new JsonEventImpl(token, JsonEventType.END_OBJECT, null, null);
break;
}
case END_ARRAY: {
event = new JsonEventImpl(token, JsonEventType.END_ARRAY, null, null);
break;
}
default:
throw new UnsupportedOperationException("Token " + token + " not implemented");
}
pending.add(event);
}
}
private void checkPending() {
if (!emitting) {
emitting = true;
try {
while (true) {
if (demand > 0L) {
JsonEventImpl currentToken = pending.poll();
if (currentToken == null) {
break;
} else {
tokenHandler.handle(currentToken);
}
} else {
break;
}
}
if (ended) {
if (pending.isEmpty()) {
checkExceptions();
Handler handler = endHandler;
endHandler = null;
if (handler != null) {
handler.handle(null);
}
}
} else {
if (demand == 0L) {
if (stream != null) {
stream.pause();
}
} else {
if (stream != null) {
stream.resume();
}
}
}
} catch (Exception e) {
if (exceptionHandler != null) {
exceptionHandler.handle(e);
} else {
throw e;
}
} finally {
emitting = false;
}
}
}
private void checkExceptions() {
List exceptions = collectedExceptions;
collectedExceptions = null;
if (exceptions != null && exceptions.size() > 0) {
if (exceptionHandler != null) {
for (IOException ioe : exceptions) {
exceptionHandler.handle(ioe);
}
} else {
IOException ioe = exceptions.get(0);
throw new DecodeException(ioe.getMessage(), ioe);
}
}
}
@Override
public JsonParser objectEventMode() {
objectValueMode = false;
return this;
}
@Override
public JsonParser objectValueMode() {
objectValueMode = true;
return this;
}
@Override
public JsonParser arrayEventMode() {
arrayValueMode = false;
return this;
}
@Override
public JsonParser arrayValueMode() {
arrayValueMode = true;
return this;
}
/**
* A parser implementation that feeds from a list of tokens instead of bytes.
*/
private static class TokenParser extends ParserBase {
private ArrayDeque tokens = new ArrayDeque<>();
private String text;
private TokenParser(IOContext ctxt, int features) {
super(ctxt, features);
}
@Override
public JsonToken nextToken() throws IOException {
if (tokens.isEmpty()) {
return null;
}
text = null;
_numTypesValid = NR_UNKNOWN;
_numberLong = 0L;
_numberDouble = 0L;
_currToken = (JsonToken) tokens.removeFirst();
if (_currToken == JsonToken.FIELD_NAME) {
String field = (String) tokens.removeFirst();
_parsingContext.setCurrentName(field);
text = field;
} else if (_currToken == JsonToken.VALUE_NUMBER_INT) {
Long v = (Long) tokens.removeFirst();
_numTypesValid = NR_LONG;
_numberLong = v;
} else if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) {
Double v = (Double) tokens.removeFirst();
_numTypesValid = NR_DOUBLE;
_numberDouble = v;
} else if (_currToken == JsonToken.VALUE_STRING) {
text = (String) tokens.removeFirst();
}
return _currToken;
}
@Override
public String getText() {
return text;
}
@Override
public char[] getTextCharacters() {
throw new UnsupportedOperationException();
}
@Override
public int getTextLength() {
throw new UnsupportedOperationException();
}
@Override
public int getTextOffset() {
throw new UnsupportedOperationException();
}
@Override
public ObjectCodec getCodec() {
throw new UnsupportedOperationException();
}
@Override
public void setCodec(ObjectCodec c) {
throw new UnsupportedOperationException();
}
@Override
protected void _closeInput() {
}
}
private class BufferingHandler implements Handler {
Handler handler;
int depth;
TokenParser buffer;
@Override
public void handle(JsonEventImpl event) {
String fieldName = event.fieldName();
if (fieldName != null) {
buffer.tokens.add(JsonToken.FIELD_NAME);
buffer.tokens.add(fieldName);
}
try {
switch (event.type()) {
case START_OBJECT:
case START_ARRAY:
if (depth++ == 0) {
JsonFactory factory = new JsonFactory();
buffer = new TokenParser(new IOContext(factory._getBufferRecycler(), this, true), com.fasterxml.jackson.core.JsonParser.Feature.collectDefaults());
}
buffer.tokens.add(event.token());
break;
case VALUE:
JsonToken token = event.token();
buffer.tokens.add(token);
if (token != JsonToken.VALUE_FALSE && token != JsonToken.VALUE_TRUE && token != JsonToken.VALUE_NULL) {
buffer.tokens.add(event.value());
}
break;
case END_OBJECT:
case END_ARRAY:
buffer.tokens.add(event.token());
if (--depth == 0) {
handler.handle(null);
buffer.close();
buffer = null;
}
break;
default:
throw new UnsupportedOperationException("Not implemented " + event);
}
} catch (IOException e) {
// Should not happen as we are buffering
throw new VertxException(e);
}
}
T convert(Class type) {
return JacksonCodec.fromParser(buffer, type);
}
}
@Override
public JsonParser write(Buffer buffer) {
handle(buffer);
return this;
}
@Override
public JsonParser exceptionHandler(Handler handler) {
exceptionHandler = handler;
return this;
}
}