/* * 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.isis.viewer.restfulobjects.applib.client; import java.io.IOException; import java.util.List; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status.Family; import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; import org.apache.isis.viewer.restfulobjects.applib.LinkRepresentation; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.google.common.collect.Lists; public class RepresentationWalker { static class Step { private final String key; private final LinkRepresentation link; private final JsonRepresentation body; private final RestfulResponse<? extends JsonRepresentation> response; private String error; private final Exception exception; public Step(final String key, final LinkRepresentation link, final JsonRepresentation body, final RestfulResponse<? extends JsonRepresentation> response, final String error, final Exception exception) { this.key = key; this.link = link; this.body = body; this.response = response; this.error = error; this.exception = exception; } @Override public String toString() { return "Step [key=" + key + ", link=" + (link != null ? link.getHref() : "(null)") + ", error=" + error + "]"; } } private final RestfulClient restfulClient; private final List<Step> steps = Lists.newLinkedList(); public RepresentationWalker(final RestfulClient restfulClient, final Response response) { this.restfulClient = restfulClient; final RestfulResponse<JsonRepresentation> jsonResp = RestfulResponse.of(response); addStep(null, null, null, jsonResp, null, null); } private Step addStep(final String key, final LinkRepresentation link, final JsonRepresentation body, final RestfulResponse<JsonRepresentation> jsonResp, final String error, final Exception ex) { final Step step = new Step(key, link, body, jsonResp, error, ex); steps.add(0, step); if (error != null) { if (jsonResp.getStatus().getFamily() != Family.SUCCESSFUL) { step.error = "response status code: " + jsonResp.getStatus(); } } return step; } public void walk(final String path) { walk(path, null); } public void walk(final String path, final JsonRepresentation invokeBody) { final Step previousStep = currentStep(); if (previousStep.error != null) { return; } final RestfulResponse<? extends JsonRepresentation> jsonResponse = previousStep.response; JsonRepresentation entity; try { entity = jsonResponse.getEntity(); } catch (final Exception e) { addStep(path, null, null, null, "exception: " + e.getMessage(), e); return; } LinkRepresentation link; try { link = entity.getLink(path); } catch (final Exception e) { addStep(path, null, null, null, "exception: " + e.getMessage(), e); return; } if (link == null) { addStep(path, null, null, null, "no such link '" + path + "'", null); return; } final RestfulResponse<JsonRepresentation> response; try { if (invokeBody != null) { response = restfulClient.follow(link, invokeBody); } else { response = restfulClient.follow(link); } } catch (final Exception e) { addStep(path, link, null, null, "failed to follow link: " + e.getMessage(), e); return; } addStep(path, link, null, response, null, null); } /** * The entity returned from the previous walk. * * <p> * Will return null if the previous walk returned an error. */ public JsonRepresentation getEntity() throws JsonParseException, JsonMappingException, IOException { final Step currentStep = currentStep(); if (currentStep.response == null || currentStep.error != null) { return null; } return currentStep.response.getEntity(); } /** * The response returned from the previous walk. * * <p> * Once a walk/performed has been attempted, is guaranteed to return a * non-null value. (Conversely, will return <tt>null</tt> immediately after * instantiation and prior to a walk being attempted/performed). */ public RestfulResponse<?> getResponse() { final Step currentStep = currentStep(); return currentStep != null ? currentStep.response : null; } /** * The error (if any) that occurred from the previous walk. */ public String getError() { final Step currentStep = currentStep(); return currentStep != null ? currentStep.error : null; } /** * The exception (if any) that occurred from the previous walk. * * <p> * Will only ever be populated if {@link #getError()} is non-null. */ public Exception getException() { final Step currentStep = currentStep(); return currentStep != null ? currentStep.exception : null; } /** * The step that has just been walked. */ private Step currentStep() { return steps.get(0); } }