[OLINGO-731] Debug interfaces part 2
This commit is contained in:
parent
8f763aadea
commit
fb65199d28
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -39,6 +39,7 @@ public class ODataRequest {
|
|||
private String rawODataPath;
|
||||
private String rawBaseUri;
|
||||
private String rawServiceResolutionUri;
|
||||
private String protocol;
|
||||
|
||||
/**
|
||||
* Gets the HTTP method.
|
||||
|
@ -203,4 +204,21 @@ public class ODataRequest {
|
|||
public void setRawServiceResolutionUri(final String rawServiceResolutionUri) {
|
||||
this.rawServiceResolutionUri = rawServiceResolutionUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protocol version used e.g. HTTP/1.1
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP protocol used
|
||||
* @param protocol
|
||||
* @see #getProtocol()
|
||||
*/
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.olingo.server.api.debug;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
||||
|
@ -31,8 +34,10 @@ public interface DebugResponseHelper {
|
|||
* @param request
|
||||
* @param applicationResponse
|
||||
* @param exception
|
||||
* @param serverEnvironmentVaribles
|
||||
* @param runtimeInformation
|
||||
* @return the debug response or the raw application response in case an exception occurred.
|
||||
*/
|
||||
ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception);
|
||||
|
||||
ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception,
|
||||
Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.olingo.server.api.debug;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
@ -44,6 +47,6 @@ public interface DebugSupport {
|
|||
* @return a new debug response which will be send to the client
|
||||
*/
|
||||
ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse response,
|
||||
Exception exception);
|
||||
Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.olingo.server.api.debug;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
@ -36,12 +39,13 @@ public class DefaultDebugSupport implements DebugSupport {
|
|||
|
||||
@Override
|
||||
public ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse applicationResponse,
|
||||
Exception exception) {
|
||||
Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
|
||||
// Check if debugFormat is supported by the library
|
||||
if (DebugSupport.ODATA_DEBUG_JSON.equalsIgnoreCase(debugFormat)
|
||||
|| DebugSupport.ODATA_DEBUG_HTML.equalsIgnoreCase(debugFormat)
|
||||
|| DebugSupport.ODATA_DEBUG_DOWNLOAD.equalsIgnoreCase(debugFormat)) {
|
||||
return odata.createDebugResponseHelper(debugFormat).createDebugResponse(request, applicationResponse, exception);
|
||||
return odata.createDebugResponseHelper(debugFormat).createDebugResponse(request, applicationResponse, exception,
|
||||
serverEnvironmentVaribles, runtimeInformation);
|
||||
} else {
|
||||
// Debug format is not supported by the library by default so in order to avoid an exception we will just give
|
||||
// back the original response from the application.
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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.api.debug;
|
||||
|
||||
/**
|
||||
* <p>Runtime measurements.</p>
|
||||
* <p>All times are in nanoseconds since some fixed but arbitrary time
|
||||
* (perhaps in the future, so values may be negative).</p>
|
||||
* @see System#nanoTime()
|
||||
*/
|
||||
public class RuntimeMeasurement {
|
||||
|
||||
private String className;
|
||||
private String methodName;
|
||||
private long timeStarted;
|
||||
private long timeStopped;
|
||||
|
||||
/**
|
||||
* Sets the class name.
|
||||
* @param className the name of the class that is measured
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name.
|
||||
* @return the name of the class that is measured
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the method name.
|
||||
* @param methodName the name of the method that is measured
|
||||
*/
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method name.
|
||||
* @return the name of the method that is measured
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time.
|
||||
* @param timeStarted the start time in nanoseconds
|
||||
* @see System#nanoTime()
|
||||
*/
|
||||
public void setTimeStarted(long timeStarted) {
|
||||
this.timeStarted = timeStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start time.
|
||||
* @return the start time in nanoseconds or 0 if not set yet
|
||||
* @see System#nanoTime()
|
||||
*/
|
||||
public long getTimeStarted() {
|
||||
return timeStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stop time.
|
||||
* @param timeStopped the stop time in nanoseconds
|
||||
* @see System#nanoTime()
|
||||
*/
|
||||
public void setTimeStopped(long timeStopped) {
|
||||
this.timeStopped = timeStopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stop time.
|
||||
* @return the stop time in nanoseconds or 0 if not set yet
|
||||
* @see System#nanoTime()
|
||||
*/
|
||||
public long getTimeStopped() {
|
||||
return timeStopped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return className + "." + methodName + ": duration: " + (timeStopped - timeStarted);
|
||||
}
|
||||
}
|
|
@ -55,7 +55,10 @@
|
|||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -69,11 +72,6 @@
|
|||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -58,6 +58,7 @@ public class ODataHandler {
|
|||
private CustomETagSupport customETagSupport;
|
||||
|
||||
private UriInfo uriInfo;
|
||||
private Exception lastThrownException;
|
||||
|
||||
public ODataHandler(final OData server, final ServiceMetadata serviceMetadata) {
|
||||
odata = server;
|
||||
|
@ -75,37 +76,37 @@ public class ODataHandler {
|
|||
|
||||
} catch (final UriValidationException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (final UriParserSemanticException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (final UriParserSyntaxException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (final UriParserException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (ContentNegotiatorException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (SerializerException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (DeserializerException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (PreconditionException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (ODataHandlerException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (ODataApplicationException e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
} catch (Exception e) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
|
||||
handleException(request, response, serverError);
|
||||
handleException(request, response, serverError, e);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
@ -124,8 +125,8 @@ public class ODataHandler {
|
|||
}
|
||||
|
||||
public void handleException(final ODataRequest request, final ODataResponse response,
|
||||
final ODataServerError serverError) {
|
||||
|
||||
final ODataServerError serverError, Exception exception) {
|
||||
this.lastThrownException = exception;
|
||||
ErrorProcessor exceptionProcessor;
|
||||
try {
|
||||
exceptionProcessor = selectProcessor(ErrorProcessor.class);
|
||||
|
@ -187,4 +188,8 @@ public class ODataHandler {
|
|||
public CustomETagSupport getCustomETagSupport() {
|
||||
return customETagSupport;
|
||||
}
|
||||
|
||||
public Exception getLastThrownException() {
|
||||
return lastThrownException;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -41,6 +43,7 @@ import org.apache.olingo.server.api.ODataResponse;
|
|||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.debug.DebugSupport;
|
||||
import org.apache.olingo.server.api.debug.RuntimeMeasurement;
|
||||
import org.apache.olingo.server.api.etag.CustomETagSupport;
|
||||
import org.apache.olingo.server.api.processor.Processor;
|
||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||
|
@ -53,10 +56,17 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
|
|||
private static final Logger LOG = LoggerFactory.getLogger(ODataHttpHandlerImpl.class);
|
||||
|
||||
private final ODataHandler handler;
|
||||
private DebugSupport debugSupport;
|
||||
private final OData odata;
|
||||
private int split = 0;
|
||||
|
||||
// debug stuff
|
||||
private final List<RuntimeMeasurement> runtimeInformation = new ArrayList<RuntimeMeasurement>();
|
||||
private DebugSupport debugSupport;
|
||||
private String debugFormat;
|
||||
private boolean isDebugMode = false;
|
||||
|
||||
public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata serviceMetadata) {
|
||||
this.odata = odata;
|
||||
handler = new ODataHandler(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
|
@ -65,31 +75,101 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
|
|||
Exception exception = null;
|
||||
ODataRequest odRequest = null;
|
||||
ODataResponse odResponse;
|
||||
resolveDebugMode(request);
|
||||
int processMethodHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "process");
|
||||
|
||||
try {
|
||||
odRequest = new ODataRequest();
|
||||
int requestHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "fillODataRequest");
|
||||
fillODataRequest(odRequest, request, split);
|
||||
stopRuntimeMeasurement(requestHandel);
|
||||
|
||||
int responseHandel = startRuntimeMeasurement("ODataHandler", "process");
|
||||
odResponse = handler.process(odRequest);
|
||||
stopRuntimeMeasurement(responseHandel);
|
||||
// ALL future methods after process must not throw exceptions!
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
odResponse = handleException(odRequest, e);
|
||||
}
|
||||
stopRuntimeMeasurement(processMethodHandel);
|
||||
|
||||
if (debugSupport != null) {
|
||||
String debugFormat = getDebugQueryParameter(request);
|
||||
if (debugFormat != null) {
|
||||
// TODO: Should we be more careful here with response assignement in order to not loose the original response?
|
||||
// TODO: How should we react to exceptions here?
|
||||
odResponse = debugSupport.createDebugResponse(debugFormat, odRequest, odResponse, exception);
|
||||
if (isDebugMode) {
|
||||
debugSupport.init(odata);
|
||||
// TODO: Should we be more careful here with response assignement in order to not loose the original response?
|
||||
// TODO: How should we react to exceptions here?
|
||||
if (exception == null) {
|
||||
// This is to ensure that we have access to the thrown OData Exception
|
||||
// TODO: Should we make this hack
|
||||
exception = handler.getLastThrownException();
|
||||
}
|
||||
Map<String, String> serverEnvironmentVaribles = createEnvironmentVariablesMap(request);
|
||||
|
||||
odResponse =
|
||||
debugSupport.createDebugResponse(debugFormat, odRequest, odResponse, exception, serverEnvironmentVaribles,
|
||||
runtimeInformation);
|
||||
}
|
||||
|
||||
convertToHttp(response, odResponse);
|
||||
}
|
||||
|
||||
private String getDebugQueryParameter(HttpServletRequest request) {
|
||||
// TODO Auto-generated method stub
|
||||
return "";
|
||||
private void resolveDebugMode(HttpServletRequest request) {
|
||||
if (debugSupport != null) {
|
||||
// Should we read the parameter from the servlet here and ignore multiple parameters?
|
||||
debugFormat = request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER);
|
||||
// Debug format is present and we have a debug support processor registered so we are in debug mode
|
||||
isDebugMode = debugFormat != null;
|
||||
}
|
||||
}
|
||||
|
||||
public int startRuntimeMeasurement(final String className, final String methodName) {
|
||||
if (isDebugMode) {
|
||||
int handleId = runtimeInformation.size();
|
||||
|
||||
final RuntimeMeasurement measurement = new RuntimeMeasurement();
|
||||
measurement.setTimeStarted(System.nanoTime());
|
||||
measurement.setClassName(className);
|
||||
measurement.setMethodName(methodName);
|
||||
|
||||
runtimeInformation.add(measurement);
|
||||
|
||||
return handleId;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRuntimeMeasurement(final int handle) {
|
||||
if (isDebugMode && handle < runtimeInformation.size()) {
|
||||
long stopTime = System.nanoTime();
|
||||
RuntimeMeasurement runtimeMeasurement = runtimeInformation.get(handle);
|
||||
if (runtimeMeasurement != null) {
|
||||
runtimeMeasurement.setTimeStopped(stopTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> createEnvironmentVariablesMap(HttpServletRequest request) {
|
||||
LinkedHashMap<String, String> environment = new LinkedHashMap<String, String>();
|
||||
environment.put("authType", request.getAuthType());
|
||||
environment.put("localAddr", request.getLocalAddr());
|
||||
environment.put("localName", request.getLocalName());
|
||||
environment.put("localPort", getIntAsString(request.getLocalPort()));
|
||||
environment.put("pathInfo", request.getPathInfo());
|
||||
environment.put("pathTranslated", request.getPathTranslated());
|
||||
environment.put("remoteAddr", request.getRemoteAddr());
|
||||
environment.put("remoteHost", request.getRemoteHost());
|
||||
environment.put("remotePort", getIntAsString(request.getRemotePort()));
|
||||
environment.put("remoteUser", request.getRemoteUser());
|
||||
environment.put("scheme", request.getScheme());
|
||||
environment.put("serverName", request.getServerName());
|
||||
environment.put("serverPort", getIntAsString(request.getServerPort()));
|
||||
environment.put("servletPath", request.getServletPath());
|
||||
return environment;
|
||||
}
|
||||
|
||||
private String getIntAsString(final int number) {
|
||||
return number == 0 ? "unknown" : Integer.toString(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,7 +187,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
|
|||
} else {
|
||||
serverError = ODataExceptionHelper.createServerErrorObject(e);
|
||||
}
|
||||
handler.handleException(odRequest, resp, serverError);
|
||||
handler.handleException(odRequest, resp, serverError, e);
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
@ -153,6 +233,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
|
|||
throws ODataLibraryException {
|
||||
try {
|
||||
odRequest.setBody(httpRequest.getInputStream());
|
||||
odRequest.setProtocol(httpRequest.getProtocol());
|
||||
extractHeaders(odRequest, httpRequest);
|
||||
extractUri(odRequest, httpRequest, split);
|
||||
extractMethod(odRequest, httpRequest);
|
||||
|
|
|
@ -145,7 +145,7 @@ public class ODataImpl extends OData {
|
|||
public DebugResponseHelper createDebugResponseHelper(String debugFormat) {
|
||||
//TODO: What should we do with invalid formats?
|
||||
//TODO: Support more debug formats
|
||||
return new DebugResponseHelperImpl();
|
||||
return new DebugResponseHelperImpl(debugFormat);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* Debug information.
|
||||
*/
|
||||
public interface DebugInfo {
|
||||
|
||||
/**
|
||||
* Gets the name of this debug information part, useful as title.
|
||||
* @return the name
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Appends the content of this debug information part
|
||||
* to the given JSON stream writer.
|
||||
* @param jsonGenerator a JSON generator
|
||||
*/
|
||||
public void appendJson(JsonGenerator jsonGenerator) throws IOException;
|
||||
|
||||
/**
|
||||
* Appends the content of this debug information part to the given writer.
|
||||
* @param writer a {@link Writer}
|
||||
*/
|
||||
public void appendHtml(Writer writer) throws IOException;
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Response body debug information.
|
||||
*/
|
||||
public class DebugInfoBody implements DebugInfo {
|
||||
|
||||
private static enum ResponseContent {JSON, XML, TEXT, IMAGE};
|
||||
|
||||
private final ODataResponse response;
|
||||
private final ResponseContent responseContent;
|
||||
|
||||
//private final String serviceRoot;
|
||||
// private final boolean isXml;
|
||||
// private final boolean isJson;
|
||||
// private final boolean isText;
|
||||
// private final boolean isImage;
|
||||
|
||||
public DebugInfoBody(final ODataResponse response, final String serviceRoot) {
|
||||
this.response = response;
|
||||
// TODO: make header case insensitive
|
||||
final String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE);
|
||||
//TODO: Differentiate better
|
||||
if (contentType != null) {
|
||||
responseContent = ResponseContent.JSON;
|
||||
} else {
|
||||
responseContent = ResponseContent.TEXT;
|
||||
}
|
||||
// isXml = contentType.contains("xml");
|
||||
// isJson = !isXml && contentType.startsWith(HttpContentType.APPLICATION_JSON);
|
||||
// isText = isXml || isJson || contentType.startsWith("text/")
|
||||
// || contentType.startsWith(HttpContentType.APPLICATION_HTTP)
|
||||
// || contentType.startsWith(HttpContentType.MULTIPART_MIXED);
|
||||
// isImage = !isText && contentType.startsWith("image/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Body";
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public void appendJson(final JsonGenerator gen) throws IOException {
|
||||
gen.writeString(getContentString());
|
||||
}
|
||||
|
||||
private String getContentString() {
|
||||
try {
|
||||
String contentString;
|
||||
switch (responseContent) {
|
||||
case IMAGE:
|
||||
//TODO: DecodeString as base 64
|
||||
contentString = "Currently not supported";
|
||||
break;
|
||||
case JSON:
|
||||
case XML:
|
||||
case TEXT:
|
||||
default:
|
||||
// TODO: Remove IOUtils from core dependency
|
||||
contentString = IOUtils.toString(response.getContent(), "UTF-8");
|
||||
break;
|
||||
}
|
||||
return contentString;
|
||||
} catch (IOException e) {
|
||||
return "Could not parse Body for Debug Output";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @Override
|
||||
// public void appendHtml(final Writer writer) throws IOException {
|
||||
// final String body = getContentString();
|
||||
// if (isImage) {
|
||||
// writer.append("<img src=\"data:").append(response.getContentHeader()).append(";base64,")
|
||||
// .append(body)
|
||||
// .append("\" />\n");
|
||||
// } else {
|
||||
// writer.append("<pre class=\"code").append(isXml ? " xml" : isJson ? " json" : "").append("\">\n")
|
||||
// .append(isXml || isJson ?
|
||||
// addLinks(ODataDebugResponseWrapper.escapeHtml(isXml ? formatXml(body) : formatJson(body)), isXml) :
|
||||
// ODataDebugResponseWrapper.escapeHtml(body))
|
||||
// .append("</pre>\n");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private String formatXml(final String xml) throws IOException {
|
||||
// try {
|
||||
// Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
// StreamResult outputTarget = new StreamResult(new StringWriter());
|
||||
// transformer.transform(new StreamSource(new StringReader(xml)), outputTarget);
|
||||
// return outputTarget.getWriter().toString();
|
||||
// } catch (final TransformerException e) {
|
||||
// return xml;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private String formatJson(final String json) {
|
||||
// return new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create().toJson(new JsonParser().parse(json));
|
||||
// }
|
||||
//
|
||||
// private String addLinks(final String source, final boolean isXml) {
|
||||
// final String debugOption = ODataDebugResponseWrapper.ODATA_DEBUG_QUERY_PARAMETER + "="
|
||||
// + ODataDebugResponseWrapper.ODATA_DEBUG_HTML;
|
||||
// final String urlPattern = "("
|
||||
// + (isXml ? "(?:href|src|base)=" : "\"(?:uri|media_src|edit_media|__next)\":\\p{Space}*")
|
||||
// + "\")(.+?)\"";
|
||||
// return (isXml ? source.replaceAll("(xmlns(?::\\p{Alnum}+)?=\")(.+?)\"", "$1<span class=\"ns\">$2</span>\"") :
|
||||
// source)
|
||||
// .replaceAll(urlPattern, "$1<a href=\"" + serviceRoot + "$2?" + debugOption + "\">$2</a>\"")
|
||||
// .replaceAll("(<a href=\"" + Pattern.quote(serviceRoot) + ')' + Pattern.quote(serviceRoot), "$1")
|
||||
// .replaceAll("<a href=\"(.+?)\\?(.+?)\\?" + debugOption, "<a href=\"$1?$2&" + debugOption)
|
||||
// .replaceAll("&amp;", "&");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void appendHtml(Writer writer) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.ODataLibraryException.ODataErrorMessage;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Exception debug information.
|
||||
*/
|
||||
public class DebugInfoException implements DebugInfo {
|
||||
|
||||
private final Exception exception;
|
||||
|
||||
public DebugInfoException(final Exception exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Stacktrace";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(final JsonGenerator gen) throws IOException {
|
||||
gen.writeStartObject();
|
||||
gen.writeFieldName("exceptions");
|
||||
gen.writeStartArray();
|
||||
Throwable throwable = exception;
|
||||
while (throwable != null) {
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("class", throwable.getClass().getCanonicalName());
|
||||
gen.writeStringField("message", getMessage(throwable));
|
||||
gen.writeFieldName("invocation");
|
||||
appendJsonStackTraceElement(gen, throwable.getStackTrace()[0]);
|
||||
gen.writeEndObject();
|
||||
|
||||
// Get next exception in the cause list
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
gen.writeEndArray();
|
||||
|
||||
gen.writeFieldName("stacktrace");
|
||||
gen.writeStartArray();
|
||||
for (final StackTraceElement stackTraceElement : exception.getStackTrace()) {
|
||||
appendJsonStackTraceElement(gen, stackTraceElement);
|
||||
}
|
||||
gen.writeEndArray();
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
private String getMessage(final Throwable throwable) {
|
||||
String message;
|
||||
if (throwable instanceof ODataLibraryException) {
|
||||
ODataLibraryException ex = (ODataLibraryException) throwable;
|
||||
// We use the default locale
|
||||
ODataErrorMessage translatedMessage = ex.getTranslatedMessage(null);
|
||||
// We provide the best message we can
|
||||
message = translatedMessage.getMessage() == null ? ex.getMessage() : translatedMessage.getMessage();
|
||||
} else {
|
||||
message = throwable.getMessage();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private void appendJsonStackTraceElement(final JsonGenerator gen, final StackTraceElement element)
|
||||
throws IOException {
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("class", element.getClassName());
|
||||
gen.writeStringField("method", element.getMethodName());
|
||||
gen.writeStringField("line", Integer.toString(element.getLineNumber()));
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(Writer writer) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public void appendHtml(final Writer writer) throws IOException {
|
||||
// appendException(exception, writer);
|
||||
// writer.append("<h2>Stacktrace</h2>\n");
|
||||
// int count = 0;
|
||||
// for (final StackTraceElement stackTraceElement : exception.getStackTrace()) {
|
||||
// appendStackTraceElement(stackTraceElement, ++count == 1, count == exception.getStackTrace().length, writer);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void appendException(final Throwable throwable, final Writer writer) throws IOException {
|
||||
// if (throwable.getCause() != null) {
|
||||
// appendException(throwable.getCause(), writer);
|
||||
// }
|
||||
// final StackTraceElement details = throwable.getStackTrace()[0];
|
||||
// writer.append("<h2>").append(throwable.getClass().getCanonicalName()).append("</h2>\n")
|
||||
// .append("<p>")
|
||||
// .append(ODataDebugResponseWrapper.escapeHtml(getMessageText(throwable)))
|
||||
// .append("</p>\n");
|
||||
// appendStackTraceElement(details, true, true, writer);
|
||||
// }
|
||||
//
|
||||
// private void appendStackTraceElement(final StackTraceElement stackTraceElement,
|
||||
// final boolean isFirst, final boolean isLast, final Writer writer) throws IOException {
|
||||
// if (isFirst) {
|
||||
// writer.append("<table>\n<thead>\n")
|
||||
// .append("<tr>\n<th class=\"name\">Class</th>\n")
|
||||
// .append("<th class=\"name\">Method</th>\n")
|
||||
// .append("<th class=\"value\">Line number in class</th>\n</tr>\n")
|
||||
// .append("</thead>\n<tbody>\n");
|
||||
// }
|
||||
// writer.append("<tr>\n<td class=\"name\">").append(stackTraceElement.getClassName()).append("</td>\n")
|
||||
// .append("<td class=\"name\">").append(stackTraceElement.getMethodName()).append("</td>\n")
|
||||
// .append("<td class=\"value\">").append(Integer.toString(stackTraceElement.getLineNumber()))
|
||||
// .append("</td>\n</tr>\n");
|
||||
// if (isLast) {
|
||||
// writer.append("</tbody>\n</table>\n");
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Request debug information.
|
||||
*/
|
||||
public class DebugInfoRequest implements DebugInfo {
|
||||
|
||||
private final String method;
|
||||
private final String uri;
|
||||
private final String protocol;
|
||||
private final Map<String, String> headers;
|
||||
|
||||
public DebugInfoRequest(ODataRequest request) {
|
||||
method = request.getMethod() == null ? "unkown" : request.getMethod().toString();
|
||||
uri = request.getRawRequestUri() == null ? "unkown" : request.getRawRequestUri();
|
||||
protocol = request.getProtocol() == null ? "unkown" : request.getProtocol();
|
||||
// TODO: Should we really wrap the headers here or keep the original structure?
|
||||
headers = wrapHeaders(request.getAllHeaders());
|
||||
}
|
||||
|
||||
private Map<String, String> wrapHeaders(Map<String, List<String>> allHeaders) {
|
||||
Map<String, String> localHeaders = new HashMap<String, String>();
|
||||
for (Map.Entry<String, List<String>> entry : allHeaders.entrySet()) {
|
||||
String value = null;
|
||||
if (entry.getValue() != null) {
|
||||
value = "";
|
||||
boolean first = true;
|
||||
for (String valuePart : entry.getValue()) {
|
||||
if (!first) {
|
||||
value = value + ", ";
|
||||
}
|
||||
value = value + valuePart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return localHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(final Writer writer) throws IOException {
|
||||
// writer.append("<h2>Request Method</h2>\n")
|
||||
// .append("<p>").append(method).append("</p>\n")
|
||||
// .append("<h2>Request URI</h2>\n")
|
||||
// .append("<p>").append(DebugResponseHelperImpl.escapeHtml(uri.toString())).append("</p>\n")
|
||||
// .append("<h2>Request Protocol</h2>\n")
|
||||
// .append("<p>").append(protocol).append("</p>\n");
|
||||
// writer.append("<h2>Request Headers</h2>\n")
|
||||
// .append("<table>\n<thead>\n")
|
||||
// .append("<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n")
|
||||
// .append("</thead>\n<tbody>\n");
|
||||
// for (final String name : headers.keySet()) {
|
||||
// for (final String value : headers.get(name)) {
|
||||
// if (value != null) {
|
||||
// writer.append("<tr><td class=\"name\">").append(name).append("</td>")
|
||||
// .append("<td class=\"value\">").append(DebugResponseHelperImpl.escapeHtml(value))
|
||||
// .append("</td></tr>\n");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// writer.append("</tbody>\n</table>\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Request";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(JsonGenerator gen) throws IOException {
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("method", method);
|
||||
|
||||
gen.writeStringField("uri", uri);
|
||||
|
||||
gen.writeStringField("protocol", protocol);
|
||||
|
||||
if (!headers.isEmpty()) {
|
||||
gen.writeFieldName("headers");
|
||||
DebugResponseHelperImpl.appendJsonTable(gen, headers);
|
||||
}
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Response debug information.
|
||||
*/
|
||||
public class DebugInfoResponse implements DebugInfo {
|
||||
|
||||
private final ODataResponse response;
|
||||
private final String serviceRoot;
|
||||
private final HttpStatusCode status;
|
||||
private final Map<String, String> headers;
|
||||
|
||||
public DebugInfoResponse(final ODataResponse applicationResponse, final String serviceRoot) {
|
||||
this.response = applicationResponse;
|
||||
this.serviceRoot = serviceRoot;
|
||||
status = HttpStatusCode.fromStatusCode(response.getStatusCode());
|
||||
headers = response.getHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Response";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(final JsonGenerator gen) throws IOException {
|
||||
gen.writeStartObject();
|
||||
|
||||
if (status != null) {
|
||||
gen.writeFieldName("status");
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("code", Integer.toString(status.getStatusCode()));
|
||||
gen.writeStringField("info", status.getInfo());
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
if (headers != null && !headers.isEmpty()) {
|
||||
gen.writeFieldName("headers");
|
||||
DebugResponseHelperImpl.appendJsonTable(gen, headers);
|
||||
}
|
||||
|
||||
gen.writeFieldName("body");
|
||||
new DebugInfoBody(response, serviceRoot).appendJson(gen);
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(final Writer writer) throws IOException {
|
||||
// writer.append("<h2>Status Code</h2>\n")
|
||||
// .append("<p>").append(Integer.toString(status.getStatusCode())).append(' ')
|
||||
// .append(status.getInfo()).append("</p>\n")
|
||||
// .append("<h2>Response Headers</h2>\n");
|
||||
// ODataDebugResponseWrapper.appendHtmlTable(writer, headers);
|
||||
// if (response.getContentHeader() != null && response.getEntity() != null) {
|
||||
// writer.append("<h2>Response Body</h2>\n");
|
||||
// new DebugInfoBody(response, serviceRoot).appendHtml(writer);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.server.api.debug.RuntimeMeasurement;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Runtime debug information.
|
||||
*/
|
||||
public class DebugInfoRuntime implements DebugInfo {
|
||||
|
||||
private final RuntimeNode rootNode;
|
||||
|
||||
public DebugInfoRuntime(List<RuntimeMeasurement> runtimeInformation) {
|
||||
rootNode = new RuntimeNode();
|
||||
for (final RuntimeMeasurement runtimeMeasurement : runtimeInformation) {
|
||||
rootNode.add(runtimeMeasurement);
|
||||
}
|
||||
rootNode.combineRuntimeMeasurements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Runtime";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(JsonGenerator gen) throws IOException {
|
||||
appendJsonChildren(gen, rootNode);
|
||||
}
|
||||
|
||||
private void appendJsonChildren(JsonGenerator gen, RuntimeNode node) throws IOException {
|
||||
gen.writeStartArray();
|
||||
for (RuntimeNode child : node.children) {
|
||||
appendJsonNode(gen, child);
|
||||
}
|
||||
gen.writeEndArray();
|
||||
}
|
||||
|
||||
private void appendJsonNode(JsonGenerator gen, RuntimeNode node) throws IOException {
|
||||
gen.writeStartObject();
|
||||
gen.writeStringField("class", node.className);
|
||||
gen.writeStringField("method ", node.methodName);
|
||||
|
||||
if (node.timeStopped == 0) {
|
||||
gen.writeNullField("duration");
|
||||
} else {
|
||||
gen.writeStringField("duration", Long.toString((node.timeStopped - node.timeStarted) / 1000));
|
||||
gen.writeStringField("unit", "µs");
|
||||
}
|
||||
|
||||
if (!node.children.isEmpty()) {
|
||||
gen.writeFieldName("children");
|
||||
appendJsonChildren(gen, node);
|
||||
}
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(Writer writer) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
//
|
||||
// @Override
|
||||
// public void appendHtml(final Writer writer) throws IOException {
|
||||
// appendRuntimeNode(rootNode, "", true, writer);
|
||||
// }
|
||||
//
|
||||
// private void appendRuntimeNode(final RuntimeNode node, final String draw, final boolean isLast, final Writer writer)
|
||||
// throws IOException {
|
||||
// if (node.className != null) {
|
||||
// writer.append("<li>")
|
||||
// .append("<span class=\"code\">")
|
||||
// .append("<span class=\"draw\">").append(draw)
|
||||
// .append(isLast ? "└" : "├").append("─ </span>")
|
||||
// .append("<span class=\"class\">").append(node.className).append("</span>.")
|
||||
// .append("<span class=\"method\">").append(node.methodName).append("(…)")
|
||||
// .append("</span></span>");
|
||||
// long time = node.timeStopped == 0 ? 0 : (node.timeStopped - node.timeStarted) / 1000;
|
||||
// writer.append("<span class=\"").append(time == 0 ? "null" : "numeric")
|
||||
// .append("\" title=\"").append(time == 0 ? "Stop time missing" : "Gross duration")
|
||||
// .append("\">").append(time == 0 ? "unfinished" : Long.toString(time) + " µs")
|
||||
// .append("</span>\n");
|
||||
// }
|
||||
// if (!node.children.isEmpty()) {
|
||||
// writer.append("<ol class=\"tree\">\n");
|
||||
// for (final RuntimeNode childNode : node.children) {
|
||||
// appendRuntimeNode(childNode,
|
||||
// node.className == null ? draw : draw + (isLast ? " " : "│") + " ",
|
||||
// node.children.indexOf(childNode) == node.children.size() - 1,
|
||||
// writer);
|
||||
// }
|
||||
// writer.append("</ol>\n");
|
||||
// }
|
||||
// if (node.className != null) {
|
||||
// writer.append("</li>\n");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private class RuntimeNode {
|
||||
|
||||
protected String className;
|
||||
protected String methodName;
|
||||
protected long timeStarted;
|
||||
protected long timeStopped;
|
||||
protected List<RuntimeNode> children = new ArrayList<RuntimeNode>();
|
||||
|
||||
protected RuntimeNode() {
|
||||
timeStarted = 0;
|
||||
timeStopped = Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private RuntimeNode(final RuntimeMeasurement runtimeMeasurement) {
|
||||
className = runtimeMeasurement.getClassName();
|
||||
methodName = runtimeMeasurement.getMethodName();
|
||||
timeStarted = runtimeMeasurement.getTimeStarted();
|
||||
timeStopped = runtimeMeasurement.getTimeStopped();
|
||||
}
|
||||
|
||||
protected boolean add(final RuntimeMeasurement runtimeMeasurement) {
|
||||
if (timeStarted <= runtimeMeasurement.getTimeStarted()
|
||||
&& timeStopped != 0 && timeStopped >= runtimeMeasurement.getTimeStopped()) {
|
||||
for (RuntimeNode candidate : children) {
|
||||
if (candidate.add(runtimeMeasurement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
children.add(new RuntimeNode(runtimeMeasurement));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines runtime measurements with identical class names and method
|
||||
* names into one measurement, assuming that they originate from a loop
|
||||
* or a similar construct where a summary measurement has been intended.
|
||||
*/
|
||||
protected void combineRuntimeMeasurements() {
|
||||
RuntimeNode preceding = null;
|
||||
for (Iterator<RuntimeNode> iterator = children.iterator(); iterator.hasNext();) {
|
||||
final RuntimeNode child = iterator.next();
|
||||
if (preceding != null
|
||||
&& preceding.timeStopped != 0 && child.timeStopped != 0
|
||||
&& preceding.timeStopped <= child.timeStarted
|
||||
&& preceding.children.isEmpty() && child.children.isEmpty()
|
||||
&& preceding.methodName.equals(child.methodName)
|
||||
&& preceding.className.equals(child.className)) {
|
||||
preceding.timeStarted = child.timeStarted - (preceding.timeStopped - preceding.timeStarted);
|
||||
preceding.timeStopped = child.timeStopped;
|
||||
|
||||
iterator.remove();
|
||||
} else {
|
||||
preceding = child;
|
||||
child.combineRuntimeMeasurements();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
/**
|
||||
* Server debug information.
|
||||
*/
|
||||
public class DebugInfoServer implements DebugInfo {
|
||||
|
||||
private final Map<String, String> serverEnvironmentVaribles;
|
||||
|
||||
public DebugInfoServer(Map<String, String> serverEnvironmentVaribles) {
|
||||
this.serverEnvironmentVaribles = serverEnvironmentVaribles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Environment";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(JsonGenerator gen) throws IOException {
|
||||
DebugResponseHelperImpl.appendJsonTable(gen, serverEnvironmentVaribles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(Writer writer) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
// private final Map<String, String> environment;
|
||||
//
|
||||
// public DebugInfoServer(final HttpServletRequest httpServletRequest) {
|
||||
// environment = new TreeMap<String, String>();
|
||||
// environment.put("authType", httpServletRequest.getAuthType());
|
||||
// environment.put("localAddr", httpServletRequest.getLocalAddr());
|
||||
// environment.put("localName", httpServletRequest.getLocalName());
|
||||
// addInt("localPort", httpServletRequest.getLocalPort());
|
||||
// environment.put("pathInfo", httpServletRequest.getPathInfo());
|
||||
// environment.put("pathTranslated", httpServletRequest.getPathTranslated());
|
||||
// environment.put("remoteAddr", httpServletRequest.getRemoteAddr());
|
||||
// environment.put("remoteHost", httpServletRequest.getRemoteHost());
|
||||
// addInt("remotePort", httpServletRequest.getRemotePort());
|
||||
// environment.put("remoteUser", httpServletRequest.getRemoteUser());
|
||||
// environment.put("scheme", httpServletRequest.getScheme());
|
||||
// environment.put("serverName", httpServletRequest.getServerName());
|
||||
// addInt("serverPort", httpServletRequest.getServerPort());
|
||||
// environment.put("servletPath", httpServletRequest.getServletPath());
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public void appendHtml(final Writer writer) throws IOException {
|
||||
// final Package pack = ODataDebugResponseWrapper.class.getPackage();
|
||||
// writer.append("<h2>Library Version</h2>\n")
|
||||
// .append("<p>").append(pack.getImplementationTitle())
|
||||
// .append(" Version ").append(pack.getImplementationVersion()).append("</p>\n")
|
||||
// .append("<h2>Server Environment</h2>\n");
|
||||
// ODataDebugResponseWrapper.appendHtmlTable(writer, environment);
|
||||
// }
|
||||
//
|
||||
// private void addInt(final String name, final int number) {
|
||||
// environment.put(name, number == 0 ? null : Integer.toString(number));
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* URI parser debug information.
|
||||
*/
|
||||
public class DebugInfoUri implements DebugInfo {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendJson(JsonGenerator jsonGenerator) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHtml(Writer writer) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
// private final UriInfo uriInfo;
|
||||
// private final FilterExpression filter;
|
||||
// private final OrderByExpression orderBy;
|
||||
// private final ExpandSelectTreeNodeImpl expandSelectTree;
|
||||
// private final ExpressionParserException exception;
|
||||
//
|
||||
// public DebugInfoUri(final UriInfo uriInfo, final ExpressionParserException exception) {
|
||||
// this.uriInfo = uriInfo;
|
||||
// filter = uriInfo == null ? null : uriInfo.getFilter();
|
||||
// orderBy = uriInfo == null ? null : uriInfo.getOrderBy();
|
||||
// expandSelectTree = uriInfo == null ? null : getExpandSelect();
|
||||
// this.exception = exception;
|
||||
// }
|
||||
//
|
||||
// private ExpandSelectTreeNodeImpl getExpandSelect() {
|
||||
// try {
|
||||
// return uriInfo.getExpand().isEmpty() && uriInfo.getSelect().isEmpty() ? null :
|
||||
// new ExpandSelectTreeCreator(uriInfo.getSelect(), uriInfo.getExpand()).create();
|
||||
// } catch (final EdmException e) {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getName() {
|
||||
// return "URI";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void appendJson(final JsonStreamWriter jsonStreamWriter) throws IOException {
|
||||
// jsonStreamWriter.beginObject();
|
||||
//
|
||||
// if (exception != null && exception.getFilterTree() != null) {
|
||||
// jsonStreamWriter.name("error")
|
||||
// .beginObject()
|
||||
// .namedStringValue("expression", exception.getFilterTree().getUriLiteral())
|
||||
// .endObject();
|
||||
// if (filter != null || orderBy != null || expandSelectTree != null) {
|
||||
// jsonStreamWriter.separator();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (filter != null) {
|
||||
// String filterString;
|
||||
// try {
|
||||
// filterString = (String) filter.accept(new JsonVisitor());
|
||||
// } catch (final ExceptionVisitExpression e) {
|
||||
// filterString = null;
|
||||
// } catch (final ODataApplicationException e) {
|
||||
// filterString = null;
|
||||
// }
|
||||
// jsonStreamWriter.name("filter").unquotedValue(filterString);
|
||||
// if (orderBy != null || expandSelectTree != null) {
|
||||
// jsonStreamWriter.separator();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (orderBy != null) {
|
||||
// String orderByString;
|
||||
// try {
|
||||
// orderByString = (String) orderBy.accept(new JsonVisitor());
|
||||
// } catch (final ExceptionVisitExpression e) {
|
||||
// orderByString = null;
|
||||
// } catch (final ODataApplicationException e) {
|
||||
// orderByString = null;
|
||||
// }
|
||||
// jsonStreamWriter.name("orderby").unquotedValue(orderByString);
|
||||
// if (expandSelectTree != null) {
|
||||
// jsonStreamWriter.separator();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (expandSelectTree != null) {
|
||||
// jsonStreamWriter.name("expandSelect").unquotedValue(expandSelectTree.toJsonString());
|
||||
// }
|
||||
//
|
||||
// jsonStreamWriter.endObject();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void appendHtml(final Writer writer) throws IOException {
|
||||
// if (exception != null && exception.getFilterTree() != null) {
|
||||
// writer.append("<h2>Expression Information</h2>\n")
|
||||
// .append("<pre class=\"code\">").append(exception.getFilterTree().getUriLiteral())
|
||||
// .append("</pre>\n");
|
||||
// // TODO: filter error position, filter tokens, filter tree
|
||||
// }
|
||||
// if (filter != null) {
|
||||
// writer.append("<h2>Filter</h2>\n")
|
||||
// .append("<ul class=\"expr\"><li>");
|
||||
// appendExpression(filter.getExpression(), writer);
|
||||
// writer.append("</li></ul>\n");
|
||||
// }
|
||||
// if (orderBy != null) {
|
||||
// writer.append("<h2>Orderby</h2>\n")
|
||||
// .append(orderBy.getOrdersCount() == 1 ? "<ul" : "<ol").append(" class=\"expr\">\n");
|
||||
// for (final OrderExpression order : orderBy.getOrders()) {
|
||||
// writer.append("<li>");
|
||||
// appendExpression(order.getExpression(), writer);
|
||||
// final ExpressionKind kind = order.getExpression().getKind();
|
||||
// if (kind == ExpressionKind.PROPERTY || kind == ExpressionKind.LITERAL) {
|
||||
// writer.append("<br />");
|
||||
// }
|
||||
// writer.append("<span class=\"order\">")
|
||||
// .append(order.getSortOrder().toString())
|
||||
// .append("</span></li>\n");
|
||||
// }
|
||||
// writer.append(orderBy.getOrdersCount() == 1 ? "</ul" : "</ol").append(">\n");
|
||||
// }
|
||||
// if (expandSelectTree != null) {
|
||||
// writer.append("<h2>Expand/Select</h2>\n");
|
||||
// appendExpandSelect(expandSelectTree, writer);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void appendExpression(final CommonExpression expression, final Writer writer) throws IOException {
|
||||
// final ExpressionKind kind = expression.getKind();
|
||||
// writer.append("<span class=\"kind\">")
|
||||
// .append(kind.toString())
|
||||
// .append("</span> <span class=\"literal\">")
|
||||
// .append(kind == ExpressionKind.MEMBER ? ((MemberExpression) expression).getProperty().getUriLiteral() :
|
||||
// expression.getUriLiteral())
|
||||
// .append("</span>, type <span class=\"type\">")
|
||||
// .append(expression.getEdmType().toString())
|
||||
// .append("</span>");
|
||||
// if (kind == ExpressionKind.UNARY) {
|
||||
// writer.append("<ul class=\"expr\"><li>");
|
||||
// appendExpression(((UnaryExpression) expression).getOperand(), writer);
|
||||
// writer.append("</li></ul>");
|
||||
// } else if (kind == ExpressionKind.BINARY) {
|
||||
// writer.append("<ol class=\"expr\"><li>");
|
||||
// appendExpression(((BinaryExpression) expression).getLeftOperand(), writer);
|
||||
// writer.append("</li><li>");
|
||||
// appendExpression(((BinaryExpression) expression).getRightOperand(), writer);
|
||||
// writer.append("</li></ol>");
|
||||
// } else if (kind == ExpressionKind.METHOD) {
|
||||
// final MethodExpression methodExpression = (MethodExpression) expression;
|
||||
// if (methodExpression.getParameterCount() > 0) {
|
||||
// writer.append("<ol class=\"expr\">");
|
||||
// for (final CommonExpression parameter : methodExpression.getParameters()) {
|
||||
// writer.append("<li>");
|
||||
// appendExpression(parameter, writer);
|
||||
// writer.append("</li>");
|
||||
// }
|
||||
// writer.append("</ol>");
|
||||
// }
|
||||
// } else if (kind == ExpressionKind.MEMBER) {
|
||||
// writer.append("<ul class=\"expr\"><li>");
|
||||
// appendExpression(((MemberExpression) expression).getPath(), writer);
|
||||
// writer.append("</li></ul>");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void appendExpandSelect(final ExpandSelectTreeNode expandSelect, final Writer writer) throws IOException {
|
||||
// writer.append("<ul class=\"expand\">\n")
|
||||
// .append("<li>");
|
||||
// if (expandSelect.isAll()) {
|
||||
// writer.append("all properties");
|
||||
// } else {
|
||||
// for (final EdmProperty property : expandSelect.getProperties()) {
|
||||
// try {
|
||||
// writer.append("property <span class=\"prop\">")
|
||||
// .append(property.getName())
|
||||
// .append("</span><br />");
|
||||
// } catch (final EdmException e) {}
|
||||
// }
|
||||
// }
|
||||
// writer.append("</li>\n");
|
||||
// if (!expandSelect.getLinks().isEmpty()) {
|
||||
// for (final String name : expandSelect.getLinks().keySet()) {
|
||||
// writer.append("<li>link <span class=\"link\">").append(name).append("</span>");
|
||||
// final ExpandSelectTreeNode link = expandSelect.getLinks().get(name);
|
||||
// if (link != null) {
|
||||
// writer.append('\n');
|
||||
// appendExpandSelect(link, writer);
|
||||
// }
|
||||
// writer.append("</li>\n");
|
||||
// }
|
||||
// }
|
||||
// writer.append("</ul>\n");
|
||||
// }
|
||||
}
|
|
@ -18,16 +18,265 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.debug;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.ODataRuntimeException;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.debug.DebugResponseHelper;
|
||||
import org.apache.olingo.server.api.debug.DebugSupport;
|
||||
import org.apache.olingo.server.api.debug.RuntimeMeasurement;
|
||||
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
public class DebugResponseHelperImpl implements DebugResponseHelper {
|
||||
|
||||
@Override
|
||||
public ODataResponse
|
||||
createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception) {
|
||||
return applicationResponse;
|
||||
private static enum DebugFormat {
|
||||
JSON, HTML, DOWNLOAD
|
||||
};
|
||||
|
||||
private final DebugFormat requestedFormat;
|
||||
|
||||
public DebugResponseHelperImpl(String debugFormat) {
|
||||
if (DebugSupport.ODATA_DEBUG_HTML.equals(debugFormat)) {
|
||||
requestedFormat = DebugFormat.HTML;
|
||||
} else if (DebugSupport.ODATA_DEBUG_DOWNLOAD.equals(debugFormat)) {
|
||||
requestedFormat = DebugFormat.DOWNLOAD;
|
||||
} else {
|
||||
requestedFormat = DebugFormat.JSON;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse,
|
||||
Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
|
||||
|
||||
try {
|
||||
final List<DebugInfo> parts =
|
||||
createParts(request, applicationResponse, exception, serverEnvironmentVaribles, runtimeInformation);
|
||||
|
||||
ODataResponse response = new ODataResponse();
|
||||
String contentTypeString;
|
||||
InputStream body;
|
||||
switch (requestedFormat) {
|
||||
case DOWNLOAD:
|
||||
response.setHeader("Content-Disposition", "attachment; filename=OData-Response."
|
||||
+ new Date().toString().replace(' ', '_').replace(':', '.') + ".html");
|
||||
// Download is the same as html except for the above header
|
||||
case HTML:
|
||||
body = wrapInHtml(parts);
|
||||
contentTypeString = ContentType.TEXT_HTML.toContentTypeString();
|
||||
break;
|
||||
case JSON:
|
||||
default:
|
||||
body = wrapInJson(parts);
|
||||
contentTypeString = ContentType.APPLICATION_JSON.toContentTypeString();
|
||||
break;
|
||||
}
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, contentTypeString);
|
||||
response.setContent(body);
|
||||
|
||||
return response;
|
||||
} catch (IOException e) {
|
||||
// Should not happen
|
||||
// TODO: Check what we can do here.
|
||||
throw new ODataRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<DebugInfo> createParts(ODataRequest request, ODataResponse applicationResponse, Exception exception,
|
||||
Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
|
||||
List<DebugInfo> parts = new ArrayList<DebugInfo>();
|
||||
|
||||
// request
|
||||
parts.add(new DebugInfoRequest(request));
|
||||
|
||||
// response
|
||||
// TODO: Check service URI
|
||||
parts.add(new DebugInfoResponse(applicationResponse, request.getRawBaseUri()));
|
||||
|
||||
// server
|
||||
if (serverEnvironmentVaribles != null && !serverEnvironmentVaribles.isEmpty()) {
|
||||
parts.add(new DebugInfoServer(serverEnvironmentVaribles));
|
||||
}
|
||||
|
||||
// // URI
|
||||
// Throwable candidate = exception;
|
||||
// while (candidate != null && !(candidate instanceof ExpressionParserException)) {
|
||||
// candidate = candidate.getCause();
|
||||
// }
|
||||
// final ExpressionParserException expressionParserException = (ExpressionParserException) candidate;
|
||||
// if (uriInfo != null
|
||||
// && (uriInfo.getFilter() != null || uriInfo.getOrderBy() != null
|
||||
// || !uriInfo.getExpand().isEmpty() || !uriInfo.getSelect().isEmpty())
|
||||
// || expressionParserException != null && expressionParserException.getFilterTree() != null) {
|
||||
// parts.add(new DebugInfoUri(uriInfo, expressionParserException));
|
||||
// }
|
||||
//
|
||||
// // runtime measurements
|
||||
if (runtimeInformation != null && !runtimeInformation.isEmpty()) {
|
||||
parts.add(new DebugInfoRuntime(runtimeInformation));
|
||||
}
|
||||
//
|
||||
// // exceptions
|
||||
if (exception != null) {
|
||||
parts.add(new DebugInfoException(exception));
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
private InputStream wrapInJson(final List<DebugInfo> parts) throws IOException {
|
||||
CircleStreamBuffer csb = new CircleStreamBuffer();
|
||||
JsonGenerator gen = new JsonFactory().createGenerator(csb.getOutputStream(), JsonEncoding.UTF8);
|
||||
|
||||
gen.writeStartObject();
|
||||
DebugInfo requestInfo = parts.get(0);
|
||||
// TODO: Should we really translate to lower case here?
|
||||
gen.writeFieldName(requestInfo.getName().toLowerCase(Locale.ROOT));
|
||||
requestInfo.appendJson(gen);
|
||||
|
||||
DebugInfo responseInfo = parts.get(1);
|
||||
gen.writeFieldName(responseInfo.getName().toLowerCase(Locale.ROOT));
|
||||
responseInfo.appendJson(gen);
|
||||
|
||||
gen.writeFieldName("server");
|
||||
gen.writeStartObject();
|
||||
String version = DebugResponseHelperImpl.class.getPackage().getImplementationVersion();
|
||||
if (version != null) {
|
||||
gen.writeStringField("version", version);
|
||||
} else {
|
||||
gen.writeNullField("version");
|
||||
}
|
||||
for (DebugInfo part : parts.subList(2, parts.size())) {
|
||||
gen.writeFieldName(part.getName().toLowerCase(Locale.ROOT));
|
||||
part.appendJson(gen);
|
||||
}
|
||||
gen.writeEndObject();
|
||||
|
||||
gen.writeEndObject();
|
||||
gen.close();
|
||||
|
||||
return csb.getInputStream();
|
||||
}
|
||||
|
||||
private InputStream wrapInHtml(final List<DebugInfo> parts) throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
// PathInfo pathInfo = null;
|
||||
// try {
|
||||
// pathInfo = context.getPathInfo();
|
||||
// } catch (final ODataException e) {}
|
||||
//
|
||||
// writer.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n")
|
||||
// .append(" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n")
|
||||
// .append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n")
|
||||
// .append("<head>\n")
|
||||
// .append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n")
|
||||
// .append("<title>")
|
||||
// .append(pathInfo == null ? "" :
|
||||
// escapeHtml(pathInfo.getServiceRoot().relativize(pathInfo.getRequestUri()).getPath()))
|
||||
// .append("</title>\n")
|
||||
// .append("<style type=\"text/css\">\n")
|
||||
// .append("body { font-family: Arial, sans-serif; font-size: 13px;\n")
|
||||
// .append(" line-height: 16px; margin: 0;\n")
|
||||
// .append(" background-color: #eeeeee; color: #333333; }\n")
|
||||
// .append(".header { float: left; }\n")
|
||||
// .append(".header a { line-height: 22px; padding: 10px 18px;\n")
|
||||
// .append(" text-decoration: none; color: #333333; }\n")
|
||||
// .append(":target, .header:nth-last-child(2) { background-color: #cccccc; }\n")
|
||||
// .append(":target ~ .header:nth-last-child(2) { background-color: inherit; }\n")
|
||||
// .append(".header:focus, .header:hover,\n")
|
||||
// .append(" .header:nth-last-child(2):focus, .header:nth-last-child(2):hover\n")
|
||||
// .append(" { background-color: #999999; }\n")
|
||||
// .append(".section { position: absolute; top: 42px; min-width: 100%;\n")
|
||||
// .append(" padding-top: 18px; border-top: 1px solid #dddddd; }\n")
|
||||
// .append(".section > * { margin-left: 18px; }\n")
|
||||
// .append(":target + .section, .section:last-child { display: block; }\n")
|
||||
// .append(".section, :target + .section ~ .section { display: none; }\n")
|
||||
// .append("h1 { font-size: 18px; font-weight: normal; margin: 10px 0; }\n")
|
||||
// .append("h2 { font-size: 15px; }\n")
|
||||
// .append("h2:not(:first-child) { margin-top: 2em; }\n")
|
||||
// .append("table { border-collapse: collapse; border-spacing: 0;\n")
|
||||
// .append(" margin-top: 1.5em; }\n")
|
||||
// .append("table, thead { border-width: 1px 0; border-style: solid;\n")
|
||||
// .append(" border-color: #dddddd; text-align: left; }\n")
|
||||
// .append("th.name, td.name { padding: 1ex 2em 1ex 0; }\n")
|
||||
// .append("tbody > tr:hover { background-color: #cccccc; }\n")
|
||||
// .append(".code { font-family: \"Courier New\", monospace; }\n")
|
||||
// .append(".code, .tree li { line-height: 15px; }\n")
|
||||
// .append(".code a { text-decoration: underline; color: #666666; }\n")
|
||||
// .append(".xml .ns { font-style: italic; color: #999999; }\n")
|
||||
// .append("ul, .tree { list-style-type: none; }\n")
|
||||
// .append("div > ul.expr, div > .expand, .tree { padding-left: 0; }\n")
|
||||
// .append(".expr, .expand, .null, .numeric { padding-left: 1.5em; }\n")
|
||||
// .append("</style>\n")
|
||||
// .append("</head>\n")
|
||||
// .append("<body>\n");
|
||||
// char count = '0';
|
||||
// for (final DebugInfo part : parts) {
|
||||
// writer.append("<div class=\"header\" id=\"sec").append(++count).append("\">\n")
|
||||
// .append("<h1><a href=\"#sec").append(count).append("\">")
|
||||
// .append(part.getName())
|
||||
// .append("</a></h1>\n")
|
||||
// .append("</div>\n")
|
||||
// .append("<div class=\"section\">\n");
|
||||
// part.appendHtml(writer);
|
||||
// writer.append("</div>\n");
|
||||
// }
|
||||
// writer.append("</body>\n")
|
||||
// .append("</html>\n")
|
||||
// .close();
|
||||
byte[] bytes = writer.toString().getBytes("UTF-8");
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
protected static String escapeHtml(final String value) {
|
||||
return value == null ? null : value.replace("&", "&").replace("<", "<").replace(">", ">");
|
||||
}
|
||||
|
||||
protected static void appendJsonTable(final JsonGenerator gen, final Map<String, String> entries)
|
||||
throws IOException {
|
||||
gen.writeStartObject();
|
||||
|
||||
for (Map.Entry<String, String> entry : entries.entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
gen.writeStringField(entry.getKey(), entry.getValue());
|
||||
} else {
|
||||
gen.writeNullField(entry.getKey());
|
||||
}
|
||||
}
|
||||
gen.writeEndObject();
|
||||
}
|
||||
//
|
||||
// protected static void appendHtmlTable(final Writer writer, final Map<String, String> entries) throws IOException {
|
||||
// writer.append("<table>\n<thead>\n")
|
||||
// .append("<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n")
|
||||
// .append("</thead>\n<tbody>\n");
|
||||
// for (final String name : entries.keySet()) {
|
||||
// final String value = entries.get(name);
|
||||
// if (value != null) {
|
||||
// writer.append("<tr><td class=\"name\">").append(name).append("</td>")
|
||||
// .append("<td class=\"value\">")
|
||||
// .append(ODataDebugResponseWrapper.escapeHtml(value))
|
||||
// .append("</td></tr>\n");
|
||||
// }
|
||||
// }
|
||||
// writer.append("</tbody>\n</table>\n");
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -160,7 +160,6 @@
|
|||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
Loading…
Reference in New Issue