use of org.structr.rest.serialization.StreamingJsonWriter in project structr by structr.
the class JsonRestServlet method doGetOrHead.
private void doGetOrHead(final HttpServletRequest request, final HttpServletResponse response, final boolean returnContent) throws ServletException, IOException {
SecurityContext securityContext = null;
Authenticator authenticator = null;
Result result = null;
Resource resource = null;
try {
// first thing to do!
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// isolate request authentication in a transaction
try (final Tx tx = StructrApp.getInstance().tx()) {
authenticator = config.getAuthenticator();
securityContext = authenticator.initializeAndExamineRequest(request, response);
tx.success();
}
final App app = StructrApp.getInstance(securityContext);
// set default value for property view
propertyView.set(securityContext, config.getDefaultPropertyView());
// evaluate constraints and measure query time
double queryTimeStart = System.nanoTime();
// isolate resource authentication
try (final Tx tx = app.tx()) {
resource = ResourceHelper.applyViewTransformation(request, securityContext, ResourceHelper.optimizeNestedResourceChain(securityContext, request, resourceMap, propertyView), propertyView);
authenticator.checkResourceAccess(securityContext, request, resource.getResourceSignature(), propertyView.get(securityContext));
tx.success();
}
// add sorting & paging
String pageSizeParameter = request.getParameter(REQUEST_PARAMETER_PAGE_SIZE);
String pageParameter = request.getParameter(REQUEST_PARAMETER_PAGE_NUMBER);
String sortOrder = request.getParameter(REQUEST_PARAMETER_SORT_ORDER);
String sortKeyName = request.getParameter(REQUEST_PARAMETER_SORT_KEY);
String outputDepth = request.getParameter(REQUEST_PARAMTER_OUTPUT_DEPTH);
boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
int pageSize = Services.parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
int page = Services.parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
int depth = Services.parseInt(outputDepth, config.getOutputNestingDepth());
String baseUrl = request.getRequestURI();
PropertyKey sortKey = null;
// set sort key
if (sortKeyName != null) {
Class<? extends GraphObject> type = resource.getEntityClass();
if (type == null) {
// fallback to default implementation
// if no type can be determined
type = AbstractNode.class;
}
sortKey = StructrApp.getConfiguration().getPropertyKeyForDatabaseName(type, sortKeyName, false);
}
// isolate doGet
boolean retry = true;
while (retry) {
try (final Tx tx = app.tx()) {
result = resource.doGet(sortKey, sortDescending, pageSize, page);
tx.success();
retry = false;
} catch (RetryException ddex) {
retry = true;
}
}
if (result == null) {
throw new FrameworkException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Unable to retrieve result, check database connection");
}
if (returnContent) {
if (!(resource instanceof StaticRelationshipResource) && !result.isPrimitiveArray() && !result.isEmpty()) {
result.setIsCollection(resource.isCollectionResource());
result.setIsPrimitiveArray(resource.isPrimitiveArray());
}
PagingHelper.addPagingParameter(result, pageSize, page);
// timing..
double queryTimeEnd = System.nanoTime();
// store property view that will be used to render the results
result.setPropertyView(propertyView.get(securityContext));
// allow resource to modify result set
resource.postProcessResultSet(result);
DecimalFormat decimalFormat = new DecimalFormat("0.000000000", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
result.setQueryTime(decimalFormat.format((queryTimeEnd - queryTimeStart) / 1000000000.0));
if (outputDepth != null) {
result.setOutputNestingDepth(depth);
}
String accept = request.getHeader("Accept");
if (accept != null && accept.contains("text/html")) {
final StreamingHtmlWriter htmlStreamer = new StreamingHtmlWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("text/html; charset=utf-8");
final Writer writer = response.getWriter();
htmlStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
} else {
final StreamingJsonWriter jsonStreamer = new StreamingJsonWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("application/json; charset=utf-8");
final Writer writer = response.getWriter();
jsonStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
}
}
response.setStatus(HttpServletResponse.SC_OK);
} catch (FrameworkException frameworkException) {
// set status & write JSON output
response.setStatus(frameworkException.getStatus());
gson.get().toJson(frameworkException, response.getWriter());
response.getWriter().println();
} catch (JsonSyntaxException jsex) {
logger.warn("JsonSyntaxException in GET", jsex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Json syntax exception in GET: " + jsex.getMessage()));
} catch (JsonParseException jpex) {
logger.warn("JsonParseException in GET", jpex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Parser exception in GET: " + jpex.getMessage()));
} catch (Throwable t) {
logger.warn("Exception in GET (URI: {})", securityContext != null ? securityContext.getCompoundRequestURI() : "(null SecurityContext)");
logger.warn(" => Error thrown: ", t);
int code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Exception in GET: " + t.getMessage()));
} finally {
try {
// response.getWriter().flush();
response.getWriter().close();
} catch (Throwable t) {
logger.warn("Unable to flush and close response: {}", t.getMessage());
}
}
}
use of org.structr.rest.serialization.StreamingJsonWriter in project structr by structr.
the class ToJsonFunction method apply.
@Override
public Object apply(final ActionContext ctx, final Object caller, final Object[] sources) {
if (sources != null && sources.length >= 1 && sources.length <= 3) {
try {
final SecurityContext securityContext = ctx.getSecurityContext();
final Value<String> view = new StaticValue<>("public");
if (sources.length > 1) {
view.set(securityContext, sources[1].toString());
}
int outputDepth = 3;
if (sources.length > 2 && sources[2] instanceof Number) {
outputDepth = ((Number) sources[2]).intValue();
}
final StreamingJsonWriter jsonStreamer = new StreamingJsonWriter(view, true, outputDepth);
final StringWriter writer = new StringWriter();
if (sources[0] instanceof GraphObject) {
jsonStreamer.streamSingle(securityContext, writer, (GraphObject) sources[0]);
} else if (sources[0] instanceof List) {
final List list = (List) sources[0];
jsonStreamer.stream(securityContext, writer, new Result(list, list.size(), true, false), null);
} else if (sources[0] instanceof Map) {
final GraphObjectMap map = new GraphObjectMap();
this.recursivelyConvertMapToGraphObjectMap(map, (Map) sources[0], outputDepth);
jsonStreamer.stream(securityContext, writer, new Result(map, false), null);
}
return writer.getBuffer().toString();
} catch (Throwable t) {
logException(caller, t, sources);
}
return "";
} else {
logParameterError(caller, sources, ctx.isJavaScriptContext());
}
return usage(ctx.isJavaScriptContext());
}
Aggregations