This is an automated email from the ASF dual-hosted git repository.
rareddy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata4.git
The following commit(s) were added to refs/heads/master by this push:
new 7da68d1 OLINGO-1389 adding support for posting to a navigation
new 9e94d95 Merge branch 'pr54'
7da68d1 is described below
commit 7da68d113891bc9f175c417da4021d6cffdb9c39
Author: Steven Hawkins <[email protected]>
AuthorDate: Tue Aug 27 20:30:11 2019 -0400
OLINGO-1389 adding support for posting to a navigation
---
.../olingo/server/core/requests/DataRequest.java | 46 +++++++--
.../olingo/server/example/TripPinDataModel.java | 2 +-
.../olingo/server/example/TripPinHandler.java | 26 ++++-
.../olingo/server/example/TripPinServiceTest.java | 114 +++++++++++++++++++++
4 files changed, 175 insertions(+), 13 deletions(-)
diff --git
a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 11a092f..a52e178 100644
---
a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++
b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -277,10 +277,20 @@ public class DataRequest extends ServiceRequest {
public boolean assertHttpMethod(ODataResponse response) throws
ODataHandlerException {
// the create/update/delete to navigation property is done through
references
// see # 11.4.6
- if (!getNavigations().isEmpty() && !isGET()) {
- return methodNotAllowed(response, httpMethod(),
- "create/update/delete to navigation property is done through
references",
- allowedMethods());
+ if (!getNavigations().isEmpty()) {
+ if (isPOST()) {
+ UriResourceNavigation last = getNavigations().getLast();
+ if
(!(getEntitySet().getRelatedBindingTarget(last.getProperty().getName())
+ instanceof EdmEntitySet)) {
+ return methodNotAllowed(response, httpMethod(),
+ "navigation updates must be to an entity contained in an
entity set",
+ allowedMethods());
+ }
+ } else if (!isGET()) {
+ return methodNotAllowed(response, httpMethod(),
+ "update/delete to navigation property is done through
references",
+ allowedMethods());
+ }
}
if ((isGET() || isDELETE()) && getReturnRepresentation() !=
ReturnRepresentation.NONE) {
@@ -315,13 +325,14 @@ public class DataRequest extends ServiceRequest {
public void execute(ServiceHandler handler, ODataResponse response)
throws ODataLibraryException, ODataApplicationException {
+ ContextURL contextURL = getContextURL(odata);
EntityResponse entityResponse =
EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response);
+ contextURL, false, response);
if (isGET()) {
if (isCollection()) {
handler.read(DataRequest.this,
- EntitySetResponse.getInstance(DataRequest.this,
getContextURL(odata), false, response));
+ EntitySetResponse.getInstance(DataRequest.this, contextURL,
false, response));
} else {
handler.read(DataRequest.this,entityResponse);
}
@@ -338,24 +349,37 @@ public class DataRequest extends ServiceRequest {
} else if (ifNoneMatch) {
// 11.4.4
entityResponse = EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response,
getReturnRepresentation());
+ contextURL, false, response, getReturnRepresentation());
handler.createEntity(DataRequest.this, getEntityFromClient(),
entityResponse);
} else {
handler.upsertEntity(DataRequest.this, getEntityFromClient(),
isPATCH(), getETag(),
entityResponse);
}
} else if (isPOST()) {
- entityResponse = EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response, getReturnRepresentation());
- handler.createEntity(DataRequest.this,
getEntityFromClient(),entityResponse);
+ if (!getNavigations().isEmpty()) {
+ entityResponse = EntityResponse.getInstance(DataRequest.this,
+ contextURL, false, response, getReturnRepresentation());
+ UriResourceNavigation last = getNavigations().getLast();
+ EdmEntityType navigationType = last.getProperty().getType();
+ Entity entity = getEntityFromClient(navigationType);
+ handler.createEntity(DataRequest.this, entity,entityResponse);
+ } else {
+ entityResponse = EntityResponse.getInstance(DataRequest.this,
+ contextURL, false, response, getReturnRepresentation());
+ handler.createEntity(DataRequest.this,
getEntityFromClient(),entityResponse);
+ }
} else if (isDELETE()) {
handler.deleteEntity(DataRequest.this, getETag(), entityResponse);
}
}
private Entity getEntityFromClient() throws DeserializerException {
+ return getEntityFromClient(getEntitySet().getEntityType());
+ }
+
+ private Entity getEntityFromClient(EdmEntityType entityType) throws
DeserializerException {
ODataDeserializer deserializer =
odata.createDeserializer(getRequestContentType(), getServiceMetaData());
- return deserializer.entity(getODataRequest().getBody(),
getEntitySet().getEntityType()).getEntity();
+ return deserializer.entity(getODataRequest().getBody(),
entityType).getEntity();
}
@Override
diff --git
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
index 562eac0..cde9b74 100644
---
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
+++
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
@@ -493,7 +493,7 @@ public class TripPinDataModel {
map = new HashMap<String, Object>();
this.peopleLinks.put((String)
parentEntity.getProperty(key).getValue(), map);
}
- map.put("Photo", childEntity.getProperty(key).getValue());
+ map.put("Photo",
((Long)childEntity.getProperty("Id").getValue()).intValue());
setLink(parentEntity, navigation, childEntity);
} else if (type.getName().equals("Trip") &&
navigation.equals("PlanItems")) {
Map<String, Object> map =
this.tripLinks.get(parentEntity.getProperty(key).getValue());
diff --git
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
index 4a92198..19b2898 100644
---
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
+++
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
@@ -238,7 +238,12 @@ public class TripPinHandler implements ServiceHandler {
public void createEntity(DataRequest request, Entity entity, EntityResponse
response)
throws ODataLibraryException, ODataApplicationException {
EdmEntitySet edmEntitySet = request.getEntitySet();
-
+
+ if (!request.getNavigations().isEmpty()) {
+ UriResourceNavigation lastNavigation =
request.getNavigations().getLast();
+ edmEntitySet =
(EdmEntitySet)edmEntitySet.getRelatedBindingTarget(lastNavigation.getProperty().getName());
+ }
+
Entity created = this.dataModel.createEntity(edmEntitySet, entity,
request.getODataRequest().getRawBaseUri());
try {
@@ -271,6 +276,25 @@ public class TripPinHandler implements ServiceHandler {
} catch (URISyntaxException e) {
throw new ODataApplicationException(e.getMessage(), 500,
Locale.getDefault());
}
+
+ if (!request.getNavigations().isEmpty()) {
+ UriResourceNavigation lastNavigation =
request.getNavigations().getLast();
+
+ String parentRequest = request.getODataRequest().getRawRequestUri();
+ parentRequest = parentRequest.substring(0,
parentRequest.lastIndexOf('/'));
+
+ DataRequest bindingRequest;
+ try {
+ bindingRequest = request.parseLink(new URI(parentRequest));
+ } catch (URISyntaxException e) {
+ throw new ODataApplicationException(e.getMessage(), 500,
Locale.getDefault());
+ }
+
+ Entity reference =
this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
+ bindingRequest.getKeyPredicates());
+
+ this.dataModel.addNavigationLink(lastNavigation.getProperty().getName(),
reference, created);
+ }
response.writeCreatedEntity(edmEntitySet, created);
}
diff --git
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index fa32eef..53a21e6 100644
---
a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++
b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -552,6 +552,46 @@ public class TripPinServiceTest {
assertTrue(node.get("value").isArray());
assertEquals("scottketchum",
((ArrayNode)node.get("value")).get(1).get("UserName").asText());
}
+
+ @Ignore("4.01 style binding not supported")
+ @Test
+ public void testCreateEntityWithLinkToRelatedEntitiesIds() throws Exception {
+ String payload = "{\n" +
+ " \"UserName\":\"olingo\",\n" +
+ " \"FirstName\":\"Olingo\",\n" +
+ " \"LastName\":\"Apache\",\n" +
+ " \"Emails\":[\n" +
+ " \"[email protected]\"\n" +
+ " ],\n" +
+ " \"AddressInfo\":[\n" +
+ " {\n" +
+ " \"Address\":\"100 apache Ln.\",\n" +
+ " \"City\":{\n" +
+ " \"CountryRegion\":\"United States\",\n" +
+ " \"Name\":\"Boise\",\n" +
+ " \"Region\":\"ID\"\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"Gender\":\"0\",\n" +
+ " \"Concurrency\":635585295719432047,\n" +
+ "\"Friends\":[" +
+ "{\"@id\": \"People('russellwhyte')\"},\n" +
+ "{\"@id\": \"People('scottketchum')\"}\n" +
+ "]"+
+ "}";
+ HttpPost postRequest = new HttpPost(baseURL + "/People");
+ postRequest.setEntity(new StringEntity(payload,
ContentType.APPLICATION_JSON));
+ postRequest.setHeader("Prefer", "return=minimal");
+ HttpResponse response = httpSend(postRequest, 204);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('olingo')/Friends", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#People",
node.get("@odata.context").asText());
+ assertTrue(node.get("value").isArray());
+ assertEquals("scottketchum",
((ArrayNode)node.get("value")).get(1).get("UserName").asText());
+ }
@Test
public void testUpdatePrimitiveProperty() throws Exception {
@@ -779,6 +819,80 @@ public class TripPinServiceTest {
node = getJSONNode(response);
assertNull("/People('russellwhyte')", ((ArrayNode)
node.get("value")).get(2));
}
+
+ @Test
+ public void testAddEntityToNavigationFailsNotEntitySet() throws Exception {
+ // adding to an entity that is not part of an entity set
+ // goes against a few assumptions in downstream code, so
+ // not handling for now
+ String msg = "{\n" +
+ "\"TripId\": 1010,\n" +
+ "\"Description\": \"The trip of a lifetime.\",\n" +
+ "\"Name\": \"Grand Prize\",\n" +
+ "\"Budget\": 100000\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Trips";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type",
"application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 405);
+ EntityUtils.consumeQuietly(response.getEntity());
+ }
+
+ @Test
+ public void testAddEntityToNavigation() throws Exception {
+ String msg = "{\n" +
+ "\"Id\": 1010,\n" +
+ "\"Name\": \"Grand Prize\"\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Photo";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type",
"application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 201);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('vincentcalabrese')/Photo", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#Photos/$entity",
node.get("@odata.context").asText());
+ assertEquals("Grand Prize", node.get("Name").asText());
+ }
+
+ @Test
+ public void testAddEntityToNavigationSelf() throws Exception {
+ String payload = "{\n" +
+ " \"UserName\":\"olingo\",\n" +
+ " \"FirstName\":\"Olingo\",\n" +
+ " \"LastName\":\"Apache\",\n" +
+ " \"Emails\":[\n" +
+ " \"[email protected]\"\n" +
+ " ],\n" +
+ " \"AddressInfo\":[\n" +
+ " {\n" +
+ " \"Address\":\"100 apache Ln.\",\n" +
+ " \"City\":{\n" +
+ " \"CountryRegion\":\"United States\",\n" +
+ " \"Name\":\"Boise\",\n" +
+ " \"Region\":\"ID\"\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"Gender\":\"0\",\n" +
+ " \"Concurrency\":635585295719432047\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Friends";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(payload,
ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type",
"application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 201);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('vincentcalabrese')/Friends", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#People",
node.get("@odata.context").asText());
+ assertTrue(node.get("value").isArray());
+ assertEquals("olingo",
((ArrayNode)node.get("value")).get(2).get("UserName").asText());
+ }
@Test
public void testDeleteReference() throws Exception {