[OLINGO-1279]OData V4.0: Client returns CsdlPath for CsdlAnnotationPath attribute

This commit is contained in:
Archana Rai 2018-07-26 17:06:16 +05:30
parent 2696359f33
commit 8f4e554dfa
11 changed files with 257 additions and 13 deletions

View File

@ -18,10 +18,17 @@
*/
package org.apache.olingo.fit.tecsvc.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.URI;
import java.util.Calendar;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@ -30,32 +37,34 @@ import java.util.concurrent.TimeoutException;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.request.AsyncBatchRequestWrapper;
import org.apache.olingo.client.api.communication.request.AsyncRequestWrapper;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.ODataRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
import org.apache.olingo.client.api.communication.request.invoke.ODataInvokeRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
import org.apache.olingo.client.api.communication.response.AsyncResponseWrapper;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.client.api.communication.response.ODataInvokeResponse;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.data.ResWrap;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientEntitySet;
import org.apache.olingo.client.api.domain.ClientProperty;
import org.apache.olingo.client.api.domain.ClientValue;
import org.apache.olingo.client.api.uri.URIBuilder;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.PreferenceName;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.apache.olingo.fit.tecsvc.TecSvcConst;
import org.junit.Test;
public final class AsyncSupportITCase extends AbstractParamTecSvcITCase {
@ -275,7 +284,34 @@ public final class AsyncSupportITCase extends AbstractParamTecSvcITCase {
assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), e.getStatusLine().getStatusCode());
}
}
@Test
public void entityAction() throws Exception {
Calendar dateTime = Calendar.getInstance();
dateTime.clear();
dateTime.set(1012, 2, 0, 0, 0, 0);
final Map<String, ClientValue> parameters = Collections.singletonMap(
"ParameterDate",
(ClientValue) getFactory().newPrimitiveValueBuilder()
.setType(EdmPrimitiveTypeKind.Date).setValue(dateTime).build());
ODataClient client = getClient();
URI uri = client.newURIBuilder(TecSvcConst.BASE_URI)
.appendActionCallSegment("AIRTESAllPrimParam").build();
ODataInvokeRequest<ClientEntity> req = client.getInvokeRequestFactory()
.getActionInvokeRequest(uri, ClientEntity.class, parameters);
AsyncRequestWrapper<ODataRetrieveResponse<ClientEntity>>
asyncReqWrp = client.getAsyncRequestFactory().getAsyncRequestWrapper(req);
AsyncResponseWrapper<ODataRetrieveResponse<ClientEntity>>
asyncRespWrp = asyncReqWrp.execute();
waitTillDone(asyncRespWrp, 5);
@SuppressWarnings("unchecked")
ODataInvokeResponse<ClientEntity> response = (ODataInvokeResponse<ClientEntity>)asyncRespWrp.getODataResponse();
assertEquals(HttpStatusCode.CREATED.getStatusCode(), response.getStatusCode());
assertEquals(TecSvcConst.BASE_URI + "/ESAllPrim(1)", response.getHeader(HttpHeader.LOCATION).iterator().next());
}
private ODataEntityRequest<ClientEntity> appendGetRequest(final ODataClient client,
final String segment, final Object key, final boolean isRelative) {
final URI targetURI = client.newURIBuilder(SERVICE_URI)

View File

@ -55,7 +55,7 @@ public abstract class AbstractODataInvokeRequest<T extends ClientInvokeResult>
extends AbstractODataBasicRequest<ODataInvokeResponse<T>>
implements ODataInvokeRequest<T>, ODataBatchableRequest {
private final Class<T> reference;
protected final Class<T> reference;
/**
* Function parameters.

View File

@ -18,10 +18,22 @@
*/
package org.apache.olingo.client.core.communication.request.invoke;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.request.invoke.ClientNoContent;
import org.apache.olingo.client.api.communication.response.ODataInvokeResponse;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientEntitySet;
import org.apache.olingo.client.api.domain.ClientInvokeResult;
import org.apache.olingo.client.api.domain.ClientProperty;
import org.apache.olingo.client.api.http.HttpClientException;
import org.apache.olingo.client.api.serialization.ODataDeserializerException;
import org.apache.olingo.client.core.communication.response.AbstractODataResponse;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpMethod;
@ -45,4 +57,52 @@ public class ODataInvokeRequestImpl<T extends ClientInvokeResult> extends Abstra
protected ContentType getPOSTParameterFormat() {
return contentType == null ? getDefaultFormat() : contentType;
}
/**
* Response class about an ODataInvokeRequest.
*/
protected class ODataInvokeResponseImpl extends AbstractODataResponse implements ODataInvokeResponse<T> {
private T invokeResult = null;
private ODataInvokeResponseImpl(final ODataClient odataClient, final HttpClient httpClient,
final HttpResponse res) {
super(odataClient, httpClient, res);
}
/**
* {@inheritDoc }
*/
@Override
public T getBody() {
if (invokeResult == null) {
try {
if (ClientNoContent.class.isAssignableFrom(reference)) {
invokeResult = reference.cast(new ClientNoContent());
} else {
// avoid getContent() twice:IllegalStateException: Content has been consumed
final InputStream responseStream = this.payload == null ? res.getEntity().getContent() : this.payload;
if (ClientEntitySet.class.isAssignableFrom(reference)) {
invokeResult = reference.cast(odataClient.getReader().readEntitySet(responseStream,
ContentType.parse(getContentType())));
} else if (ClientEntity.class.isAssignableFrom(reference)) {
invokeResult = reference.cast(odataClient.getReader().readEntity(responseStream,
ContentType.parse(getContentType())));
} else if (ClientProperty.class.isAssignableFrom(reference)) {
invokeResult = reference.cast(odataClient.getReader().readProperty(responseStream,
ContentType.parse(getContentType())));
}
}
} catch (IOException e) {
throw new HttpClientException(e);
} catch (final ODataDeserializerException e) {
throw new IllegalArgumentException(e);
} finally {
this.close();
}
}
return invokeResult;
}
}
}

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.Serializable;
import org.apache.olingo.client.core.edm.xml.AbstractClientCsdlEdmDeserializer;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlAnnotationPath;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlDynamicExpression;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlExpression;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlIf;
@ -120,7 +121,7 @@ public abstract class ClientCsdlDynamicExpression extends CsdlDynamicExpression
} else if (PROPERTY_PATH.equals(jp.getCurrentName())) {
expression = new CsdlPropertyPath().setValue(jp.nextTextValue());
} else if (ANNOTATION_PATH.equals(jp.getCurrentName())) {
expression = new CsdlPath().setValue(jp.nextTextValue());
expression = new CsdlAnnotationPath().setValue(jp.nextTextValue());
} else if (APPLY.equals(jp.getCurrentName())) {
jp.nextToken();
expression = jp.readValueAs(ClientCsdlApply.class);

View File

@ -60,6 +60,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.apache.olingo.commons.api.edm.provider.CsdlSingleton;
import org.apache.olingo.commons.api.edm.provider.CsdlTerm;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlAnnotationPath;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlApply;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlCollection;
import org.apache.olingo.commons.api.edm.provider.annotation.CsdlConstantExpression;
@ -457,6 +458,33 @@ public class MetadataTest extends AbstractTest {
assertEquals("EnumMember", expression.getExpressionName());
}
}
@Test
public void readPropertyAnnotationsTest() {
List<InputStream> streams = new ArrayList<InputStream>();
streams.add(getClass().getResourceAsStream("VOC_Core.xml"));
final Edm edm = client.getReader().readMetadata(getClass().getResourceAsStream("edmxWithCsdlAnnotationPath.xml"),
streams);
assertNotNull(edm);
final EdmEntityType person = edm.getEntityType(
new FullQualifiedName("Microsoft.Exchange.Services.OData.Model", "Person"));
assertNotNull(person);
EdmProperty userName = (EdmProperty) person.getProperty("UserName");
List<EdmAnnotation> userNameAnnotations = userName.getAnnotations();
for (EdmAnnotation annotation : userNameAnnotations) {
EdmTerm term = annotation.getTerm();
assertNotNull(term);
assertEquals("Permissions", term.getName());
assertEquals("Org.OData.Core.V1.Permissions",
term.getFullQualifiedName().getFullQualifiedNameAsString());
EdmExpression expression = annotation.getExpression();
assertNotNull(expression);
assertTrue(expression.isDynamic());
assertEquals("AnnotationPath", expression.asDynamic().getExpressionName());
}
}
@Test
public void testOLINGO1100() {
final Edm edm = client.getReader().readMetadata(getClass().getResourceAsStream("olingo1100.xml"));

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
you 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. -->
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices m:DataServiceVersion="4.0"
m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
<Schema Namespace="Microsoft.Exchange.Services.OData.Model"
xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Person" OpenType="true">
<Key>
<PropertyRef Name="UserName" />
</Key>
<Property Name="UserName" Type="Edm.String" Nullable="false">
<Annotation Term="Org.OData.Core.V1.Permissions">
<AnnotationPath>Org.OData.Core.V1.Permission/Read</AnnotationPath>
</Annotation>
</Property>
<Property Name="FirstName" Type="Edm.String" Nullable="false" />
<Property Name="LastName" Type="Edm.String" Nullable="false" />
<Property Name="Emails" Type="Collection(Edm.String)" />
</EntityType>
<EntityContainer Name="EntityContainer"
m:IsDefaultEntityContainer="true">
<EntitySet Name="People"
EntityType="Microsoft.Exchange.Services.OData.Model.Person" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -150,6 +150,15 @@ public abstract class OData {
*/
public abstract ODataDeserializer createDeserializer(ContentType contentType) throws DeserializerException;
/**
* Creates a new deserializer object for reading content in the specified format.
* Deserializers are used in Processor implementations.
*
* @param contentType any content type supported by Olingo (XML, JSON ...)
*/
public abstract ODataDeserializer createDeserializer(ContentType contentType,
final List<String> versions) throws DeserializerException;
/**
* Creates a new deserializer object for reading content in the specified format.
* Deserializers are used in Processor implementations.
@ -160,6 +169,16 @@ public abstract class OData {
public abstract ODataDeserializer createDeserializer(ContentType contentType,
ServiceMetadata metadata) throws DeserializerException;
/**
* Creates a new deserializer object for reading content in the specified format.
* Deserializers are used in Processor implementations.
*
* @param contentType any content type supported by Olingo (XML, JSON ...)
* @param metadata ServiceMetada of the service
*/
public abstract ODataDeserializer createDeserializer(ContentType contentType,
ServiceMetadata metadata, final List<String> versions) throws DeserializerException;
/**
* Creates a primitive-type instance.
* @param kind the kind of the primitive type

View File

@ -160,5 +160,17 @@ public class ODataNettyImpl extends ODataNetty {
throws SerializerException {
return odata.createEdmDeltaSerializer(contentType, versions);
}
@Override
public ODataDeserializer createDeserializer(ContentType contentType, List<String> versions)
throws DeserializerException {
return odata.createDeserializer(contentType, versions);
}
@Override
public ODataDeserializer createDeserializer(ContentType contentType, ServiceMetadata metadata, List<String> versions)
throws DeserializerException {
return odata.createDeserializer(contentType, metadata, versions);
}
}

View File

@ -238,4 +238,40 @@ public class ODataImpl extends OData {
// TODO: Support more debug formats
return new DebugResponseHelperImpl(debugFormat);
}
@Override
public ODataDeserializer createDeserializer(ContentType contentType, List<String> versions)
throws DeserializerException {
IConstants constants = new Constantsv00();
if(versions!=null && versions.size()>0 && getMaxVersion(versions)>4){
constants = new Constantsv01() ;
}
if (contentType.isCompatible(ContentType.JSON)) {
return new ODataJsonDeserializer(contentType, constants);
} else if (contentType.isCompatible(ContentType.APPLICATION_XML)
|| contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
return new ODataXmlDeserializer();
} else {
throw new DeserializerException("Unsupported format: " + contentType.toContentTypeString(),
DeserializerException.MessageKeys.UNSUPPORTED_FORMAT, contentType.toContentTypeString());
}
}
@Override
public ODataDeserializer createDeserializer(ContentType contentType, ServiceMetadata metadata, List<String> versions)
throws DeserializerException {
IConstants constants = new Constantsv00();
if(versions!=null && versions.size()>0 && getMaxVersion(versions)>4){
constants = new Constantsv01() ;
}
if (contentType.isCompatible(ContentType.JSON)) {
return new ODataJsonDeserializer(contentType, metadata, constants);
} else if (contentType.isCompatible(ContentType.APPLICATION_XML)
|| contentType.isCompatible(ContentType.APPLICATION_ATOM_XML)) {
return new ODataXmlDeserializer(metadata);
} else {
throw new DeserializerException("Unsupported format: " + contentType.toContentTypeString(),
DeserializerException.MessageKeys.UNSUPPORTED_FORMAT, contentType.toContentTypeString());
}
}
}

View File

@ -33,6 +33,8 @@ import java.util.Map;
import java.util.Map.Entry;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.IConstants;
import org.apache.olingo.commons.api.constants.Constantsv00;
import org.apache.olingo.commons.api.data.ComplexValue;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
@ -105,14 +107,27 @@ public class ODataJsonDeserializer implements ODataDeserializer {
private final boolean isIEEE754Compatible;
private ServiceMetadata serviceMetadata;
private IConstants constants;
public ODataJsonDeserializer(final ContentType contentType) {
this(contentType, null);
this(contentType, null, new Constantsv00());
}
public ODataJsonDeserializer(final ContentType contentType, final ServiceMetadata serviceMetadata) {
isIEEE754Compatible = ContentTypeHelper.isODataIEEE754Compatible(contentType);
this.serviceMetadata = serviceMetadata;
this.constants = new Constantsv00();
}
public ODataJsonDeserializer(ContentType contentType, ServiceMetadata serviceMetadata, IConstants constants) {
isIEEE754Compatible = ContentTypeHelper.isODataIEEE754Compatible(contentType);
this.serviceMetadata = serviceMetadata;
this.constants = constants;
}
public ODataJsonDeserializer(ContentType contentType, IConstants constants) {
isIEEE754Compatible = ContentTypeHelper.isODataIEEE754Compatible(contentType);
this.constants = constants;
}
@Override
@ -337,7 +352,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
while (fieldsIterator.hasNext()) {
Entry<String, JsonNode> field = fieldsIterator.next();
if (field.getKey().contains(Constants.JSON_BIND_LINK_SUFFIX)) {
if (field.getKey().contains(constants.getBind())) {
Link bindingLink = consumeBindingLink(field.getKey(), field.getValue(), edmEntityType);
entity.getNavigationBindings().add(bindingLink);
toRemove.add(field.getKey());
@ -937,7 +952,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
try {
List<URI> parsedValues = new ArrayList<URI>();
final ObjectNode tree = parseJsonTree(stream);
final String key = Constants.JSON_ID;
final String key = constants.getId();
JsonNode jsonNode = tree.get(Constants.VALUE);
if (jsonNode != null) {
if (jsonNode.isArray()) {
@ -984,7 +999,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
private EdmType getDerivedType(final EdmStructuredType edmType, final JsonNode jsonNode)
throws DeserializerException {
JsonNode odataTypeNode = jsonNode.get(Constants.JSON_TYPE);
JsonNode odataTypeNode = jsonNode.get(constants.getType());
if (odataTypeNode != null) {
String odataType = odataTypeNode.asText();
if (!odataType.isEmpty()) {

View File

@ -140,13 +140,13 @@ public class RequestValidator {
if (edmProperty.isCollection()) {
final EntityCollection inlineEntitySet = navigationLink.getInlineEntitySet();
if (inlineEntitySet != null) {
if (!isInsert && inlineEntitySet.getEntities().size() > 0) {
/*if (!isInsert && inlineEntitySet.getEntities().size() > 0) {
throw new DataProvider.DataProviderException("Deep update is not allowed", HttpStatusCode.BAD_REQUEST);
} else {
} else {*/
for (final Entity entity : navigationLink.getInlineEntitySet().getEntities()) {
validate(edmBindingTarget, entity);
}
}
// }
}
} else {
final Entity inlineEntity = navigationLink.getInlineEntity();