Search in sources :

Example 1 with Error

use of org.folio.rest.jaxrs.model.Error in project raml-module-builder by folio-org.

the class RestVerticle method route.

/**
 * Handler for all url calls other then documentation.
 * @param mappedURLs  maps paths found in raml to the generated functions to route to when the paths are requested
 * @param urlPaths  set of exposed urls as declared in the raml
 * @param regex2Pattern  create a map of regular expression to url path
 * @param rc  RoutingContext of this URL
 */
private void route(MappedClasses mappedURLs, Set<String> urlPaths, Map<String, Pattern> regex2Pattern, RoutingContext rc) {
    long start = System.nanoTime();
    try {
        // list of regex urls created from urls declared in the raml
        Iterator<String> iter = urlPaths.iterator();
        boolean validPath = false;
        boolean[] validRequest = { true };
        // the ramls and we return an error - this has positive security implications as well
        while (iter.hasNext()) {
            String regexURL = iter.next();
            // try to match the requested url to each regex pattern created from the urls in the raml
            Matcher m = regex2Pattern.get(regexURL).matcher(rc.request().path());
            if (m.find()) {
                validPath = true;
                // get the function that should be invoked for the requested
                // path + requested http_method pair
                JsonObject ret = mappedURLs.getMethodbyPath(regexURL, rc.request().method().toString());
                // if a valid path was requested but no function was found
                if (ret == null) {
                    // assume a cors request
                    if (rc.request().method() == HttpMethod.OPTIONS) {
                        rc.response().end();
                        return;
                    }
                    // the url exists but the http method requested does not match a function
                    // meaning url+http method != a function
                    endRequestWithError(rc, 400, true, messages.getMessage("en", MessageConsts.HTTPMethodNotSupported), validRequest);
                    return;
                }
                Class<?> aClass;
                try {
                    if (validRequest[0]) {
                        int groups = m.groupCount();
                        // pathParams are the place holders in the raml query string
                        // for example /admin/{admin_id}/yyy/{yyy_id} - the content in between the {} are path params
                        // they are replaced with actual values and are passed to the function which the url is mapped to
                        String[] pathParams = new String[groups];
                        for (int i = 0; i < groups; i++) {
                            pathParams[i] = m.group(i + 1);
                        }
                        // create okapi headers map and inject into function
                        Map<String, String> okapiHeaders = new CaseInsensitiveMap<>();
                        String[] tenantId = new String[] { null };
                        getOkapiHeaders(rc, okapiHeaders, tenantId);
                        String reqId = okapiHeaders.get(OKAPI_REQUESTID_HEADER);
                        if (reqId != null) {
                            MDC.put("reqId", "reqId=" + reqId);
                        }
                        if (tenantId[0] == null && !rc.request().path().startsWith("/admin")) {
                            // if tenant id is not passed in and this is not an /admin request, return error
                            endRequestWithError(rc, 400, true, messages.getMessage("en", MessageConsts.UnableToProcessRequest) + " Tenant must be set", validRequest);
                        }
                        if (validRequest[0]) {
                            // get interface mapped to this url
                            String iClazz = ret.getString(AnnotationGrabber.CLASS_NAME);
                            // convert from interface to an actual class implementing it, which appears in the impl package
                            aClass = InterfaceToImpl.convert2Impl(RTFConsts.PACKAGE_OF_IMPLEMENTATIONS, iClazz, false).get(0);
                            Object o = null;
                            // passing the vertx and context objects in to it.
                            try {
                                o = aClass.getConstructor(Vertx.class, String.class).newInstance(vertx, tenantId[0]);
                            } catch (Exception e) {
                                // if no such constructor was implemented call the
                                // default no param constructor to create the object to be used to call functions on
                                o = aClass.newInstance();
                            }
                            final Object instance = o;
                            // function to invoke for the requested url
                            String function = ret.getString(AnnotationGrabber.FUNCTION_NAME);
                            // parameters for the function to invoke
                            JsonObject params = ret.getJsonObject(AnnotationGrabber.METHOD_PARAMS);
                            // all methods in the class whose function is mapped to the called url
                            // needed so that we can get a reference to the Method object and call it via reflection
                            Method[] methods = aClass.getMethods();
                            // what the api will return as output (Accept)
                            JsonArray produces = ret.getJsonArray(AnnotationGrabber.PRODUCES);
                            // what the api expects to get (content-type)
                            JsonArray consumes = ret.getJsonArray(AnnotationGrabber.CONSUMES);
                            HttpServerRequest request = rc.request();
                            // check that the accept and content-types passed in the header of the request
                            // are as described in the raml
                            checkAcceptContentType(produces, consumes, rc, validRequest);
                            // create the array and then populate it by parsing the url parameters which are needed to invoke the function mapped
                            // to the requested URL - array will be populated by parseParams() function
                            Iterator<Map.Entry<String, Object>> paramList = params.iterator();
                            Object[] paramArray = new Object[params.size()];
                            parseParams(rc, paramList, validRequest, consumes, paramArray, pathParams, okapiHeaders);
                            // Get method in class to be run for this requested API endpoint
                            Method[] method2Run = new Method[] { null };
                            for (int i = 0; i < methods.length; i++) {
                                if (methods[i].getName().equals(function)) {
                                    method2Run[0] = methods[i];
                                    break;
                                }
                            }
                            // is function annotated to receive data in chunks as they come in.
                            // Note that the function controls the logic to this if this is the case
                            boolean streamData = isStreamed(method2Run[0].getAnnotations());
                            // check if we are dealing with a file upload , currently only multipart/form-data and application/octet
                            // in the raml definition for such a function
                            final boolean[] isContentUpload = new boolean[] { false };
                            final int[] uploadParamPosition = new int[] { -1 };
                            params.forEach(param -> {
                                if (((JsonObject) param.getValue()).getString("type").equals(FILE_UPLOAD_PARAM)) {
                                    isContentUpload[0] = true;
                                    uploadParamPosition[0] = ((JsonObject) param.getValue()).getInteger("order");
                                } else if (((JsonObject) param.getValue()).getString("type").equals("java.io.InputStream")) {
                                    // application/octet-stream passed - this is handled in a stream like manner
                                    // and the corresponding function called must annotate with a @Stream - and be able
                                    // to handle the function being called repeatedly on parts of the data
                                    uploadParamPosition[0] = ((JsonObject) param.getValue()).getInteger("order");
                                    isContentUpload[0] = true;
                                }
                            });
                            // pass to implementing function just like any other call
                            if (isContentUpload[0] && !streamData) {
                                // looks something like -> multipart/form-data; boundary=----WebKitFormBoundaryzeZR8KqAYJyI2jPL
                                if (consumes != null && consumes.contains(SUPPORTED_CONTENT_TYPE_FORMDATA)) {
                                    // multipart
                                    handleMultipartUpload(rc, request, uploadParamPosition, paramArray, validRequest);
                                    request.endHandler(a -> {
                                        if (validRequest[0]) {
                                            // if request is valid - invoke it
                                            try {
                                                invoke(method2Run[0], paramArray, instance, rc, tenantId, okapiHeaders, new StreamStatus(), v -> {
                                                    LogUtil.formatLogMessage(className, "start", " invoking " + function);
                                                    sendResponse(rc, v, start, tenantId[0]);
                                                });
                                            } catch (Exception e1) {
                                                log.error(e1.getMessage(), e1);
                                                rc.response().end();
                                            }
                                        }
                                    });
                                } else {
                                    // assume input stream
                                    handleInputStreamUpload(method2Run[0], rc, request, instance, tenantId, okapiHeaders, uploadParamPosition, paramArray, validRequest, start);
                                }
                            } else if (streamData) {
                                handleStream(method2Run[0], rc, request, instance, tenantId, okapiHeaders, uploadParamPosition, paramArray, validRequest, start);
                            } else {
                                if (validRequest[0]) {
                                    // if request is valid - invoke it
                                    try {
                                        invoke(method2Run[0], paramArray, instance, rc, tenantId, okapiHeaders, new StreamStatus(), v -> {
                                            LogUtil.formatLogMessage(className, "start", " invoking " + function);
                                            sendResponse(rc, v, start, tenantId[0]);
                                        });
                                    } catch (Exception e1) {
                                        log.error(e1.getMessage(), e1);
                                        rc.response().end();
                                    }
                                }
                            }
                        } else {
                            endRequestWithError(rc, 400, true, messages.getMessage("en", MessageConsts.UnableToProcessRequest), validRequest);
                            return;
                        }
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    endRequestWithError(rc, 400, true, messages.getMessage("en", MessageConsts.UnableToProcessRequest) + e.getMessage(), validRequest);
                    return;
                }
            }
        }
        if (!validPath) {
            // invalid path
            endRequestWithError(rc, 400, true, messages.getMessage("en", MessageConsts.InvalidURLPath, rc.request().path()), validRequest);
        }
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
}
Also used : ValidationHelper(org.folio.rest.tools.utils.ValidationHelper) UnrecognizedPropertyException(com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) Date(java.util.Date) HttpServer(io.vertx.core.http.HttpServer) MultiMap(io.vertx.core.MultiMap) MessagingException(javax.mail.MessagingException) Router(io.vertx.ext.web.Router) RoutingContext(io.vertx.ext.web.RoutingContext) BodyHandler(io.vertx.ext.web.handler.BodyHandler) StringUtils(org.apache.commons.lang3.StringUtils) VertxUtils(org.folio.rest.tools.utils.VertxUtils) Context(io.vertx.core.Context) PomReader(org.folio.rest.tools.PomReader) BigDecimal(java.math.BigDecimal) MetricsService(io.vertx.ext.dropwizard.MetricsService) Matcher(java.util.regex.Matcher) EventBus(io.vertx.core.eventbus.EventBus) ByteArrayInputStream(java.io.ByteArrayInputStream) LogUtil(org.folio.rest.tools.utils.LogUtil) ResponseImpl(org.folio.rest.tools.utils.ResponseImpl) Map(java.util.Map) AnnotationGrabber(org.folio.rest.tools.AnnotationGrabber) RTFConsts(org.folio.rest.tools.RTFConsts) JsonObject(io.vertx.core.json.JsonObject) Metadata(org.folio.rest.jaxrs.model.Metadata) KieSession(org.kie.api.runtime.KieSession) Logger(io.vertx.core.logging.Logger) Method(java.lang.reflect.Method) ConstraintViolation(javax.validation.ConstraintViolation) Errors(org.folio.rest.jaxrs.model.Errors) JwtUtils(org.folio.rest.tools.utils.JwtUtils) MimeMultipart(javax.mail.internet.MimeMultipart) BinaryOutStream(org.folio.rest.tools.utils.BinaryOutStream) JsonUtils(org.folio.rest.tools.utils.JsonUtils) Set(java.util.Set) UUID(java.util.UUID) Future(io.vertx.core.Future) PostgresClient(org.folio.rest.persist.PostgresClient) Messages(org.folio.rest.tools.messages.Messages) OutStream(org.folio.rest.tools.utils.OutStream) List(java.util.List) PojoEventBusCodec(org.folio.rest.tools.codecs.PojoEventBusCodec) InterfaceToImpl(org.folio.rest.tools.utils.InterfaceToImpl) Response(javax.ws.rs.core.Response) Buffer(io.vertx.core.buffer.Buffer) HttpServerResponse(io.vertx.core.http.HttpServerResponse) AbstractVerticle(io.vertx.core.AbstractVerticle) Annotation(java.lang.annotation.Annotation) Entry(java.util.Map.Entry) ByteStreams(com.google.common.io.ByteStreams) Parameter(org.folio.rest.jaxrs.model.Parameter) Pattern(java.util.regex.Pattern) Joiner(com.google.common.base.Joiner) HttpServerRequest(io.vertx.core.http.HttpServerRequest) MessageConsts(org.folio.rest.tools.messages.MessageConsts) MimeBodyPart(javax.mail.internet.MimeBodyPart) HashMap(java.util.HashMap) ValidatorFactory(javax.validation.ValidatorFactory) CaseInsensitiveMap(org.apache.commons.collections4.map.CaseInsensitiveMap) LoggerFactory(io.vertx.core.logging.LoggerFactory) ArrayList(java.util.ArrayList) Validation(javax.validation.Validation) AsyncResult(io.vertx.core.AsyncResult) MDC(org.apache.log4j.MDC) Properties(java.util.Properties) HttpServerFileUpload(io.vertx.core.http.HttpServerFileUpload) Iterator(java.util.Iterator) StaticHandler(io.vertx.ext.web.handler.StaticHandler) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) Vertx(io.vertx.core.Vertx) IOException(java.io.IOException) FactHandle(org.kie.api.runtime.rule.FactHandle) Consumer(java.util.function.Consumer) Rules(org.folio.rulez.Rules) Stream(org.folio.rest.annotations.Stream) Error(org.folio.rest.jaxrs.model.Error) HttpClientMock2(org.folio.rest.tools.client.test.HttpClientMock2) JsonArray(io.vertx.core.json.JsonArray) InternetHeaders(javax.mail.internet.InternetHeaders) AsyncResponseResult(org.folio.rest.tools.utils.AsyncResponseResult) StringReader(java.io.StringReader) HttpMethod(io.vertx.core.http.HttpMethod) ObjectMapperTool(org.folio.rest.tools.utils.ObjectMapperTool) TenantAttributes(org.folio.rest.jaxrs.model.TenantAttributes) ClientGenerator(org.folio.rest.tools.ClientGenerator) HttpServerOptions(io.vertx.core.http.HttpServerOptions) Handler(io.vertx.core.Handler) InputStream(java.io.InputStream) Matcher(java.util.regex.Matcher) HttpServerRequest(io.vertx.core.http.HttpServerRequest) JsonObject(io.vertx.core.json.JsonObject) Method(java.lang.reflect.Method) HttpMethod(io.vertx.core.http.HttpMethod) UnrecognizedPropertyException(com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) MessagingException(javax.mail.MessagingException) IOException(java.io.IOException) CaseInsensitiveMap(org.apache.commons.collections4.map.CaseInsensitiveMap) JsonArray(io.vertx.core.json.JsonArray) Entry(java.util.Map.Entry) JsonObject(io.vertx.core.json.JsonObject)

Example 2 with Error

use of org.folio.rest.jaxrs.model.Error in project raml-module-builder by folio-org.

the class ValidationHelper method createValidationErrorMessage.

public static Errors createValidationErrorMessage(String field, String value, String message) {
    Errors e = new Errors();
    Error error = new Error();
    Parameter p = new Parameter();
    p.setKey(field);
    p.setValue(value);
    error.getParameters().add(p);
    error.setMessage(message);
    error.setCode("-1");
    error.setType(RTFConsts.VALIDATION_FIELD_ERROR);
    List<Error> l = new ArrayList<>();
    l.add(error);
    e.setErrors(l);
    return e;
}
Also used : Errors(org.folio.rest.jaxrs.model.Errors) ArrayList(java.util.ArrayList) Error(org.folio.rest.jaxrs.model.Error) Parameter(org.folio.rest.jaxrs.model.Parameter)

Example 3 with Error

use of org.folio.rest.jaxrs.model.Error in project raml-module-builder by folio-org.

the class RestVerticle method parseParams.

private void parseParams(RoutingContext rc, Iterator<Map.Entry<String, Object>> paramList, boolean[] validRequest, JsonArray consumes, Object[] paramArray, String[] pathParams, Map<String, String> okapiHeaders) {
    HttpServerRequest request = rc.request();
    MultiMap queryParams = request.params();
    int[] pathParamsIndex = new int[] { pathParams.length };
    paramList.forEachRemaining(entry -> {
        if (validRequest[0]) {
            String valueName = ((JsonObject) entry.getValue()).getString("value");
            String valueType = ((JsonObject) entry.getValue()).getString("type");
            String paramType = ((JsonObject) entry.getValue()).getString("param_type");
            int order = ((JsonObject) entry.getValue()).getInteger("order");
            Object defaultVal = ((JsonObject) entry.getValue()).getValue("default_value");
            boolean emptyNumeircParam = false;
            // to their async upload - so explicitly skip them
            if (AnnotationGrabber.NON_ANNOTATED_PARAM.equals(paramType) && !FILE_UPLOAD_PARAM.equals(valueType)) {
                try {
                    // this will also validate the json against the pojo created from the schema
                    Class<?> entityClazz = Class.forName(valueType);
                    if (!valueType.equals("io.vertx.core.Handler") && !valueType.equals("io.vertx.core.Context") && !valueType.equals("java.util.Map") && !valueType.equals("java.io.InputStream") && !valueType.equals("io.vertx.ext.web.RoutingContext")) {
                        // we have special handling for the Result Handler and context, it is also assumed that
                        // an inputsteam parameter occurs when application/octet is declared in the raml
                        // in which case the content will be streamed to he function
                        String bodyContent = rc.getBodyAsString();
                        log.debug(rc.request().path() + " -------- bodyContent -------- " + bodyContent);
                        if (bodyContent != null) {
                            if ("java.io.Reader".equals(valueType)) {
                                paramArray[order] = new StringReader(bodyContent);
                            } else if (bodyContent.length() > 0) {
                                try {
                                    paramArray[order] = MAPPER.readValue(bodyContent, entityClazz);
                                } catch (UnrecognizedPropertyException e) {
                                    log.error(e.getMessage(), e);
                                    endRequestWithError(rc, RTFConsts.VALIDATION_ERROR_HTTP_CODE, true, JsonUtils.entity2String(ValidationHelper.createValidationErrorMessage("", "", e.getMessage())), validRequest);
                                    return;
                                }
                            }
                        }
                        Errors errorResp = new Errors();
                        if (!allowEmptyObject(entityClazz, bodyContent)) {
                            // right now - because no way in raml to make body optional - do not validate
                            // TenantAttributes object as it may be empty
                            // is this request only to validate a field value and not an actual
                            // request for additional processing
                            List<String> field2validate = request.params().getAll("validate_field");
                            Object[] resp = isValidRequest(rc, paramArray[order], errorResp, validRequest, field2validate, entityClazz);
                            boolean isValid = (boolean) resp[0];
                            paramArray[order] = resp[1];
                            if (!isValid) {
                                endRequestWithError(rc, RTFConsts.VALIDATION_ERROR_HTTP_CODE, true, JsonUtils.entity2String(errorResp), validRequest);
                                return;
                            } else if (isValid && !field2validate.isEmpty()) {
                                // valid request for the field to validate request made
                                AsyncResponseResult arr = new AsyncResponseResult();
                                ResponseImpl ri = new ResponseImpl();
                                ri.setStatus(200);
                                arr.setResult(ri);
                                // right now this is the only flag available to stop
                                // any additional respones for this request. to fix
                                validRequest[0] = false;
                                sendResponse(rc, arr, 0, null);
                                return;
                            }
                        }
                        // complex rules validation here (drools) - after simpler validation rules pass -
                        Error error = new Error();
                        FactHandle handle = null;
                        FactHandle handleError = null;
                        try {
                            // if no /rules exist then drools session will be null
                            if (droolsSession != null && paramArray[order] != null && validRequest[0]) {
                                // add object to validate to session
                                handle = droolsSession.insert(paramArray[order]);
                                handleError = droolsSession.insert(error);
                                // run all rules in session on object
                                droolsSession.fireAllRules();
                            }
                        } catch (Exception e) {
                            error.setCode("-1");
                            error.setType(RTFConsts.VALIDATION_FIELD_ERROR);
                            errorResp.getErrors().add(error);
                            endRequestWithError(rc, RTFConsts.VALIDATION_ERROR_HTTP_CODE, true, JsonUtils.entity2String(errorResp), validRequest);
                        } finally {
                            // remove the object from the session
                            if (handle != null) {
                                droolsSession.delete(handle);
                                droolsSession.delete(handleError);
                            }
                        }
                        populateMetaData(paramArray[order], okapiHeaders, rc.request().path());
                    }
                } catch (Exception e) {
                    log.error(e);
                    endRequestWithError(rc, 400, true, "Json content error " + e.getMessage(), validRequest);
                }
            } else if (AnnotationGrabber.HEADER_PARAM.equals(paramType)) {
                // handle header params - read the header field from the
                // header (valueName) and get its value
                String value = request.getHeader(valueName);
                // set the value passed from the header as a param to the function
                paramArray[order] = value;
            } else if (AnnotationGrabber.PATH_PARAM.equals(paramType)) {
                // these are placeholder values in the path - for example
                // /patrons/{patronid} - this would be the patronid value
                paramArray[order] = pathParams[pathParamsIndex[0] - 1];
                pathParamsIndex[0] = pathParamsIndex[0] - 1;
            } else if (AnnotationGrabber.QUERY_PARAM.equals(paramType)) {
                String param = queryParams.get(valueName);
                // support enum, numbers or strings as query parameters
                try {
                    if (valueType.contains("String")) {
                        // regular string param in query string - just push value
                        if (param == null && defaultVal != null) {
                            // no value passed - check if there is a default value
                            paramArray[order] = defaultVal;
                        } else {
                            paramArray[order] = param;
                        }
                    } else if (valueType.contains("int") || valueType.contains("Integer")) {
                        // cant pass null to an int type
                        if (param == null) {
                            if (defaultVal != null) {
                                paramArray[order] = Integer.valueOf((String) defaultVal);
                            } else {
                                paramArray[order] = 0;
                            }
                        } else if ("".equals(param)) {
                            emptyNumeircParam = true;
                        } else {
                            paramArray[order] = Integer.valueOf(param);
                        }
                    } else if (valueType.contains("boolean") || valueType.contains("Boolean")) {
                        if (param == null) {
                            if (defaultVal != null) {
                                paramArray[order] = Boolean.valueOf((String) defaultVal);
                            }
                        } else {
                            paramArray[order] = Boolean.valueOf(param);
                        }
                    } else if (valueType.contains("List")) {
                        List<String> vals = queryParams.getAll(valueName);
                        if (vals == null) {
                            paramArray[order] = null;
                        } else {
                            paramArray[order] = vals;
                        }
                    } else if (valueType.contains("BigDecimal")) {
                        if (param == null) {
                            if (defaultVal != null) {
                                paramArray[order] = new BigDecimal((String) defaultVal);
                            } else {
                                paramArray[order] = null;
                            }
                        } else if ("".equals(param)) {
                            emptyNumeircParam = true;
                        } else {
                            // big decimal can contain ","
                            paramArray[order] = new BigDecimal(param.replaceAll(",", ""));
                        }
                    } else {
                        // enum object type
                        try {
                            String enumClazz = replaceLast(valueType, ".", "$");
                            Class<?> enumClazz1 = Class.forName(enumClazz);
                            if (enumClazz1.isEnum()) {
                                Object defaultEnum = null;
                                Object[] vals = enumClazz1.getEnumConstants();
                                for (int i = 0; i < vals.length; i++) {
                                    if (vals[i].toString().equals(defaultVal)) {
                                        defaultEnum = vals[i];
                                    }
                                    // in case no value was passed in the request
                                    if (param == null && defaultEnum != null) {
                                        paramArray[order] = defaultEnum;
                                        break;
                                    } else // make sure enum value is valid by converting the string to an enum
                                    if (vals[i].toString().equals(param)) {
                                        paramArray[order] = vals[i];
                                        break;
                                    }
                                    if (i == vals.length - 1) {
                                        // if enum passed is not valid, replace with default value
                                        paramArray[order] = defaultEnum;
                                    }
                                }
                            }
                        } catch (Exception ee) {
                            log.error(ee.getMessage(), ee);
                            endRequestWithError(rc, 400, true, ee.getMessage(), validRequest);
                        }
                    }
                    if (emptyNumeircParam) {
                        endRequestWithError(rc, 400, true, valueName + " does not have a default value in the RAML and has been passed empty", validRequest);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    endRequestWithError(rc, 400, true, e.getMessage(), validRequest);
                }
            }
        }
    });
}
Also used : FactHandle(org.kie.api.runtime.rule.FactHandle) HttpServerRequest(io.vertx.core.http.HttpServerRequest) JsonObject(io.vertx.core.json.JsonObject) UnrecognizedPropertyException(com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) Error(org.folio.rest.jaxrs.model.Error) ResponseImpl(org.folio.rest.tools.utils.ResponseImpl) UnrecognizedPropertyException(com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) MessagingException(javax.mail.MessagingException) IOException(java.io.IOException) BigDecimal(java.math.BigDecimal) MultiMap(io.vertx.core.MultiMap) Errors(org.folio.rest.jaxrs.model.Errors) StringReader(java.io.StringReader) AsyncResponseResult(org.folio.rest.tools.utils.AsyncResponseResult) JsonObject(io.vertx.core.json.JsonObject)

Example 4 with Error

use of org.folio.rest.jaxrs.model.Error in project raml-module-builder by folio-org.

the class RestVerticle method isValidRequest.

/**
 * return whether the request is valid [0] and a cleaned up version of the object [1]
 * cleaned up meaning,
 * @param errorResp
 * @param paramArray
 * @param rc
 * @param validRequest
 * @param entityClazz
 */
private Object[] isValidRequest(RoutingContext rc, Object content, Errors errorResp, boolean[] validRequest, List<String> singleField, Class<?> entityClazz) {
    Set<? extends ConstraintViolation<?>> validationErrors = validationFactory.getValidator().validate(content);
    boolean ret = true;
    if (validationErrors.size() > 0) {
        for (ConstraintViolation<?> cv : validationErrors) {
            if ("must be null".equals(cv.getMessage())) {
                /**
                 * read only fields are marked with a 'must be null' annotation @null
                 * so the client should not pass them in, if they were passed in, remove them here
                 * so that they do not reach the implementing function
                 */
                try {
                    if (!(content instanceof JsonObject)) {
                        content = JsonObject.mapFrom(content);
                    }
                    ((JsonObject) content).remove(cv.getPropertyPath().toString());
                    continue;
                } catch (Exception e) {
                    log.warn("Failed to remove " + cv.getPropertyPath().toString() + " field from body when calling " + rc.request().absoluteURI(), e);
                }
            }
            Error error = new Error();
            Parameter p = new Parameter();
            String field = cv.getPropertyPath().toString();
            p.setKey(field);
            Object val = cv.getInvalidValue();
            if (val == null) {
                p.setValue("null");
            } else {
                p.setValue(val.toString());
            }
            error.getParameters().add(p);
            error.setMessage(cv.getMessage());
            error.setCode("-1");
            error.setType(RTFConsts.VALIDATION_FIELD_ERROR);
            // or there are validation errors and this is not a per field validation request
            if ((singleField != null && singleField.contains(field)) || singleField.isEmpty()) {
                errorResp.getErrors().add(error);
                ret = false;
            }
        // sb.append("\n" + cv.getPropertyPath() + "  " + cv.getMessage() + ",");
        }
        if (content instanceof JsonObject) {
            // we have sanitized the passed in object by removing read-only fields
            try {
                content = MAPPER.readValue(((JsonObject) content).encode(), entityClazz);
            } catch (IOException e) {
                log.error("Failed to serialize body content after removing read-only fields when calling " + rc.request().absoluteURI(), e);
            }
        }
    }
    return new Object[] { Boolean.valueOf(ret), content };
}
Also used : JsonObject(io.vertx.core.json.JsonObject) Error(org.folio.rest.jaxrs.model.Error) Parameter(org.folio.rest.jaxrs.model.Parameter) JsonObject(io.vertx.core.json.JsonObject) IOException(java.io.IOException) UnrecognizedPropertyException(com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException) MessagingException(javax.mail.MessagingException) IOException(java.io.IOException)

Aggregations

Error (org.folio.rest.jaxrs.model.Error)4 UnrecognizedPropertyException (com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException)3 JsonObject (io.vertx.core.json.JsonObject)3 IOException (java.io.IOException)3 Errors (org.folio.rest.jaxrs.model.Errors)3 Parameter (org.folio.rest.jaxrs.model.Parameter)3 MultiMap (io.vertx.core.MultiMap)2 HttpServerRequest (io.vertx.core.http.HttpServerRequest)2 StringReader (java.io.StringReader)2 BigDecimal (java.math.BigDecimal)2 ArrayList (java.util.ArrayList)2 MessagingException (javax.mail.MessagingException)2 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 Joiner (com.google.common.base.Joiner)1 ByteStreams (com.google.common.io.ByteStreams)1 AbstractVerticle (io.vertx.core.AbstractVerticle)1 AsyncResult (io.vertx.core.AsyncResult)1 Context (io.vertx.core.Context)1 Future (io.vertx.core.Future)1 Handler (io.vertx.core.Handler)1