[Olingo-731] add json uri tab support

This commit is contained in:
Christian Amend 2015-08-12 17:20:14 +02:00
parent f2c7be2d12
commit 36ae03957c
8 changed files with 641 additions and 18 deletions

View File

@ -85,7 +85,7 @@ public interface ExpressionVisitor<T> {
* @throws ExpressionVisitException Thrown if an exception while traversing occured
* @throws ODataApplicationException Thrown by the application
*/
T visitLiteral(String literal) throws ExpressionVisitException, ODataApplicationException;
T visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException;
/**
* Called for each traversed {@link Member} expression

View File

@ -113,12 +113,10 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
parts.add(new DebugTabServer(serverEnvironmentVaribles));
}
// TODO:Enable URIDebugInfo
// URI
// if (uriInfo != null && (uriInfo.getFilterOption() != null || uriInfo.getOrderByOption() != null
// || uriInfo.getExpandOption() != null || uriInfo.getSelectOption() != null)) {
// parts.add(new DebugInfoUri(uriInfo));
// }
if (debugInfo.getUriInfo() != null ) {
parts.add(new DebugTabUri(debugInfo.getUriInfo()));
}
// runtime measurements
List<RuntimeMeasurement> runtimeInformation = debugInfo.getRuntimeInformation();

View File

@ -20,21 +20,31 @@ package org.apache.olingo.server.core.debug;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
import org.apache.olingo.server.api.uri.queryoption.SelectItem;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import com.fasterxml.jackson.core.JsonGenerator;
/**
* URI parser debug information.
*/
public class DebugTabUri implements DebugTab {
private UriInfo uriInfo;
private final UriInfo uriInfo;
private final SelectOption selectOption;
private final ExpandOption expandOption;
public DebugTabUri(UriInfo uriInfo) {
this.uriInfo = uriInfo;
this.selectOption = uriInfo == null ? null : uriInfo.getSelectOption();
this.expandOption = uriInfo == null ? null : uriInfo.getExpandOption();
}
@Override
@ -43,15 +53,93 @@ public class DebugTabUri implements DebugTab {
}
@Override
public void appendJson(JsonGenerator jsonGenerator) throws IOException {
// TODO Auto-generated method stub
public void appendJson(JsonGenerator gen) throws IOException {
if (uriInfo == null) {
gen.writeNull();
return;
}
gen.writeStartObject();
if (uriInfo.getFilterOption() != null) {
gen.writeFieldName("filter");
appendJsonExpressionString(gen, uriInfo.getFilterOption().getExpression());
}
if (uriInfo.getOrderByOption() != null && uriInfo.getOrderByOption().getOrders() != null
&& !uriInfo.getOrderByOption().getOrders().isEmpty()) {
gen.writeFieldName("orderby");
gen.writeStartObject();
gen.writeStringField("nodeType", "orderCollection");
gen.writeFieldName("orders");
gen.writeStartArray();
for(OrderByItem item : uriInfo.getOrderByOption().getOrders()){
gen.writeStartObject();
gen.writeStringField("nodeType", "order");
gen.writeStringField("sortorder", item.isDescending() ? "desc" : "asc");
gen.writeFieldName("expression");
appendJsonExpressionString(gen, item.getExpression());
gen.writeEndObject();
}
gen.writeEndArray();
gen.writeEndObject();
}
if (selectOption != null && !selectOption.getSelectItems().isEmpty()) {
appendSelectedPropertiesJson(gen, selectOption.getSelectItems());
}
gen.writeEndObject();
}
private void appendJsonExpressionString(JsonGenerator gen, Expression expression) throws IOException {
if(expression == null){
gen.writeNull();
return;
}
String expressionJsonString;
try {
expressionJsonString = expression.accept(new ExpressionJsonVisitor());
} catch (Exception e) {
expressionJsonString = "Exception in Debug Filter visitor occoured: " + e.getMessage();
}
gen.writeRawValue(expressionJsonString);
}
private void appendSelectedPropertiesJson(JsonGenerator gen, List<SelectItem> selectItems) throws IOException {
gen.writeFieldName("select");
gen.writeStartArray();
for (SelectItem selectItem : selectItems) {
appendSelectItemJson(gen, selectItem);
}
gen.writeEndArray();
}
private void appendSelectItemJson(JsonGenerator gen, SelectItem selectItem) throws IOException {
String selectedProperty = "";
if (selectItem.isStar()) {
if (selectItem.getAllOperationsInSchemaNameSpace() == null) {
selectedProperty = "*";
} else {
selectedProperty = selectItem.getAllOperationsInSchemaNameSpace().getFullQualifiedNameAsString() + ".*";
}
} else {
boolean first = true;
for (UriResource resourcePart : selectItem.getResourcePath().getUriResourceParts()) {
if (!first) {
selectedProperty = selectedProperty + "/";
}
selectedProperty = resourcePart.toString();
}
}
}
@Override
public void appendHtml(Writer writer) throws IOException {
// TODO Auto-generated method stub
}
// private final UriInfo uriInfo;

View File

@ -0,0 +1,361 @@
/*
* 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 org.apache.olingo.server.core.debug;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
/**
* A custom expression visitor which writes down the tree from top to bottom
*/
public class ExpressionJsonVisitor implements ExpressionVisitor<String> {
@Override
public String visitBinaryOperator(BinaryOperatorKind operator, String left, String right)
throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValue("nodeType", "binary").separator().namedStringValue("operator",
operator.toString()).separator().namedStringValueRaw("type", getType(operator)).separator().name("left")
.unquotedValue(left).separator().name("right").unquotedValue(right).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitUnaryOperator(UnaryOperatorKind operator, String operand) throws ExpressionVisitException,
ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValue("nodeType", "unary").separator()
.namedStringValueRaw("operator", operator.toString()).separator().namedStringValueRaw("type",
getType(operator)).separator().name("operand").unquotedValue(operand).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitMethodCall(MethodKind methodCall, List<String> parameters) throws ExpressionVisitException,
ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "method").separator()
.namedStringValueRaw("operator", methodCall.toString()).separator().namedStringValueRaw("type",
getType(methodCall)).separator().name("parameters").beginArray();
boolean first = true;
for (String parameter : parameters) {
if (first) {
first = false;
} else {
jsonStreamWriter.separator();
}
jsonStreamWriter.unquotedValue(parameter);
}
jsonStreamWriter.endArray().endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValue("nodeType", "lambdaFunction").separator()
.namedStringValue("lambdaVariable", lambdaVariable).separator().name("expression");
// Write expression string object
String expressionJsonTree = expression.accept(this);
jsonStreamWriter.unquotedValue(expressionJsonTree).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "literal").separator().namedStringValueRaw("type",
getTypeString(literal.getType())).separator().namedStringValue("value", literal.getText()).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured");
}
}
@Override
public String visitMember(UriInfoResource member) throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
List<UriResource> uriResourceParts = member.getUriResourceParts();
jsonStreamWriter.beginObject().namedStringValue("nodeType", "member").separator()
.namedStringValueRaw("type", getType(uriResourceParts)).separator();
// write all member properties in an array
jsonStreamWriter.name("resourceSegments").beginArray();
if (uriResourceParts != null) {
boolean first = true;
for (UriResource segment : uriResourceParts) {
if (first) {
first = false;
} else {
jsonStreamWriter.separator();
}
appendUriResourcePartObject(jsonStreamWriter, segment);
}
}
jsonStreamWriter.endArray();
jsonStreamWriter.endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "alias").separator()
.namedStringValue("alias", aliasName).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "type").separator()
.namedStringValueRaw("type", getTypeString(type)).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitLambdaReference(String variableName) throws ExpressionVisitException, ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "lambdaReference").separator()
.namedStringValueRaw("name", variableName).endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
@Override
public String visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException,
ODataApplicationException {
try {
StringWriter writer = new StringWriter();
JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
jsonStreamWriter.beginObject().namedStringValueRaw("nodeType", "enum").separator()
.namedStringValueRaw("type", getTypeString(type)).separator();
jsonStreamWriter.name("values").beginArray();
if (enumValues != null) {
boolean first = true;
for (String value : enumValues) {
if (first) {
first = false;
} else {
jsonStreamWriter.separator();
}
jsonStreamWriter.stringValue(value);
}
}
jsonStreamWriter.endArray();
jsonStreamWriter.endObject();
writer.flush();
return writer.toString();
} catch (final IOException e) {
throw new ExpressionVisitException("IOException occoured", e);
}
}
private String getType(UnaryOperatorKind operator) {
switch (operator) {
case MINUS:
return "Number";
case NOT:
return "Boolean";
default:
return "unknown";
}
}
private String getType(MethodKind methodCall) {
switch (methodCall) {
case STARTSWITH:
case CONTAINS:
case ENDSWITH:
case ISOF:
return "Boolean";
case INDEXOF:
case LENGTH:
case ROUND:
case FLOOR:
case CEILING:
case DAY:
case HOUR:
case MINUTE:
case MONTH:
case SECOND:
case FRACTIONALSECONDS:
return "Number";
case CAST:
case CONCAT:
case DATE:
case GEODISTANCE:
case GEOINTERSECTS:
case GEOLENGTH:
case MAXDATETIME:
case MINDATETIME:
case NOW:
case SUBSTRING:
case TIME:
case TOLOWER:
case TOTALOFFSETMINUTES:
case TOTALSECONDS:
case TOUPPER:
case TRIM:
case YEAR:
return "String";
default:
return "unkown";
}
}
private void appendUriResourcePartObject(JsonStreamWriter jsonStreamWriter, UriResource segment) throws IOException,
ExpressionVisitException, ODataApplicationException {
if (segment instanceof UriResourceLambdaAll) {
UriResourceLambdaAll all = (UriResourceLambdaAll) segment;
String lambdaJsonObjectString = visitLambdaExpression("ALL", all.getLambdaVariable(), all.getExpression());
jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
return;
} else if (segment instanceof UriResourceLambdaAny) {
UriResourceLambdaAny any = (UriResourceLambdaAny) segment;
String lambdaJsonObjectString = visitLambdaExpression("ANY", any.getLambdaVariable(), any.getExpression());
jsonStreamWriter.unquotedValue(lambdaJsonObjectString);
return;
} else if (segment instanceof UriResourcePartTyped) {
String typeName =
((UriResourcePartTyped) segment).getType().getFullQualifiedName().getFullQualifiedNameAsString();
jsonStreamWriter.beginObject().namedStringValue("nodeType", segment.getKind().toString()).separator()
.namedStringValue("name", segment.toString()).separator().namedStringValueRaw("type", typeName).endObject();
} else {
jsonStreamWriter.beginObject().namedStringValue("nodeType", segment.getKind().toString()).separator()
.namedStringValue("name", segment.toString()).separator().namedStringValueRaw("type", null).endObject();
}
}
private String getType(BinaryOperatorKind operator) {
switch (operator) {
case MUL:
case DIV:
case MOD:
case ADD:
case SUB:
return "Number";
case HAS:
case GT:
case GE:
case LT:
case LE:
case EQ:
case NE:
case AND:
case OR:
return "Boolean";
default:
return "unkown";
}
}
private String getTypeString(EdmType type) {
if (type == null) {
return null;
}
return type.getFullQualifiedName().getFullQualifiedNameAsString();
}
private String getType(List<UriResource> uriResourceParts) {
if (uriResourceParts == null || uriResourceParts.isEmpty()) {
return null;
}
UriResource lastSegment = uriResourceParts.get(uriResourceParts.size() - 1);
EdmType type = null;
if (lastSegment instanceof UriResourcePartTyped) {
type = ((UriResourcePartTyped) lastSegment).getType();
}
return type == null ? "unknown" : type.getFullQualifiedName().getFullQualifiedNameAsString();
}
}

View File

@ -0,0 +1,175 @@
/*
* 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 org.apache.olingo.server.core.debug;
import java.io.IOException;
import java.io.Writer;
/**
* Writes JSON output.
*
*/
class JsonStreamWriter {
private final Writer writer;
public JsonStreamWriter(final Writer writer) {
this.writer = writer;
}
public JsonStreamWriter beginObject() throws IOException {
writer.append('{');
return this;
}
public JsonStreamWriter endObject() throws IOException {
writer.append('}');
return this;
}
public JsonStreamWriter beginArray() throws IOException {
writer.append('[');
return this;
}
public JsonStreamWriter endArray() throws IOException {
writer.append(']');
return this;
}
public JsonStreamWriter name(final String name) throws IOException {
writer.append('"').append(name).append('"').append(':');
return this;
}
public JsonStreamWriter unquotedValue(final String value) throws IOException {
writer.append(value == null ? "null" : value);
return this;
}
public JsonStreamWriter stringValueRaw(final String value) throws IOException {
if (value == null) {
writer.append("null");
} else {
writer.append('"').append(value).append('"');
}
return this;
}
public JsonStreamWriter stringValue(final String value) throws IOException {
if (value == null) {
writer.append("null");
} else {
writer.append('"');
escape(value);
writer.append('"');
}
return this;
}
public JsonStreamWriter namedStringValueRaw(final String name, final String value) throws IOException {
name(name);
stringValueRaw(value);
return this;
}
public JsonStreamWriter namedStringValue(final String name, final String value) throws IOException {
name(name);
stringValue(value);
return this;
}
public JsonStreamWriter separator() throws IOException {
writer.append(',');
return this;
}
/**
* Writes the JSON-escaped form of a Java String value according to RFC 4627.
* @param value the Java String
* @throws IOException if an I/O error occurs
*/
protected void escape(final String value) throws IOException {
// RFC 4627 says: "All Unicode characters may be placed within the
// quotation marks except for the characters that must be escaped:
// quotation mark, reverse solidus, and the control characters
// (U+0000 through U+001F)."
// All output here is done on character basis which should be faster
// than writing Strings.
for (int i = 0; i < value.length(); i++) {
final char c = value.charAt(i);
switch (c) {
case '\\':
writer.append('\\').append(c);
break;
case '"':
writer.append('\\').append(c);
break;
case '\b':
writer.append('\\').append('b');
break;
case '\t':
writer.append('\\').append('t');
break;
case '\n':
writer.append('\\').append('n');
break;
case '\f':
writer.append('\\').append('f');
break;
case '\r':
writer.append('\\').append('r');
break;
case '\u0000':
case '\u0001':
case '\u0002':
case '\u0003':
case '\u0004':
case '\u0005':
case '\u0006':
case '\u0007':
case '\u000B':
case '\u000E':
case '\u000F':
case '\u0010':
case '\u0011':
case '\u0012':
case '\u0013':
case '\u0014':
case '\u0015':
case '\u0016':
case '\u0017':
case '\u0018':
case '\u0019':
case '\u001A':
case '\u001B':
case '\u001C':
case '\u001D':
case '\u001E':
case '\u001F':
final int lastHexDigit = c % 0x10;
writer.append('\\').append('u').append('0').append('0')
.append(c >= '\u0010' ? '1' : '0')
.append((char) ((lastHexDigit > 9 ? 'A' : '0') + lastHexDigit % 10));
break;
default:
writer.append(c);
}
}
}
}

View File

@ -51,7 +51,7 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
@Override
public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
return visitor.visitLiteral(text);
return visitor.visitLiteral(this);
}
}

View File

@ -36,6 +36,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKin
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
@ -167,9 +168,8 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand>
}
@Override
public VisitorOperand visitLiteral(final String literal) throws ExpressionVisitException, ODataApplicationException {
return new UntypedOperand(literal);
public VisitorOperand visitLiteral(final Literal literal) throws ExpressionVisitException, ODataApplicationException {
return new UntypedOperand(literal.getText());
}
@Override

View File

@ -33,6 +33,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKin
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
@ -82,8 +83,8 @@ public class FilterTreeToText implements ExpressionVisitor<String> {
}
@Override
public String visitLiteral(final String literal) throws ExpressionVisitException {
return "<" + literal + ">";
public String visitLiteral(final Literal literal) throws ExpressionVisitException {
return "<" + literal.getText() + ">";
}
@Override