private boolean traverse(List<?> list, List<ErrorMessage> topLevelErrors) { boolean smurfFound = false; // traverse the tree in the response, and react to the known types for (Object data : list) { if (data instanceof DataList) { smurfFound = traverse(((DataList<?>) data).asList(), topLevelErrors); } else if (data instanceof DataProcessor.DemoData) { DataProcessor.DemoData content = (DataProcessor.DemoData) data; if (DemoComponent.SMURF.equals(content.content())) { topLevelErrors.add(new ErrorMessage("There's a smurf!")); smurfFound = true; } } if (smurfFound) { break; } } return smurfFound; }
@Override public void beginResponse(OutputStream stream) throws IOException { writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8.newEncoder()); if (getResponse().data().request().errors().size() == 0) { writer.write("OK\n"); } else { writer.write("Oops!\n"); } writer.write(heading); writer.write('\n'); }
/** * <p>Render this response using the renderer's own threads and return a future indicating whether the rendering * was successful. The data list tree will be traversed asynchronously, and * the pertinent methods will be called as data becomes available.</p> * * <p>If rendering fails, the exception causing this will be wrapped in an * ExecutionException and thrown from blocked calls to Future.get()</p> * * @return a future indicating whether rendering was successful */ @Override public final ListenableFuture<Boolean> render(OutputStream stream, RESPONSE response, Execution execution, Request request) { if (beforeHandoverMode) { // rendering has already started or is already complete beforeHandoverMode = false; if ( ! dataListListenerStack.isEmpty() && dataListListenerStack.getFirst().list.incoming().isComplete()) { // We're not waiting for async completion, so kick off more rendering due to the implicit complete // (return Response from chain) causing this method to be called getExecutor().execute(dataListListenerStack.getFirst()); } return success; } else { // This is the start of rendering return startRender(stream, response, execution, request); } }
@Override public Response process(Request request, Execution execution) { Response response; List<?> d; DemoProperty p = new DemoProperty(); String terms = request.properties().getString(TERMS); if (terms != null) { for (String s : splitter.split(terms)) { p.add(s); } } else { for (DemoConfig.Demo demo : defaultTermSet.demo()) { p.add(demo.term()); } } request.properties().set(DemoProperty.NAME_AS_COMPOUND, p); response = execution.process(request); d = response.data().asList(); traverse(d, response.data().request().errors()); return response; }
@SuppressWarnings("unchecked") @Override public Response process(Request request, Execution execution) { // process the request request.properties().set("foo", "bar"); // pass it down the chain to get a response Response response = execution.process(request); // process the response response.data().add(new StringData(request, message)); // return the response up the chain return response; }
@Override public Response process(Request request, Execution execution) { Response r = new Response(request); @SuppressWarnings("unchecked") DataList<Data> current = r.data(); DataList<Data> previous = null; String exampleProperty = request.properties().getString(DemoHandler.REQUEST_URI); Object o = request.properties().get(AnnotatingProcessor.DemoProperty.NAME_AS_COMPOUND); if (exampleProperty != null) { current.add(new DemoData(request, exampleProperty)); } if (o instanceof AnnotatingProcessor.DemoProperty) { // create a nested result set with a level for each term for (String s : ((AnnotatingProcessor.DemoProperty) o).terms()) { String normalized = termChecker.normalize(s); DemoData data = new DemoData(request, normalized); if (current == null) { current = ArrayDataList.create(request); } current.add(data); if (previous != null) { previous.add(current); } previous = current; current = null; } } return r; }
@Override public void complete() { // Add headers addHeadersAndStatusFrom(processingResponse.data()); if ( ! explicitStatusSet) { // Set status from errors TODO: This could be decomplicated a bit List<ErrorMessage> errors = flattenErrors(processingResponse); boolean isSuccess = !(processingResponse.data().asList().isEmpty() && !errors.isEmpty()); // NOT success if ( no data AND are errors ) setStatus(getHttpResponseStatus(isSuccess, processingRequest, errors.size() == 0 ? null : errors.get(0), errors)); } }
renderTrace(); if ( ! list.request().errors().isEmpty() && ! rendered(list.request())) { jsonWriter.beginField("errors"); jsonWriter.beginArray(); for (ErrorMessage error : list.request().errors()) { if (renderedRequests == null) renderedRequests = new IdentityHashMap<>(); renderedRequests.put(list.request(),list.request()); jsonWriter.beginArrayValue(); if (error.getCause() != null) { // render object
@SuppressWarnings("unchecked") private Set<ErrorMessage> flattenErrors(Set<ErrorMessage> errors, Data data) { if (data.request() == null) return Collections.EMPTY_SET; // Not allowed, but handle anyway errors = addTo(errors, data.request().errors()); if (data instanceof DataList) { for (Data item : ((DataList<Data>) data).asList()) errors = flattenErrors(errors, item); } return errors; }
/** * This sets header and status from special Data items used for the purpose. * Do both at once to avoid traversing the data tree twice. */ @SuppressWarnings("unchecked") private void addHeadersAndStatusFrom(DataList<Data> dataList) { for (Data data : dataList.asList()) { if (data instanceof ResponseHeaders) { headers().addAll(((ResponseHeaders) data).headers()); } else if ( ! explicitStatusSet && (data instanceof ResponseStatus)) { setStatus(((ResponseStatus)data).code()); explicitStatusSet = true; } else if (data instanceof DataList) { addHeadersAndStatusFrom((DataList) data); } } }