secondLevelRelations = relationType.getRelations();
+ for (String secondLevelRelation : secondLevelRelations) {
+ Expand expand = new Expand()
+ .addElement(new PathElement(relation))
+ .addElement(new PathElement(secondLevelRelation));
+ request.getQuery().addExpand(expand);
+ JSONObject response = request.executeGet();
+ EntityUtils.checkResponse(response, request.clone().reNest(), entityCounts);
}
- } catch (JSONException e) {
- e.printStackTrace();
- Assert.fail("An Exception occurred during testing!:\n" + e.getMessage());
}
}
/**
- * This helper method is checking multilevel $expand for a collection.
+ * This helper method is checking nested expands two levels deep including
+ * select, top, skip and count options. For instance:
+ *
+ * ObservedProperties(722)?
+ * $select=name,description&
+ * $expand=Datastreams(
+ * $select=name,unitOfMeasurement,Thing,ObservedProperty;
+ * $expand=Thing(
+ * $select=name,Datastreams,Locations
+ * ),
+ * Sensor(
+ * $select=description,metadata
+ * ),
+ * ObservedProperty(
+ * $select=name,description
+ * ),
+ * Observations(
+ * $select=result,Datastream;
+ * $count=false
+ * );
+ * $count=true
+ * )
+ *
*
* @param entityType Entity type from EntityType enum list
*/
- private void checkExpandtForEntityTypeMultilevel(EntityType entityType) {
-
- List expandedRelations;
- String[] relations = EntityRelations.getRelationsListFor(entityType);
- for (String relation : relations) {
- String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation);
-
- for (String secondLevelRelation : secondLevelRelations) {
- expandedRelations = new ArrayList<>();
- expandedRelations.add(relation + "/" + secondLevelRelation);
- String response = getEntities(entityType, -1, null, null, expandedRelations);
- checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations);
+ private void checkNestedExpandForEntity(EntityType entityType, Object entityId) {
+ PathElement collectionPathElement = new PathElement(entityType.plural);
+ PathElement entityPathElement = new PathElement(entityType.plural, entityId);
+ Request request2 = new Request(rootUri);
+ request2.addElement(collectionPathElement);
+ boolean even = true;
+ long skip = 0;
+
+ List parentRelations = entityType.getRelations();
+ for (String parentRelation : parentRelations) {
+ EntityType parentRelationEntityType = EntityType.getForRelation(parentRelation);
+ List childRelations = parentRelationEntityType.getRelations();
+ for (String childRelation : childRelations) {
+ EntityType childRelationEntityType = EntityType.getForRelation(childRelation);
+ Request request = new Request(rootUri);
+ request.addElement(entityPathElement);
+ Query query = request.getQuery();
+ entityType.getHalfPropertiesRelations(query.getSelect(), even);
+ query.setCount(even);
+ query.setTop(2L);
+ query.setSkip(skip);
+ Expand expand = new Expand()
+ .addElement(new PathElement(parentRelation));
+ query.addExpand(expand);
+ even = !even;
+ skip = 1 - skip;
+
+ query = expand.getQuery();
+ query.setCount(even);
+ query.setTop(2L);
+ query.setSkip(skip);
+ parentRelationEntityType.getHalfPropertiesRelations(query.getSelect(), even);
+ expand = new Expand()
+ .addElement(new PathElement(childRelation));
+ query.addExpand(expand);
+ even = !even;
+ skip = 1 - skip;
+
+ query = expand.getQuery();
+ childRelationEntityType.getHalfPropertiesRelations(query.getSelect(), even);
+ query.setCount(even);
+ query.setTop(2L);
+ query.setSkip(skip);
+ even = !even;
+ skip = 1 - skip;
+
+ JSONObject response = request.executeGet();
+ EntityUtils.checkResponse(response, request, entityCounts);
+
+ request.getPath().clear();
+ request.addElement(collectionPathElement);
+ response = request.executeGet();
+ EntityUtils.checkResponse(response, request, entityCounts);
}
- }
- expandedRelations = new ArrayList<>();
- for (String relation : relations) {
- String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation);
- for (String secondLevelRelation : secondLevelRelations) {
- expandedRelations.add(relation + "/" + secondLevelRelation);
- String response = getEntities(entityType, -1, null, null, expandedRelations);
- checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations);
+
+ Query query1 = request2.getQuery();
+ Expand expand = new Expand()
+ .addElement(new PathElement(parentRelation));
+ query1.addExpand(expand);
+ entityType.getHalfPropertiesRelations(query1.getSelect(), even);
+ query1.setCount(even);
+ even = !even;
+
+ Query query2 = expand.getQuery();
+ for (String childRelation : childRelations) {
+ parentRelationEntityType.getHalfPropertiesRelations(query2.getSelect(), even);
+ query2.setCount(even);
+ EntityType childRelationEntityType = EntityType.getForRelation(childRelation);
+ expand = new Expand()
+ .addElement(new PathElement(childRelation));
+ query2.addExpand(expand);
+ even = !even;
+
+ Query query3 = expand.getQuery();
+ childRelationEntityType.getHalfPropertiesRelations(query3.getSelect(), even);
+ query3.setCount(even);
+ even = !even;
+
+ JSONObject response = request2.executeGet();
+ EntityUtils.checkResponse(response, request2, entityCounts);
+ even = !even;
}
}
}
@@ -1569,45 +980,13 @@ private void checkExpandtForEntityTypeMultilevel(EntityType entityType) {
* @param entityType Entity type from EntityType enum list
*/
private void checkCountForEntityType(EntityType entityType) {
+ Request request = new Request(rootUri);
+ request.addElement(new PathElement(entityType.plural));
+ request.getQuery().setCount(true);
+ EntityUtils.checkResponse(request.executeGet(), request, entityCounts);
- String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=true");
- Map responseMap = HTTPMethods.doGet(urlString);
- String response = responseMap.get("response").toString();
- int count = -1;
- try {
- count = new JSONObject(response).getInt("@iot.count");
- } catch (JSONException e) {
- Assert.fail("the query asked for count but the response does not contain count, for getting collection: " + entityType);
- }
- switch (entityType) {
- case THING:
- case LOCATION:
- case FEATURE_OF_INTEREST:
- Assert.assertEquals(count, 2, "The count for " + entityType + "should be 2, but it is " + count);
- break;
- case OBSERVED_PROPERTY:
- Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count);
- break;
- case HISTORICAL_LOCATION:
- case SENSOR:
- case DATASTREAM:
- Assert.assertEquals(count, 4, "The count for " + entityType + "should be 4, but it is " + count);
- break;
- case OBSERVATION:
- Assert.assertEquals(count, 12, "The count for " + entityType + "should be 12, but it is " + count);
- break;
- default:
- break;
- }
-
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=false");
- responseMap = HTTPMethods.doGet(urlString);
- response = responseMap.get("response").toString();
- try {
- Assert.assertNull(new JSONObject(response).getInt("@iot.count"), "the query asked for not count but the response does contain count, for getting collection: " + entityType);
- Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType);
- } catch (JSONException e) {
- }
+ request.getQuery().setCount(false);
+ EntityUtils.checkResponse(request.executeGet(), request, entityCounts);
}
/**
@@ -1615,88 +994,24 @@ private void checkCountForEntityType(EntityType entityType) {
*
* @param entityType Entity type from EntityType enum list
*/
- private void checkCountForEntityTypeRelations(EntityType entityType) {
- try {
- String[] relations = EntityRelations.getRelationsListFor(entityType);
- String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null);
- Map responseMap = HTTPMethods.doGet(urlString);
- String response = responseMap.get("response").toString();
- JSONArray array = new JSONObject(response).getJSONArray("value");
- if (array.length() == 0) {
- return;
- }
- long id = array.getJSONObject(0).getLong(ControlInformation.ID);
-
- for (String relation : relations) {
- if (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeatureOfInterest")) {
- return;
- }
- EntityType relationEntityType = getEntityTypeFor(relation);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$count=true");
- responseMap = HTTPMethods.doGet(urlString);
- response = responseMap.get("response").toString();
- int count = -1;
- try {
- count = new JSONObject(response).getInt("@iot.count");
- } catch (JSONException e) {
- Assert.fail("the query asked for count but the response does not contain count, for getting collection: " + entityType);
- }
- switch (relationEntityType) {
- case THING:
- case LOCATION:
- Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count);
- break;
- case HISTORICAL_LOCATION:
- case DATASTREAM:
- switch (entityType) {
- case THING:
- Assert.assertEquals(count, 2, "The count for " + entityType + "should be 2, but it is " + count);
- break;
- case SENSOR:
- Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count);
- break;
- case OBSERVED_PROPERTY:
- Assert.assertTrue(count == 2 || count == 1, "The count for " + entityType + "should be 1 or 2, but it is " + count);
- break;
- }
- break;
- case OBSERVATION:
- if (entityType.equals(EntityType.DATASTREAM)) {
- Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count);
- } else if (entityType.equals(EntityType.FEATURE_OF_INTEREST)) {
- Assert.assertEquals(count, 6, "The count for " + entityType + "should be 6, but it is " + count);
- }
- break;
- default:
- break;
- }
-
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$count=false");
- responseMap = HTTPMethods.doGet(urlString);
- response = responseMap.get("response").toString();
- try {
- Assert.assertNull(new JSONObject(response).getInt("@iot.count"), "the query asked for not count but the response does contain count, for getting collection: " + entityType);
- Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType);
- } catch (JSONException e) {
- }
+ private void checkCountForEntityTypeRelations(EntityType entityType, Object entityId) {
+ List relations = entityType.getRelations();
+ for (String relation : relations) {
+ if (!EntityType.isPlural(relation)) {
+ continue;
}
- } catch (JSONException e) {
- e.printStackTrace();
- Assert.fail("An Exception occurred during testing!:\n" + e.getMessage());
+ Request request = new Request(rootUri);
+ request.addElement(new PathElement(entityType.plural, entityId))
+ .addElement(new PathElement(relation));
+ Query query = request.getQuery();
+ query.setCount(true);
+ EntityUtils.checkResponse(request.executeGet(), request, entityCounts);
+
+ query.setCount(false);
+ EntityUtils.checkResponse(request.executeGet(), request, entityCounts);
}
}
- /**
- * This helper method is the start point for checking $expand response.
- *
- * @param entityType Entity type from EntityType enum list
- * @param response The response to be checked
- * @param expandedRelations List of expanded relations
- */
- private void checkEntitiesAllAspectsForExpandResponse(EntityType entityType, String response, List expandedRelations) {
- checkEntitiesRelations(entityType, response, null, expandedRelations);
- }
-
/**
* This helper method is checking $filter for a collection.
*
@@ -1705,47 +1020,52 @@ private void checkEntitiesAllAspectsForExpandResponse(EntityType entityType, Str
* should always be supported.
*/
private void checkFilterForEntityType(EntityType entityType) throws UnsupportedEncodingException {
- String[] properties = EntityProperties.getPropertiesListFor(entityType);
+ List properties = entityType.getProperties();
List filteredProperties;
List samplePropertyValues;
- for (int i = 0; i < properties.length; i++) {
+ for (int i = 0; i < properties.size(); i++) {
+ EntityType.EntityProperty property = properties.get(i);
filteredProperties = new ArrayList<>();
samplePropertyValues = new ArrayList<>();
- String property = properties[i];
- filteredProperties.add(property);
- if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) {
+ // TODO: Do we need a canFilter here, or are those sets the same?
+ if (!property.canSort) {
continue;
}
+ filteredProperties.add(property.name);
Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(entityType, i);
+ if (propertyValue == null) {
+ // No sample value available.
+ continue;
+ }
samplePropertyValues.add(propertyValue);
propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8");
- String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20lt%20" + propertyValue);
+ String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20lt%20" + propertyValue);
Map responseMap = HTTPMethods.doGet(urlString);
String response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20le%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20le%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20eq%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20eq%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20ne%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20ne%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20ge%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20ge%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20gt%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20gt%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2);
@@ -1760,8 +1080,8 @@ private void checkFilterForEntityType(EntityType entityType) throws UnsupportedE
* should always be supported.
*/
private void checkFilterForEntityTypeRelations(EntityType entityType) throws UnsupportedEncodingException {
- String[] relations = EntityRelations.getRelationsListFor(entityType);
- String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null);
+ List relations = entityType.getRelations();
+ String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null);
Map responseMap = HTTPMethods.doGet(urlString);
String response = responseMap.get("response").toString();
JSONArray array = null;
@@ -1774,61 +1094,64 @@ private void checkFilterForEntityTypeRelations(EntityType entityType) throws Uns
if (array.length() == 0) {
return;
}
- long id = 0;
+ Object id = null;
try {
- id = array.getJSONObject(0).getLong(ControlInformation.ID);
+ id = array.getJSONObject(0).get(ControlInformation.ID);
} catch (JSONException e) {
e.printStackTrace();
Assert.fail("An Exception occurred during testing!:\n" + e.getMessage());
}
for (String relation : relations) {
- if (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeatureOfInterest")) {
+ if (!EntityType.isPlural(relation)) {
return;
}
- EntityType relationEntityType = getEntityTypeFor(relation);
+ EntityType relationEntityType = EntityType.getForRelation(relation);
- String[] properties = EntityProperties.getPropertiesListFor(relationEntityType);
+ List properties = relationEntityType.getProperties();
List filteredProperties;
List samplePropertyValues;
- for (int i = 0; i < properties.length; i++) {
+ for (int i = 0; i < properties.size(); i++) {
filteredProperties = new ArrayList<>();
samplePropertyValues = new ArrayList<>();
- String property = properties[i];
- filteredProperties.add(property);
- if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) {
+ EntityType.EntityProperty property = properties.get(i);
+ if (!property.canSort) {
continue;
}
+ filteredProperties.add(property.name);
Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(relationEntityType, i);
+ if (propertyValue == null) {
+ continue;
+ }
samplePropertyValues.add(propertyValue);
propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8");
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20lt%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20lt%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20le%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20le%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20eq%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20eq%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20ne%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20ne%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20ge%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20ge%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1);
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20gt%20" + propertyValue);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20gt%20" + propertyValue);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2);
@@ -1900,40 +1223,10 @@ private void checkPropertiesForFilter(String response, List properties,
}
}
- /**
- * Find EntityType from its name string
- *
- * @param name entity type name string
- * @return The entity type from EntityType enum list
- */
- private EntityType getEntityTypeFor(String name) {
- switch (name.toLowerCase()) {
- case "thing":
- case "things":
- return EntityType.THING;
- case "location":
- case "locations":
- return EntityType.LOCATION;
- case "historicallocation":
- case "historicallocations":
- return EntityType.HISTORICAL_LOCATION;
- case "datastream":
- case "datastreams":
- return EntityType.DATASTREAM;
- case "sensor":
- case "sensors":
- return EntityType.SENSOR;
- case "observedproperty":
- case "observedproperties":
- return EntityType.OBSERVED_PROPERTY;
- case "observation":
- case "observations":
- return EntityType.OBSERVATION;
- case "featureofinterest":
- case "featuresofinterest":
- return EntityType.FEATURE_OF_INTEREST;
- }
- return null;
+ private Object postAndGetId(String urlString, String postContent) {
+ Map responseMap = HTTPMethods.doPost(urlString, postContent);
+ String response = responseMap.get("response").toString();
+ return Utils.idObjectFromPostResult(response);
}
/**
@@ -2007,41 +1300,39 @@ private void createEntities() {
+ " }\n"
+ " ]\n"
+ "}";
- String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null);
- Map responseMap = HTTPMethods.doPost(urlString, urlParameters);
- String response = responseMap.get("response").toString();
- thingId1 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")")));
+ String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, null, null, null);
+ thingId1 = postAndGetId(urlString, urlParameters);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.LOCATION, null);
- responseMap = HTTPMethods.doGet(urlString);
- response = responseMap.get("response").toString();
+ Map responseMap = HTTPMethods.doGet(urlString);
+ String response = responseMap.get("response").toString();
JSONArray array = new JSONObject(response).getJSONArray("value");
- locationId1 = array.getJSONObject(0).getLong(ControlInformation.ID);
+ locationId1 = array.getJSONObject(0).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.DATASTREAM, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
array = new JSONObject(response).getJSONArray("value");
- datastreamId1 = array.getJSONObject(0).getLong(ControlInformation.ID);
- datastreamId2 = array.getJSONObject(1).getLong(ControlInformation.ID);
+ datastreamId1 = array.getJSONObject(0).get(ControlInformation.ID);
+ datastreamId2 = array.getJSONObject(1).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.SENSOR, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- sensorId1 = new JSONObject(response).getLong(ControlInformation.ID);
+ sensorId1 = new JSONObject(response).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVED_PROPERTY, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- observedPropertyId1 = new JSONObject(response).getLong(ControlInformation.ID);
+ observedPropertyId1 = new JSONObject(response).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.SENSOR, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- sensorId2 = new JSONObject(response).getLong(ControlInformation.ID);
- urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVED_PROPERTY, null);
+ sensorId2 = new JSONObject(response).get(ControlInformation.ID);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVED_PROPERTY, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- observedPropertyId2 = new JSONObject(response).getLong(ControlInformation.ID);
+ observedPropertyId2 = new JSONObject(response).get(ControlInformation.ID);
//Second Thing
urlParameters = "{\n"
@@ -2096,7 +1387,7 @@ private void createEntities() {
+ " \"description\": \"datastream 2\",\n"
+ " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n"
+ " \"ObservedProperty\": {\n"
- + " \"@iot.id\": " + observedPropertyId2 + "\n"
+ + " \"@iot.id\": " + quoteIdForJson(observedPropertyId2) + "\n"
+ " },\n"
+ " \"Sensor\": {\n"
+ " \"name\": \"sensor 4 \",\n"
@@ -2107,43 +1398,41 @@ private void createEntities() {
+ " }\n"
+ " ]\n"
+ "}";
- urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null);
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- thingId2 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")")));
+ urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, null, null, null);
+ thingId2 = postAndGetId(urlString, urlParameters);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.LOCATION, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
array = new JSONObject(response).getJSONArray("value");
- locationId2 = array.getJSONObject(0).getLong(ControlInformation.ID);
+ locationId2 = array.getJSONObject(0).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.DATASTREAM, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
array = new JSONObject(response).getJSONArray("value");
- datastreamId3 = array.getJSONObject(0).getLong(ControlInformation.ID);
- datastreamId4 = array.getJSONObject(1).getLong(ControlInformation.ID);
+ datastreamId3 = array.getJSONObject(0).get(ControlInformation.ID);
+ datastreamId4 = array.getJSONObject(1).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.SENSOR, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- sensorId3 = new JSONObject(response).getLong(ControlInformation.ID);
+ sensorId3 = new JSONObject(response).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVED_PROPERTY, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- observedPropertyId3 = new JSONObject(response).getLong(ControlInformation.ID);
+ observedPropertyId3 = new JSONObject(response).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, EntityType.SENSOR, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- sensorId4 = new JSONObject(response).getLong(ControlInformation.ID);
+ sensorId4 = new JSONObject(response).get(ControlInformation.ID);
//HistoricalLocations
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, null, null);
urlParameters = "{\"Locations\": [\n"
+ " {\n"
- + " \"@iot.id\": " + locationId2 + "\n"
+ + " \"@iot.id\": " + quoteIdForJson(locationId2) + "\n"
+ " }\n"
+ " ]}";
HTTPMethods.doPatch(urlString, urlParameters);
@@ -2151,7 +1440,7 @@ private void createEntities() {
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, null, null);
urlParameters = "{\"Locations\": [\n"
+ " {\n"
- + " \"@iot.id\": " + locationId1 + "\n"
+ + " \"@iot.id\": " + quoteIdForJson(locationId1) + "\n"
+ " }\n"
+ " ]}";
HTTPMethods.doPatch(urlString, urlParameters);
@@ -2160,15 +1449,15 @@ private void createEntities() {
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
array = new JSONObject(response).getJSONArray("value");
- historicalLocationId1 = array.getJSONObject(0).getLong(ControlInformation.ID);
- historicalLocationId2 = array.getJSONObject(1).getLong(ControlInformation.ID);
+ historicalLocationId1 = array.getJSONObject(0).get(ControlInformation.ID);
+ historicalLocationId2 = array.getJSONObject(1).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.HISTORICAL_LOCATION, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
array = new JSONObject(response).getJSONArray("value");
- historicalLocationId3 = array.getJSONObject(0).getLong(ControlInformation.ID);
- historicalLocationId4 = array.getJSONObject(1).getLong(ControlInformation.ID);
+ historicalLocationId3 = array.getJSONObject(0).get(ControlInformation.ID);
+ historicalLocationId4 = array.getJSONObject(1).get(ControlInformation.ID);
//Observations
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVATION, null);
@@ -2176,103 +1465,116 @@ private void createEntities() {
+ " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n"
+ " \"result\": 1 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId1 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId1 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-02T00:00:00Z\",\n"
+ " \"result\": 2 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId2 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId2 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-03T00:00:00Z\",\n"
+ " \"result\": 3 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId3 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId3 = postAndGetId(urlString, urlParameters);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVATION, null);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-04T00:00:00Z\",\n"
+ " \"result\": 4 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId4 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId4 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-05T00:00:00Z\",\n"
+ " \"result\": 5 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId5 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId5 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-06T00:00:00Z\",\n"
+ " \"result\": 6 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId6 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId6 = postAndGetId(urlString, urlParameters);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVATION, null);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-07T00:00:00Z\",\n"
+ " \"result\": 7 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId7 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId7 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-08T00:00:00Z\",\n"
+ " \"result\": 8 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId8 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId8 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-09T00:00:00Z\",\n"
+ " \"result\": 9 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId9 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId9 = postAndGetId(urlString, urlParameters);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, EntityType.OBSERVATION, null);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-10T00:00:00Z\",\n"
+ " \"result\": 10 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId10 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId10 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-11T00:00:00Z\",\n"
+ " \"result\": 11 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId11 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId11 = postAndGetId(urlString, urlParameters);
urlParameters = "{\n"
+ " \"phenomenonTime\": \"2015-03-12T00:00:00Z\",\n"
+ " \"result\": 12 \n"
+ " }";
- responseMap = HTTPMethods.doPost(urlString, urlParameters);
- response = responseMap.get("response").toString();
- observationId12 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")));
+ observationId12 = postAndGetId(urlString, urlParameters);
//FeatureOfInterest
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId1, EntityType.FEATURE_OF_INTEREST, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- featureOfInterestId1 = new JSONObject(response).getLong(ControlInformation.ID);
+ featureOfInterestId1 = new JSONObject(response).get(ControlInformation.ID);
urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId7, EntityType.FEATURE_OF_INTEREST, null);
responseMap = HTTPMethods.doGet(urlString);
response = responseMap.get("response").toString();
- featureOfInterestId2 = new JSONObject(response).getLong(ControlInformation.ID);
+ featureOfInterestId2 = new JSONObject(response).get(ControlInformation.ID);
+
+ entityCounts.setGlobalCount(EntityType.DATASTREAM, 4);
+ entityCounts.setGlobalCount(EntityType.FEATURE_OF_INTEREST, 2);
+ entityCounts.setGlobalCount(EntityType.HISTORICAL_LOCATION, 4);
+ entityCounts.setGlobalCount(EntityType.LOCATION, 2);
+ entityCounts.setGlobalCount(EntityType.OBSERVATION, 12);
+ entityCounts.setGlobalCount(EntityType.OBSERVED_PROPERTY, 3);
+ entityCounts.setGlobalCount(EntityType.SENSOR, 4);
+ entityCounts.setGlobalCount(EntityType.THING, 2);
+
+ entityCounts.setCount(EntityType.THING, thingId1, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.THING, thingId2, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.THING, thingId1, EntityType.HISTORICAL_LOCATION, 2);
+ entityCounts.setCount(EntityType.THING, thingId2, EntityType.HISTORICAL_LOCATION, 2);
+ entityCounts.setCount(EntityType.THING, thingId1, EntityType.DATASTREAM, 2);
+ entityCounts.setCount(EntityType.THING, thingId2, EntityType.DATASTREAM, 2);
+ entityCounts.setCount(EntityType.LOCATION, locationId1, EntityType.THING, 1);
+ entityCounts.setCount(EntityType.LOCATION, locationId2, EntityType.THING, 1);
+ entityCounts.setCount(EntityType.LOCATION, locationId1, EntityType.HISTORICAL_LOCATION, 2);
+ entityCounts.setCount(EntityType.LOCATION, locationId2, EntityType.HISTORICAL_LOCATION, 2);
+ entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId1, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId2, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId3, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId4, EntityType.LOCATION, 1);
+ entityCounts.setCount(EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVATION, 3);
+ entityCounts.setCount(EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVATION, 3);
+ entityCounts.setCount(EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVATION, 3);
+ entityCounts.setCount(EntityType.DATASTREAM, datastreamId4, EntityType.OBSERVATION, 3);
+ entityCounts.setCount(EntityType.SENSOR, sensorId1, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.SENSOR, sensorId2, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.SENSOR, sensorId3, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.SENSOR, sensorId4, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId1, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId2, EntityType.DATASTREAM, 2);
+ entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId3, EntityType.DATASTREAM, 1);
+ entityCounts.setCount(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1, EntityType.OBSERVATION, 6);
+ entityCounts.setCount(EntityType.FEATURE_OF_INTEREST, featureOfInterestId2, EntityType.OBSERVATION, 6);
} catch (JSONException e) {
e.printStackTrace();
@@ -2281,29 +1583,6 @@ private void createEntities() {
}
- /**
- * The helper method to check if a list contains a entity name string
- *
- * @param list The list to be searched
- * @param entity The entity name to be checked
- * @return True if the entity name exists is the list, false otherwise
- */
- private boolean listContainsString(List list, String entity) {
- for (String item : list) {
- if (item.toLowerCase().contains(entity.toLowerCase())) {
- if (entity.toLowerCase().equals("locations") && (item.toLowerCase().equals("historicallocations/thing") || item.toLowerCase().equals("historicallocations") || item.toLowerCase().equals("things/historicallocations") || item.toLowerCase().equals("thing/historicallocations"))) {
- continue;
- }
- if (!entity.contains("/") && item.contains("/" + entity)) {
- continue;
- }
- return true;
-
- }
- }
- return false;
- }
-
/**
* This method is run after all the tests of this class is run and clean the
* database.
@@ -2329,13 +1608,13 @@ private void deleteEntityType(EntityType entityType) {
JSONArray array = null;
do {
try {
- String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null);
+ String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null);
Map responseMap = HTTPMethods.doGet(urlString);
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
JSONObject result = new JSONObject(responseMap.get("response").toString());
array = result.getJSONArray("value");
for (int i = 0; i < array.length(); i++) {
- long id = array.getJSONObject(i).getLong(ControlInformation.ID);
+ Object id = array.getJSONObject(i).get(ControlInformation.ID);
deleteEntity(entityType, id);
}
} catch (JSONException e) {
@@ -2352,7 +1631,7 @@ private void deleteEntityType(EntityType entityType) {
* @param entityType Entity type in from EntityType enum
* @param id The id of requested entity
*/
- private void deleteEntity(EntityType entityType, long id) {
+ private void deleteEntity(EntityType entityType, Object id) {
String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null);
Map responseMap = HTTPMethods.doDelete(urlString);
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
diff --git a/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java b/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java
index 7a0d99e..2448f50 100644
--- a/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java
+++ b/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java
@@ -4,14 +4,11 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.opengis.cite.sta10.SuiteAttribute;
import org.opengis.cite.sta10.util.ControlInformation;
-import org.opengis.cite.sta10.util.EntityProperties;
-import org.opengis.cite.sta10.util.EntityRelations;
import org.opengis.cite.sta10.util.EntityType;
import org.opengis.cite.sta10.util.HTTPMethods;
import org.opengis.cite.sta10.util.ServiceURLBuilder;
@@ -151,8 +148,8 @@ public void readPropertyOfEntityAndCheckResponse() {
private void readPropertyOfEntityWithEntityType(EntityType entityType) {
try {
String response = getEntities(entityType);
- Long id = new JSONObject(response).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID);
- for (String property : EntityProperties.getPropertiesListFor(entityType)) {
+ Object id = new JSONObject(response).getJSONArray("value").getJSONObject(0).get(ControlInformation.ID);
+ for (EntityType.EntityProperty property : entityType.getProperties()) {
checkGetPropertyOfEntity(entityType, id, property);
checkGetPropertyValueOfEntity(entityType, id, property);
}
@@ -170,20 +167,20 @@ private void readPropertyOfEntityWithEntityType(EntityType entityType) {
* @param id The id of the entity
* @param property The property to get requested
*/
- private void checkGetPropertyOfEntity(EntityType entityType, long id, String property) {
+ private void checkGetPropertyOfEntity(EntityType entityType, Object id, EntityType.EntityProperty property) {
try {
- Map responseMap = getEntity(entityType, id, property);
+ Map responseMap = getEntity(entityType, id, property.name);
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
- Assert.assertEquals(responseCode, 200, "Reading property \"" + property + "\" of the existing " + entityType.name() + " with id " + id + " failed.");
+ Assert.assertEquals(responseCode, 200, "Reading property \"" + property.name + "\" of the existing " + entityType.name() + " with id " + id + " failed.");
String response = responseMap.get("response").toString();
JSONObject entity = null;
- entity = new JSONObject(response.toString());
+ entity = new JSONObject(response);
try {
- Assert.assertNotNull(entity.get(property), "Reading property \"" + property + "\"of \"" + entityType + "\" fails.");
+ Assert.assertNotNull(entity.get(property.name), "Reading property \"" + property.name + "\"of \"" + entityType + "\" fails.");
} catch (JSONException e) {
- Assert.fail("Reading property \"" + property + "\"of \"" + entityType + "\" fails.");
+ Assert.fail("Reading property \"" + property.name + "\"of \"" + entityType + "\" fails.");
}
- Assert.assertEquals(entity.length(), 1, "The response for getting property " + property + " of a " + entityType + " returns more properties!");
+ Assert.assertEquals(entity.length(), 1, "The response for getting property " + property.name + " of a " + entityType + " returns more properties!");
} catch (JSONException e) {
e.printStackTrace();
Assert.fail("An Exception occurred during testing!:\n" + e.getMessage());
@@ -198,15 +195,19 @@ private void checkGetPropertyOfEntity(EntityType entityType, long id, String pro
* @param id The id of the entity
* @param property The property to get requested
*/
- private void checkGetPropertyValueOfEntity(EntityType entityType, long id, String property) {
- Map responseMap = getEntity(entityType, id, property + "/$value");
+ private void checkGetPropertyValueOfEntity(EntityType entityType, Object id, EntityType.EntityProperty property) {
+ Map responseMap = getEntity(entityType, id, property.name + "/$value");
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
+ if (responseCode != 200 && property.optional) {
+ // The property is optional, and probably not present.
+ return;
+ }
Assert.assertEquals(responseCode, 200, "Reading property value of \"" + property + "\" of the exitixting " + entityType.name() + " with id " + id + " failed.");
String response = responseMap.get("response").toString();
- if (!property.equals("location") && !property.equals("feature") && !property.equals("unitOfMeasurement")) {
- Assert.assertEquals(response.indexOf("{"), -1, "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails.");
+ if ("object".equalsIgnoreCase(property.jsonType)) {
+ Assert.assertEquals(response.indexOf("{"), 0, "Reading property value of \"" + property + "\" of \"" + entityType + "\" fails.");
} else {
- Assert.assertEquals(response.indexOf("{"), 0, "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails.");
+ Assert.assertEquals(response.indexOf("{"), -1, "Reading property value of \"" + property + "\" of \"" + entityType + "\" fails.");
}
}
@@ -235,35 +236,8 @@ public void checkResourcePaths() {
*/
private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) {
List entityTypes = new ArrayList<>();
- List ids = new ArrayList<>();
- switch (entityType) {
- case THING:
- entityTypes.add("Things");
- break;
- case LOCATION:
- entityTypes.add("Locations");
- break;
- case HISTORICAL_LOCATION:
- entityTypes.add("HistoricalLocations");
- break;
- case DATASTREAM:
- entityTypes.add("Datastreams");
- break;
- case SENSOR:
- entityTypes.add("Sensors");
- break;
- case OBSERVATION:
- entityTypes.add("Observations");
- break;
- case OBSERVED_PROPERTY:
- entityTypes.add("ObservedProperties");
- break;
- case FEATURE_OF_INTEREST:
- entityTypes.add("FeaturesOfInterest");
- break;
- default:
- Assert.fail("Entity type is not recognized in SensorThings API : " + entityType);
- }
+ List ids = new ArrayList<>();
+ entityTypes.add(entityType.plural);
readRelatedEntity(entityTypes, ids);
}
@@ -273,21 +247,26 @@ private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) {
*
* @param entityTypes List of entity type from EntityType enum list for the
* chain
- * @param ids List of ids for teh chain
+ * @param ids List of ids for the chain
*/
- private void readRelatedEntity(List entityTypes, List ids) {
+ private void readRelatedEntity(List entityTypes, List ids) {
if (entityTypes.size() > resourcePathLevel) {
return;
}
try {
+ String headName = entityTypes.get(entityTypes.size() - 1);
+ EntityType headEntity = EntityType.getForRelation(headName);
+ boolean isPlural = EntityType.isPlural(headName);
String urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, null);
Map responseMap = HTTPMethods.doGet(urlString);
Assert.assertEquals(responseMap.get("response-code"), 200, "Reading relation of the entity failed: " + entityTypes.toString());
String response = responseMap.get("response").toString();
- if (!entityTypes.get(entityTypes.size() - 1).toLowerCase().equals("featuresofinterest") && !entityTypes.get(entityTypes.size() - 1).endsWith("s")) {
- return;
+ Object id;
+ if (isPlural) {
+ id = new JSONObject(response).getJSONArray("value").getJSONObject(0).get(ControlInformation.ID);
+ } else {
+ id = new JSONObject(response).get(ControlInformation.ID);
}
- Long id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID);
//check $ref
urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, "$ref");
@@ -299,8 +278,12 @@ private void readRelatedEntity(List entityTypes, List ids) {
if (entityTypes.size() == resourcePathLevel) {
return;
}
- ids.add(id);
- for (String relation : EntityRelations.getRelationsListFor(entityTypes.get(entityTypes.size() - 1))) {
+ if (EntityType.isPlural(headName)) {
+ ids.add(id);
+ } else {
+ ids.add(null);
+ }
+ for (String relation : headEntity.getRelations()) {
entityTypes.add(relation);
readRelatedEntity(entityTypes, ids);
entityTypes.remove(entityTypes.size() - 1);
@@ -320,17 +303,27 @@ private void readRelatedEntity(List entityTypes, List ids) {
* @param response The response for GET association link request
* @param entityTypes List of entity type from EntityType enum list for the
* chain
- * @param ids List of ids for teh chain
+ * @param ids List of ids for the chain
*/
- private void checkAssociationLinks(String response, List entityTypes, List ids) {
+ private void checkAssociationLinks(String response, List entityTypes, List ids) {
try {
- Assert.assertTrue(response.indexOf("value") != -1, "The GET entities Association Link response does not match SensorThings API : missing \"value\" in response.: " + entityTypes.toString() + ids.toString());
- JSONArray value = new JSONObject(response.toString()).getJSONArray("value");
- int count = 0;
- for (int i = 0; i < value.length() && count < 2; i++) {
- count++;
- JSONObject obj = value.getJSONObject(i);
+ if (EntityType.isPlural(entityTypes.get(entityTypes.size() - 1))) {
+ Assert.assertTrue(response.contains("value"), "The GET entities Association Link response does not match SensorThings API : missing \"value\" in response.: " + entityTypes.toString() + ids.toString());
+ JSONArray value = new JSONObject(response).getJSONArray("value");
+ int count = 0;
+ for (int i = 0; i < value.length() && count < 2; i++) {
+ count++;
+ JSONObject obj = value.getJSONObject(i);
+ try {
+ Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), "The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString());
+ } catch (JSONException e) {
+ Assert.fail("The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString());
+ }
+ Assert.assertEquals(obj.length(), 1, "The Association Link contains properties other than self-link.: " + entityTypes.toString() + ids.toString());
+ }
+ } else {
+ JSONObject obj = new JSONObject(response);
try {
Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), "The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString());
} catch (JSONException e) {
@@ -353,7 +346,7 @@ private void checkAssociationLinks(String response, List entityTypes, Li
private String readEntityWithEntityType(EntityType entityType) {
try {
String response = getEntities(entityType);
- Long id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID);
+ Object id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).get(ControlInformation.ID);
Map responseMap = getEntity(entityType, id, null);
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
Assert.assertEquals(responseCode, 200, "Reading existing " + entityType.name() + " with id " + id + " failed.");
@@ -393,6 +386,7 @@ public void checkServiceRootUri() {
addedLinks.put("Locations", false);
addedLinks.put("HistoricalLocations", false);
addedLinks.put("Datastreams", false);
+ addedLinks.put("MultiDatastreams", false);
addedLinks.put("Sensors", false);
addedLinks.put("Observations", false);
addedLinks.put("ObservedProperties", false);
@@ -407,50 +401,11 @@ public void checkServiceRootUri() {
}
String name = entity.getString("name");
String nameUrl = entity.getString("url");
- switch (name) {
- case "Things":
- Assert.assertEquals(nameUrl, rootUri + "/Things", "The URL for Things in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("Things");
- addedLinks.put(name, true);
- break;
- case "Locations":
- Assert.assertEquals(nameUrl, rootUri + "/Locations", "The URL for Locations in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("Locations");
- addedLinks.put(name, true);
- break;
- case "HistoricalLocations":
- Assert.assertEquals(nameUrl, rootUri + "/HistoricalLocations", "The URL for HistoricalLocations in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("HistoricalLocations");
- addedLinks.put(name, true);
- break;
- case "Datastreams":
- Assert.assertEquals(nameUrl, rootUri + "/Datastreams", "The URL for Datastreams in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("Datastreams");
- addedLinks.put(name, true);
- break;
- case "Sensors":
- Assert.assertEquals(nameUrl, rootUri + "/Sensors", "The URL for Sensors in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("Sensors");
- addedLinks.put(name, true);
- break;
- case "Observations":
- Assert.assertEquals(nameUrl, rootUri + "/Observations", "The URL for Observations in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("Observations");
- addedLinks.put(name, true);
- break;
- case "ObservedProperties":
- Assert.assertEquals(nameUrl, rootUri + "/ObservedProperties", "The URL for ObservedProperties in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("ObservedProperties");
- addedLinks.put(name, true);
- break;
- case "FeaturesOfInterest":
- Assert.assertEquals(nameUrl, rootUri + "/FeaturesOfInterest", "The URL for FeaturesOfInterest in Service Root URI is not compliant to SensorThings API.");
- addedLinks.remove("FeaturesOfInterest");
- addedLinks.put(name, true);
- break;
- default:
- Assert.fail("There is a component in Service Root URI response that is not in SensorThings API : " + name);
- break;
+ if (addedLinks.containsKey(name)) {
+ Assert.assertEquals(nameUrl, rootUri + "/" + name, "The URL for " + name + " in Service Root URI is not compliant to SensorThings API.");
+ addedLinks.put(name, true);
+ } else {
+ Assert.fail("There is a component in Service Root URI response that is not in SensorThings API : " + name);
}
}
for (String key : addedLinks.keySet()) {
@@ -472,18 +427,18 @@ public void checkServiceRootUri() {
private String getEntities(EntityType entityType) {
String urlString = rootUri;
if (entityType != null) {
- urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null);
+ urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null);
}
Map responseMap = HTTPMethods.doGet(urlString);
String response = responseMap.get("response").toString();
int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
Assert.assertEquals(responseCode, 200, "Error during getting entities: " + ((entityType != null) ? entityType.name() : "root URI"));
if (entityType != null) {
- Assert.assertTrue(response.indexOf("value") != -1, "The GET entities response for entity type \"" + entityType + "\" does not match SensorThings API : missing \"value\" in response.");
+ Assert.assertTrue(response.contains("value"), "The GET entities response for entity type \"" + entityType + "\" does not match SensorThings API : missing \"value\" in response.");
} else { // GET Service Base URI
- Assert.assertTrue(response.indexOf("value") != -1, "The GET entities response for service root URI does not match SensorThings API : missing \"value\" in response.");
+ Assert.assertTrue(response.contains("value"), "The GET entities response for service root URI does not match SensorThings API : missing \"value\" in response.");
}
- return response.toString();
+ return response;
}
/**
@@ -493,10 +448,10 @@ private String getEntities(EntityType entityType) {
* @param id The if of the specific entity
* @param property The requested property of the entity
* @return The response-code and response (body) of the request in Map
- * format.
+ * format.
*/
- private Map getEntity(EntityType entityType, long id, String property) {
- if (id == -1) {
+ private Map getEntity(EntityType entityType, Object id, String property) {
+ if (id == null) {
return null;
}
String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, property);
@@ -611,9 +566,12 @@ private void checkEntitiesProperties(EntityType entityType, String response) {
private void checkEntityProperties(EntityType entityType, Object response) {
try {
JSONObject entity = new JSONObject(response.toString());
- for (String property : EntityProperties.getPropertiesListFor(entityType)) {
+ for (EntityType.EntityProperty property : entityType.getProperties()) {
+ if (property.optional) {
+ continue;
+ }
try {
- Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\".");
+ Assert.assertNotNull(entity.get(property.name), "Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\".");
} catch (JSONException e) {
Assert.fail("Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\".");
}
@@ -660,7 +618,7 @@ private void checkEntitiesRelations(EntityType entityType, String response) {
private void checkEntityRelations(EntityType entityType, Object response) {
try {
JSONObject entity = new JSONObject(response.toString());
- for (String relation : EntityRelations.getRelationsListFor(entityType)) {
+ for (String relation : entityType.getRelations()) {
try {
Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + "\".");
} catch (JSONException e) {
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java b/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java
new file mode 100644
index 0000000..4a749f1
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A helper class for keeping track of entity counts. Both global counts, and
+ * linked counts per individual entity.
+ *
+ * @author Hylke van der Schaaf
+ */
+public class EntityCounts {
+
+ private final Map globalCounts = new EnumMap<>(EntityType.class);
+ private final Map>> linkedCounts = new EnumMap<>(EntityType.class);
+
+ public long getCount(EntityType type) {
+ Long count = globalCounts.get(type);
+ return count == null ? -1 : count;
+ }
+
+ public long getCount(EntityType parentType, Object parentId, EntityType linkedType) {
+ Map> parents = linkedCounts.get(parentType);
+ if (parents == null) {
+ return -1;
+ }
+ Map parent = parents.get(parentId);
+ if (parent == null) {
+ return -1;
+ }
+ Long count = parent.get(linkedType);
+ return count == null ? -1 : count;
+ }
+
+ private Map> getParents(EntityType type) {
+ Map> parents = linkedCounts.get(type);
+ if (parents == null) {
+ parents = new HashMap<>();
+ linkedCounts.put(type, parents);
+ }
+ return parents;
+ }
+
+ private Map getCounts(EntityType parentType, Object parentId) {
+ Map> parents = getParents(parentType);
+ Map parent = parents.get(parentId);
+ if (parent == null) {
+ parent = new EnumMap<>(EntityType.class);
+ parents.put(parentId, parent);
+ }
+ return parent;
+ }
+
+ public EntityCounts setGlobalCount(EntityType type, long count) {
+ globalCounts.put(type, count);
+ return this;
+ }
+
+ public EntityCounts setCount(EntityType parentType, Object parentId, EntityType linkedType, long count) {
+ getCounts(parentType, parentId).put(linkedType, count);
+ return this;
+ }
+
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java b/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java
deleted file mode 100644
index 9ced9a5..0000000
--- a/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.opengis.cite.sta10.util;
-
-/**
- * Mandatory properties of each entity.
- */
-public class EntityProperties {
-
- /**
- * List of Mandatory properties for Thing entity.
- */
- public static final String[] THING_PROPERTIES = {"name", "description"};
- /**
- * List of Mandatory properties for Location entity.
- */
- public static final String[] LOCATION_PROPERTIES = {"name", "description", "encodingType", "location"};
- /**
- * List of Mandatory properties for HistoricalLocation entity.
- */
- public static final String[] HISTORICAL_LOCATION_PROPERTIES = {"time"};
- /**
- * List of Mandatory properties for Datastream entity.
- */
- public static final String[] DATASTREAM_PROPERTIES = {"name", "description", "unitOfMeasurement", "observationType"};
- /**
- * List of Mandatory properties for Sensor entity.
- */
- public static final String[] SENSOR_PROPERTIES = {"name", "description", "encodingType", "metadata"};
- /**
- * List of Mandatory properties for ObservedProperty entity.
- */
- public static final String[] OBSERVED_PROPETY_PROPERTIES = {"name", "definition", "description"};
- /**
- * List of Mandatory properties for Observation entity.
- */
- public static final String[] OBSERVATION_PROPERTIES = {"phenomenonTime", "result", "resultTime"};
- /**
- * List of Mandatory properties for FeatureOfInterest entity.
- */
- public static final String[] FEATURE_OF_INTEREST_PROPERTIES = {"name", "description", "encodingType", "feature"};
-
- /**
- * Returning the list of mandatory properties for the given entity name.
- *
- * @param name The type of entity in String format
- * @return List of all mandatory properties for the given entity
- */
- public static String[] getPropertiesListFor(String name) {
- switch (name.toLowerCase()) {
- case "thing":
- case "things":
- return THING_PROPERTIES;
- case "location":
- case "locations":
- return LOCATION_PROPERTIES;
- case "historicallocation":
- case "historicallocations":
- return HISTORICAL_LOCATION_PROPERTIES;
- case "datastream":
- case "datastreams":
- return DATASTREAM_PROPERTIES;
- case "sensor":
- case "sensors":
- return SENSOR_PROPERTIES;
- case "observedproperty":
- case "observedproperties":
- return OBSERVED_PROPETY_PROPERTIES;
- case "observation":
- case "observations":
- return OBSERVATION_PROPERTIES;
- case "featureofinterest":
- case "featuresofinterest":
- return FEATURE_OF_INTEREST_PROPERTIES;
- }
- return null;
- }
-
- /**
- * Returning the list of mandatory properties for the given entityType.
- *
- * @param entityType The type of entity from EntityType enum
- * @return List of all mandatory properties for the given entityType
- */
- public static String[] getPropertiesListFor(EntityType entityType) {
- switch (entityType) {
- case THING:
- return THING_PROPERTIES;
- case LOCATION:
- return LOCATION_PROPERTIES;
- case FEATURE_OF_INTEREST:
- return FEATURE_OF_INTEREST_PROPERTIES;
- case OBSERVED_PROPERTY:
- return OBSERVED_PROPETY_PROPERTIES;
- case HISTORICAL_LOCATION:
- return HISTORICAL_LOCATION_PROPERTIES;
- case SENSOR:
- return SENSOR_PROPERTIES;
- case DATASTREAM:
- return DATASTREAM_PROPERTIES;
- case OBSERVATION:
- return OBSERVATION_PROPERTIES;
- default:
- break;
- }
- return null;
- }
-}
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java b/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java
index 638783a..9df4828 100644
--- a/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java
+++ b/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java
@@ -56,25 +56,29 @@ public class EntityPropertiesSampleValue {
* "entityType" positioned in location "index" in the list
*/
public static Comparable getPropertyValueFor(EntityType entityType, int index) {
- switch (entityType) {
- case THING:
- return THING_PROPERTIES_Values[index];
- case LOCATION:
- return LOCATION_PROPERTIES_Values[index];
- case FEATURE_OF_INTEREST:
- return FEATURE_OF_INTEREST_PROPERTIES_Values[index];
- case OBSERVED_PROPERTY:
- return OBSERVED_PROPETY_PROPERTIES_Values[index];
- case HISTORICAL_LOCATION:
- return HISTORICAL_LOCATION_PROPERTIES_Values[index];
- case SENSOR:
- return SENSOR_PROPERTIES_Values[index];
- case DATASTREAM:
- return DATASTREAM_PROPERTIES_Values[index];
- case OBSERVATION:
- return OBSERVATION_PROPERTIES_Values[index];
- default:
- break;
+ try {
+ switch (entityType) {
+ case THING:
+ return THING_PROPERTIES_Values[index];
+ case LOCATION:
+ return LOCATION_PROPERTIES_Values[index];
+ case FEATURE_OF_INTEREST:
+ return FEATURE_OF_INTEREST_PROPERTIES_Values[index];
+ case OBSERVED_PROPERTY:
+ return OBSERVED_PROPETY_PROPERTIES_Values[index];
+ case HISTORICAL_LOCATION:
+ return HISTORICAL_LOCATION_PROPERTIES_Values[index];
+ case SENSOR:
+ return SENSOR_PROPERTIES_Values[index];
+ case DATASTREAM:
+ return DATASTREAM_PROPERTIES_Values[index];
+ case OBSERVATION:
+ return OBSERVATION_PROPERTIES_Values[index];
+ default:
+ break;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ // No sample value for this property...
}
return null;
}
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java b/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java
deleted file mode 100644
index c56c794..0000000
--- a/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.opengis.cite.sta10.util;
-
-/**
- * List of the entity relations for each entity type.
- */
-public class EntityRelations {
- /**
- * List of entity relations for Thing entity.
- */
- public static final String[] THING_RELATIONS = {"Datastreams", "Locations", "HistoricalLocations"};
- /**
- * List of entity relations for Location entity.
- */
- public static final String[] LOCATION_RELATIONS = {"Things", "HistoricalLocations"};
- /**
- * List of entity relations for HistoricalLocation entity.
- */
- public static final String[] HISTORICAL_LOCATION_RELATIONS = {"Thing", "Locations"};
- /**
- * List of entity relations for Datastream entity.
- */
- public static final String[] DATASTREAM_RELATIONS = {"Thing", "Sensor", "ObservedProperty", "Observations"};
- /**
- * List of entity relations for Sensor entity.
- */
- public static final String[] SENSOR_RELATIONS = {"Datastreams"};
- /**
- * List of entity relations for Observation entity.
- */
- public static final String[] OBSERVATION_RELATIONS = {"Datastream", "FeatureOfInterest"};
- /**
- * List of entity relations for ObservedProperty entity.
- */
- public static final String[] OBSERVED_PROPERTY_RELATIONS = {"Datastreams"};
- /**
- * List of entity relations for FeatureOfInterest entity.
- */
- public static final String[] FEATURE_OF_INTEREST_RELATIONS = {"Observations"};
-
-
- /**
- * Returning the list of entity relations for the given entityType.
- *
- * @param entityType The type of entity from EntityType enum
- * @return List of all entity relations for the given entityType
- */
- public static String[] getRelationsListFor(EntityType entityType) {
- switch (entityType) {
- case THING:
- return THING_RELATIONS;
- case LOCATION:
- return LOCATION_RELATIONS;
- case FEATURE_OF_INTEREST:
- return FEATURE_OF_INTEREST_RELATIONS;
- case OBSERVED_PROPERTY:
- return OBSERVED_PROPERTY_RELATIONS;
- case HISTORICAL_LOCATION:
- return HISTORICAL_LOCATION_RELATIONS;
- case SENSOR:
- return SENSOR_RELATIONS;
- case DATASTREAM:
- return DATASTREAM_RELATIONS;
- case OBSERVATION:
- return OBSERVATION_RELATIONS;
- default:
- break;
- }
- return null;
- }
-
- /**
- * Returning the list of entity relations for the given entity name.
- *
- * @param name The type of entity in String format
- * @return List of all entity relations for the given entity
- */
- public static String[] getRelationsListFor(String name) {
- switch (name.toLowerCase()) {
- case "thing":
- case "things":
- return THING_RELATIONS;
- case "location":
- case "locations":
- return LOCATION_RELATIONS;
- case "historicallocation":
- case "historicallocations":
- return HISTORICAL_LOCATION_RELATIONS;
- case "datastream":
- case "datastreams":
- return DATASTREAM_RELATIONS;
- case "sensor":
- case "sensors":
- return SENSOR_RELATIONS;
- case "observedproperty":
- case "observedproperties":
- return OBSERVED_PROPERTY_RELATIONS;
- case "observation":
- case "observations":
- return OBSERVATION_RELATIONS;
- case "featureofinterest":
- case "featuresofinterest":
- return FEATURE_OF_INTEREST_RELATIONS;
- }
- return null;
- }
-
-}
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityType.java b/src/main/java/org/opengis/cite/sta10/util/EntityType.java
index a010028..3a6998e 100644
--- a/src/main/java/org/opengis/cite/sta10/util/EntityType.java
+++ b/src/main/java/org/opengis/cite/sta10/util/EntityType.java
@@ -1,15 +1,197 @@
package org.opengis.cite.sta10.util;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
/**
* List of entity types in SensorThings API.
*/
public enum EntityType {
- THING,
- LOCATION,
- SENSOR,
- OBSERVED_PROPERTY,
- OBSERVATION,
- DATASTREAM,
- FEATURE_OF_INTEREST,
- HISTORICAL_LOCATION
+ THING("Thing", "Things"),
+ LOCATION("Location", "Locations"),
+ SENSOR("Sensor", "Sensors"),
+ OBSERVED_PROPERTY("ObservedProperty", "ObservedProperties"),
+ OBSERVATION("Observation", "Observations"),
+ DATASTREAM("Datastream", "Datastreams"),
+ FEATURE_OF_INTEREST("FeatureOfInterest", "FeaturesOfInterest"),
+ HISTORICAL_LOCATION("HistoricalLocation", "HistoricalLocations");
+
+ /**
+ * The class representing an EntityProperty.
+ */
+ public static class EntityProperty {
+
+ public final String name;
+ public final boolean optional;
+ public final boolean canSort;
+ public final String jsonType;
+
+ public EntityProperty(String name, boolean optional, boolean canSort, String jsonType) {
+ this.name = name;
+ this.optional = optional;
+ this.canSort = canSort;
+ this.jsonType = jsonType;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+ /**
+ * The singular name of the entity type.
+ */
+ public final String singular;
+ /**
+ * The plural (collection) name of the entity type.
+ */
+ public final String plural;
+ private final List properties = new ArrayList<>();
+ private final Map propertiesByName = new HashMap<>();
+ private final List relations = new ArrayList<>();
+
+ private static final Map NAMES_MAP = new HashMap<>();
+ private static final Set NAMES_PLURAL = new HashSet<>();
+
+ static {
+ // TODO: Add properties, fix test that break
+ THING.addProperty("name", false, true);
+ THING.addProperty("description", false, true);
+ THING.addProperty("properties", true, false, "object");
+ THING.addRelations(DATASTREAM.plural, HISTORICAL_LOCATION.plural, LOCATION.plural);
+
+ LOCATION.addProperty("name", false, true);
+ LOCATION.addProperty("description", false, true);
+ LOCATION.addProperty("encodingType", false, true);
+ LOCATION.addProperty("location", false, false, "object");
+ LOCATION.addRelations(HISTORICAL_LOCATION.plural, THING.plural);
+
+ SENSOR.addProperty("name", false, true);
+ SENSOR.addProperty("description", false, true);
+ SENSOR.addProperty("encodingType", false, true);
+ SENSOR.addProperty("metadata", false, true);
+ SENSOR.addRelations(DATASTREAM.plural);
+
+ OBSERVED_PROPERTY.addProperty("name", false, true);
+ OBSERVED_PROPERTY.addProperty("definition", false, true);
+ OBSERVED_PROPERTY.addProperty("description", false, true);
+ OBSERVED_PROPERTY.addRelations(DATASTREAM.plural);
+
+ OBSERVATION.addProperty("phenomenonTime", false, true);
+ OBSERVATION.addProperty("result", false, true, "any");
+ OBSERVATION.addProperty("resultTime", false, true);
+ OBSERVATION.addProperty("resultQuality", true, true);
+ OBSERVATION.addProperty("validTime", true, true);
+ OBSERVATION.addProperty("parameters", true, true, "object");
+ OBSERVATION.addRelations(DATASTREAM.singular, FEATURE_OF_INTEREST.singular);
+
+ DATASTREAM.addProperty("name", false, true);
+ DATASTREAM.addProperty("description", false, true);
+ DATASTREAM.addProperty("unitOfMeasurement", false, false, "object");
+ DATASTREAM.addProperty("observationType", false, true);
+ DATASTREAM.addProperty("observedArea", true, false, "object");
+ DATASTREAM.addProperty("phenomenonTime", true, true);
+ DATASTREAM.addProperty("resultTime", true, true);
+ DATASTREAM.addRelations(THING.singular, SENSOR.singular, OBSERVED_PROPERTY.singular, OBSERVATION.plural);
+
+ FEATURE_OF_INTEREST.addProperty("name", false, true);
+ FEATURE_OF_INTEREST.addProperty("description", false, true);
+ FEATURE_OF_INTEREST.addProperty("encodingType", false, true);
+ FEATURE_OF_INTEREST.addProperty("feature", false, false, "object");
+ FEATURE_OF_INTEREST.addRelations(OBSERVATION.plural);
+
+ HISTORICAL_LOCATION.addProperty("time", false, true);
+ HISTORICAL_LOCATION.addRelations(THING.singular, LOCATION.plural);
+
+ for (EntityType entityType : EntityType.values()) {
+ NAMES_MAP.put(entityType.singular, entityType);
+ NAMES_MAP.put(entityType.plural, entityType);
+ NAMES_PLURAL.add(entityType.plural);
+ }
+ }
+
+ public static EntityType getForRelation(String relation) {
+ EntityType entityType = NAMES_MAP.get(relation);
+ if (entityType == null) {
+ throw new IllegalArgumentException("Unknown relation: " + relation);
+ }
+ return entityType;
+ }
+
+ public static boolean isPlural(String relation) {
+ return NAMES_PLURAL.contains(relation);
+ }
+
+ private EntityType(String singular, String plural) {
+ this.singular = singular;
+ this.plural = plural;
+ }
+
+ public String getRootEntitySet() {
+ return plural;
+ }
+
+ public List getRelations() {
+ return Collections.unmodifiableList(relations);
+ }
+
+ public List getProperties() {
+ return Collections.unmodifiableList(properties);
+ }
+
+ public Set getPropertyNames() {
+ return propertiesByName.keySet();
+ }
+
+ public EntityProperty getPropertyForName(String property) {
+ return propertiesByName.get(property);
+ }
+
+ /**
+ * Clears and then fills the target list with either the odd or even
+ * properties and relations. Always returns "id".
+ *
+ * @param target the list to fill.
+ * @param even if true, the even properties are taken, otherwise the odd.
+ */
+ public void getHalfPropertiesRelations(List target, final boolean even) {
+ target.clear();
+ target.add("id");
+ boolean isEven = true;
+ for (EntityProperty property : properties) {
+ if (even == isEven) {
+ target.add(property.name);
+ }
+ isEven = !isEven;
+ }
+ for (String relation : relations) {
+ if (even == isEven) {
+ target.add(relation);
+ }
+ isEven = !isEven;
+ }
+ }
+
+ private void addProperty(String name, boolean optional, boolean canSort) {
+ EntityProperty property = new EntityProperty(name, optional, canSort, "string");
+ properties.add(property);
+ propertiesByName.put(name, property);
+ }
+
+ private void addProperty(String name, boolean optional, boolean canSort, String jsonType) {
+ EntityProperty property = new EntityProperty(name, optional, canSort, jsonType);
+ properties.add(property);
+ propertiesByName.put(name, property);
+ }
+
+ private void addRelations(String... relations) {
+ this.relations.addAll(Arrays.asList(relations));
+ }
+
}
diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java b/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java
new file mode 100644
index 0000000..2468dfb
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java
@@ -0,0 +1,245 @@
+package org.opengis.cite.sta10.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.testng.Assert;
+
+/**
+ * Utility methods for comparing results and cleaning the service.
+ *
+ * @author Hylke van der Schaaf
+ */
+public class EntityUtils {
+
+ /**
+ * Find the expected count value for the given request. Can not determine
+ * the count for paths like /Datastreams(xxx)/Thing/Locations since the id
+ * of the Thing can not be determined from the path.
+ *
+ * @param request The request to determine the count for.
+ * @param entityCounts The object holding the entity counts.
+ * @return The expected count for the given request.
+ */
+ public static long findCountForRequest(Request request, EntityCounts entityCounts) {
+ Object parentId = -1;
+ long count = -1;
+ EntityType parentType = null;
+ for (PathElement element : request.getPath()) {
+ EntityType elementType = element.getEntityType();
+ if (element.getId() != null) {
+ parentId = element.getId();
+ parentType = elementType;
+ count = -1;
+ } else if (parentType == null) {
+ if (!element.isCollection()) {
+ throw new IllegalArgumentException("Non-collection requested without parent.");
+ }
+ count = entityCounts.getCount(elementType);
+ } else if (element.isCollection()) {
+ count = entityCounts.getCount(parentType, parentId, elementType);
+ parentType = null;
+ parentId = -1;
+ } else {
+ count = -1;
+ // Can not determine the id of this single-entity.
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Checks the given response against the given request.
+ *
+ * @param response The response object to check.
+ * @param request The request to check the response against.
+ * @param entityCounts The object with the expected entity counts.
+ */
+ public static void checkResponse(JSONObject response, Request request, EntityCounts entityCounts) {
+ try {
+ if (request.isCollection()) {
+ checkCollection(response.getJSONArray("value"), request, entityCounts);
+
+ // check count for request
+ Query expandQuery = request.getQuery();
+ Boolean count = expandQuery.getCount();
+ String countProperty = "@iot.count";
+ if (count != null) {
+ if (count) {
+ Assert.assertTrue(response.has(countProperty), "Response should have property " + countProperty + " for request: '" + request.toString() + "'");
+ } else {
+ Assert.assertFalse(response.has(countProperty), "Response should not have property " + countProperty + " for request: '" + request.toString() + "'");
+ }
+ }
+
+ long expectedCount = findCountForRequest(request, entityCounts);
+ if (response.has(countProperty) && expectedCount != -1) {
+ long foundCount = response.getLong(countProperty);
+ Assert.assertEquals(foundCount, expectedCount, "Incorrect count for collection of " + request.getEntityType() + " for request: '" + request.toString() + "'");
+ }
+ Long top = expandQuery.getTop();
+ if (top != null && expectedCount != -1) {
+ int foundNumber = response.getJSONArray("value").length();
+ long skip = expandQuery.getSkip() == null ? 0 : expandQuery.getSkip();
+
+ long expectedNumber = Math.max(0, Math.min(expectedCount - skip, top));
+ if (foundNumber != expectedNumber) {
+ Assert.fail("Requested " + top + " of " + expectedCount + ", expected " + expectedNumber + " with skip of " + skip + " but received " + foundNumber + " for request: '" + request.toString() + "'");
+ }
+
+ String nextLinkProperty = "@iot.nextLink";
+ if (foundNumber + skip < expectedCount) {
+ // should have nextLink
+ Assert.assertTrue(response.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for request: '" + request.toString() + "'");
+ } else {
+ // should not have nextLink
+ Assert.assertFalse(response.has(nextLinkProperty), "Entity should not have " + nextLinkProperty + " for request: '" + request.toString() + "'");
+ }
+
+ }
+
+ } else {
+ checkEntity(response, request, entityCounts);
+ }
+ } catch (JSONException ex) {
+ Assert.fail("Failure when checking response of query '" + request.getLastUrl() + "'", ex);
+ }
+ }
+
+ /**
+ * Check a collection from a response, against the given expand as present
+ * in the request.
+ *
+ * @param collection The collection of items to check.
+ * @param expand The expand that led to the collection.
+ * @param entityCounts The object with the expected entity counts.
+ * @throws JSONException if there is a problem with the json.
+ */
+ public static void checkCollection(JSONArray collection, Expand expand, EntityCounts entityCounts) throws JSONException {
+ // Check entities
+ for (int i = 0; i < collection.length(); i++) {
+ checkEntity(collection.getJSONObject(i), expand, entityCounts);
+ }
+ // todo: check orderby
+ // todo: check filter
+ }
+
+ /**
+ * Check the given entity from a response against the given expand.
+ *
+ * @param entity The entity to check.
+ * @param expand The expand that led to the entity.
+ * @param entityCounts The object with the expected entity counts.
+ * @throws JSONException if there is a problem with the json.
+ */
+ public static void checkEntity(JSONObject entity, Expand expand, EntityCounts entityCounts) throws JSONException {
+ EntityType entityType = expand.getEntityType();
+ Query query = expand.getQuery();
+
+ // Check properties & select
+ List select = new ArrayList<>(query.getSelect());
+ if (select.isEmpty()) {
+ select.add("id");
+ select.addAll(entityType.getPropertyNames());
+ if (expand.isToplevel()) {
+ select.addAll(entityType.getRelations());
+ }
+ }
+ if (select.contains("id")) {
+ Assert.assertTrue(entity.has("@iot.id"), "Entity should have property @iot.id for request: '" + expand.toString() + "'");
+ } else {
+ Assert.assertFalse(entity.has("@iot.id"), "Entity should not have property @iot.id for request: '" + expand.toString() + "'");
+ }
+ for (EntityType.EntityProperty property : entityType.getProperties()) {
+ if (select.contains(property.name)) {
+ Assert.assertTrue(
+ entity.has(property.name) || property.optional,
+ "Entity should have property " + property.name + " for request: '" + expand.toString() + "'");
+ } else {
+ Assert.assertFalse(entity.has(property.name), "Entity should not have property " + property.name + " for request: '" + expand.toString() + "'");
+ }
+ }
+ for (String relationName : entityType.getRelations()) {
+ String propertyName = relationName + "@iot.navigationLink";
+ if (select.contains(relationName)) {
+ Assert.assertTrue(entity.has(propertyName), "Entity should have property " + propertyName + " for request: '" + expand.toString() + "'");
+ } else {
+ Assert.assertFalse(entity.has(propertyName), "Entity should not have property " + propertyName + " for request: '" + expand.toString() + "'");
+ }
+ }
+
+ // Entity id in case we need to check counts.
+ Object entityId = entity.opt("@iot.id");
+
+ // Check expand
+ List relations = new ArrayList<>(entityType.getRelations());
+ for (Expand subExpand : query.getExpand()) {
+ PathElement path = subExpand.getPath().get(0);
+ String propertyName = path.getPropertyName();
+ if (!entity.has(propertyName)) {
+ Assert.fail("Entity should have expanded " + propertyName + " for request: '" + expand.toString() + "'");
+ }
+
+ // Check the expanded items
+ if (subExpand.isCollection()) {
+ checkCollection(entity.getJSONArray(propertyName), subExpand, entityCounts);
+ } else {
+ checkEntity(entity.getJSONObject(propertyName), subExpand, entityCounts);
+ }
+ relations.remove(propertyName);
+
+ // For expanded collections, check count, top, skip
+ if (subExpand.isCollection()) {
+ // Check count
+ Query expandQuery = subExpand.getQuery();
+ Boolean count = expandQuery.getCount();
+ String countProperty = propertyName + "@iot.count";
+ boolean hasCountProperty = entity.has(countProperty);
+ if (count != null) {
+ if (count) {
+ Assert.assertTrue(hasCountProperty, "Entity should have property " + countProperty + " for request: '" + expand.toString() + "'");
+ } else {
+ Assert.assertFalse(hasCountProperty, "Entity should not have property " + countProperty + " for request: '" + expand.toString() + "'");
+ }
+ }
+
+ long expectedCount = entityCounts.getCount(entityType, entityId, EntityType.getForRelation(propertyName));
+ if (hasCountProperty && expectedCount != -1) {
+ long foundCount = entity.getLong(countProperty);
+ Assert.assertEquals(foundCount, expectedCount, "Found incorrect count for " + countProperty);
+ }
+
+ Long top = expandQuery.getTop();
+ if (top != null && expectedCount != -1) {
+ int foundNumber = entity.getJSONArray(propertyName).length();
+ long skip = expandQuery.getSkip() == null ? 0 : expandQuery.getSkip();
+
+ long expectedNumber = Math.min(expectedCount - skip, top);
+ if (foundNumber != expectedNumber) {
+ Assert.fail("Requested " + top + " of " + expectedCount + ", expected " + expectedNumber + " with skip of " + skip + " but received " + foundNumber);
+ }
+
+ String nextLinkProperty = propertyName + "@iot.nextLink";
+ if (foundNumber + skip < expectedCount) {
+ // should have nextLink
+ Assert.assertTrue(entity.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for expand " + subExpand.toString());
+ } else {
+ // should not have nextLink
+ Assert.assertFalse(entity.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for expand " + subExpand.toString());
+ }
+
+ }
+
+ }
+ }
+ for (String propertyName : relations) {
+ if (entity.has(propertyName)) {
+ Assert.fail("Entity should not have expanded " + propertyName + " for request: '" + expand.toString() + "'");
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/Expand.java b/src/main/java/org/opengis/cite/sta10/util/Expand.java
new file mode 100644
index 0000000..c8fb4a5
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/Expand.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link java.lang.Object#clone()} returns a deep copy.
+ *
+ * @author Hylke van der Schaaf
+ */
+public class Expand implements Cloneable {
+
+ private final List path = new ArrayList<>();
+ private final Query query;
+
+ public Expand() {
+ query = new Query();
+ query.setParent(this);
+ }
+
+ public Expand(Query query) {
+ this.query = query;
+ query.setParent(this);
+ }
+
+ public List getPath() {
+ return path;
+ }
+
+ public Expand addElement(PathElement element) {
+ path.add(element);
+ return this;
+ }
+
+ public boolean isCollection() {
+ return path.get(path.size() - 1).isCollection();
+ }
+
+ public EntityType getEntityType() {
+ return path.get(path.size() - 1).getEntityType();
+ }
+
+ public Query getQuery() {
+ return query;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ boolean firstDone = false;
+ for (PathElement element : path) {
+ if (firstDone) {
+ sb.append("/");
+ } else {
+ firstDone = true;
+ }
+ sb.append(element.toString());
+ }
+ if (!query.isEmpty()) {
+ sb.append('(');
+ sb.append(query.toString(true));
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+
+ public boolean isToplevel() {
+ return false;
+ }
+
+ /**
+ * Turns a multi-level expand (Datastreams/Sensor) into nested expands.
+ *
+ * @return a proper nested expand.
+ */
+ public Expand reNest() {
+ if (path.size() == 1) {
+ return this;
+ }
+ query.reNestExpands();
+ Query currentQuery = query;
+ Expand currentExpand = null;
+ for (int i = path.size() - 1; i >= 0; i--) {
+ currentExpand = new Expand(currentQuery);
+ currentExpand.addElement(path.get(i));
+ currentQuery = new Query();
+ currentQuery.addExpand(currentExpand);
+ }
+ return currentExpand;
+ }
+
+ @Override
+ public Expand clone() {
+ Expand clone;
+ try {
+ // Can't use super.clone() since that would make the path of the
+ // clone a reference to our path.
+ clone = getClass().newInstance();
+ } catch (InstantiationException | IllegalAccessException ex) {
+ // should not happen
+ throw new IllegalStateException(ex);
+ }
+ for (PathElement item : path) {
+ clone.path.add(item.clone());
+ }
+ clone.query.duplicate(query);
+ return clone;
+ }
+
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java
index b7a416e..1ad05d4 100644
--- a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java
+++ b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java
@@ -1,4 +1,3 @@
-
package org.opengis.cite.sta10.util;
import org.apache.http.client.ClientProtocolException;
@@ -101,7 +100,7 @@ public static Map doPost(String urlString, String postBody) {
wr.write(postData);
}
- Map result = new HashMap();
+ Map result = new HashMap<>();
result.put("response-code", connection.getResponseCode());
if (connection.getResponseCode() == 201) {
result.put("response", connection.getHeaderField("location"));
diff --git a/src/main/java/org/opengis/cite/sta10/util/PathElement.java b/src/main/java/org/opengis/cite/sta10/util/PathElement.java
new file mode 100644
index 0000000..75c4083
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/PathElement.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+/**
+ *
+ * @author Hylke van der Schaaf
+ */
+public class PathElement implements Cloneable {
+
+ private final EntityType entityType;
+ private final boolean plural;
+ private final Object id;
+
+ public PathElement(EntityType entityType, boolean plural, Object id) {
+ this.entityType = entityType;
+ this.plural = plural;
+ this.id = id;
+ }
+
+ public PathElement(String pathPart) {
+ this(pathPart, null);
+ }
+
+ public PathElement(String pathPart, Object id) {
+ entityType = EntityType.getForRelation(pathPart);
+ plural = EntityType.isPlural(pathPart);
+ this.id = id;
+ }
+
+ public EntityType getEntityType() {
+ return entityType;
+ }
+
+ public String getPropertyName() {
+ return plural ? entityType.plural : entityType.singular;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder value = new StringBuilder();
+ value.append(plural ? entityType.plural : entityType.singular);
+ if (id != null) {
+ value.append('(').append(Utils.quoteIdForUrl(id)).append(')');
+ }
+ return value.toString();
+ }
+
+ public boolean isCollection() {
+ return plural && id == null;
+ }
+
+ public Object getId() {
+ return id;
+ }
+
+ @Override
+ protected PathElement clone() {
+ PathElement clone;
+ try {
+ clone = (PathElement) super.clone();
+ } catch (CloneNotSupportedException ex) {
+ // should not happen
+ throw new IllegalStateException(ex);
+ }
+ return clone;
+ }
+
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/Query.java b/src/main/java/org/opengis/cite/sta10/util/Query.java
new file mode 100644
index 0000000..dbbdc32
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/Query.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Hylke van der Schaaf
+ */
+public class Query {
+
+ /**
+ * The value of the count option, or null if not set.
+ */
+ private Boolean count;
+ /**
+ * The value of the top option, or null if not set.
+ */
+ private Long top;
+ /**
+ * The value of the skip option, or null if not set.
+ */
+ private Long skip;
+ /**
+ * The value of the expand option, empty if not set.
+ */
+ private final List expand = new ArrayList<>();
+ /**
+ * The value of the select option, empty if not set.
+ */
+ private final List select = new ArrayList<>();
+ /**
+ * The value of the orderBy option, or null if not set.
+ */
+ private String orderBy;
+ /**
+ * The value of the filter option, or null if not set.
+ */
+ private String filter;
+ /**
+ * The expand this query is part of.
+ */
+ private Expand parent;
+
+ public void setParent(Expand parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * creates the url version of the query.
+ *
+ * @param inExpand flag to indicate the query is part of an Expand option.
+ * @return the Query as a string to be used in a URL.
+ */
+ public String toString(boolean inExpand) {
+ char separator = inExpand ? ';' : '&';
+ boolean isCollection = parent.isCollection();
+
+ StringBuilder sb = new StringBuilder();
+ if (top != null && isCollection) {
+ sb.append(separator).append("$top=").append(top);
+ }
+ if (skip != null && isCollection) {
+ sb.append(separator).append("$skip=").append(skip);
+ }
+ if (!select.isEmpty()) {
+ sb.append(separator).append("$select=");
+ boolean firstDone = false;
+ for (String property : select) {
+ if (firstDone) {
+ sb.append(",");
+ } else {
+ firstDone = true;
+ }
+ sb.append(property);
+ }
+ }
+ if (filter != null && isCollection) {
+ sb.append(separator).append("$filter=");
+ String filterString = filter;
+ if (!inExpand) {
+ filterString = Utils.urlEncode(filterString);
+ }
+ sb.append(filterString);
+ }
+ if (!expand.isEmpty()) {
+ sb.append(separator).append("$expand=");
+ boolean firstDone = false;
+ for (Expand e : expand) {
+ if (firstDone) {
+ sb.append(",");
+ } else {
+ firstDone = true;
+ }
+ String expandUrl = e.toString();
+ sb.append(expandUrl);
+ }
+ }
+ if (orderBy != null && isCollection) {
+ sb.append(separator).append("$orderby=").append(orderBy);
+ }
+ if (count != null && isCollection) {
+ sb.append(separator).append("$count=").append(count);
+ }
+ if (sb.length() > 0) {
+ return sb.substring(1);
+ }
+ return "";
+ }
+
+ /**
+ * Properly nests the expands. Removes duplicates.
+ */
+ public void reNestExpands() {
+ List newExpands = new ArrayList<>();
+ Map expandMap = new EnumMap<>(EntityType.class);
+ for (Expand oldExpand : expand) {
+ Expand reNest = oldExpand.reNest();
+ EntityType entityType = reNest.getEntityType();
+ if (expandMap.containsKey(entityType)) {
+ Expand existing = expandMap.get(entityType);
+ existing.getQuery().addExpand(reNest.getQuery().getExpand());
+ existing.getQuery().reNestExpands();
+ } else {
+ newExpands.add(reNest);
+ expandMap.put(entityType, reNest);
+ }
+ }
+ expand.clear();
+ expand.addAll(newExpands);
+ }
+
+ public boolean isEmpty() {
+ return count == null
+ && top == null
+ && skip == null
+ && expand.isEmpty()
+ && select.isEmpty()
+ && orderBy == null
+ && filter == null;
+ }
+
+ /**
+ * The value of the count option, or null if not set.
+ *
+ * @return the count
+ */
+ public Boolean getCount() {
+ return count;
+ }
+
+ /**
+ * The value of the count option, or null if not set.
+ *
+ * @param count the count to set
+ * @return this Query;
+ */
+ public Query setCount(Boolean count) {
+ this.count = count;
+ return this;
+ }
+
+ /**
+ * The value of the top option, or null if not set.
+ *
+ * @return the top
+ */
+ public Long getTop() {
+ return top;
+ }
+
+ /**
+ * Set the value of the top option.
+ *
+ * @param top the top to set
+ * @return this Query;
+ */
+ public Query setTop(Long top) {
+ this.top = top;
+ return this;
+ }
+
+ /**
+ * The value of the skip option, or null if not set.
+ *
+ * @return the skip
+ */
+ public Long getSkip() {
+ return skip;
+ }
+
+ /**
+ * Set the value of the skip option.
+ *
+ * @param skip the skip to set
+ * @return this Query;
+ */
+ public Query setSkip(Long skip) {
+ this.skip = skip;
+ return this;
+ }
+
+ /**
+ * The value of the expand option, empty if not set.
+ *
+ * @return the expand
+ */
+ public List getExpand() {
+ return expand;
+ }
+
+ /**
+ * Add an expand option.
+ *
+ * @param expand the expand to add.
+ * @return this Query;
+ */
+ public Query addExpand(Expand expand) {
+ this.expand.add(expand);
+ return this;
+ }
+
+ /**
+ * Add a list of expand options.
+ *
+ * @param expand the expands to add
+ * @return this Query;
+ */
+ public Query addExpand(List expand) {
+ this.expand.addAll(expand);
+ return this;
+ }
+
+ /**
+ * The value of the select option, empty if not set.
+ *
+ * @return the select
+ */
+ public List getSelect() {
+ return select;
+ }
+
+ /**
+ * The value of the select option, empty if not set.
+ *
+ * @param select the select to add
+ * @return this Query;
+ */
+ public Query addSelect(String select) {
+ this.select.add(select);
+ return this;
+ }
+
+ /**
+ * The value of the filter option, or null if not set.
+ *
+ * @return the filter
+ */
+ public String getFilter() {
+ return filter;
+ }
+
+ /**
+ * The value of the filter option, or null if not set.
+ *
+ * @param filter the filter to set
+ * @return this Query;
+ */
+ public Query setFilter(String filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ /**
+ * Duplicate the source into this query by making a deep copy.
+ *
+ * @param source the source to duplicate.
+ */
+ public void duplicate(Query source) {
+ count = source.count;
+ filter = source.filter;
+ orderBy = source.orderBy;
+ skip = source.skip;
+ top = source.top;
+ for (Expand item : source.expand) {
+ expand.add(item.clone());
+ }
+ for (String item : source.select) {
+ select.add(item);
+ }
+ }
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/Request.java b/src/main/java/org/opengis/cite/sta10/util/Request.java
new file mode 100644
index 0000000..feffaed
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/Request.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+import java.util.Map;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.testng.Assert;
+
+/**
+ *
+ * @author Hylke van der Schaaf
+ */
+public class Request extends Expand {
+
+ private String baseUrl;
+ private String lastUrl;
+
+ public Request() {
+ }
+
+ public Request(String baseUrl) {
+ this.baseUrl = baseUrl;
+ }
+
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+
+ public void setBaseUrl(String baseUrl) {
+ this.baseUrl = baseUrl;
+ }
+
+ @Override
+ public Request reNest() {
+ getQuery().reNestExpands();
+ return this;
+ }
+
+ @Override
+ public boolean isToplevel() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ if (lastUrl == null) {
+ buildUrl();
+ }
+ return lastUrl;
+ }
+
+ public String getLastUrl() {
+ return lastUrl;
+ }
+
+ public String buildUrl() {
+ StringBuilder urlString = new StringBuilder(baseUrl);
+ for (PathElement element : getPath()) {
+ urlString.append('/').append(element.toString());
+ }
+ urlString.append('?').append(getQuery().toString(false));
+ lastUrl = urlString.toString();
+ return lastUrl;
+ }
+
+ public JSONObject executeGet() {
+ String fetchUrl = buildUrl();
+ Map responseMap = HTTPMethods.doGet(fetchUrl);
+ String response = responseMap.get("response").toString();
+ int responseCode = Integer.parseInt(responseMap.get("response-code").toString());
+ if (responseCode != 200) {
+ Assert.assertEquals(responseCode, 200, "Error during request: " + fetchUrl);
+ }
+ JSONObject jsonResponse = null;
+ try {
+ jsonResponse = new JSONObject(response);
+ } catch (JSONException ex) {
+ ex.printStackTrace();
+ Assert.fail("Failed to parse response for request: " + fetchUrl, ex);
+ }
+ return jsonResponse;
+ }
+
+ @Override
+ public Request clone() {
+ Request clone = (Request) super.clone();
+ clone.baseUrl = baseUrl;
+ return clone;
+ }
+
+}
diff --git a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java
index 6423383..d819412 100644
--- a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java
+++ b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java
@@ -1,8 +1,7 @@
package org.opengis.cite.sta10.util;
-import org.testng.Assert;
-
import java.util.List;
+import org.testng.Assert;
/**
* Utility class that helps preparing the URL string for the targeted entity.
@@ -19,7 +18,7 @@ public class ServiceURLBuilder {
* @param property The targeted property or the query string
* @return The URL String created based on the input parameters
*/
- public static String buildURLString(String rootURI, EntityType parentEntityType, long parentId, EntityType relationEntityType, String property) {
+ public static String buildURLString(String rootURI, EntityType parentEntityType, Object parentId, EntityType relationEntityType, String property) {
String urlString = rootURI;
if (relationEntityType == null) {
switch (parentEntityType) {
@@ -51,13 +50,13 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType);
return null;
}
- if (parentId != -1) {
- urlString += "(" + parentId + ")";
+ if (parentId != null) {
+ urlString += "(" + Utils.quoteIdForUrl(parentId) + ")";
}
} else {
switch (parentEntityType) {
case THING:
- urlString += "/Things(" + parentId + ")";
+ urlString += "/Things(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case LOCATION:
urlString += "/Locations";
@@ -73,7 +72,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case LOCATION:
- urlString += "/Locations(" + parentId + ")";
+ urlString += "/Locations(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case THING:
urlString += "/Things";
@@ -86,7 +85,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case HISTORICAL_LOCATION:
- urlString += "/HistoricalLocations(" + parentId + ")";
+ urlString += "/HistoricalLocations(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case THING:
urlString += "/Thing";
@@ -99,7 +98,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case DATASTREAM:
- urlString += "/Datastreams(" + parentId + ")";
+ urlString += "/Datastreams(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case THING:
urlString += "/Thing";
@@ -118,7 +117,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case SENSOR:
- urlString += "/Sensors(" + parentId + ")";
+ urlString += "/Sensors(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case DATASTREAM:
urlString += "/Datastreams";
@@ -128,7 +127,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case OBSERVATION:
- urlString += "/Observations(" + parentId + ")";
+ urlString += "/Observations(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case THING:
case DATASTREAM:
@@ -142,7 +141,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case OBSERVED_PROPERTY:
- urlString += "/ObservedProperties(" + parentId + ")";
+ urlString += "/ObservedProperties(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case DATASTREAM:
urlString += "/Datastreams";
@@ -152,7 +151,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
}
break;
case FEATURE_OF_INTEREST:
- urlString += "/FeaturesOfInterest(" + parentId + ")";
+ urlString += "/FeaturesOfInterest(" + Utils.quoteIdForUrl(parentId) + ")";
switch (relationEntityType) {
case OBSERVATION:
urlString += "/Observations";
@@ -184,7 +183,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType,
* @param property The targeted property or the query string
* @return The URL String created based on the input parameters
*/
- public static String buildURLString(String rootURI, List entityTypes, List ids, String property) {
+ public static String buildURLString(String rootURI, List entityTypes, List ids, String property) {
String urlString = rootURI;
if (entityTypes.size() != ids.size() && entityTypes.size() != ids.size() + 1) {
Assert.fail("There is problem with the path of entities!!!");
@@ -195,7 +194,12 @@ public static String buildURLString(String rootURI, List entityTypes, Li
for (int i = 0; i < entityTypes.size(); i++) {
urlString += entityTypes.get(i);
if (i < ids.size()) {
- urlString += "(" + ids.get(i) + ")/";
+ Object id = ids.get(i);
+ if (id == null) {
+ urlString += "/";
+ } else {
+ urlString += "(" + Utils.quoteIdForUrl(id) + ")/";
+ }
}
}
if (urlString.charAt(urlString.length() - 1) == '/') {
diff --git a/src/main/java/org/opengis/cite/sta10/util/Utils.java b/src/main/java/org/opengis/cite/sta10/util/Utils.java
new file mode 100644
index 0000000..f9808dc
--- /dev/null
+++ b/src/main/java/org/opengis/cite/sta10/util/Utils.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 Open Geospatial Consortium.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opengis.cite.sta10.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+/**
+ *
+ * @author jab
+ */
+public class Utils {
+
+ private Utils() {
+ }
+
+ public static String urlEncode(String link) {
+ try {
+ return URLEncoder.encode(link, StandardCharsets.UTF_8.name());
+ } catch (UnsupportedEncodingException ex) {
+ }
+ return link;
+ }
+
+ /**
+ * Quote the ID for use in json, if needed.
+ *
+ * @param id The id to quote.
+ * @return The quoted id.
+ */
+ public static String quoteIdForJson(Object id) {
+ if (id instanceof Number) {
+ return id.toString();
+ }
+ return "\"" + id + "\"";
+ }
+
+ /**
+ * Quote the ID for use in URLs, if needed.
+ *
+ * @param id The id to quote.
+ * @return The quoted id.
+ */
+ public static String quoteIdForUrl(Object id) {
+ if (id instanceof Number) {
+ return id.toString();
+ }
+ return "'" + id + "'";
+ }
+
+ public static Object idObjectFromPostResult(String postResultLine) {
+ int pos1 = postResultLine.lastIndexOf("(") + 1;
+ int pos2 = postResultLine.lastIndexOf(")");
+ String part = postResultLine.substring(pos1, pos2);
+ try {
+ return Long.parseLong(part);
+ } catch (NumberFormatException exc) {
+ // Id was not a long, thus a String.
+ if (!part.startsWith("'") || !part.endsWith("'")) {
+ throw new IllegalArgumentException("Strings in urls must be quoted with single quotes.");
+ }
+ return part.substring(1, part.length() - 1);
+ }
+ }
+}