/** * 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.server.resources; import java.util.List; import java.util.Map; import com.google.common.collect.Lists; import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.consent.Consent; import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter; import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse; import org.apache.isis.viewer.restfulobjects.rendering.RendererContext; import org.apache.isis.viewer.restfulobjects.rendering.RestfulObjectsApplicationException; /** * Utility class that encapsulates the logic for parsing arguments to be invoked by an * {@link org.apache.isis.core.metamodel.spec.feature.ObjectAction}. */ public class ObjectActionArgHelper { private final RendererContext rendererContext; private final ObjectAdapter objectAdapter; private final ObjectAction action; public ObjectActionArgHelper( final RendererContext rendererContext, final ObjectAdapter objectAdapter, final ObjectAction action) { this.rendererContext = rendererContext; this.objectAdapter = objectAdapter; this.action = action; } public List<ObjectAdapter> parseAndValidateArguments(final JsonRepresentation arguments) { final List<JsonRepresentation> argList = argListFor(action, arguments); final List<ObjectAdapter> argAdapters = Lists.newArrayList(); final List<ObjectActionParameter> parameters = action.getParameters(); boolean valid = true; for (int i = 0; i < argList.size(); i++) { final JsonRepresentation argRepr = argList.get(i); final ObjectSpecification paramSpec = parameters.get(i).getSpecification(); try { final ObjectAdapter argAdapter = new JsonParserHelper(rendererContext, paramSpec).objectAdapterFor(argRepr); argAdapters.add(argAdapter); // validate individual arg final ObjectActionParameter parameter = parameters.get(i); final Object argPojo = argAdapter!=null?argAdapter.getObject():null; final String reasonNotValid = parameter.isValid(objectAdapter, argPojo, InteractionInitiatedBy.USER ); if (reasonNotValid != null) { argRepr.mapPut("invalidReason", reasonNotValid); valid = false; } } catch (final IllegalArgumentException e) { argAdapters.add(null); valid = false; } } // validate all args final ObjectAdapter[] argArray = argAdapters.toArray(new ObjectAdapter[0]); final Consent consent = action.isProposedArgumentSetValid(objectAdapter, argArray, InteractionInitiatedBy.USER); if (consent.isVetoed()) { arguments.mapPut("x-ro-invalidReason", consent.getReason()); valid = false; } if(!valid) { throw RestfulObjectsApplicationException.createWithBody(RestfulResponse.HttpStatusCode.VALIDATION_FAILED, arguments, "Validation failed, see body for details"); } return argAdapters; } private static List<JsonRepresentation> argListFor(final ObjectAction action, final JsonRepresentation arguments) { final List<JsonRepresentation> argList = Lists.newArrayList(); // ensure that we have no arguments that are not parameters for (final Map.Entry<String, JsonRepresentation> arg : arguments.mapIterable()) { final String argName = arg.getKey(); if(argName.startsWith("x-ro")) { continue; } if (action.getParameterById(argName) == null) { String reason = String.format("Argument '%s' found but no such parameter", argName); arguments.mapPut("x-ro-invalidReason", reason); throw RestfulObjectsApplicationException.createWithBody(RestfulResponse.HttpStatusCode.BAD_REQUEST, arguments, reason); } } // ensure that an argument value has been provided for all non-optional // parameters final List<ObjectActionParameter> parameters = action.getParameters(); for (final ObjectActionParameter param : parameters) { final String paramId = param.getId(); final JsonRepresentation argRepr = arguments.getRepresentation(paramId); if (argRepr == null && !param.isOptional()) { String reason = String.format("No argument found for (mandatory) parameter '%s'", paramId); arguments.mapPut("x-ro-invalidReason", reason); throw RestfulObjectsApplicationException.createWithBody(RestfulResponse.HttpStatusCode.BAD_REQUEST, arguments, reason); } argList.add(argRepr); } return argList; } }