private static List<Map.Entry<String, Object>> orderMapEntries(
     RecordDataSchema schema, DataMap map) {
   List<Map.Entry<String, Object>> output = new ArrayList<Map.Entry<String, Object>>(map.size());
   List<RecordDataSchema.Field> fields = schema.getFields();
   // collect fields in the record schema in the order the fields are declared
   for (RecordDataSchema.Field field : fields) {
     String fieldName = field.getName();
     Object found = map.get(fieldName);
     if (found != null) {
       output.add(new AbstractMap.SimpleImmutableEntry<String, Object>(fieldName, found));
     }
   }
   // collect fields that are in the DataMap that is not in the record schema.
   List<Map.Entry<String, Object>> uncollected =
       new ArrayList<Map.Entry<String, Object>>(map.size() - output.size());
   for (Map.Entry<String, Object> e : map.entrySet()) {
     if (schema.contains(e.getKey()) == false) {
       uncollected.add(e);
     }
   }
   Collections.sort(
       uncollected,
       new Comparator<Map.Entry<String, Object>>() {
         @Override
         public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
           return o1.getKey().compareTo(o2.getKey());
         }
       });
   output.addAll(uncollected);
   return output;
 }
示例#2
0
  // TODO modify this method to accept a CollectionRequest as it's first parameter once our server
  // code has been
  //      updated to work with the new representation of BatchUpdateRequests and
  // BatchPartialUpdateRequests. As of now
  //      we are still converting to the old representation using
  // CollectionRequestUtil.convertToBatchRequest
  private static void checkInput(
      DataMap dataMap, Map<Long, Greeting> inputMap, Set<String> uriIds) {
    Assert.assertEquals(dataMap.size(), uriIds.size());

    for (String key : dataMap.keySet()) {
      DataMap inputDM = dataMap.getDataMap(key);
      Greeting expectedGreeting = inputMap.get(Long.parseLong(key));
      Assert.assertTrue(uriIds.contains(key));
      Assert.assertTrue(inputDM.equals(expectedGreeting.data()));
    }
  }
 /**
  * Build list of {@link Validator} instances for a given "validate" property.
  *
  * <p>The value of the "validate" property should be a {@link DataMap}.
  *
  * @param validateObject the value of the "validate" property.
  * @param path to the schema.
  * @param source is the source that contains the "validate" property. The source is usually the
  *     {@link DataSchema} that contains the "validate" property except when a field contains the
  *     "validate" property, in this case the source is a {@link RecordDataSchema.Field}.
  * @return the list of {@link Validator} instances constructed for the "validate" property.
  */
 private List<Validator> buildValidatorList(
     Object validateObject, List<String> path, Object source) {
   List<Validator> validatorList;
   if (validateObject.getClass() != DataMap.class) {
     addMessage(path, "\"validate\" property of %1$s is not a DataMap\n", source);
     validatorList = NO_VALIDATORS;
   } else {
     DataMap validateMap = (DataMap) validateObject;
     List<ValidatorInfo> validatorInfoList = new ArrayList<ValidatorInfo>(validateMap.size());
     for (Map.Entry<String, Object> entry : validateMap.entrySet()) {
       Object config = entry.getValue();
       String key = entry.getKey();
       Class<? extends Validator> clazz = locateValidatorClass(key, path, source);
       if (clazz == null) {
         addMessage(
             path,
             "\"validate\" property of %1$s, unable to find Validator for \"%2$s\"\n",
             source,
             key);
         continue;
       }
       if (config.getClass() != DataMap.class) {
         addMessage(
             path,
             "\"validate\" property of %1$s, value of \"%2$s\" is not a DataMap\n",
             source,
             key);
         continue;
       }
       try {
         Constructor<? extends Validator> ctor = clazz.getConstructor(DataMap.class);
         DataMap configDataMap = (DataMap) config;
         Integer priority = configDataMap.getInteger(VALIDATOR_PRIORITY);
         Validator validator = ctor.newInstance(configDataMap);
         validatorInfoList.add(new ValidatorInfo(priority, validator));
       } catch (Exception e) {
         addMessage(
             path,
             "\"validate\" property of %1$s, %2$s cannot be instantiated for \"%3$s\", %4$s\n",
             source,
             clazz.getName(),
             key,
             e);
       }
     }
     Collections.sort(validatorInfoList, PRIORITY_COMPARATOR);
     validatorList = new ArrayList<Validator>(validatorInfoList.size());
     for (ValidatorInfo validatorInfo : validatorInfoList) {
       validatorList.add(validatorInfo._validator);
     }
   }
   assert (validatorList != null);
   return validatorList;
 }
示例#4
0
  /**
   * Converts a String -> Object based representation of query params into a {@link DataMap}
   *
   * @param queryParams
   * @param queryParamClasses
   * @param version
   * @return
   */
  public static DataMap convertToDataMap(
      Map<String, Object> queryParams,
      Map<String, Class<?>> queryParamClasses,
      ProtocolVersion version) {
    DataMap result = new DataMap(queryParams.size());
    for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
      String key = entry.getKey();
      Object value = entry.getValue();

      if (RestConstants.PROJECTION_PARAMETERS.contains(key)) {
        @SuppressWarnings("unchecked")
        List<PathSpec> pathSpecs = (List<PathSpec>) value;
        result.put(key, MaskCreator.createPositiveMask(pathSpecs).getDataMap());
      } else {
        result.put(key, paramToDataObject(value, queryParamClasses.get(key), version));
      }
    }
    result.makeReadOnly();
    return result;
  }
  private CollectionRequest<KeyValueRecord<K, PatchRequest<V>>> buildReadOnlyInput() {
    try {
      DataMap map = new DataMap();
      @SuppressWarnings({"unchecked", "rawtypes"})
      CollectionRequest<KeyValueRecord<K, PatchRequest<V>>> input =
          new CollectionRequest(map, KeyValueRecord.class);

      for (Map.Entry<K, PatchRequest<V>> inputEntityEntry : _partialUpdateInputMap.entrySet()) {
        K key = getReadOnlyOrCopyKey(inputEntityEntry.getKey());
        PatchRequest<V> entity = getReadOnlyOrCopyDataTemplate(inputEntityEntry.getValue());
        KeyValueRecord<K, PatchRequest<V>> keyValueRecord =
            _keyValueRecordFactory.create(key, entity);
        keyValueRecord.data().setReadOnly();
        input.getElements().add(keyValueRecord);
      }

      map.setReadOnly();
      return input;
    } catch (CloneNotSupportedException cloneException) {
      throw new IllegalArgumentException("Entity cannot be copied.", cloneException);
    }
  }
 private void genericCompositionTest(
     DataMap data1, DataMap data2, DataMap expected, String description)
     throws DataProcessingException, CloneNotSupportedException {
   String dataBefore = data1.toString();
   String data2Clone = data2.toString();
   DataComplexProcessor processor = new DataComplexProcessor(new MaskComposition(), data2, data1);
   processor.run(false);
   assertEquals(
       data1,
       expected,
       "The following test failed: \n"
           + description
           + "\nData1: "
           + dataBefore
           + "\nData2: "
           + data2
           + "\nExpected: "
           + expected
           + "\nActual result: "
           + data1);
   assertEquals(data2.toString(), data2Clone, "Operation data should not be modified");
 }
示例#7
0
 /**
  * This method 'exposes' changes conveyed in the patch's meta commands to the main document.
  * Contents of $set commands are moved to the node which contains $set command. Names of removed
  * fields from $delete commands are moved to the nod which contains $delete command. The effect is
  * that patch will resemble structurally document which it is supposed to modify. This allows
  * application of projection to such patch to discover which changes relate to fields specified by
  * that projection. Examples: $delete: ['x', 'y', 'z'] => x: true, y: true, z: true $set: {x: 10,
  * y: {z: 'yeey'}, t: [10]} => x: 10, y: {z: 'yeey'}, t: [10]
  *
  * <p>This method works in-place, meaning that the doc may be mutated.
  */
 private static void expose(DataMap doc) {
   Set<String> fields = doc.keySet();
   DataMap toAdd = new DataMap();
   for (String f : fields) {
     Object v = doc.get(f);
     if (f.equals(PatchConstants.DELETE_COMMAND)) {
       for (Object removedFields : (DataList) v) {
         toAdd.put((String) removedFields, true);
       }
     } else if (f.equals(PatchConstants.SET_COMMAND)) {
       toAdd.putAll((DataMap) v);
     } else if (v instanceof DataMap) {
       expose((DataMap) v);
     }
   }
   doc.putAll(toAdd);
 }
示例#8
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));
   }
 }
示例#9
0
 static {
   EMPTY_DATAMAP.makeReadOnly();
 }
示例#10
0
    private Object translate(Object value, DataSchema dataSchema, Schema avroSchema) {
      AvroOverride avroOverride = getAvroOverride(dataSchema);
      if (avroOverride != null) {
        return avroOverride
            .getCustomDataTranslator()
            .dataToAvroGeneric(this, value, dataSchema, avroSchema);
      }

      DataSchema dereferencedDataSchema = dataSchema.getDereferencedDataSchema();
      DataSchema.Type type = dereferencedDataSchema.getType();
      Object result;
      switch (type) {
        case NULL:
          if (value != Data.NULL) {
            appendMessage("value must be null for null schema");
            result = BAD_RESULT;
            break;
          }
          result = null;
          break;
        case BOOLEAN:
          result = ((Boolean) value).booleanValue();
          break;
        case INT:
          result = ((Number) value).intValue();
          break;
        case LONG:
          result = ((Number) value).longValue();
          break;
        case FLOAT:
          result = ((Number) value).floatValue();
          break;
        case DOUBLE:
          result = ((Number) value).doubleValue();
          break;
        case STRING:
          result = new Utf8((String) value);
          break;
        case BYTES:
          result = ByteBuffer.wrap(translateBytes(value));
          break;
        case ENUM:
          String enumValue = value.toString();
          EnumDataSchema enumDataSchema = (EnumDataSchema) dereferencedDataSchema;
          if (enumDataSchema.getSymbols().contains(enumValue) == false) {
            appendMessage(
                "enum value %1$s not one of %2$s", enumValue, enumDataSchema.getSymbols());
            result = BAD_RESULT;
            break;
          }
          result = _avroAdapter.createEnumSymbol(avroSchema, enumValue);
          break;
        case FIXED:
          byte[] bytes = translateBytes(value);
          FixedDataSchema fixedDataSchema = (FixedDataSchema) dereferencedDataSchema;
          if (fixedDataSchema.getSize() != bytes.length) {
            appendMessage(
                "ByteString size %1$d != FixedDataSchema size %2$d",
                bytes.length, fixedDataSchema.getSize());
            result = null;
            break;
          }
          GenericData.Fixed fixed = new GenericData.Fixed(avroSchema);
          fixed.bytes(bytes);
          result = fixed;
          break;
        case MAP:
          DataMap map = (DataMap) value;
          DataSchema valueDataSchema = ((MapDataSchema) dereferencedDataSchema).getValues();
          Schema valueAvroSchema = avroSchema.getValueType();
          Map<String, Object> avroMap = new HashMap<String, Object>(map.size());
          for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            _path.addLast(key);
            Object entryAvroValue = translate(entry.getValue(), valueDataSchema, valueAvroSchema);
            _path.removeLast();
            avroMap.put(key, entryAvroValue);
          }
          result = avroMap;
          break;
        case ARRAY:
          DataList list = (DataList) value;
          DataSchema elementDataSchema = ((ArrayDataSchema) dereferencedDataSchema).getItems();
          Schema elementAvroSchema = avroSchema.getElementType();
          GenericData.Array<Object> avroList =
              new GenericData.Array<Object>(list.size(), avroSchema);
          for (int i = 0; i < list.size(); i++) {
            _path.addLast(i);
            Object entryAvroValue = translate(list.get(i), elementDataSchema, elementAvroSchema);
            _path.removeLast();
            avroList.add(entryAvroValue);
          }
          result = avroList;
          break;
        case RECORD:
          map = (DataMap) value;
          RecordDataSchema recordDataSchema = (RecordDataSchema) dereferencedDataSchema;
          GenericData.Record avroRecord = new GenericData.Record(avroSchema);
          for (RecordDataSchema.Field field : recordDataSchema.getFields()) {
            String fieldName = field.getName();
            DataSchema fieldDataSchema = field.getType();
            Schema.Field avroField = avroSchema.getField(fieldName);
            if (avroField == null) {
              // field present in input but there is no field for it in Avro schema.
              // TODO: Whether and how to indicate this condition to clients.
              continue;
            }
            _path.addLast(fieldName);
            Schema fieldAvroSchema = avroField.schema();
            Object fieldValue = map.get(fieldName);
            boolean isOptional = field.getOptional();
            if (isOptional) {
              if (fieldDataSchema.getDereferencedType() != DataSchema.Type.UNION) {
                if (fieldValue == null) {
                  fieldValue = Data.NULL;
                  fieldDataSchema = DataSchemaConstants.NULL_DATA_SCHEMA;
                }
                Map.Entry<String, Schema> fieldAvroEntry =
                    findUnionMember(fieldDataSchema, fieldAvroSchema);
                if (fieldAvroEntry == null) {
                  _path.removeLast();
                  continue;
                }
                fieldAvroSchema = fieldAvroEntry.getValue();
              } else {
                // already a union
                if (fieldValue == null) {
                  // field is not present
                  fieldValue = Data.NULL;
                  fieldDataSchema = DataSchemaConstants.NULL_DATA_SCHEMA;
                }
              }
            } else {
              if (fieldValue == null) {
                appendMessage("required field is absent");
                _path.removeLast();
                continue;
              }
            }
            Object fieldAvroValue = translate(fieldValue, fieldDataSchema, fieldAvroSchema);
            avroRecord.put(fieldName, fieldAvroValue);
            _path.removeLast();
          }
          result = avroRecord;
          break;
        case UNION:
          UnionDataSchema unionDataSchema = (UnionDataSchema) dereferencedDataSchema;
          String key;
          Object memberValue;
          if (value == Data.NULL) {
            key = DataSchemaConstants.NULL_TYPE;
            memberValue = Data.NULL;
          } else {
            map = (DataMap) value;
            Map.Entry<String, Object> entry = map.entrySet().iterator().next();
            key = entry.getKey();
            memberValue = entry.getValue();
          }
          DataSchema memberDataSchema = unionDataSchema.getType(key);
          Map.Entry<String, Schema> memberAvroEntry = findUnionMember(memberDataSchema, avroSchema);
          if (memberAvroEntry == null) {
            result = BAD_RESULT;
            break;
          }
          Schema memberAvroSchema = memberAvroEntry.getValue();
          _path.addLast(memberAvroEntry.getKey());
          Object memberAvroValue = translate(memberValue, memberDataSchema, memberAvroSchema);
          _path.removeLast();
          result = memberAvroValue;
          break;
        default:
          appendMessage("schema type unknown %1$s", dereferencedDataSchema.getType());
          result = BAD_RESULT;
          break;
      }
      return result;
    }
示例#11
0
    private Object translate(Object value, DataSchema dataSchema, Schema avroSchema) {
      AvroOverride avroOverride = getAvroOverride(dataSchema);
      if (avroOverride != null) {
        return avroOverride
            .getCustomDataTranslator()
            .avroGenericToData(this, value, avroSchema, dataSchema);
      }

      DataSchema dereferencedDataSchema = dataSchema.getDereferencedDataSchema();
      DataSchema.Type type = dereferencedDataSchema.getType();
      Object result;
      switch (type) {
        case NULL:
          if (value != null) {
            appendMessage("value must be null for null schema");
            result = BAD_RESULT;
            break;
          }
          result = Data.NULL;
          break;
        case BOOLEAN:
          result = ((Boolean) value).booleanValue();
          break;
        case INT:
          result = ((Number) value).intValue();
          break;
        case LONG:
          result = ((Number) value).longValue();
          break;
        case FLOAT:
          result = ((Number) value).floatValue();
          break;
        case DOUBLE:
          result = ((Number) value).doubleValue();
          break;
        case STRING:
          result = value.toString();
          break;
        case BYTES:
          ByteBuffer byteBuffer = (ByteBuffer) value;
          ByteString byteString = ByteString.copy(byteBuffer);
          byteBuffer.rewind();
          result = byteString;
          break;
        case ENUM:
          String enumValue = value.toString();
          EnumDataSchema enumDataSchema = (EnumDataSchema) dereferencedDataSchema;
          if (enumDataSchema.getSymbols().contains(enumValue) == false) {
            appendMessage(
                "enum value %1$s not one of %2$s", enumValue, enumDataSchema.getSymbols());
            result = BAD_RESULT;
            break;
          }
          result = enumValue;
          break;
        case FIXED:
          GenericFixed fixed = (GenericFixed) value;
          byte[] fixedBytes = fixed.bytes();
          FixedDataSchema fixedDataSchema = (FixedDataSchema) dereferencedDataSchema;
          if (fixedDataSchema.getSize() != fixedBytes.length) {
            appendMessage(
                "GenericFixed size %1$d != FixedDataSchema size %2$d",
                fixedBytes.length, fixedDataSchema.getSize());
            result = BAD_RESULT;
            break;
          }
          byteString = ByteString.copy(fixedBytes);
          result = byteString;
          break;
        case MAP:
          @SuppressWarnings("unchecked")
          Map<?, Object> map = (Map<?, Object>) value;
          DataSchema valueDataSchema = ((MapDataSchema) dereferencedDataSchema).getValues();
          Schema valueAvroSchema = avroSchema.getValueType();
          DataMap dataMap = new DataMap(map.size());
          for (Map.Entry<?, Object> entry : map.entrySet()) {
            String key = entry.getKey().toString();
            _path.addLast(key);
            Object entryValue = translate(entry.getValue(), valueDataSchema, valueAvroSchema);
            _path.removeLast();
            dataMap.put(key, entryValue);
          }
          result = dataMap;
          break;
        case ARRAY:
          GenericArray<?> list = (GenericArray<?>) value;
          DataSchema elementDataSchema = ((ArrayDataSchema) dereferencedDataSchema).getItems();
          Schema elementAvroSchema = avroSchema.getElementType();
          DataList dataList = new DataList(list.size());
          for (int i = 0; i < list.size(); i++) {
            _path.addLast(i);
            Object entryValue = translate(list.get(i), elementDataSchema, elementAvroSchema);
            _path.removeLast();
            dataList.add(entryValue);
          }
          result = dataList;
          break;
        case RECORD:
          GenericRecord record = (GenericRecord) value;
          RecordDataSchema recordDataSchema = (RecordDataSchema) dereferencedDataSchema;
          dataMap = new DataMap(avroSchema.getFields().size());
          for (RecordDataSchema.Field field : recordDataSchema.getFields()) {
            String fieldName = field.getName();
            Object fieldValue = record.get(fieldName);
            // fieldValue could be null if the Avro schema does not contain the named field or
            // the field is present with a null value. In either case we do not add a value
            // to the translated DataMap. We do not consider optional/required/default here
            // either (i.e. it is not an error if a required field is missing); the user can
            // later call ValidateDataAgainstSchema with various
            // settings for RequiredMode to obtain the desired behaviour.
            if (fieldValue == null) {
              continue;
            }
            boolean isOptional = field.getOptional();
            DataSchema fieldDataSchema = field.getType();
            Schema fieldAvroSchema = avroSchema.getField(fieldName).schema();
            if (isOptional && (fieldDataSchema.getDereferencedType() != DataSchema.Type.UNION)) {
              // Avro schema should be union with 2 types: null and the field's type.
              Map.Entry<String, Schema> fieldAvroEntry =
                  findUnionMember(fieldDataSchema, fieldAvroSchema);
              if (fieldAvroEntry == null) {
                continue;
              }
              fieldAvroSchema = fieldAvroEntry.getValue();
            }
            _path.addLast(fieldName);
            dataMap.put(fieldName, translate(fieldValue, fieldDataSchema, fieldAvroSchema));
            _path.removeLast();
          }
          result = dataMap;
          break;
        case UNION:
          UnionDataSchema unionDataSchema = (UnionDataSchema) dereferencedDataSchema;
          Map.Entry<DataSchema, Schema> memberSchemas =
              findUnionMemberSchema(value, unionDataSchema, avroSchema);
          if (memberSchemas == null) {
            result = BAD_RESULT;
            break;
          }
          if (value == null) {
            // schema must be "null" schema
            result = Data.NULL;
          } else {
            DataSchema memberDataSchema = memberSchemas.getKey();
            Schema memberAvroSchema = memberSchemas.getValue();
            String key = memberDataSchema.getUnionMemberKey();
            dataMap = new DataMap(1);
            _path.addLast(key);
            dataMap.put(key, translate(value, memberDataSchema, memberAvroSchema));
            _path.removeLast();
            result = dataMap;
          }
          break;
        default:
          appendMessage("schema type unknown %1$s", dereferencedDataSchema.getType());
          result = BAD_RESULT;
          break;
      }
      return result;
    }
 static {
   ENTITY_BODY.put("testFieldName", "testValue");
   ENTITY_BODY.put("testInteger", 1);
 }
示例#13
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;
  }