예제 #1
0
 /**
  * This method trims doc (1st arg) according to projected (2nd arg), which may have been modified
  * by projection. This method works in-place, meaning that the doc may be mutated.
  */
 private static void trim(DataMap doc, DataMap projected) {
   DataMap toAddDoc = new DataMap();
   Set<String> fields = doc.keySet();
   List<String> toRemoveDoc = new ArrayList<String>(fields.size());
   for (String f : fields) {
     Object v = doc.get(f);
     if (f.equals(PatchConstants.DELETE_COMMAND)) {
       DataList deletedFields = (DataList) v;
       DataList filteredDeleteFields = new DataList();
       for (Object patchDeleteField : deletedFields) {
         if (projected.containsKey(patchDeleteField)) {
           filteredDeleteFields.add(patchDeleteField);
         }
       }
       toRemoveDoc.add(f);
       if (!filteredDeleteFields.isEmpty()) {
         toAddDoc.put(PatchConstants.DELETE_COMMAND, filteredDeleteFields);
       }
     } else if (f.equals(PatchConstants.SET_COMMAND)) {
       DataMap setFields = (DataMap) v;
       Set<String> setFieldNames = setFields.keySet();
       List<String> toRemove = new LinkedList<String>();
       DataMap filteredSetFields = new DataMap();
       for (String setFieldName : setFieldNames) {
         if (projected.containsKey(setFieldName)) {
           filteredSetFields.put(setFieldName, projected.get(setFieldName));
         }
         toRemove.add(setFieldName);
       }
       for (String fieldToRemove : toRemove) {
         setFields.remove(fieldToRemove);
         if (filteredSetFields.containsKey(fieldToRemove)) {
           setFields.put(fieldToRemove, filteredSetFields.get(fieldToRemove));
         }
       }
       if (setFields.isEmpty()) {
         toRemoveDoc.add(f);
       }
     } else if (v instanceof DataMap) {
       if (projected.containsKey(f)) {
         trim((DataMap) v, (DataMap) projected.get(f));
       } else {
         toRemoveDoc.add(f);
       }
     }
   }
   // apply changes to doc
   for (String f : toRemoveDoc) {
     doc.remove(f);
   }
   for (String f : toAddDoc.keySet()) {
     doc.put(f, toAddDoc.get(f));
   }
 }
예제 #2
0
  /**
   * Build arguments for resource method invocation. Combines various types of arguments into a
   * single array.
   *
   * @param positionalArguments pass-through arguments coming from {@link RestLiArgumentBuilder}
   * @param resourceMethod the resource method
   * @param context {@link ResourceContext}
   * @param template {@link DynamicRecordTemplate}
   * @return array of method argument for method invocation.
   */
  @SuppressWarnings("deprecation")
  public static Object[] buildArgs(
      final Object[] positionalArguments,
      final ResourceMethodDescriptor resourceMethod,
      final ResourceContext context,
      final DynamicRecordTemplate template) {
    List<Parameter<?>> parameters = resourceMethod.getParameters();
    Object[] arguments = Arrays.copyOf(positionalArguments, parameters.size());

    fixUpComplexKeySingletonArraysInArguments(arguments);

    for (int i = positionalArguments.length; i < parameters.size(); ++i) {
      Parameter<?> param = parameters.get(i);
      try {
        if (param.getParamType() == Parameter.ParamType.KEY
            || param.getParamType() == Parameter.ParamType.ASSOC_KEY_PARAM) {
          Object value = context.getPathKeys().get(param.getName());
          if (value != null) {
            arguments[i] = value;
            continue;
          }
        } else if (param.getParamType() == Parameter.ParamType.CALLBACK) {
          continue;
        } else if (param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT_PARAM
            || param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT) {
          continue; // don't know what to fill in yet
        } else if (param.getParamType() == Parameter.ParamType.HEADER) {
          HeaderParam headerParam = param.getAnnotations().get(HeaderParam.class);
          String value = context.getRequestHeaders().get(headerParam.value());
          arguments[i] = value;
          continue;
        }
        // Since we have multiple different types of MaskTrees that can be passed into resource
        // methods,
        // we must evaluate based on the param type (annotation used)
        else if (param.getParamType() == Parameter.ParamType.PROJECTION
            || param.getParamType() == Parameter.ParamType.PROJECTION_PARAM) {
          arguments[i] = context.getProjectionMask();
          continue;
        } else if (param.getParamType() == Parameter.ParamType.METADATA_PROJECTION_PARAM) {
          arguments[i] = context.getMetadataProjectionMask();
          continue;
        } else if (param.getParamType() == Parameter.ParamType.PAGING_PROJECTION_PARAM) {
          arguments[i] = context.getPagingProjectionMask();
          continue;
        } else if (param.getParamType() == Parameter.ParamType.CONTEXT
            || param.getParamType() == Parameter.ParamType.PAGING_CONTEXT_PARAM) {
          PagingContext ctx =
              RestUtils.getPagingContext(context, (PagingContext) param.getDefaultValue());
          arguments[i] = ctx;
          continue;
        } else if (param.getParamType() == Parameter.ParamType.PATH_KEYS
            || param.getParamType() == Parameter.ParamType.PATH_KEYS_PARAM) {
          arguments[i] = context.getPathKeys();
          continue;
        } else if (param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT
            || param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT_PARAM) {
          arguments[i] = context;
          continue;
        } else if (param.getParamType() == Parameter.ParamType.VALIDATOR_PARAM) {
          RestLiDataValidator validator =
              new RestLiDataValidator(
                  resourceMethod.getResourceModel().getResourceClass().getAnnotations(),
                  resourceMethod.getResourceModel().getValueClass(),
                  resourceMethod.getMethodType());
          arguments[i] = validator;
          continue;
        } else if (param.getParamType() == Parameter.ParamType.POST) {
          // handle action parameters
          if (template != null) {
            DataMap data = template.data();
            if (data.containsKey(param.getName())) {
              arguments[i] = template.getValue(param);
              continue;
            }
          }
        } else if (param.getParamType() == Parameter.ParamType.QUERY) {
          Object value;
          if (DataTemplate.class.isAssignableFrom(param.getType())) {
            value = buildDataTemplateArgument(context, param);
          } else {
            value = buildRegularArgument(context, param);
          }

          if (value != null) {
            arguments[i] = value;
            continue;
          }
        } else if (param.getParamType() == Parameter.ParamType.BATCH
            || param.getParamType() == Parameter.ParamType.RESOURCE_KEY) {
          // should not come to this routine since it should be handled by passing in
          // positionalArguments
          throw new RoutingException(
              "Parameter '" + param.getName() + "' should be passed in as a positional argument",
              HttpStatus.S_400_BAD_REQUEST.getCode());
        } else {
          // unknown param type
          throw new RoutingException(
              "Parameter '"
                  + param.getName()
                  + "' has an unknown parameter type '"
                  + param.getParamType().name()
                  + "'",
              HttpStatus.S_400_BAD_REQUEST.getCode());
        }
      } catch (TemplateRuntimeException e) {
        throw new RoutingException(
            "Parameter '" + param.getName() + "' is invalid",
            HttpStatus.S_400_BAD_REQUEST.getCode());
      }

      try {
        // Handling null-valued parameters not provided in resource context or entity body
        // check if it is optional parameter
        if (param.isOptional() && param.hasDefaultValue()) {
          arguments[i] = param.getDefaultValue();
        } else if (param.isOptional() && !param.getType().isPrimitive()) {
          // optional primitive parameter must have default value or provided
          arguments[i] = null;
        } else {
          throw new RoutingException(
              "Parameter '" + param.getName() + "' is required",
              HttpStatus.S_400_BAD_REQUEST.getCode());
        }
      } catch (ResourceConfigException e) {
        // Parameter default value format exception should result in server error code 500.
        throw new RestLiServiceException(
            HttpStatus.S_500_INTERNAL_SERVER_ERROR,
            "Parameter '" + param.getName() + "' default value is invalid",
            e);
      }
    }
    return arguments;
  }