private BatchChangeSetPart createBatchChangeSetPart( Edm edm, Map<String, String> contentIdMap, Olingo2BatchChangeRequest batchRequest) throws EdmException, URISyntaxException, EntityProviderException, IOException, ODataApplicationException { // build body string String resourcePath = batchRequest.getResourcePath(); // is it a referenced entity? if (resourcePath.startsWith("$")) { resourcePath = replaceContentId(edm, resourcePath, contentIdMap); } final UriInfoWithType uriInfo = parseUri(edm, resourcePath, null); // serialize data into ODataResponse object, if set in request and this is not a DELETE request final Map<String, String> headers = new HashMap<String, String>(); byte[] body = null; if (batchRequest.getBody() != null && !Operation.DELETE.equals(batchRequest.getOperation())) { final ODataResponse response = writeContent(edm, uriInfo, batchRequest.getBody()); // copy response headers for (String header : response.getHeaderNames()) { headers.put(header, response.getHeader(header)); } // get (http) entity which is for default Olingo2 implementation an InputStream body = response.getEntity() instanceof InputStream ? EntityProvider.readBinary((InputStream) response.getEntity()) : null; if (body != null) { headers.put(HttpHeaders.CONTENT_LENGTH, String.valueOf(body.length)); } } // Olingo is sensitive to batch part charset case!! headers.put(HttpHeaders.ACCEPT, getResourceContentType(uriInfo).toString().toLowerCase()); if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) { headers.put(HttpHeaders.CONTENT_TYPE, getContentType()); } // add request headers headers.putAll(batchRequest.getHeaders()); final String contentId = batchRequest.getContentId(); if (contentId != null) { contentIdMap.put("$" + contentId, resourcePath); } return BatchChangeSetPart.uri(createBatchUri(batchRequest)) .method(batchRequest.getOperation().getHttpMethod()) .contentId(contentId) .headers(headers) .body(body == null ? null : new String(body, Consts.UTF_8)) .build(); }
@Override public ODataResponse deleteEntity(DeleteUriInfo uriInfo, String contentType) throws ODataException { LOG.debug("Deleting Entity: " + uriInfo); if ("Cars".equals(uriInfo.getTargetEntitySet().getName())) { int key = getKeyValue(uriInfo.getKeyPredicates().get(0)); // if there is no entry with this key available, one should return // "404 Not Found" // return ODataResponse.status(HttpStatusCodes.NOT_FOUND).build(); // now one can delete the entry with this particular key in the // backend... } else if ("Manufacturers".equals(uriInfo.getTargetEntitySet().getName())) { int key = getKeyValue(uriInfo.getKeyPredicates().get(0)); // now one can delete the entry with this particular key in the // backend... } // we can return Status Code 204 No Content because the URI Parsing // already guarantees that // a) only valid URIs are dispatched (also checked against the metadata) // b) 404 Not Found is already returned above, when the entry does not // exist return ODataResponse.status(HttpStatusCodes.NO_CONTENT).build(); }
@Override public ODataResponse updateEntity( PutMergePatchUriInfo uriInfo, InputStream content, String requestContentType, boolean merge, String contentType) throws ODataException { LOG.debug("Updating Entity: " + uriInfo); EntityProviderReadProperties properties = EntityProviderReadProperties.init().mergeSemantic(false).build(); ODataEntry entry = EntityProvider.readEntry( requestContentType, uriInfo.getTargetEntitySet(), content, properties); // if something goes wrong in deserialization this is managed via the // ExceptionMapper, // no need for an application to do exception handling here an convert // the exceptions in HTTP exceptions Map<String, Object> data = entry.getProperties(); if ("Cars".equals(uriInfo.getTargetEntitySet().getName())) { int key = getKeyValue(uriInfo.getKeyPredicates().get(0)); // if there is no entry with this key available, one should return // "404 Not Found" // return ODataResponse.status(HttpStatusCodes.NOT_FOUND).build(); // now one can use the data to create the entry in the backend ... String model = (String) data.get("Model"); // ... } else if ("Manufacturers".equals(uriInfo.getTargetEntitySet().getName())) { int key = getKeyValue(uriInfo.getKeyPredicates().get(0)); // now one can use the data to create the entry in the backend ... } // we can return Status Code 204 No Content because the URI Parsing // already guarantees that // a) only valid URIs are dispatched (also checked against the metadata) // b) 404 Not Found is already returned above, when the entry does not // exist return ODataResponse.status(HttpStatusCodes.NO_CONTENT).build(); }
private ODataResponse parseBatchRequest(final Edm edm, final List<Olingo2BatchRequest> batchParts) throws IOException, EntityProviderException, ODataApplicationException, EdmException, URISyntaxException { // create Batch request from parts final ArrayList<BatchPart> parts = new ArrayList<BatchPart>(); final ArrayList<BatchChangeSetPart> changeSetParts = new ArrayList<BatchChangeSetPart>(); final Map<String, String> contentIdMap = new HashMap<String, String>(); for (Olingo2BatchRequest batchPart : batchParts) { if (batchPart instanceof Olingo2BatchQueryRequest) { // need to add change set parts collected so far?? if (!changeSetParts.isEmpty()) { addChangeSetParts(parts, changeSetParts); changeSetParts.clear(); contentIdMap.clear(); } // add to request parts final UriInfoWithType uriInfo = parseUri(edm, batchPart.getResourcePath(), null); parts.add(createBatchQueryPart(uriInfo, (Olingo2BatchQueryRequest) batchPart)); } else { // add to change set parts final BatchChangeSetPart changeSetPart = createBatchChangeSetPart(edm, contentIdMap, (Olingo2BatchChangeRequest) batchPart); changeSetParts.add(changeSetPart); } } // add any remaining change set parts if (!changeSetParts.isEmpty()) { addChangeSetParts(parts, changeSetParts); } final String boundary = BOUNDARY_PREFIX + UUID.randomUUID(); InputStream batchRequest = EntityProvider.writeBatchRequest(parts, boundary); // two blank lines are already added. No need to add extra blank lines final String contentHeader = BATCH_CONTENT_TYPE + BOUNDARY_PARAMETER + boundary; return ODataResponse.entity(batchRequest).contentHeader(contentHeader).build(); }
private ODataResponse writeContent(Edm edm, UriInfoWithType uriInfo, Object content) throws ODataApplicationException, EdmException, EntityProviderException, URISyntaxException, IOException { String responseContentType = getContentType(); ODataResponse response; switch (uriInfo.getUriType()) { case URI4: case URI5: // simple property final List<EdmProperty> simplePropertyPath = uriInfo.getPropertyPath(); final EdmProperty simpleProperty = simplePropertyPath.get(simplePropertyPath.size() - 1); responseContentType = simpleProperty.getMimeType(); if (uriInfo.isValue()) { response = EntityProvider.writePropertyValue(simpleProperty, content); responseContentType = TEXT_PLAIN_WITH_CS_UTF_8.toString(); } else { response = EntityProvider.writeProperty(getContentType(), simpleProperty, content); } break; case URI3: // complex property final List<EdmProperty> complexPropertyPath = uriInfo.getPropertyPath(); final EdmProperty complexProperty = complexPropertyPath.get(complexPropertyPath.size() - 1); response = EntityProvider.writeProperty(responseContentType, complexProperty, content); break; case URI7A: // $links with 0..1 cardinality property final EdmEntitySet targetLinkEntitySet = uriInfo.getTargetEntitySet(); EntityProviderWriteProperties linkProperties = EntityProviderWriteProperties.serviceRoot(new URI(serviceUri + SEPARATOR)).build(); @SuppressWarnings("unchecked") final Map<String, Object> linkMap = (Map<String, Object>) content; response = EntityProvider.writeLink( responseContentType, targetLinkEntitySet, linkMap, linkProperties); break; case URI7B: // $links with * cardinality property final EdmEntitySet targetLinksEntitySet = uriInfo.getTargetEntitySet(); EntityProviderWriteProperties linksProperties = EntityProviderWriteProperties.serviceRoot(new URI(serviceUri + SEPARATOR)).build(); @SuppressWarnings("unchecked") final List<Map<String, Object>> linksMap = (List<Map<String, Object>>) content; response = EntityProvider.writeLinks( responseContentType, targetLinksEntitySet, linksMap, linksProperties); break; case URI1: case URI2: case URI6A: case URI6B: // Entity final EdmEntitySet targetEntitySet = uriInfo.getTargetEntitySet(); EntityProviderWriteProperties properties = EntityProviderWriteProperties.serviceRoot(new URI(serviceUri + SEPARATOR)).build(); @SuppressWarnings("unchecked") final Map<String, Object> objectMap = (Map<String, Object>) content; response = EntityProvider.writeEntry(responseContentType, targetEntitySet, objectMap, properties); break; case URI9: // $batch @SuppressWarnings("unchecked") final List<Olingo2BatchRequest> batchParts = (List<Olingo2BatchRequest>) content; response = parseBatchRequest(edm, batchParts); break; default: // notify exception and return!!! throw new ODataApplicationException( "Unsupported resource type " + uriInfo.getTargetType(), Locale.ENGLISH); } return response.getContentHeader() != null ? response : ODataResponse.fromResponse(response).contentHeader(responseContentType).build(); }
private <T> void writeContent( final Edm edm, HttpEntityEnclosingRequestBase httpEntityRequest, final UriInfoWithType uriInfo, final Object content, final Olingo2ResponseHandler<T> responseHandler) { try { // process resource by UriType final ODataResponse response = writeContent(edm, uriInfo, content); // copy all response headers for (String header : response.getHeaderNames()) { httpEntityRequest.setHeader(header, response.getHeader(header)); } // get (http) entity which is for default Olingo2 implementation an InputStream if (response.getEntity() instanceof InputStream) { httpEntityRequest.setEntity(new InputStreamEntity((InputStream) response.getEntity())); /* // avoid sending it without a header field set if (!httpEntityRequest.containsHeader(HttpHeaders.CONTENT_TYPE)) { httpEntityRequest.addHeader(HttpHeaders.CONTENT_TYPE, getContentType()); } */ } // execute HTTP request final Header requestContentTypeHeader = httpEntityRequest.getFirstHeader(HttpHeaders.CONTENT_TYPE); final ContentType requestContentType = requestContentTypeHeader != null ? ContentType.parse(requestContentTypeHeader.getValue()) : contentType; execute( httpEntityRequest, requestContentType, new AbstractFutureCallback<T>(responseHandler) { @SuppressWarnings("unchecked") @Override public void onCompleted(HttpResponse result) throws IOException, EntityProviderException, BatchException, ODataApplicationException { // if a entity is created (via POST request) the response body contains the new // created entity HttpStatusCodes statusCode = HttpStatusCodes.fromStatusCode(result.getStatusLine().getStatusCode()); // look for no content, or no response body!!! final boolean noEntity = result.getEntity() == null || result.getEntity().getContentLength() == 0; if (statusCode == HttpStatusCodes.NO_CONTENT || noEntity) { responseHandler.onResponse( (T) HttpStatusCodes.fromStatusCode(result.getStatusLine().getStatusCode())); } else { switch (uriInfo.getUriType()) { case URI9: // $batch final List<BatchSingleResponse> singleResponses = EntityProvider.parseBatchResponse( result.getEntity().getContent(), result.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue()); // parse batch response bodies final List<Olingo2BatchResponse> responses = new ArrayList<Olingo2BatchResponse>(); Map<String, String> contentIdLocationMap = new HashMap<String, String>(); final List<Olingo2BatchRequest> batchRequests = (List<Olingo2BatchRequest>) content; final Iterator<Olingo2BatchRequest> iterator = batchRequests.iterator(); for (BatchSingleResponse response : singleResponses) { final Olingo2BatchRequest request = iterator.next(); if (request instanceof Olingo2BatchChangeRequest && ((Olingo2BatchChangeRequest) request).getContentId() != null) { contentIdLocationMap.put( "$" + ((Olingo2BatchChangeRequest) request).getContentId(), response.getHeader(HttpHeaders.LOCATION)); } try { responses.add(parseResponse(edm, contentIdLocationMap, request, response)); } catch (Exception e) { // report any parsing errors as error response responses.add( new Olingo2BatchResponse( Integer.parseInt(response.getStatusCode()), response.getStatusInfo(), response.getContentId(), response.getHeaders(), new ODataApplicationException( "Error parsing response for " + request + ": " + e.getMessage(), Locale.ENGLISH, e))); } } responseHandler.onResponse((T) responses); break; case URI4: case URI5: // simple property // get the response content as Object for $value or Map<String, Object> // otherwise final List<EdmProperty> simplePropertyPath = uriInfo.getPropertyPath(); final EdmProperty simpleProperty = simplePropertyPath.get(simplePropertyPath.size() - 1); if (uriInfo.isValue()) { responseHandler.onResponse( (T) EntityProvider.readPropertyValue( simpleProperty, result.getEntity().getContent())); } else { responseHandler.onResponse( (T) EntityProvider.readProperty( getContentType(), simpleProperty, result.getEntity().getContent(), EntityProviderReadProperties.init().build())); } break; case URI3: // complex property // get the response content as Map<String, Object> final List<EdmProperty> complexPropertyPath = uriInfo.getPropertyPath(); final EdmProperty complexProperty = complexPropertyPath.get(complexPropertyPath.size() - 1); responseHandler.onResponse( (T) EntityProvider.readProperty( getContentType(), complexProperty, result.getEntity().getContent(), EntityProviderReadProperties.init().build())); break; case URI7A: // $links with 0..1 cardinality property // get the response content as String final EdmEntitySet targetLinkEntitySet = uriInfo.getTargetEntitySet(); responseHandler.onResponse( (T) EntityProvider.readLink( getContentType(), targetLinkEntitySet, result.getEntity().getContent())); break; case URI7B: // $links with * cardinality property // get the response content as java.util.List<String> final EdmEntitySet targetLinksEntitySet = uriInfo.getTargetEntitySet(); responseHandler.onResponse( (T) EntityProvider.readLinks( getContentType(), targetLinksEntitySet, result.getEntity().getContent())); break; case URI1: case URI2: case URI6A: case URI6B: // Entity // get the response content as an ODataEntry object responseHandler.onResponse( (T) EntityProvider.readEntry( response.getContentHeader(), uriInfo.getTargetEntitySet(), result.getEntity().getContent(), EntityProviderReadProperties.init().build())); break; default: throw new ODataApplicationException( "Unsupported resource type " + uriInfo.getTargetType(), Locale.ENGLISH); } } } }); } catch (ODataException e) { responseHandler.onException(e); } catch (URISyntaxException e) { responseHandler.onException(e); } catch (UnsupportedEncodingException e) { responseHandler.onException(e); } catch (IOException e) { responseHandler.onException(e); } }