diff --git a/docs/openapi.yaml b/docs/openapi.yaml
index 476277151..107bc219f 100644
--- a/docs/openapi.yaml
+++ b/docs/openapi.yaml
@@ -300,7 +300,7 @@ paths:
- name: q
in: query
- description: 'The attribute query is used for querying allowed quantitative properties.
Used to query on a value of a resource attribute using `<`,`>`,`<=`,`>=`,`!=`, `==` operators.
For e.g, attribute > value, attribute < value, attribute >= value, attribute <= value, attribute != value and attribute == value.
Allowed values for all operators is double.
For the operator `==` if the query is on `id` then the only value allowed is an `data exchange ID` of a resource.'
+ description: 'The attribute query is used for querying allowed quantitative properties.
Used to query on a value of a resource attribute using `<`,`>`,`<=`,`>=`,`!=`, `==` operators.
Additionally, a user can search a resource attribute with a alpha-numeric value using `==` operator. For e.g, attribute > value, attribute < value, attribute >= value, attribute <= value, attribute != value and attribute == value.
Allowed values for all operators is double, and as a special case alpha-nmeric values are allowed for `==`.
For the operator `==` if the query is on `id` then the only value allowed is an `data exchange ID` of a resource.'
schema:
type: string
maxLength: 512
@@ -405,6 +405,12 @@ paths:
curl --location -g --request GET 'https://example.com/ngsi-ld/v1/entities?id=UUID&geoproperty=location&georel=near;maxDistance=10&geometry=Point&coordinates=[21.178,72.834]&options=count' \
--header 'token: '
+ - lang: 'cURL'
+ label: 'search by string attribute'
+ source: |
+ curl --location --request GET 'https://example.com/ngsi-ld/v1/entities?id=UUID&offset=0&limit=10&q=license_plate==GJ05BU3663' \
+ --header 'token: '
+
deprecated: false
description: |
@@ -452,7 +458,7 @@ paths:
The attribute query is used for querying allowed quantitative properties.
- Used to query on a value of a resource attribute using `<`,`>`,`<=`,`>=`,`!=`,`==` operators.
- For e.g, attribute > value, attribute < value, attribute >= value, attribute <= value and attribute == value.
- - Allowed values for all operators is double.
+ - Allowed values for all operators is double and alphanumeric for `==` operator.
- For the operator `==` if the query is on `id` then the only value allowed is an `data exchange ID` of a resource.
- e.g, `q=attribute-name>attribute-value`
diff --git a/src/main/java/iudx/resource/server/apiserver/handlers/FailureHandler.java b/src/main/java/iudx/resource/server/apiserver/handlers/FailureHandler.java
index 7d2b3b0b0..23b059644 100644
--- a/src/main/java/iudx/resource/server/apiserver/handlers/FailureHandler.java
+++ b/src/main/java/iudx/resource/server/apiserver/handlers/FailureHandler.java
@@ -29,7 +29,7 @@ public void handle(RoutingContext context) {
new RestResponse.Builder()
.withType(exception.getUrn().getUrn())
.withTitle(code.getDescription())
- .withMessage(code.getDescription())
+ .withMessage(exception.getMessage())
.build()
.toJson();
diff --git a/src/main/java/iudx/resource/server/apiserver/query/QueryMapper.java b/src/main/java/iudx/resource/server/apiserver/query/QueryMapper.java
index 553bf69d0..e4cfaf7ed 100644
--- a/src/main/java/iudx/resource/server/apiserver/query/QueryMapper.java
+++ b/src/main/java/iudx/resource/server/apiserver/query/QueryMapper.java
@@ -1,19 +1,20 @@
package iudx.resource.server.apiserver.query;
+import static iudx.resource.server.apiserver.util.Constants.*;
import static iudx.resource.server.common.HttpStatusCode.BAD_REQUEST;
-import static iudx.resource.server.common.ResponseUrn.INVALID_ATTR_PARAM_URN;
-import static iudx.resource.server.common.ResponseUrn.INVALID_GEO_PARAM_URN;
+import static iudx.resource.server.common.ResponseUrn.*;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import iudx.resource.server.apiserver.exceptions.DxRuntimeException;
import iudx.resource.server.apiserver.util.Constants;
+import iudx.resource.server.common.HttpStatusCode;
import iudx.resource.server.common.ResponseUrn;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Arrays;
-import java.util.List;
+import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -55,14 +56,14 @@ public JsonObject toJson(NgsildQueryParams params, boolean isTemporal, boolean i
if (params.getId() != null) {
JsonArray jsonArray = new JsonArray();
params.getId().forEach(s -> jsonArray.add(s.toString()));
- json.put(Constants.JSON_ID, jsonArray);
+ json.put(JSON_ID, jsonArray);
LOGGER.debug("Info : json " + json);
}
if (params.getAttrs() != null) {
isResponseFilter = true;
JsonArray jsonArray = new JsonArray();
params.getAttrs().forEach(attribute -> jsonArray.add(attribute));
- json.put(Constants.JSON_ATTRIBUTE_FILTER, jsonArray);
+ json.put(JSON_ATTRIBUTE_FILTER, jsonArray);
LOGGER.debug("Info : json " + json);
}
if (isGeoQuery(params)) {
@@ -71,23 +72,23 @@ public JsonObject toJson(NgsildQueryParams params, boolean isTemporal, boolean i
&& params.getGeometry() != null
&& params.getGeoProperty() != null) {
isGeoSearch = true;
- if (params.getGeometry().equalsIgnoreCase(Constants.GEOM_POINT)
- && params.getGeoRel().getRelation().equals(Constants.JSON_NEAR)
+ if (params.getGeometry().equalsIgnoreCase(GEOM_POINT)
+ && params.getGeoRel().getRelation().equals(JSON_NEAR)
&& params.getGeoRel().getMaxDistance() != null) {
String[] coords = params.getCoordinates().replaceAll("\\[|\\]", "").split(",");
- json.put(Constants.JSON_LAT, Double.parseDouble(coords[0]));
- json.put(Constants.JSON_LON, Double.parseDouble(coords[1]));
- json.put(Constants.JSON_RADIUS, params.getGeoRel().getMaxDistance());
+ json.put(JSON_LAT, Double.parseDouble(coords[0]));
+ json.put(JSON_LON, Double.parseDouble(coords[1]));
+ json.put(JSON_RADIUS, params.getGeoRel().getMaxDistance());
} else {
- json.put(Constants.JSON_GEOMETRY, params.getGeometry());
- json.put(Constants.JSON_COORDINATES, params.getCoordinates());
+ json.put(JSON_GEOMETRY, params.getGeometry());
+ json.put(JSON_COORDINATES, params.getCoordinates());
json.put(
- Constants.JSON_GEOREL,
- getOrDefault(params.getGeoRel().getRelation(), Constants.JSON_WITHIN));
+ JSON_GEOREL,
+ getOrDefault(params.getGeoRel().getRelation(), JSON_WITHIN));
if (params.getGeoRel().getMaxDistance() != null) {
- json.put(Constants.JSON_MAXDISTANCE, params.getGeoRel().getMaxDistance());
+ json.put(JSON_MAXDISTANCE, params.getGeoRel().getMaxDistance());
} else if (params.getGeoRel().getMinDistance() != null) {
- json.put(Constants.JSON_MINDISTANCE, params.getGeoRel().getMinDistance());
+ json.put(JSON_MINDISTANCE, params.getGeoRel().getMinDistance());
}
}
LOGGER.debug("Info : json " + json);
@@ -106,22 +107,22 @@ public JsonObject toJson(NgsildQueryParams params, boolean isTemporal, boolean i
&& params.getTemporalRelation().getTemprel() != null
&& params.getTemporalRelation().getTime() != null) {
isTemporal = true;
- if (params.getTemporalRelation().getTemprel().equalsIgnoreCase(Constants.JSON_DURING)
- || params.getTemporalRelation().getTemprel().equalsIgnoreCase(Constants.JSON_BETWEEN)) {
+ if (params.getTemporalRelation().getTemprel().equalsIgnoreCase(JSON_DURING)
+ || params.getTemporalRelation().getTemprel().equalsIgnoreCase(JSON_BETWEEN)) {
LOGGER.debug("Info : inside during ");
- json.put(Constants.JSON_TIME, params.getTemporalRelation().getTime());
- json.put(Constants.JSON_ENDTIME, params.getTemporalRelation().getEndTime());
- json.put(Constants.JSON_TIMEREL, params.getTemporalRelation().getTemprel());
+ json.put(JSON_TIME, params.getTemporalRelation().getTime());
+ json.put(JSON_ENDTIME, params.getTemporalRelation().getEndTime());
+ json.put(JSON_TIMEREL, params.getTemporalRelation().getTemprel());
isValidTimeInterval(
- Constants.JSON_DURING,
- json.getString(Constants.JSON_TIME),
- json.getString(Constants.JSON_ENDTIME),
+ JSON_DURING,
+ json.getString(JSON_TIME),
+ json.getString(JSON_ENDTIME),
isAsyncQuery);
} else {
- json.put(Constants.JSON_TIME, params.getTemporalRelation().getTime().toString());
- json.put(Constants.JSON_TIMEREL, params.getTemporalRelation().getTemprel());
+ json.put(JSON_TIME, params.getTemporalRelation().getTime().toString());
+ json.put(JSON_TIMEREL, params.getTemporalRelation().getTemprel());
}
LOGGER.debug("Info : json " + json);
}
@@ -132,25 +133,25 @@ public JsonObject toJson(NgsildQueryParams params, boolean isTemporal, boolean i
for (String term : qterms) {
query.add(getQueryTerms(term));
}
- json.put(Constants.JSON_ATTR_QUERY, query);
+ json.put(JSON_ATTR_QUERY, query);
LOGGER.debug("Info : json " + json);
}
if (params.getGeoProperty() != null) {
- json.put(Constants.JSON_GEOPROPERTY, params.getGeoProperty());
+ json.put(JSON_GEOPROPERTY, params.getGeoProperty());
LOGGER.debug("Info : json " + json);
}
if (params.getOptions() != null) {
- json.put(Constants.IUDXQUERY_OPTIONS, params.getOptions());
+ json.put(IUDXQUERY_OPTIONS, params.getOptions());
LOGGER.debug("Info : json " + json);
}
if (params.getPageFrom() != null) {
- json.put(Constants.NGSILDQUERY_FROM, params.getPageFrom());
+ json.put(NGSILDQUERY_FROM, params.getPageFrom());
}
if (params.getPageSize() != null) {
- json.put(Constants.NGSILDQUERY_SIZE, params.getPageSize());
+ json.put(NGSILDQUERY_SIZE, params.getPageSize());
}
- json.put(Constants.JSON_SEARCH_TYPE, getSearchType(isAsyncQuery));
+ json.put(JSON_SEARCH_TYPE, getSearchType(isAsyncQuery));
LOGGER.debug("Info : json " + json);
return json;
}
@@ -162,12 +163,12 @@ public JsonObject toJson(NgsildQueryParams params, boolean isTemporal, boolean i
private void isValidTimeInterval(
String timeRel, String time, String endTime, boolean isAsyncQuery) {
long totalDaysAllowed = 0;
- if (timeRel.equalsIgnoreCase(Constants.JSON_DURING)) {
+ if (timeRel.equalsIgnoreCase(JSON_DURING)) {
if (isNullorEmpty(time) || isNullorEmpty(endTime)) {
DxRuntimeException ex =
new DxRuntimeException(
BAD_REQUEST.getValue(),
- ResponseUrn.INVALID_TEMPORAL_PARAM_URN,
+ INVALID_TEMPORAL_PARAM_URN,
"time and endTime both are mandatory for during Query.");
this.context.fail(400, ex);
}
@@ -181,25 +182,25 @@ private void isValidTimeInterval(
DxRuntimeException exc =
new DxRuntimeException(
BAD_REQUEST.getValue(),
- ResponseUrn.INVALID_TEMPORAL_PARAM_URN,
+ INVALID_TEMPORAL_PARAM_URN,
"time and endTime both are mandatory for during Query.");
this.context.fail(400, exc);
}
}
if (isAsyncQuery
- && totalDaysAllowed > Constants.VALIDATION_MAX_DAYS_INTERVAL_ALLOWED_FOR_ASYNC) {
+ && totalDaysAllowed > VALIDATION_MAX_DAYS_INTERVAL_ALLOWED_FOR_ASYNC) {
DxRuntimeException ex =
new DxRuntimeException(
BAD_REQUEST.getValue(),
- ResponseUrn.INVALID_TEMPORAL_PARAM_URN,
+ INVALID_TEMPORAL_PARAM_URN,
"time interval greater than 1 year is not allowed");
this.context.fail(400, ex);
}
- if (!isAsyncQuery && totalDaysAllowed > Constants.VALIDATION_MAX_DAYS_INTERVAL_ALLOWED) {
+ if (!isAsyncQuery && totalDaysAllowed > VALIDATION_MAX_DAYS_INTERVAL_ALLOWED) {
DxRuntimeException ex =
new DxRuntimeException(
BAD_REQUEST.getValue(),
- ResponseUrn.INVALID_TEMPORAL_PARAM_URN,
+ INVALID_TEMPORAL_PARAM_URN,
"time interval greater than 10 days is not allowed");
this.context.fail(400, ex);
}
@@ -228,59 +229,62 @@ private T getOrDefault(T value, T def) {
private String getSearchType(boolean isAsyncQuery) {
StringBuilder searchType = new StringBuilder();
if (isTemporal) {
- searchType.append(Constants.JSON_TEMPORAL_SEARCH);
+ searchType.append(JSON_TEMPORAL_SEARCH);
} else if (!isTemporal && !isAsyncQuery) {
- searchType.append(Constants.JSON_LATEST_SEARCH);
+ searchType.append(JSON_LATEST_SEARCH);
}
if (isGeoSearch) {
- searchType.append(Constants.JSON_GEO_SEARCH);
+ searchType.append(JSON_GEO_SEARCH);
}
if (isResponseFilter) {
- searchType.append(Constants.JSON_RESPONSE_FILTER_SEARCH);
+ searchType.append(JSON_RESPONSE_FILTER_SEARCH);
}
if (isAttributeSearch) {
- searchType.append(Constants.JSON_ATTRIBUTE_SEARCH);
+ searchType.append(JSON_ATTRIBUTE_SEARCH);
}
return searchType.toString().isEmpty()
? ""
: searchType.substring(0, searchType.length() - 1).toString();
}
- JsonObject getQueryTerms(String queryTerms) {
+ JsonObject getQueryTerms(final String queryTerms) {
JsonObject json = new JsonObject();
- int length = queryTerms.length();
- List allowedSpecialCharacter = Arrays.asList('>', '=', '<', '!');
- List allowedOperators = Arrays.asList(">", "=", "<", ">=", "<=", "==", "!=");
- int startIndex = 0;
- boolean specialCharFound = false;
- for (int i = 0; i < length; i++) {
- Character c = queryTerms.charAt(i);
- if (!(Character.isLetter(c) || Character.isDigit(c)) && !specialCharFound) {
- if (allowedSpecialCharacter.contains(c)) {
- json.put(Constants.JSON_ATTRIBUTE, queryTerms.substring(startIndex, i));
- startIndex = i;
- specialCharFound = true;
- } else {
- LOGGER.debug("Ignore " + c.toString());
- DxRuntimeException ex =
- new DxRuntimeException(
- BAD_REQUEST.getValue(), INVALID_ATTR_PARAM_URN, "Operator not allowed.");
- this.context.fail(400, ex);
- }
+ String jsonOperator = "";
+ String jsonValue = "";
+ String jsonAttribute = "";
+
+ String[] attributes = queryTerms.split(";");
+ LOGGER.info("Attributes : {} ", attributes);
+
+ for (String attr : attributes) {
+
+ String[] attributeQueryTerms =
+ attr.split("((?=>)|(?<=>)|(?=<)|(?<=<)|(?<==)|(?=!)|(?<=!)|(?==)|(?===))");
+ LOGGER.info(Arrays.stream(attributeQueryTerms).collect(Collectors.toList()));
+ LOGGER.info(attributeQueryTerms.length);
+ if (attributeQueryTerms.length == 3) {
+ jsonOperator = attributeQueryTerms[1];
+ jsonValue = attributeQueryTerms[2];
+ json.put(JSON_OPERATOR, jsonOperator).put(JSON_VALUE, jsonValue);
+ } else if (attributeQueryTerms.length == 4) {
+ jsonOperator = attributeQueryTerms[1].concat(attributeQueryTerms[2]);
+ jsonValue = attributeQueryTerms[3];
+ json.put(JSON_OPERATOR, jsonOperator).put(JSON_VALUE, jsonValue);
} else {
- if (specialCharFound && (Character.isLetter(c) || Character.isDigit(c))) {
- json.put(Constants.JSON_OPERATOR, queryTerms.substring(startIndex, i));
- json.put(Constants.JSON_VALUE, queryTerms.substring(i));
- break;
- }
+ throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage());
}
+ jsonAttribute = attributeQueryTerms[0];
+ json.put(JSON_ATTRIBUTE, jsonAttribute);
}
- if (!allowedOperators.contains(json.getString(Constants.JSON_OPERATOR))) {
- DxRuntimeException ex =
- new DxRuntimeException(
- BAD_REQUEST.getValue(), INVALID_ATTR_PARAM_URN, "Operator not allowed.");
- this.context.fail(400, ex);
- }
+
return json;
}
+
+ public int failureCode() {
+ return HttpStatusCode.BAD_REQUEST.getValue();
+ }
+
+ public String failureMessage() {
+ return INVALID_PARAM_VALUE_URN.getMessage();
+ }
}
diff --git a/src/main/java/iudx/resource/server/apiserver/util/Constants.java b/src/main/java/iudx/resource/server/apiserver/util/Constants.java
index 7ada10fc2..f2b0053a9 100644
--- a/src/main/java/iudx/resource/server/apiserver/util/Constants.java
+++ b/src/main/java/iudx/resource/server/apiserver/util/Constants.java
@@ -281,6 +281,7 @@ public class Constants {
List.of("during", "between");
public static final Pattern VALIDATION_Q_ATTR_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{1,100}$");
+ public static final Pattern VALIDATION_Q_VALUE_PATTERN = Pattern.compile("^[a-zA-Z0-9_.]{1,100}$");
// subscriptions queries
public static final String CREATE_SUB_SQL =
diff --git a/src/main/java/iudx/resource/server/apiserver/validation/types/QtypeValidator.java b/src/main/java/iudx/resource/server/apiserver/validation/types/QtypeValidator.java
index 77b8c817e..1dd43aaad 100644
--- a/src/main/java/iudx/resource/server/apiserver/validation/types/QtypeValidator.java
+++ b/src/main/java/iudx/resource/server/apiserver/validation/types/QtypeValidator.java
@@ -24,18 +24,14 @@ public QtypeValidator(final String value, final boolean required) {
this.required = required;
}
- private boolean isValidOperator(final String value) {
- return VALIDATION_ALLOWED_OPERATORS.contains(value);
- }
-
- public boolean isValidValue(final String value) {
- try {
- Float.parseFloat(value);
- return true;
- } catch (NumberFormatException ex) {
- LOGGER.info("Passed value in q parameter is not float");
- throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(value));
- }
+ private boolean isValidOperator(final String value, final boolean isNumericString) {
+ LOGGER.info(value);
+ LOGGER.info(value.equalsIgnoreCase("=="));
+ LOGGER.info(isNumericString);
+ LOGGER.info(VALIDATION_ALLOWED_OPERATORS.contains(value));
+ return isNumericString
+ ? VALIDATION_ALLOWED_OPERATORS.contains(value)
+ : value.equalsIgnoreCase("==");
}
private boolean isValidId(final JsonObject json) {
@@ -48,42 +44,84 @@ private boolean isValidId(final JsonObject json) {
}
}
- public boolean isValidAttributeValue(final String value) {
- LOGGER.debug("value,{},{}", value, VALIDATION_Q_ATTR_PATTERN.matcher(value).matches());
+
+ public boolean isValidAttribute(final String value) {
+ LOGGER.info("value,{},{}", value, VALIDATION_Q_ATTR_PATTERN.matcher(value).matches());
return VALIDATION_Q_ATTR_PATTERN.matcher(value).matches();
}
+ public boolean isValidAttributeValue(final String value) {
+ LOGGER.info("value,{},{}", value, VALIDATION_Q_VALUE_PATTERN.matcher(value).matches());
+ return VALIDATION_Q_VALUE_PATTERN.matcher(value).matches();
+ }
+
+
+
JsonObject getQueryTerms(final String queryTerms) {
JsonObject json = new JsonObject();
+ String jsonOperator = "";
+ String jsonValue = "";
+ String jsonAttribute = "";
String[] attributes = queryTerms.split(";");
- LOGGER.debug(attributes);
+ LOGGER.info("Attributes : {} ", attributes);
for (String attr : attributes) {
String[] attributeQueryTerms =
- attr.split("((?=>)|(?<=>)|(?=<)|(?<=<)|(?==)|(?<==)|(?=!)|(?<=!))");
- LOGGER.debug(Arrays.stream(attributeQueryTerms).collect(Collectors.toList()));
- LOGGER.debug(attributeQueryTerms.length);
+ attr.split("((?=>)|(?<=>)|(?=<)|(?<=<)|(?<==)|(?=!)|(?<=!)|(?==)|(?===))");
+ LOGGER.info(Arrays.stream(attributeQueryTerms).collect(Collectors.toList()));
+ LOGGER.info(attributeQueryTerms.length);
if (attributeQueryTerms.length == 3) {
- json.put(JSON_OPERATOR, attributeQueryTerms[1]).put(JSON_VALUE, attributeQueryTerms[2]);
+ jsonOperator = attributeQueryTerms[1];
+ jsonValue = attributeQueryTerms[2];
+ json.put(JSON_OPERATOR, jsonOperator).put(JSON_VALUE, jsonValue);
} else if (attributeQueryTerms.length == 4) {
- json.put(JSON_OPERATOR, attributeQueryTerms[1].concat(attributeQueryTerms[2]))
- .put(JSON_VALUE, attributeQueryTerms[3]);
+ jsonOperator = attributeQueryTerms[1].concat(attributeQueryTerms[2]);
+ jsonValue = attributeQueryTerms[3];
+ json.put(JSON_OPERATOR, jsonOperator).put(JSON_VALUE, jsonValue);
} else {
throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(value));
}
- json.put(JSON_ATTRIBUTE, attributeQueryTerms[0]);
+ jsonAttribute = attributeQueryTerms[0];
+ json.put(JSON_ATTRIBUTE, jsonAttribute);
+ boolean isNumericString = isNumericString(jsonValue);
+ if (!isValidOperator(jsonOperator, isNumericString)) {
+ LOGGER.info("invalid operator : {} ", jsonOperator);
+ throw new DxRuntimeException(
+ failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(jsonOperator));
+ }
+ if (!isValidAttribute(jsonAttribute)) {
+ LOGGER.info("invalid attribute : {} ", jsonAttribute);
+ throw new DxRuntimeException(
+ failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(jsonAttribute));
+ }
+ if (!isValidAttributeValue(jsonValue)) {
+ LOGGER.info("invalid json value : {} ", jsonValue);
+ throw new DxRuntimeException(
+ failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(jsonValue));
+ }
}
- LOGGER.debug(json);
-
return json;
}
+ private boolean isNumericString(String jsonValue) {
+ boolean isNumericString;
+ LOGGER.debug("Parsing value : {} as a float", jsonValue);
+ try {
+ Float.parseFloat(jsonValue);
+ isNumericString = true;
+ } catch (NumberFormatException ne) {
+ LOGGER.info("String based search");
+ isNumericString = false;
+ }
+ return isNumericString;
+ }
+
@Override
public boolean isValid() {
- LOGGER.debug("value : " + value + " required : " + required);
+ LOGGER.info("value : " + value + " required : " + required);
if (required && (value == null || value.isBlank())) {
LOGGER.error("Validation error : null or blank value for required mandatory field");
throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage());
@@ -104,26 +142,11 @@ public boolean isValid() {
try {
qjson = getQueryTerms(value);
} catch (Exception ex) {
- LOGGER.error("Validation error : Operator not allowed.");
- throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(value));
- }
- if (!isValidAttributeValue(qjson.getString(JSON_ATTRIBUTE))) {
- LOGGER.error("Validation error : Not a valid attribute in <> query");
- throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(value));
+ LOGGER.error("Validation error : Operation not allowed.");
+ throw ex;
}
- if (!isValidOperator(qjson.getString(JSON_OPERATOR))) {
- LOGGER.error("Validation error : Not a valid Operator in <> query");
- throw new DxRuntimeException(failureCode(), INVALID_PARAM_VALUE_URN, failureMessage(value));
- }
- // if (!isValidAttributeValue(qJson.getString(JSON_VALUE))) {
- // throw ValidationException.ValidationExceptionFactory
- // .generateNotMatchValidationException("Not a valid attribute value in <> query");
- // }
- if (!isValidId(qjson)) {
- return false;
- }
- return true;
+ return isValidId(qjson);
}
@Override
diff --git a/src/test/java/iudx/resource/server/apiserver/integrationTests/validations/validationAPIsIT.java b/src/test/java/iudx/resource/server/apiserver/integrationTests/validations/validationAPIsIT.java
index eda2c041e..a5ee32646 100644
--- a/src/test/java/iudx/resource/server/apiserver/integrationTests/validations/validationAPIsIT.java
+++ b/src/test/java/iudx/resource/server/apiserver/integrationTests/validations/validationAPIsIT.java
@@ -361,7 +361,7 @@ void GetEntityInvOperator() {
.then()
.statusCode(400)
.body("title", equalTo("Bad Request"))
- .body("type", equalTo("urn:dx:rs:invalidAttributeParam"))
+ .body("type", equalTo("urn:dx:rs:invalidParameterValue"))
.extract()
.response();
}
diff --git a/src/test/java/iudx/resource/server/apiserver/query/QueryMapperTest.java b/src/test/java/iudx/resource/server/apiserver/query/QueryMapperTest.java
index decafba3f..53e666dbc 100644
--- a/src/test/java/iudx/resource/server/apiserver/query/QueryMapperTest.java
+++ b/src/test/java/iudx/resource/server/apiserver/query/QueryMapperTest.java
@@ -18,17 +18,17 @@
import static iudx.resource.server.apiserver.util.Constants.NGSILDQUERY_TIME;
import static iudx.resource.server.apiserver.util.Constants.NGSILDQUERY_TIMEPROPERTY;
import static iudx.resource.server.apiserver.util.Constants.NGSILDQUERY_TIMEREL;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.stream.Stream;
+
+import iudx.resource.server.apiserver.exceptions.DxRuntimeException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
@@ -50,10 +50,21 @@
@ExtendWith({VertxExtension.class,MockitoExtension.class})
public class QueryMapperTest {
- private QueryMapper qm;
@Mock
RoutingContext context;
+ private QueryMapper qm;
+ static Stream invalidQTermsValues() {
+ // Add any valid value which will pass successfully.
+ return Stream.of(
+ Arguments.of("refrenceLevel+10", "Operator not allowed."),
+ Arguments.of("refrenceLevel/-10", "Operator not allowed."),
+ Arguments.of("refrenceLevel<+10", "Operator not allowed."),
+ Arguments.of("refrenceLevel>&10", "Operator not allowed."),
+ Arguments.of("refrenceLevel>+10", "Operator not allowed."),
+ Arguments.of("refrenceLevel+<10", "Operator not allowed."));
+
+ }
@BeforeEach
public void setup(Vertx vertx, VertxTestContext testContext) {
@@ -136,7 +147,7 @@ public void testToJson4GeoQuery(Vertx vertx, VertxTestContext testContext) {
assertFalse(json.containsKey(NGSILDQUERY_ENDTIME));
testContext.completeNow();
}
-
+
@Test
@Description("QueryMapper test for temporal queries(during)")
public void testToJson4TemporalDuringQuery(Vertx vertx, VertxTestContext testContext) {
@@ -176,7 +187,7 @@ public void testToJson4TemporalQuery(Vertx vertx, VertxTestContext testContext)
assertTrue(json.containsKey(NGSILDQUERY_TIME));
testContext.completeNow();
}
-
+
@Test
@Description("QueryMapper test for temporal queries(Invalid time format)")
public void testToJson4TemporalInvalidTimeQuery(Vertx vertx, VertxTestContext testContext) {
@@ -213,27 +224,16 @@ public void testToJson4SimpleAttributeQuery(Vertx vertx, VertxTestContext testCo
testContext.completeNow();
}
-
- static Stream invalidQTermsValues() {
- // Add any valid value which will pass successfully.
- return Stream.of(
- Arguments.of("refrenceLevel+10", "Operator not allowed."),
- Arguments.of("refrenceLevel/-10", "Operator not allowed."),
- Arguments.of("refrenceLevel<>10", "Operator not allowed."),
- Arguments.of("refrenceLevel><10", "Operator not allowed."),
- Arguments.of("refrenceLevel>+10", "Operator not allowed."),
- Arguments.of("refrenceLevel+<10", "Operator not allowed."));
-
- }
-
@ParameterizedTest
+ @Disabled /* Request Validation Check done in QTypeValidator - Unit is not responsible for checking validity*/
@MethodSource("invalidQTermsValues")
@Description("coordinates type parameter invalid values.")
public void testInvalidQTermValue(String value, String result, Vertx vertx,
VertxTestContext testContext) {
-
- qm.getQueryTerms(value);
- verify(context,atLeast(1)).fail(anyInt(),any());
+
+ Exception exception = assertThrows(DxRuntimeException.class, () -> qm.getQueryTerms(value));
+ String expectedMessage = exception.getMessage();
+ System.out.println(expectedMessage);
testContext.completeNow();
}
diff --git a/src/test/java/iudx/resource/server/apiserver/validation/QtypeValidatorTest.java b/src/test/java/iudx/resource/server/apiserver/validation/QtypeValidatorTest.java
index 7763404cd..702b24274 100644
--- a/src/test/java/iudx/resource/server/apiserver/validation/QtypeValidatorTest.java
+++ b/src/test/java/iudx/resource/server/apiserver/validation/QtypeValidatorTest.java
@@ -69,7 +69,7 @@ static Stream validValues() {
return Stream.of(
Arguments.of("referenceLevel>15.0", true),
Arguments.of(
- "id==iisc.ac.in/89a36273d77dac4cf38114fca1bbe64392547f86/rs.iudx.io/pune-env-flood/FWR055",
+ "license_plate==GJ05BU3663",
true),
Arguments.of(null, false));
}
@@ -77,7 +77,7 @@ static Stream validValues() {
@ParameterizedTest
@MethodSource("validValues")
@Description("success for valid q query")
- public void testValidQValue(String value, boolean required, Vertx vertx,
+ public void testValidQValue(String value, boolean required,
VertxTestContext testContext) {
qTypeValidator = new QtypeValidator(value, required);
assertTrue(qTypeValidator.isValid());
@@ -86,11 +86,11 @@ public void testValidQValue(String value, boolean required, Vertx vertx,
@ParameterizedTest
- @ValueSource(strings = {"","abcd","abcdeF","---"})
+ @ValueSource(strings = {"","abcd$","abcdeF**","---"})
@DisplayName("Test isValidValue method : with invalid value")
public void test_isValidValue_with_invalid_input(String input,VertxTestContext vertxTestContext)
{
- assertThrows(DxRuntimeException.class,()-> qTypeValidator.isValidValue(input));
+ assertFalse(qTypeValidator.isValidAttributeValue(input));
vertxTestContext.completeNow();
}
@@ -100,7 +100,7 @@ public void test_isValidValue_with_invalid_input(String input,VertxTestContext v
@DisplayName("Test isValidValue method : with invalid value")
public void test_isValidValue_with_valid_input(String input,VertxTestContext vertxTestContext)
{
- assertTrue( qTypeValidator.isValidValue(input));
+ assertTrue( qTypeValidator.isValidAttributeValue(input));
vertxTestContext.completeNow();
}
diff --git a/src/test/resources/IUDX-Resource-Server-Consumer-APIs-V5.5.0.postman_collection.json b/src/test/resources/IUDX-Resource-Server-Consumer-APIs-V5.5.0.postman_collection.json
index ad650f5c8..c131bf76e 100644
--- a/src/test/resources/IUDX-Resource-Server-Consumer-APIs-V5.5.0.postman_collection.json
+++ b/src/test/resources/IUDX-Resource-Server-Consumer-APIs-V5.5.0.postman_collection.json
@@ -1,9 +1,9 @@
{
"info": {
- "_postman_id": "1e242c76-0800-47be-a499-5caad292c700",
+ "_postman_id": "ce6bc463-6553-42fd-aca1-07f1bfb67acc",
"name": "IUDX-Resource-Server-Consumer-APIs-V5.0.0",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
- "_exporter_id": "20457128"
+ "_exporter_id": "17194681"
},
"item": [
{
@@ -9481,6 +9481,415 @@
}
]
},
+ {
+ "name": "String based Search",
+ "item": [
+ {
+ "name": "200 (Success) String ==",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 200 (OK)\", function () {",
+ " pm.response.to.have.status(200);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"title\", \"Success\");",
+ " const resultsjsonData = body.results[0];",
+ " pm.expect(body).to.have.property(\"results\");",
+ " pm.expect(resultsjsonData).to.have.property(\"id\");",
+ "});",
+ "",
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_plate==GJ05BU3663",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_plate==GJ05BU3663"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "200 (Success) Multiple String Attributes",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 200 (OK)\", function () {",
+ " pm.response.to.have.status(200);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"title\", \"Success\");",
+ " const resultsjsonData = body.results[0];",
+ " pm.expect(body).to.have.property(\"results\");",
+ " pm.expect(resultsjsonData).to.have.property(\"id\");",
+ "});",
+ "",
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_plate==GJ05BU3663;route_id==12U",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_plate==GJ05BU3663;route_id==12U"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "204 (No Content) String ==",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 200 (OK)\", function () {",
+ " pm.response.to.have.status(204);",
+ "});",
+ "",
+ "",
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_plate==GJ05BU3661",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_plate==GJ05BU3661"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "400 (Invalid Operator) String >",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 400 (Bad Request Data)\", function () {",
+ " pm.response.to.have.status(400);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"type\", \"urn:dx:rs:invalidParameterValue\");",
+ "});"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_plate>GJ05BU3663",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_plate>GJ05BU3663"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "400 (Invalid Value) String > Copy",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 400 (Bad Request Data)\", function () {",
+ " pm.response.to.have.status(400);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"type\", \"urn:dx:rs:invalidParameterValue\");",
+ "});"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_plate==!@%23$^%26*()-=_+{}:\"<>?[],./'",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_plate==!@%23$^%26*()-=_+{}:\"<>?[],./'"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "400 (Invalid Value) String > Copy 2",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 400 (Bad Request Data)\", function () {",
+ " pm.response.to.have.status(400);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"type\", \"urn:dx:rs:invalidParameterValue\");",
+ "});"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "value": "{{secureResourceToken}}",
+ "type": "text"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&offset=0&limit=10&q=license_!@%23$^==GJ05BU3663",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "offset",
+ "value": "0"
+ },
+ {
+ "key": "limit",
+ "value": "10"
+ },
+ {
+ "key": "q",
+ "value": "license_!@#$^==GJ05BU3663"
+ }
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
{
"name": "Complex Search",
"item": [
@@ -9587,6 +9996,115 @@
},
"response": []
},
+ {
+ "name": "200 (success) - Search - circle geom + temporal before + string search",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "// Test the response code",
+ "pm.test(\"response is 200 (OK)\", function () {",
+ " pm.response.to.have.status(200);",
+ "});",
+ "",
+ "// Test the response header",
+ "pm.test(\"Check response header\", function () {",
+ " pm.response.to.have.header(\"Content-Type\",\"application/json\");",
+ "});",
+ "",
+ "// Test the response",
+ "pm.test(\"Check response body\", function () { ",
+ " const body = pm.response.json();",
+ " pm.expect(body).to.have.property(\"title\", \"Success\");",
+ " const resultsjsonData = body.results[0];",
+ " pm.expect(resultsjsonData).to.have.property(\"id\");",
+ " pm.expect(resultsjsonData).to.have.property(\"speed\");",
+ "});",
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [
+ {
+ "key": "token",
+ "type": "text",
+ "value": "{{secureResourceToken}}"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{basePath}}/temporal/entities?id=83c2e5c2-3574-4e11-9530-2b1fbdfce832&geoproperty=location&georel=near;maxDistance=10&geometry=Point&coordinates=[21.178,72.834]&timerel=before&time=2020-10-19T14:00:00Z",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{basePath}}",
+ "temporal",
+ "entities"
+ ],
+ "query": [
+ {
+ "key": "id",
+ "value": "83c2e5c2-3574-4e11-9530-2b1fbdfce832"
+ },
+ {
+ "key": "geoproperty",
+ "value": "location"
+ },
+ {
+ "key": "georel",
+ "value": "near;maxDistance=10"
+ },
+ {
+ "key": "geometry",
+ "value": "Point"
+ },
+ {
+ "key": "coordinates",
+ "value": "[21.178,72.834]"
+ },
+ {
+ "key": "timerel",
+ "value": "before"
+ },
+ {
+ "key": "time",
+ "value": "2020-10-19T14:00:00Z"
+ },
+ {
+ "key": "attrs",
+ "value": "id,location,speed",
+ "disabled": true
+ },
+ {
+ "key": "options",
+ "value": "count",
+ "disabled": true
+ },
+ {
+ "key": "offset",
+ "value": "0",
+ "disabled": true
+ },
+ {
+ "key": "limit",
+ "value": "400",
+ "disabled": true
+ },
+ {
+ "key": "q",
+ "value": "license_plate==GJ05BU3663",
+ "disabled": true
+ }
+ ]
+ }
+ },
+ "response": []
+ },
{
"name": "200 (success) - Search - circle geom + temporal before + response filter with optional encryption",
"event": [