[OLINGO-175, OLINGO-205] provided (v4) context url and entity reference retrieving + it tests

This commit is contained in:
fmartelli 2014-03-26 15:40:11 +01:00
parent f0edb50813
commit 428277c26d
80 changed files with 2473 additions and 343 deletions

View File

@ -54,6 +54,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.fit.utils.Constants;
@ -144,6 +145,40 @@ public abstract class AbstractServices {
}
}
/**
* Retrieve entity reference sample.
*
* @param accept Accept header.
* @param path path.
* @param format format query option.
* @return entity reference or feed of entity reference.
*/
@GET
@Path("/{path:.*}/$ref")
public Response getEntityReference(
@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
@PathParam("path") String path,
@QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
try {
final Map.Entry<Accept, AbstractUtilities> utils = getUtilities(accept, format);
if (utils.getKey() == Accept.TEXT) {
throw new UnsupportedMediaTypeException("Unsupported media type");
}
final String filename = Base64.encodeBase64String(path.getBytes("UTF-8"));
return utils.getValue().createResponse(
FSManager.instance(getVersion()).readFile(Constants.REF + File.separatorChar + filename, utils.getKey()),
null,
utils.getKey());
} catch (Exception e) {
LOG.error("Error retrieving entity", e);
return xml.createFaultResponse(accept, e);
}
}
@MERGE
@Path("/{entitySetName}/{entityId}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON})
@ -386,7 +421,7 @@ public abstract class AbstractServices {
} else if (StringUtils.isNotBlank(skiptoken)) {
builder.append(SKIP_TOKEN).append(File.separatorChar).append(skiptoken);
} else {
builder.append(FEED);
builder.append(Commons.getLinkInfo().get(getVersion()).isSingleton(name) ? ENTITY : FEED);
}
InputStream feed = FSManager.instance(getVersion()).readFile(builder.toString(), acceptType);

View File

@ -1208,11 +1208,21 @@ public abstract class AbstractXMLUtilities extends AbstractUtilities {
writer.add(eventFactory.createStartDocument("UTF-8", "1.0"));
writer.add(property.getStart());
if (property.getStart().getAttributeByName(new QName(ATOM_DATASERVICE_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_PROPERTY_PREFIX.substring(0, 1), DATASERVICES_NS));
}
if (property.getStart().getAttributeByName(new QName(ATOM_METADATA_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_METADATA_PREFIX.substring(0, 1), METADATA_NS));
if (version == ODataVersion.v4) {
if (property.getStart().getAttributeByName(new QName(ATOM_DATASERVICE_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_PROPERTY_PREFIX.substring(0, 1), V4_DATASERVICES_NS));
}
if (property.getStart().getAttributeByName(new QName(ATOM_METADATA_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_METADATA_PREFIX.substring(0, 1), V4_METADATA_NS));
}
} else {
if (property.getStart().getAttributeByName(new QName(ATOM_DATASERVICE_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_PROPERTY_PREFIX.substring(0, 1), V3_DATASERVICES_NS));
}
if (property.getStart().getAttributeByName(new QName(ATOM_METADATA_NS)) == null) {
writer.add(eventFactory.createNamespace(ATOM_METADATA_PREFIX.substring(0, 1), V3_METADATA_NS));
}
}
writer.add(property.getContentReader());

View File

@ -41,6 +41,7 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -79,11 +80,14 @@ public abstract class Commons {
}
public static String getEntityURI(final String entitySetName, final String entityKey) {
return entitySetName + "(" + entityKey + ")";
// expected singleton in case of null key
return entitySetName + (StringUtils.isNotBlank(entityKey) ? "(" + entityKey + ")" : "");
}
public static String getEntityBasePath(final String entitySetName, final String entityKey) {
return entitySetName + File.separatorChar + getEntityKey(entityKey) + File.separatorChar;
// expected singleton in case of null key
return entitySetName + File.separatorChar
+ (StringUtils.isNotBlank(entityKey) ? getEntityKey(entityKey) + File.separatorChar : "");
}
public static String getLinksURI(
@ -266,8 +270,18 @@ public abstract class Commons {
public static Map.Entry<String, String> parseEntityURI(final String uri) {
final String relPath = uri.substring(uri.lastIndexOf("/"));
final int branchIndex = relPath.indexOf('(');
final String es = relPath.substring(0, branchIndex);
final String eid = relPath.substring(branchIndex + 1, relPath.indexOf(')'));
final String es;
final String eid;
if (branchIndex > -1) {
es = relPath.substring(0, branchIndex);
eid = relPath.substring(branchIndex + 1, relPath.indexOf(')'));
} else {
es = relPath;
eid = null;
}
return new SimpleEntry<String, String>(es, eid);
}
}

View File

@ -60,9 +60,13 @@ public class Constants {
public final static String LINK = "link";
public final static String DATASERVICES_NS = "http://schemas.microsoft.com/ado/2007/08/dataservices";
public final static String V3_DATASERVICES_NS = "http://schemas.microsoft.com/ado/2007/08/dataservices";
public final static String METADATA_NS = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
public final static String V4_DATASERVICES_NS = "http://docs.oasis-open.org/odata/ns/dataservices";
public final static String V3_METADATA_NS = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
public final static String V4_METADATA_NS = "http://docs.oasis-open.org/odata/ns/metadata";
public final static String METADATA = "metadata";
@ -72,6 +76,8 @@ public class Constants {
public final static String ENTITY = "entity";
public final static String REF = "references";
public final static String MEDIA_CONTENT_FILENAME = "$value.bin";
public final static String SKIP_TOKEN = "skiptoken";

View File

@ -28,6 +28,14 @@ public class MetadataLinkInfo {
private Map<String, EntitySet> entitySets = new HashMap<String, EntitySet>();
public void setSingleton(final String entitySetName) {
entitySets.get(entitySetName).setSingleton(true);
}
public boolean isSingleton(final String entitySetName) {
return entitySets.get(entitySetName).isSingleton();
}
public Set<String> getEntitySets() {
return entitySets.keySet();
}
@ -92,6 +100,8 @@ public class MetadataLinkInfo {
private Set<NavigationLink> links;
private boolean singleton;
public EntitySet(final String name) {
this.name = name;
links = new HashSet<NavigationLink>();
@ -135,6 +145,18 @@ public class MetadataLinkInfo {
this.links = links;
}
public EntitySet(boolean singleton) {
this.singleton = singleton;
}
public boolean isSingleton() {
return singleton;
}
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
@Override
public String toString() {
return name + ": " + links;

View File

@ -138,5 +138,9 @@ public class XMLUtilities extends org.apache.olingo.fit.utils.AbstractXMLUtiliti
if (size == 0) {
metadataLinkInfo.addEntitySet(entitySetName);
}
if (singletons.contains(entitySetName)) {
metadataLinkInfo.setSingleton(entitySetName);
}
}
}

View File

@ -0,0 +1,38 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Company",
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Company",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company",
"CompanyID": 0,
"CompanyCategory@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.CompanyCategory",
"CompanyCategory": "IT",
"Revenue@odata.type": "#Int64",
"Revenue": 100000,
"Name": "MS",
"Address":
{
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.CompanyAddress",
"Street": "1 Microsoft Way",
"City": "Redmond",
"PostalCode": "98052",
"CompanyName": "Microsoft"
},
"Employees@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Employees/$ref",
"Employees@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Employees",
"VipCustomer@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/VipCustomer/$ref",
"VipCustomer@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/VipCustomer",
"Departments@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Departments/$ref",
"Departments@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Departments",
"CoreDepartment@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/CoreDepartment/$ref",
"CoreDepartment@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/CoreDepartment",
"#Microsoft.Test.OData.Services.ODataWCFService.IncreaseRevenue":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.IncreaseRevenue",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Microsoft.Test.OData.Services.ODataWCFService.IncreaseRevenue"
},
"#Microsoft.Test.OData.Services.ODataWCFService.GetEmployeesCount":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.GetEmployeesCount",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Microsoft.Test.OData.Services.ODataWCFService.GetEmployeesCount"
}
}

View File

@ -0,0 +1,49 @@
<?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.
-->
<entry xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Company">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Company" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Employees" type="application/atom+xml;type=feed" title="Employees" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Employees" />
<link rel="http://docs.oasis-open.org/odata/ns/related/VipCustomer" type="application/atom+xml;type=entry" title="VipCustomer" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/VipCustomer" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Departments" type="application/atom+xml;type=feed" title="Departments" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/Departments" />
<link rel="http://docs.oasis-open.org/odata/ns/related/CoreDepartment" type="application/atom+xml;type=entry" title="CoreDepartment" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company/CoreDepartment" />
<title />
<updated>2014-03-24T17:09:31Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:CompanyID m:type="Int32">0</d:CompanyID>
<d:CompanyCategory m:type="#Microsoft.Test.OData.Services.ODataWCFService.CompanyCategory">IT</d:CompanyCategory>
<d:Revenue m:type="Int64">100000</d:Revenue>
<d:Name>MS</d:Name>
<d:Address m:type="#Microsoft.Test.OData.Services.ODataWCFService.CompanyAddress">
<d:Street>1 Microsoft Way</d:Street>
<d:City>Redmond</d:City>
<d:PostalCode>98052</d:PostalCode>
<d:CompanyName>Microsoft</d:CompanyName>
</d:Address>
</m:properties>
</content>
</entry>

View File

@ -0,0 +1,67 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Customers/$entity",
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Customer",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)",
"PersonID": 1,
"FirstName": "Bob",
"LastName": "Cat",
"MiddleName": null,
"HomeAddress":
{
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.HomeAddress",
"Street": "1 Microsoft Way",
"City": "London",
"PostalCode": "98052",
"FamilyName": "Cats"
},
"Home@odata.type": "#GeographyPoint",
"Home":
{
"type": "Point",
"coordinates":
[
23.1,
32.1
],
"crs":
{
"type": "name",
"properties":
{
"name": "EPSG:4326"
}
}
},
"Numbers@odata.type": "#Collection(String)",
"Numbers":
[
"111-111-1111"
],
"Emails@odata.type": "#Collection(String)",
"Emails":
[
"abc@abc.com"
],
"City": "London",
"Birthday@odata.type": "#DateTimeOffset",
"Birthday": "1957-04-03T00:00:00Z",
"TimeBetweenLastTwoOrders@odata.type": "#Duration",
"TimeBetweenLastTwoOrders": "PT0.0000001S",
"Parent@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Parent/$ref",
"Parent@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Parent",
"Orders@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Orders/$ref",
"Orders@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Orders",
"Company@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Company/$ref",
"Company@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Company",
"#Microsoft.Test.OData.Services.ODataWCFService.ResetAddress":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.ResetAddress",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Microsoft.Test.OData.Services.ODataWCFService.ResetAddress"
},
"#Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress"
}
}

View File

@ -0,0 +1,67 @@
<?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.
-->
<entry xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/"
xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data"
xmlns:m="http://docs.oasis-open.org/odata/ns/metadata"
xmlns:georss="http://www.georss.org/georss"
xmlns:gml="http://www.opengis.net/gml"
m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Customers/$entity">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Customer" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Parent" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Orders" type="application/atom+xml;type=feed" title="Orders" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Orders" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Company" type="application/atom+xml;type=entry" title="Company" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)/Company" />
<title />
<updated>2014-03-24T17:03:20Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:PersonID m:type="Int32">1</d:PersonID>
<d:FirstName>Bob</d:FirstName>
<d:LastName>Cat</d:LastName>
<d:MiddleName m:null="true" />
<d:HomeAddress m:type="#Microsoft.Test.OData.Services.ODataWCFService.HomeAddress">
<d:Street>1 Microsoft Way</d:Street>
<d:City>London</d:City>
<d:PostalCode>98052</d:PostalCode>
<d:FamilyName>Cats</d:FamilyName>
</d:HomeAddress>
<d:Home m:type="GeographyPoint">
<gml:Point gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
<gml:pos>32.1 23.1</gml:pos>
</gml:Point>
</d:Home>
<d:Numbers m:type="#Collection(String)">
<m:element>111-111-1111</m:element>
</d:Numbers>
<d:Emails m:type="#Collection(String)">
<m:element>abc@abc.com</m:element>
</d:Emails>
<d:City>London</d:City>
<d:Birthday m:type="DateTimeOffset">1957-04-03T00:00:00Z</d:Birthday>
<d:TimeBetweenLastTwoOrders m:type="Duration">PT0.0000001S</d:TimeBetweenLastTwoOrders>
</m:properties>
</content>
</entry>

View File

@ -0,0 +1,4 @@
{
"odata.metadata": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Customer/$links/Info",
"url": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company"
}

View File

@ -0,0 +1,22 @@
<?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.
-->
<uri xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Company</uri>

View File

@ -0,0 +1,10 @@
{
"odata.metadata": "http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/$metadata#Customer/$links/Orders",
"value":
[
{
"url": "http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/Orders(8)"
}
],
"odata.nextLink": "http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/Customers(1)/$links/Orders?$skiptoken=2"
}

View File

@ -0,0 +1,25 @@
<?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.
-->
<links xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">
<uri>http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/Orders(8)</uri>
<next>http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/Customers(1)/$links/Orders?$skiptoken=2</next>
</links>

View File

@ -0,0 +1,23 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Orders/$entity",
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Order",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)",
"@odata.etag": "W/\"123456789001\"",
"OrderID": 8,
"OrderDate@odata.type": "#DateTimeOffset",
"OrderDate": "2011-03-04T16:03:57Z",
"ShelfLife@odata.type": "#Duration",
"ShelfLife": "PT0.0000001S",
"OrderShelfLifes@odata.type": "#Collection(Duration)",
"OrderShelfLifes":
[
"PT0.0000001S"
],
"LoggedInEmployee@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee/$ref",
"LoggedInEmployee@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee",
"CustomerForOrder@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder/$ref",
"CustomerForOrder@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder",
"OrderDetails@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails/$ref",
"OrderDetails@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails"
}

View File

@ -0,0 +1,50 @@
<?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.
-->
<entry xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/"
xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data"
xmlns:m="http://docs.oasis-open.org/odata/ns/metadata"
xmlns:georss="http://www.georss.org/georss"
xmlns:gml="http://www.opengis.net/gml"
m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Orders/$entity"
m:etag="W/&quot;123456789001&quot;">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Order" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/LoggedInEmployee" type="application/atom+xml;type=entry" title="LoggedInEmployee" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee" />
<link rel="http://docs.oasis-open.org/odata/ns/related/CustomerForOrder" type="application/atom+xml;type=entry" title="CustomerForOrder" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder" />
<link rel="http://docs.oasis-open.org/odata/ns/related/OrderDetails" type="application/atom+xml;type=feed" title="OrderDetails" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails" />
<title />
<updated>2014-03-24T17:36:01Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:OrderID m:type="Int32">8</d:OrderID>
<d:OrderDate m:type="DateTimeOffset">2011-03-04T16:03:57Z</d:OrderDate>
<d:ShelfLife m:type="Duration">PT0.0000001S</d:ShelfLife>
<d:OrderShelfLifes m:type="#Collection(Duration)">
<m:element>PT0.0000001S</m:element>
</d:OrderShelfLifes>
</m:properties>
</content>
</entry>

View File

@ -0,0 +1 @@
W/"123456789001"

View File

@ -0,0 +1,4 @@
{
"odata.metadata": "http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/$metadata#Customer/$links/Info",
"url": "http://localhost:${cargo.servlet.port}/StaticService/V30/Static.svc/CustomerInfo(11)"
}

View File

@ -0,0 +1,4 @@
{
"odata.metadata": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Orders/$links/CustomerForOrder",
"url": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(1)"
}

View File

@ -0,0 +1,22 @@
<?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.
-->
<uri xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(1)</uri>

View File

@ -0,0 +1,48 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Orders",
"value":
[
{
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Order",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)",
"OrderID": 7,
"OrderDate@odata.type": "#DateTimeOffset",
"OrderDate": "2011-05-29T14:21:12Z",
"ShelfLife@odata.type": "#Duration",
"ShelfLife": "PT0.0000001S",
"OrderShelfLifes@odata.type": "#Collection(Duration)",
"OrderShelfLifes":
[
"PT0.0000001S"
],
"LoggedInEmployee@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/LoggedInEmployee/$ref",
"LoggedInEmployee@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/LoggedInEmployee",
"CustomerForOrder@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/CustomerForOrder/$ref",
"CustomerForOrder@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/CustomerForOrder",
"OrderDetails@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/OrderDetails/$ref",
"OrderDetails@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/OrderDetails"
},
{
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Order",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)",
"OrderID": 8,
"OrderDate@odata.type": "#DateTimeOffset",
"OrderDate": "2011-03-04T16:03:57Z",
"ShelfLife@odata.type": "#Duration",
"ShelfLife": "PT0.0000001S",
"OrderShelfLifes@odata.type": "#Collection(Duration)",
"OrderShelfLifes":
[
"PT0.0000001S"
],
"LoggedInEmployee@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee/$ref",
"LoggedInEmployee@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee",
"CustomerForOrder@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder/$ref",
"CustomerForOrder@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder",
"OrderDetails@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails/$ref",
"OrderDetails@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails"
}
]
}

View File

@ -0,0 +1,72 @@
<?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.
-->
<feed xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#Orders">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders</id>
<title />
<updated>2014-03-24T17:17:25Z</updated>
<entry>
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Order" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/LoggedInEmployee" type="application/atom+xml;type=entry" title="LoggedInEmployee" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/LoggedInEmployee" />
<link rel="http://docs.oasis-open.org/odata/ns/related/CustomerForOrder" type="application/atom+xml;type=entry" title="CustomerForOrder" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/CustomerForOrder" />
<link rel="http://docs.oasis-open.org/odata/ns/related/OrderDetails" type="application/atom+xml;type=feed" title="OrderDetails" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(7)/OrderDetails" />
<title />
<updated>2014-03-24T17:17:25Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:OrderID m:type="Int32">7</d:OrderID>
<d:OrderDate m:type="DateTimeOffset">2011-05-29T14:21:12Z</d:OrderDate>
<d:ShelfLife m:type="Duration">PT0.0000001S</d:ShelfLife>
<d:OrderShelfLifes m:type="#Collection(Duration)">
<m:element>PT0.0000001S</m:element>
</d:OrderShelfLifes>
</m:properties>
</content>
</entry>
<entry>
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Order" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/LoggedInEmployee" type="application/atom+xml;type=entry" title="LoggedInEmployee" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/LoggedInEmployee" />
<link rel="http://docs.oasis-open.org/odata/ns/related/CustomerForOrder" type="application/atom+xml;type=entry" title="CustomerForOrder" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/CustomerForOrder" />
<link rel="http://docs.oasis-open.org/odata/ns/related/OrderDetails" type="application/atom+xml;type=feed" title="OrderDetails" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Orders(8)/OrderDetails" />
<title />
<updated>2014-03-24T17:17:25Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:OrderID m:type="Int32">8</d:OrderID>
<d:OrderDate m:type="DateTimeOffset">2011-03-04T16:03:57Z</d:OrderDate>
<d:ShelfLife m:type="Duration">PT0.0000001S</d:ShelfLife>
<d:OrderShelfLifes m:type="#Collection(Duration)">
<m:element>PT0.0000001S</m:element>
</d:OrderShelfLifes>
</m:properties>
</content>
</entry>
</feed>

View File

@ -0,0 +1,51 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#People/$entity",
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.Person",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)",
"PersonID": 5,
"FirstName": "Peter",
"LastName": "Bee",
"MiddleName": null,
"HomeAddress": null,
"Home@odata.type": "#GeographyPoint",
"Home":
{
"type": "Point",
"coordinates":
[
-261.8,
-16
],
"crs":
{
"type": "name",
"properties":
{
"name": "EPSG:4326"
}
}
},
"Numbers@odata.type": "#Collection(String)",
"Numbers":
[
"555-555-5555"
],
"Emails@odata.type": "#Collection(String)",
"Emails":
[
"def@test.msn"
],
"Parent@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)/Parent/$ref",
"Parent@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)/Parent",
"#Microsoft.Test.OData.Services.ODataWCFService.ResetAddress":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.ResetAddress",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)/Microsoft.Test.OData.Services.ODataWCFService.ResetAddress"
},
"#Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)/Microsoft.Test.OData.Services.ODataWCFService.GetHomeAddress"
}
}

View File

@ -0,0 +1,55 @@
<?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.
-->
<entry xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#People/$entity">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.Person" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/People(5)/Parent" />
<title />
<updated>2014-03-24T17:20:17Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:PersonID m:type="Int32">5</d:PersonID>
<d:FirstName>Peter</d:FirstName>
<d:LastName>Bee</d:LastName>
<d:MiddleName m:null="true" />
<d:HomeAddress m:null="true" />
<d:Home m:type="GeographyPoint">
<gml:Point gml:srsName="http://www.opengis.net/def/crs/EPSG/0/4326">
<gml:pos>-16 -261.8</gml:pos>
</gml:Point>
</d:Home>
<d:Numbers m:type="#Collection(String)">
<m:element>555-555-5555</m:element>
</d:Numbers>
<d:Emails m:type="#Collection(String)">
<m:element>def@test.msn</m:element>
</d:Emails>
<d:IsRegistered m:type="Boolean">true</d:IsRegistered>
<d:Height m:type="Decimal">179</d:Height>
<d:PDC m:type="Binary">fi653p3+MklA/LdoBlhWgnMTUUEo8tEgtbMXnF0a3CUNL9BZxXpSRiD9ebTnmNR0zWPjJVIDx4tdmCnq55XrJh+RW9aI/b34wAogK3kcORw=</d:PDC>
</m:properties>
</content>
</entry>

View File

@ -0,0 +1,19 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#ProductDetails/$entity",
"@odata.type": "#Microsoft.Test.OData.Services.ODataWCFService.ProductDetail",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)",
"@odata.editLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)",
"ProductID": 6,
"ProductDetailID": 1,
"ProductName": "Candy",
"Description": "sweet snack",
"RelatedProduct@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/RelatedProduct/$ref",
"RelatedProduct@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/RelatedProduct",
"Reviews@odata.associationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/Reviews/$ref",
"Reviews@odata.navigationLink": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/Reviews",
"#Microsoft.Test.OData.Services.ODataWCFService.GetRelatedProduct":
{
"title": "Microsoft.Test.OData.Services.ODataWCFService.GetRelatedProduct",
"target": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/Microsoft.Test.OData.Services.ODataWCFService.GetRelatedProduct"
}
}

View File

@ -0,0 +1,41 @@
<?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.
-->
<entry xml:base="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#ProductDetails/$entity">
<id>http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)</id>
<category term="#Microsoft.Test.OData.Services.ODataWCFService.ProductDetail" scheme="http://docs.oasis-open.org/odata/ns/scheme" />
<link rel="edit" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)" />
<link rel="http://docs.oasis-open.org/odata/ns/related/RelatedProduct" type="application/atom+xml;type=entry" title="RelatedProduct" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/RelatedProduct" />
<link rel="http://docs.oasis-open.org/odata/ns/related/Reviews" type="application/atom+xml;type=feed" title="Reviews" href="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/ProductDetails(ProductID=6,ProductDetailID=1)/Reviews" />
<title />
<updated>2014-03-24T17:23:51Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:ProductID m:type="Int32">6</d:ProductID>
<d:ProductDetailID m:type="Int32">1</d:ProductDetailID>
<d:ProductName>Candy</d:ProductName>
<d:Description>sweet snack</d:Description>
</m:properties>
</content>
</entry>

View File

@ -0,0 +1,17 @@
{
"odata.error":
{
"code": "",
"message":
{
"lang": "en-US",
"value": "Bad request."
},
"innererror":
{
"message": "Bad request.",
"type": "Microsoft.Data.OData.BadRequest",
"stacktrace": " at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings...."
}
}
}

View File

@ -0,0 +1,30 @@
<?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.
-->
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">Bad request.</m:message>
<m:innererror>
<m:message>Bad request.</m:message>
<m:type>Microsoft.Data.OData.BadRequest</m:type>
<m:stacktrace> at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings...</m:stacktrace>
</m:innererror>
</m:error>

View File

@ -0,0 +1,11 @@
{
"odata.error":
{
"code": "",
"message":
{
"lang": "en-US",
"value": "Resource not found for the segment 'Customer'."
}
}
}

View File

@ -0,0 +1,25 @@
<?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.
-->
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">Resource not found for the segment 'Customer'.</m:message>
</m:error>

View File

@ -0,0 +1,4 @@
{
"@odata.context": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#$ref",
"@odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)"
}

View File

@ -0,0 +1,22 @@
<?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.
-->
<m:ref m:context="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/$metadata#$ref" id="http://localhost:${cargo.servlet.port}/StaticService/V40/Static.svc/Customers(PersonID=1)" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" />

View File

@ -0,0 +1,17 @@
{
"odata.error":
{
"code": "",
"message":
{
"lang": "en-US",
"value": "Unsupported media type requested."
},
"innererror":
{
"message": "Unsupported media type requested.",
"type": "Microsoft.Data.OData.ODataContentTypeException",
"stacktrace": " at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings(ODataMessageWriterSettings settings, ODataPayloadKind payloadKind, MediaTypeResolver mediaTypeResolver, MediaType&amp; mediaType, Encoding&amp; encoding)\n at Microsoft.Data.OData.ODataMessageWriter.EnsureODataFormatAndContentType()\n at Microsoft.Data.OData.ODataMessageWriter.SetHeaders(ODataPayloadKind payloadKind)\n at Microsoft.Data.OData.ODataUtils.SetHeadersForPayload(ODataMessageWriter messageWriter, ODataPayloadKind payloadKind)\n at System.Data.Services.ResponseContentTypeNegotiator.DetermineResponseFormat(ODataPayloadKind payloadKind, String acceptableMediaTypes, String acceptableCharSets)"
}
}
}

View File

@ -0,0 +1,34 @@
<?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.
-->
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">Unsupported media type requested.</m:message>
<m:innererror>
<m:message>A supported MIME type could not be found that matches the acceptable MIME types for the request. The supported type(s) 'application/atom+xml;type=feed, application/atom+xml, application/json;odata=minimalmetadata;streaming=true, application/json;odata=minimalmetadata;streaming=false, application/json;odata=minimalmetadata, application/json;odata=fullmetadata;streaming=true, application/json;odata=fullmetadata;streaming=false, application/json;odata=fullmetadata, application/json;odata=nometadata;streaming=true, application/json;odata=nometadata;streaming=false, application/json;odata=nometadata, application/json;streaming=true, application/json;streaming=false, application/json;odata=verbose, application/json' do not match any of the acceptable MIME types 'application/xml'.</m:message>
<m:type>Microsoft.Data.OData.ODataContentTypeException</m:type>
<m:stacktrace> at Microsoft.Data.OData.MediaTypeUtils.GetContentTypeFromSettings(ODataMessageWriterSettings settings, ODataPayloadKind payloadKind, MediaTypeResolver mediaTypeResolver, MediaType&amp; mediaType, Encoding&amp; encoding)&#xD;
at Microsoft.Data.OData.ODataMessageWriter.EnsureODataFormatAndContentType()&#xD;
at Microsoft.Data.OData.ODataMessageWriter.SetHeaders(ODataPayloadKind payloadKind)&#xD;
at Microsoft.Data.OData.ODataUtils.SetHeadersForPayload(ODataMessageWriter messageWriter, ODataPayloadKind payloadKind)&#xD;
at System.Data.Services.ResponseContentTypeNegotiator.DetermineResponseFormat(ODataPayloadKind payloadKind, String acceptableMediaTypes, String acceptableCharSets)</m:stacktrace>
</m:innererror>
</m:error>

View File

@ -18,6 +18,11 @@
*/
package org.apache.olingo.client.api.communication.header;
import java.util.Arrays;
import java.util.List;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* Major OData request/response header names.
*/
@ -26,7 +31,17 @@ public enum HeaderName {
/**
* The OData protocol uses the Accept request-header field, as specified in [RFC2616].
*/
accept("Accept"),
accept("Accept", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* As specified in [RFC2616], the client MAY specify the set of accepted character sets with the Accept-Charset
* header.
*/
acceptCharset("Accept-Charset", Arrays.asList(ODataServiceVersion.V40)),
/**
* As specified in [RFC2616], the client MAY specify the set of accepted natural languages with the Accept-Language
* header.
*/
acceptLanguage("Accept-Language", Arrays.asList(ODataServiceVersion.V40)),
/**
* The Content-Type header is used as specified in [RFC2616].
* <br/>
@ -44,76 +59,129 @@ public enum HeaderName {
* <li>multipart/mixed</li>
* </ul>
*/
contentType("Content-Type"),
contentType("Content-Type", Arrays.asList(ODataServiceVersion.V30)),
/**
* This header is a custom HTTP header defined for protocol versioning purposes. This header MAY be present on any
* request or response message.
*/
dataServiceVersion("DataServiceVersion"),
dataServiceVersion("DataServiceVersion", Arrays.asList(ODataServiceVersion.V30)),
/**
* This header is a custom HTTP header defined for protocol versioning purposes. This header MAY be present on any
* request or response message.
*/
odataVersion("OData-Version", Arrays.asList(ODataServiceVersion.V40)),
/**
* A response to a create operation that returns 204 No Content MUST include an OData-EntityId response header. The
* value of the header is the entity-id of the entity that was acted on by the request. The syntax of the
* OData-EntityId preference is specified in [OData-ABNF].
*/
odataEntityId("OData-EntityId", Arrays.asList(ODataServiceVersion.V40)),
/**
* An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine
* change in content of a resource at a given URL. The value of the header is an opaque string representing the state
* of the resource at the time the response was generated.
*/
etag("ETag"),
etag("ETag", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* The If-Match request-header field is used with a method to make it conditional. As specified in [RFC2616], "the
* purpose of this feature is to allow efficient updates of cached information with a minimum amount of transaction
* overhead. It is also used, on updating requests, to prevent inadvertent modification of the wrong version of a
* resource".
*/
ifMatch("If-Match"),
ifMatch("If-Match", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* The If-None-Match request header is used with a method to make it conditional. As specified in [RFC2616], "The
* purpose of this feature is to allow efficient updates of cached information with a minimum amount of transaction
* overhead. It is also used to prevent a method (for example, PUT) from inadvertently modifying an existing resource
* when the client believes that the resource does not exist."
*/
ifNoneMatch("If-None-Match"),
ifNoneMatch("If-None-Match", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* Clients SHOULD specify an OData-MaxVersion request header.
* <br />
* If specified the service MUST generate a response with an OData-Version less than or equal to the specified
* OData-MaxVersion.
* <br />
* If OData-MaxVersion is not specified, then the service SHOULD interpret the request as having an OData-MaxVersion
* equal to the maximum version supported by the service.
*/
odataMaxVersion("OData-MaxVersion", Arrays.asList(ODataServiceVersion.V40)),
/**
* This header is a custom HTTP request only header defined for protocol versioning purposes. This header MAY be
* present on any request message from client to server.
*/
maxDataServiceVersion("MaxDataServiceVersion"),
maxDataServiceVersion("MaxDataServiceVersion", Arrays.asList(ODataServiceVersion.V30)),
/**
* This header is a custom HTTP request only header defined for protocol versioning purposes. This header MAY be
* present on any request message from client to server.
*/
minDataServiceVersion("MinDataServiceVersion"),
minDataServiceVersion("MinDataServiceVersion", Arrays.asList(ODataServiceVersion.V30)),
/**
* The OData-Isolation header specifies the isolation of the current request from external changes. The only supported
* value for this header is snapshot.
* <br />
* If the service doesnt support OData-Isolation:snapshot and this header was specified on the request, the service
* MUST NOT process the request and MUST respond with 412 Precondition Failed.
* <br />
* Snapshot isolation guarantees that all data returned for a request, including multiple requests within a batch or
* results retrieved across multiple pages, will be consistent as of a single point in time. Only data modifications
* made within the request (for example, by a data modification request within the same batch) are visible. The effect
* is as if the request generates a "snapshot" of the committed data as it existed at the start of the request.
* <br />
* The OData-Isolation header may be specified on a single or batch request. If it is specified on a batch then the
* value is applied to all statements within the batch.
* <br />
* Next links returned within a snapshot return results within the same snapshot as the initial request; the client is
* not required to repeat the header on each individual page request.
* <br />
* The OData-Isolation header has no effect on links other than the next link. Navigation links, read links, and edit
* links return the current version of the data.
* <br />
* A service returns 410 Gone or 404 Not Found if a consumer tries to follow a next link referring to a snapshot that
* is no longer available.
* <br />
* The syntax of the OData-Isolation header is specified in [OData-ABNF].
* <br />
* A service MAY specify the support for OData-Isolation:snapshot using an annotation with term
* Capabilities.IsolationSupport, see [OData-VocCap].
*/
odataIsolation("OData-Isolation", Arrays.asList(ODataServiceVersion.V40)),
/**
* A Prefer header is included in a request to state the clients preferred, but not required, server behavior (that
* is, a hint to the server). The Prefer header MAY be included on any request type (within a standalone or batch
* request), and a server MAY honor the header for HTTP POST, PUT, PATCH, and MERGE requests. A Prefer header with a
* value of return-content MUST NOT be specified on a DELETE request, a batch request as a whole, or a PUT request
* to update a named stream.
*
* @see ODataPreferenceNames.
*/
prefer("Prefer"),
prefer("Prefer", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* When a Prefer header value is successfully honored by the server, it MAY include a Preference-Applied response
* header that states which preference values were honored by the server.
*/
preferenceApplied("Preference-Applied"),
preferenceApplied("Preference-Applied", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* The DataServiceId response header is returned by the server when the response payload for an HTTP PUT, POST, PATCH,
* or MERGE request is empty. The value of the header is the identifier of the entity that was acted on by the PUT,
* POST, PATCH, or MERGE request. The identifier, in this case, is the same identifier that would have been returned
* in the response payload (for example, as the value of the atom:id element for Atom responses)
*/
dataServiceId("DataServiceId"),
dataServiceId("DataServiceId", Arrays.asList(ODataServiceVersion.V30)),
/**
* Location header is used to specify the URL of an entity modified through a Data Modification request, or the
* request URL to check on the status of an asynchronous operation as described in
* <code>202 Accepted</code>.
*/
location("Location"),
location("Location", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
/**
* A service must include a
* <code>Retry-After</code> header in a
* <code>202 Accepted</code>.
*/
retryAfter("Retry-After"),
dataServiceUrlConventions("DataServiceUrlConventions"),
slug("Slug"),
retryAfter("Retry-After", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
dataServiceUrlConventions("DataServiceUrlConventions", Arrays.asList(ODataServiceVersion.V30)),
slug("Slug", Arrays.asList(ODataServiceVersion.V30)),
/**
* This header is a custom HTTP request header.
* <br/>
@ -132,12 +200,21 @@ public enum HeaderName {
* <br/>
* This header is only valid when on POST requests.
*/
xHttpMethod("X-HTTP-METHOD");
xHttpMethod("X-HTTP-METHOD", Arrays.asList(ODataServiceVersion.V30));
private final String headerName;
private HeaderName(final String headerName) {
private final List<ODataServiceVersion> supportedVersions;
private HeaderName(final String headerName, final List<ODataServiceVersion> supportedVersions) {
this.headerName = headerName;
this.supportedVersions = supportedVersions;
}
final void isSupportedBy(final ODataServiceVersion serviceVersion) {
if (!supportedVersions.contains(serviceVersion)) {
throw new ODataRuntimeException("Unsupported header " + this.toString());
}
}
@Override

View File

@ -0,0 +1,424 @@
/*
* 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.
*/
package org.apache.olingo.client.api.communication.header;
import java.util.Arrays;
import java.util.List;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* Values of the Prefer header.
*/
public class ODataPreferences {
final ODataServiceVersion serviceVersion;
public ODataPreferences(final ODataServiceVersion serviceVersion) {
this.serviceVersion = serviceVersion;
}
/**
* <code>Prefer</code> header, return content.
*
* @see HeaderName#prefer
*/
public String returnContent() {
return PreferenceNames.returnContent.isSupportedBy(serviceVersion).toString();
}
/**
* <code>Prefer</code> header, return no content.
*
* @see HeaderName#prefer
*/
public String returnNoContent() {
return PreferenceNames.returnNoContent.isSupportedBy(serviceVersion).toString();
}
/**
* @see HeaderName#dataServiceUrlConventions
*/
public String keyAsSegment() {
return PreferenceNames.keyAsSegment.isSupportedBy(serviceVersion).toString();
}
/**
* The odata.allow-entityreferences preference indicates that the service is allowed to return entity references in
* place of entities that have previously been returned, with at least the properties requested, in the same response
* (for example, when serializing the expanded results of many-to-many relationships). The service MUST NOT return
* entity references in place of requested entities if odata.allow-entityreferences has not been specified in the
* request, unless explicitly defined by other rules in this document. The syntax of the odata.allow-entityreferences
* preference is specified in [OData-ABNF].
* <br />
* In the case the service applies the odata.allow-entityreferences preference it MUST include a Preference-Applied
* response header containing the odata.allow-entityreferences preference to indicate that entity references MAY be
* returned in place of entities that have previously been returned.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String allowEntityReferences() {
return PreferenceNames.allowEntityReferences.isSupportedBy(serviceVersion).toString();
}
/**
* For scenarios in which links returned by the service are used by the client to poll for additional information, the
* client can specify the odata.callback preference to request that the service notify the client when data is
* available.
* <br />
* The odata.callback preference can be specified:
* <ul>
* <li>when requesting asynchronous processing of a request with the respond-async preference, or</li>
* <li>on a GET request to a delta link.</li>
* </ul>
* <br />
* The odata.callback preference MUST include the parameter url whose value is the URL of a callback endpoint to be
* invoked by the OData service when data is available. The syntax of the odata.callback preference is specified in
* [OData-ABNF]. For HTTP based callbacks, the OData service executes an HTTP GET request against the specified URL.
* <br />
* Services that support odata.callback SHOULD support notifying the client through HTTP. Services can advertise
* callback support using the Capabilities.CallbackSupport annotation term defined in [OData-VocCap].
* <br />
* If the service applies the odata.callback preference it MUST include the odata.callback preference in the
* Preference-Applied response header.
* <br />
* When the odata.callback preference is applied to asynchronous requests, the OData service invokes the callback
* endpoint once it has finished processing the request. The status monitor resource, returned in the Location header
* of the previously returned 202 Accepted response, can then be used to retrieve the results of the asynchronously
* executed request.
* <br />
* When the odata.callback preference is specified on a GET request to a delta link and there are no changes
* available, the OData service returns a 202 Accepted response with a Location header specifying the delta link to be
* used to check for future updates. The OData service then invokes the specified callback endpoint once new changes
* become available.
* <br />
* Combining respond-async, odata.callback and odata.track-changes preferences on a GET request to a delta-link might
* influence the response in a couple of ways.
* <ul>
* <li>If the service processes the request synchronously, and no updates are available, then the response is the same
* as if the respond-async hadnt been specified and results in a response as described above.</li>
* <li>If the service processes the request asynchronously, then it responds with a 202 Accepted response specifying
* the URL to the status monitor resource as it would have with any other asynchronous request. Once the service has
* finished processing the asynchronous request to the delta link resource, if changes are available it invokes the
* specified callback endpoint. If no changes are available, the service SHOULD wait to notify the client until
* changes are available. Once notified, the client uses the status monitor resource from the Location header of the
* previously returned 202 Accepted response to retrieve the results. In case no updates were available after
* processing the initial request, the result will contain no updates and the client can use the delta-link contained
* in the result to retrieve the updates that have since become available.</li>
* </ul>
* <br />
* If the consumer specifies the same URL as callback endpoint in multiple requests, the service MAY collate them into
* a single notification once additional data is available for any of the requests. However, the consumer MUST be
* prepared to deal with receiving up to as many notifications as it requested.
* <br /><br />
* Example: using a HTTP callback endpoint to receive notification
* <br /><br />
* Prefer: odata.callback; url="http://myserver/notfication/token/12345"
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String callback(final String url) {
return PreferenceNames.callback.isSupportedBy(serviceVersion).toString() + ";url=\"" + url + "\"";
}
/**
* The odata.continue-on-error preference on a batch request is used to request that, upon encountering a request
* within the batch that returns an error, the service return the error for that request and continue processing
* additional requests within the batch. The syntax of the odata.continue-on-error preference is specified in
* [OData-ABNF].
* <br />
* If not specified, upon encountering an error the service MUST return the error within the batch and stop processing
* additional requests within the batch.
* <br />
* A service MAY specify the support for the odata.continue-on-error preference using an annotation with term
* Capabilities.BatchContinueOnErrorSupported, see [OData-VocCap].
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String continueOnError() {
return PreferenceNames.callback.isSupportedBy(serviceVersion).toString();
}
/**
* The odata.include-annotations preference in a request for data or metadata is used to specify the set of
* annotations the client requests to be included, where applicable, in the response.
* <br/>
* The value of the odata.include-annotations preference is a comma-separated list of namespaces or namespace
* qualified term names to include or exclude, with "*" representing all. The full syntax of the
* odata.include-annotations preference is defined in [OData-ABNF].
* <br/>
* The most specific identifier always takes precedence. If the same identifier value is requested to both be excluded
* and included the behavior is undefined; the service MAY return or omit the specified vocabulary but MUST NOT raise
* an exception.
* <br/><br/>
* Example 1: a Prefer header requesting all annotations within a metadata document to be returned
* <br/><br/>
* Prefer: odata.include-annotations="*"
* <br/><br/>
* Example 2: a Prefer header requesting that no annotations are returned
* <br/><br/>
* Prefer: odata.include-annotations="-*"
* <br/><br/>
* Example 3: a Prefer header requesting that all annotations defined under the "display" namespace (recursively) be
* returned
* <br/><br/>
* Prefer: odata.include-annotations="display.*"
* <br/><br/>
* Example 4: a Prefer header requesting that the annotation with the term name subject within the display namespace
* be returned if applied
* <br/><br/>
* Prefer: odata.include-annotations="display.subject"
* <br/><br/>
* The odata.include-annotations preference is only a hint to the service. The service MAY ignore the preference and
* is free to decide whether or not to return annotations not specified in the odata.include-annotations preference.
* <br/>
* In the case that the client has specified the odata.include-annotations preference in the request, the service
* SHOULD include a Preference-Applied response header containing the odata.include-annotations preference to specify
* the annotations actually included, where applicable, in the response. This value may differ from the annotations
* requested in the Prefer header of the request.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String includeAnnotations(final String value) {
return PreferenceNames.includeAnnotations.isSupportedBy(serviceVersion).toString() + "=" + value;
}
/**
* The odata.maxpagesize preference is used to request that each collection within the response contain no more than
* the number of items specified as the positive integer value of this preference. The syntax of the odata.maxpagesize
* preference is specified in [OData-ABNF].
* <br/><br/>
* Example: a request for customers and their orders would result in a response containing one collection with
* customer entities and for every customer a separate collection with order entities. The client could specify
* <br/>
* odata.maxpagesize=50
* <br/>in order to request that each page of results contain a maximum of 50 customers, each with a maximum of 50
* orders.
* <br/><br/>
* If a collection within the result contains more than the specified odata.maxpagesize, the collection SHOULD be a
* partial set of the results with a next link to the next page of results. The client MAY specify a different value
* for this preference with every request following a next link.
* <br/>
* In the example given above, the result page should include a next link for the customer collection, if there are
* more than 50 customers, and additional next links for all returned orders collections with more than 50 entities.
* <br/>
* If the client has specified the odata.maxpagesize preference in the request, and the service limits the number of
* items in collections within the response through server-driven paging, the service MAY include a Preference-Applied
* response header containing the odata.maxpagesize preference and the maximum page size applied. This value may
* differ from the value requested by the client.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String maxPageSize(final int size) {
return PreferenceNames.maxPageSize.isSupportedBy(serviceVersion).toString() + "=" + size;
}
/**
* The odata.track-changes preference is used to request that the service return a delta link that can subsequently be
* used to obtain changes (deltas) to this result. The syntax of the odata.track-changes preference is specified in
* [OData-ABNF].
* <br />
* For paged results, the preference MUST be specified on the initial request. Services MUST ignore the
* odata.track-changes preference if applied to the next link.
* <br />
* The delta link MUST NOT be returned prior to the final page of results.
* <br />
* The service includes a Preference-Applied response header in the first page of the response containing the
* odata.track-changes preference to signal that changes are being tracked.
* <br />
* A service MAY specify the support for the odata.track-changes preference using an annotation with term
* Capabilities.ChangeTrackingSupport, see [OData-VocCap].
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String trackChanges() {
return PreferenceNames.trackChanges.isSupportedBy(serviceVersion).toString();
}
/**
* The respond-async preference, as defined in [HTTP-Prefer], allows clients to request that the service process the
* request asynchronously.
* <br/>
* If the client has specified respond-async in the request, the service MAY process the request asynchronously and
* return a 202 Accepted response.
* <br/>
* The respond-async preference MAY be used for batch requests, but the service MUST ignore the respond-async
* preference for individual requests within a batch request.
* <br/>
* In the case that the service applies the respond-async preference it MUST include a Preference-Applied response
* header containing the respond-async preference.
* <br/>
* A service MAY specify the support for the respond-async preference using an annotation with term
* Capabilities.AsynchronousRequestsSupported, see [OData-VocCap].
* <br/><br/>
* Example: a service receiving the following header might choose to respond
* <ul>
* <li>asynchronously if the synchronous processing of the request will take longer than 10 seconds</li>
* <li>synchronously after 5 seconds</li>
* <li>asynchronously (ignoring the wait preference)</li>
* <li>synchronously after 15 seconds (ignoring respond-async preference and the wait preference)</li>
* </ul>
* <br/>
* Prefer: respond-async, wait=10
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String respondAsync() {
return PreferenceNames.respondAsync.isSupportedBy(serviceVersion).toString();
}
/**
* The wait preference, as defined in [HTTP-Prefer], is used to establish an upper bound on the length of time, in
* seconds, the client is prepared to wait for the service to process the request synchronously once it has been
* received.
* <br/>
* If the respond-async preference is also specified, the client requests that the service respond asynchronously
* after the specified length of time.
* <br/>
* If the respond-async preference has not been specified, the service MAY interpret the wait as a request to timeout
* after the specified period of time.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String wait(final int value) {
return PreferenceNames.wait.isSupportedBy(serviceVersion).toString() + "=" + value;
}
/**
* The return=representation and return=minimal preferences are defined in [HTTP-Prefer],
* <br/>
* In OData, return=representation or return=minimal is defined for use with a POST, PUT, or PATCH Data Modification
* Request other than to a stream property, or to an Action Request. Specifying a preference of return=representation
* or return=minimal in a GET or DELETE request, or any request to a stream property, SHOULD return a 4xx Client
* Error.
* <br/>
* A preference of return=representation or return=minimal is allowed on an individual Data Modification Request or
* Action Request within a batch, subject to the same restrictions, but SHOULD return a 4xx Client Error if specified
* on the batch request itself.
* <br/>
* A preference of return=minimal requests that the service invoke the request but does not return content in the
* response. The service MAY apply this preference by returning 204 No Content in which case it MAY include a
* Preference-Applied response header containing the return=minimal preference.
* <br/>
* A preference of return=representation requests that the service invokes the request and returns the modified
* entity. The service MAY apply this preference by returning the successfully modified resource in the body of the
* response, formatted according to the rules specified for the requested format. In this case the service MAY include
* a Preference-Applied response header containing the return=representation preference.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String returnMinimal() {
return PreferenceNames.odataReturn.isSupportedBy(serviceVersion).toString() + "=minimal";
}
/**
* The return=representation and return=minimal preferences are defined in [HTTP-Prefer],
* <br/>
* In OData, return=representation or return=minimal is defined for use with a POST, PUT, or PATCH Data Modification
* Request other than to a stream property, or to an Action Request. Specifying a preference of return=representation
* or return=minimal in a GET or DELETE request, or any request to a stream property, SHOULD return a 4xx Client
* Error.
* <br/>
* A preference of return=representation or return=minimal is allowed on an individual Data Modification Request or
* Action Request within a batch, subject to the same restrictions, but SHOULD return a 4xx Client Error if specified
* on the batch request itself.
* <br/>
* A preference of return=minimal requests that the service invoke the request but does not return content in the
* response. The service MAY apply this preference by returning 204 No Content in which case it MAY include a
* Preference-Applied response header containing the return=minimal preference.
* <br/>
* A preference of return=representation requests that the service invokes the request and returns the modified
* entity. The service MAY apply this preference by returning the successfully modified resource in the body of the
* response, formatted according to the rules specified for the requested format. In this case the service MAY include
* a Preference-Applied response header containing the return=representation preference.
* <br/><br/>
* Supported by OData version 4.0 only.
*
* @see HeaderName#prefer
* @return preference.
*/
public String returnRepresentation() {
return PreferenceNames.odataReturn.isSupportedBy(serviceVersion).toString() + "=representation";
}
private static enum PreferenceNames {
returnContent("return-content", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
returnNoContent("return-no-content", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
keyAsSegment("KeyAsSegment", Arrays.asList(ODataServiceVersion.V30, ODataServiceVersion.V40)),
allowEntityReferences("odata.allow-entityreferences", Arrays.asList(ODataServiceVersion.V40)),
callback("odata.callback", Arrays.asList(ODataServiceVersion.V40)),
continueOnError("odata.continue-on-error", Arrays.asList(ODataServiceVersion.V40)),
includeAnnotations("odata.include-annotations", Arrays.asList(ODataServiceVersion.V40)),
maxPageSize("odata.maxpagesize", Arrays.asList(ODataServiceVersion.V40)),
trackChanges("odata.track-changes", Arrays.asList(ODataServiceVersion.V40)),
respondAsync("respond-async", Arrays.asList(ODataServiceVersion.V40)),
wait("wait", Arrays.asList(ODataServiceVersion.V40)),
odataReturn("return", Arrays.asList(ODataServiceVersion.V40));
private final String preferenceName;
private final List<ODataServiceVersion> supportedVersions;
private PreferenceNames(final String preferenceName, final List<ODataServiceVersion> supportedVersions) {
this.preferenceName = preferenceName;
this.supportedVersions = supportedVersions;
}
final PreferenceNames isSupportedBy(final ODataServiceVersion serviceVersion) {
if (!supportedVersions.contains(serviceVersion)) {
throw new ODataRuntimeException("Unsupported header " + this.toString());
}
return this;
}
@Override
public String toString() {
return preferenceName;
}
}
}

View File

@ -21,16 +21,20 @@ package org.apache.olingo.client.api.communication.request;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.http.HttpMethod;
/**
* Abstract representation of an OData request. Get instance by using factories.
*
* @see CUDRequestFactory
* @see RetrieveRequestFactory
* @see BatchRequestFactory
* @see InvokeRequestFactory
* @see StreamedRequestFactory
* @see org.apache.olingo.client.api.communication.request.cud.v3.CUDRequestFactory
* @see org.apache.olingo.client.api.communication.request.cud.v4.CUDRequestFactory
* @see org.apache.olingo.client.api.communication.request.batch.v3.BatchRequestFactory
* @see org.apache.olingo.client.api.communication.request.batch.v4.BatchRequestFactory
* @see org.apache.olingo.client.api.communication.request.invoke.v3.InvokeRequestFactory
* @see org.apache.olingo.client.api.communication.request.invoke.v4.InvokeRequestFactory
* @see org.apache.olingo.client.api.communication.request.streamed.v3.StreamedRequestFactory
* @see org.apache.olingo.client.api.communication.request.streamed.v4.StreamedRequestFactory
*/
public interface ODataRequest {
@ -175,6 +179,16 @@ public interface ODataRequest {
*/
ODataRequest addCustomHeader(final String name, final String value);
/**
* Adds a custom OData request header. The method fails in case of the header name is not supported by the current
* working version.
*
* @param name header name.
* @param value header value.
* @return current object
*/
ODataRequest addCustomHeader(final HeaderName name, final String value);
/**
* Gets byte array representation of the full request header.
*

View File

@ -34,6 +34,7 @@ public enum SegmentType {
NAVIGATION,
DERIVED_ENTITY_TYPE,
VALUE("$value"),
COUNT("$count"),
BOUND_OPERATION,
UNBOUND_OPERATION,
METADATA("$metadata"),

View File

@ -42,8 +42,7 @@ public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
*
* @param inlineCount value
* @return current URIBuilder instance
* @see QueryOption#INLINECOUNT
* @see org.apache.olingo.client.api.uri.QueryOption#INLINECOUNT
*/
URIBuilder inlineCount(InlineCount inlineCount);
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.client.api.uri.v4;
import java.util.Map;
import org.apache.olingo.client.api.uri.CommonURIBuilder;
public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
@ -65,7 +66,7 @@ public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
*
* @param idValue opaque token.
* @return current URIBuilder instance
* @see QueryOption#ID
* @see org.apache.olingo.client.api.uri.QueryOption#ID
*/
URIBuilder id(String idValue);
@ -74,7 +75,7 @@ public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
*
* @param value true or false
* @return current URIBuilder instance
* @see QueryOption#COUNT
* @see org.apache.olingo.client.api.uri.QueryOption#COUNT
*/
URIBuilder count(boolean value);
@ -83,7 +84,19 @@ public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
*
* @param expression search expression
* @return current URIBuilder instance
* @see QueryOption#SEARCH
* @see org.apache.olingo.client.api.uri.QueryOption#SEARCH
*/
URIBuilder search(String expression);
/**
* The set of expanded entities can be refined through the application of expand options, expressed as a
* semicolon-separated list of system query options, enclosed in parentheses, see [OData-URL].
*
* @param expandItem item to be expanded.
* @param options System query options. Allowed query options are: $filter, $select, $orderby, $skip, $top, $count,
* $search, $expand, and $levels.
* @return current URIBuilder instance.
* @see org.apache.olingo.client.api.uri.QueryOption#EXPAND
*/
URIBuilder expandWithOptions(String expandItem, Map<String, Object> options);
}

View File

@ -38,14 +38,10 @@ import org.apache.olingo.client.api.v3.Configuration;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.ODataServerErrorException;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.header.ODataHeaderValues;
import org.apache.olingo.client.api.communication.header.ODataHeaders;
import org.apache.olingo.client.api.communication.header.ODataPreferences;
import org.apache.olingo.client.api.communication.request.ODataRequest;
import org.apache.olingo.client.api.communication.request.ODataStreamer;
import org.apache.olingo.client.api.communication.request.batch.v3.BatchRequestFactory;
import org.apache.olingo.client.api.communication.request.cud.v3.CUDRequestFactory;
import org.apache.olingo.client.api.communication.request.invoke.v3.InvokeRequestFactory;
import org.apache.olingo.client.api.communication.request.streamed.v3.StreamedRequestFactory;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.commons.api.format.Format;
import org.apache.olingo.client.api.http.HttpClientException;
@ -66,10 +62,14 @@ import org.slf4j.LoggerFactory;
*
* @param <T> Accepted content-type formats by the request in object.
*
* @see CUDRequestFactory
* @see BatchRequestFactory
* @see InvokeRequestFactory
* @see StreamedRequestFactory
* @see org.apache.olingo.client.api.communication.request.cud.v3.CUDRequestFactory
* @see org.apache.olingo.client.api.communication.request.cud.v4.CUDRequestFactory
* @see org.apache.olingo.client.api.communication.request.batch.v3.BatchRequestFactory
* @see org.apache.olingo.client.api.communication.request.batch.v4.BatchRequestFactory
* @see org.apache.olingo.client.api.communication.request.invoke.v3.InvokeRequestFactory
* @see org.apache.olingo.client.api.communication.request.invoke.v4.InvokeRequestFactory
* @see org.apache.olingo.client.api.communication.request.streamed.v3.StreamedRequestFactory
* @see org.apache.olingo.client.api.communication.request.streamed.v4.StreamedRequestFactory
*/
public class ODataRequestImpl<T extends Format> implements ODataRequest {
@ -250,6 +250,15 @@ public class ODataRequestImpl<T extends Format> implements ODataRequest {
return this;
}
/**
* {@inheritDoc}
*/
@Override
public ODataRequest addCustomHeader(final HeaderName name, final String value) {
odataHeaders.setHeader(name, value);
return this;
}
/**
* {@inheritDoc}
*/
@ -384,7 +393,8 @@ public class ODataRequestImpl<T extends Format> implements ODataRequest {
if (odataClient.getServiceVersion() == ODataServiceVersion.V30
&& ((Configuration) odataClient.getConfiguration()).isKeyAsSegment()) {
addCustomHeader(
HeaderName.dataServiceUrlConventions.toString(), ODataHeaderValues.keyAsSegment);
HeaderName.dataServiceUrlConventions.toString(),
new ODataPreferences(odataClient.getServiceVersion()).keyAsSegment());
}
// Add all available headers

View File

@ -57,7 +57,7 @@ public class JSONServiceDocumentDeserializer extends ODataJacksonDeserializer<Ab
setMetadataContext(tree.get(Constants.JSON_CONTEXT).textValue());
}
for (final Iterator<JsonNode> itor = tree.get(Constants.JSON_VALUE).elements(); itor.hasNext();) {
for (final Iterator<JsonNode> itor = tree.get(Constants.VALUE).elements(); itor.hasNext();) {
final JsonNode node = itor.next();
final ServiceDocumentItemImpl item = new ServiceDocumentItemImpl();

View File

@ -87,21 +87,22 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
}
@Override
public Feed getFeed(final ODataEntitySet feed, final Class<? extends Feed> reference) {
final Feed feedResource = ResourceFactory.newFeed(reference);
public Feed getFeed(final ODataEntitySet entitySet, final Class<? extends Feed> reference) {
final Feed feed = ResourceFactory.newFeed(reference);
feedResource.setCount(feed.getCount());
feed.setContextURL(entitySet.getContextURL());
feed.setCount(entitySet.getCount());
final URI next = feed.getNext();
final URI next = entitySet.getNext();
if (next != null) {
feedResource.setNext(next);
feed.setNext(next);
}
for (ODataEntity entity : feed.getEntities()) {
feedResource.getEntries().add(getEntry(entity, ResourceFactory.entryClassForFeed(reference)));
for (ODataEntity entity : entitySet.getEntities()) {
feed.getEntries().add(getEntry(entity, ResourceFactory.entryClassForFeed(reference)));
}
return feedResource;
return feed;
}
@Override
@ -112,6 +113,9 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
@Override
public Entry getEntry(final ODataEntity entity, final Class<? extends Entry> reference, final boolean setType) {
final Entry entry = ResourceFactory.newEntry(reference);
entry.setContextURL(entity.getContextURL());
entry.setId(entity.getReference());
entry.setType(entity.getName());
// -------------------------------------------------------------
@ -269,13 +273,15 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
}
final URI base = defaultBaseURI == null ? resource.getBaseURI() : defaultBaseURI;
final URI next = resource.getNext();
final ODataEntitySet entitySet = next == null
? client.getObjectFactory().newEntitySet()
: client.getObjectFactory().newEntitySet(URIUtils.getURI(base, next.toASCIIString()));
entitySet.setContextURL(resource.getContextURL());
if (resource.getCount() != null) {
entitySet.setCount(resource.getCount());
}
@ -283,7 +289,7 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
for (Entry entryResource : resource.getEntries()) {
entitySet.addEntity(getODataEntity(entryResource));
}
return entitySet;
}
@ -306,16 +312,19 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
final ODataEntity entity = resource.getSelfLink() == null
? client.getObjectFactory().newEntity(resource.getType())
: client.getObjectFactory().newEntity(resource.getType(),
URIUtils.getURI(base, resource.getSelfLink().getHref()));
URIUtils.getURI(base, resource.getSelfLink().getHref()));
entity.setContextURL(resource.getContextURL());
entity.setReference(resource.getId());
if (StringUtils.isNotBlank(resource.getETag())) {
entity.setETag(resource.getETag());
}
if (resource.getEditLink() != null) {
entity.setEditLink(URIUtils.getURI(base, resource.getEditLink().getHref()));
}
for (Link link : resource.getAssociationLinks()) {
entity.addLink(client.getObjectFactory().newAssociationLink(link.getTitle(), base, link.getHref()));
}
@ -327,16 +336,16 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
if (inlineEntry == null && inlineFeed == null) {
entity.addLink(
client.getObjectFactory().newEntityNavigationLink(link.getTitle(), base, link.getHref()));
} else if (inlineFeed == null) {
} else if (inlineEntry != null) {
entity.addLink(client.getObjectFactory().newInlineEntity(
link.getTitle(), base, link.getHref(),
getODataEntity(inlineEntry,
inlineEntry.getBaseURI() == null ? base : inlineEntry.getBaseURI())));
inlineEntry.getBaseURI() == null ? base : inlineEntry.getBaseURI())));
} else {
entity.addLink(client.getObjectFactory().newInlineEntitySet(
link.getTitle(), base, link.getHref(),
getODataEntitySet(inlineFeed,
inlineFeed.getBaseURI() == null ? base : inlineFeed.getBaseURI())));
inlineFeed.getBaseURI() == null ? base : inlineFeed.getBaseURI())));
}
}
@ -374,16 +383,16 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
value = client.getPrimitiveValueBuilder().
setText(resource.getValue().asSimple().get()).
setType(resource.getType() == null
? null
: EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), resource.getType())).build();
? null
: EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), resource.getType())).build();
} else if (resource.getValue().isGeospatial()) {
value = client.getGeospatialValueBuilder().
setValue(resource.getValue().asGeospatial().get()).
setType(resource.getType() == null
|| EdmPrimitiveTypeKind.Geography.getFullQualifiedName().toString().equals(resource.getType())
|| EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().toString().equals(resource.getType())
? null
: EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), resource.getType())).build();
|| EdmPrimitiveTypeKind.Geography.getFullQualifiedName().toString().equals(resource.getType())
|| EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().toString().equals(resource.getType())
? null
: EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), resource.getType())).build();
} else if (resource.getValue().isComplex()) {
value = new ODataComplexValue(resource.getType());

View File

@ -21,6 +21,7 @@ package org.apache.olingo.client.core.uri;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -60,9 +61,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
public String getValue() {
return value;
}
}
protected final List<Segment> segments = new ArrayList<Segment>();
/**
@ -111,17 +110,11 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
@Override
public UB appendKeySegment(final Map<String, Object> segmentValues) {
if (segmentValues == null || segmentValues.isEmpty()) {
final String key = buildMultiKeySegment(segmentValues, true);
if (StringUtils.isEmpty(key)) {
segments.add(new Segment(SegmentType.KEY, noKeysWrapper()));
} else {
final StringBuilder keyBuilder = new StringBuilder().append('(');
for (Map.Entry<String, Object> entry : segmentValues.entrySet()) {
keyBuilder.append(entry.getKey()).append('=').append(URIUtils.escape(entry.getValue()));
keyBuilder.append(',');
}
keyBuilder.deleteCharAt(keyBuilder.length() - 1).append(')');
segments.add(new Segment(SegmentType.KEY, keyBuilder.toString()));
segments.add(new Segment(SegmentType.KEY, key));
}
return getThis();
@ -179,7 +172,14 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
@Override
public UB expand(final String... expandItems) {
return addQueryOption(QueryOption.EXPAND, StringUtils.join(expandItems, ","));
final List<String> values = new ArrayList<String>();
if (queryOptions.containsKey(QueryOption.EXPAND.toString())) {
values.add(queryOptions.get(QueryOption.EXPAND.toString()));
}
values.addAll(Arrays.asList(expandItems));
return addQueryOption(QueryOption.EXPAND, StringUtils.join(values, ","));
}
@Override
@ -199,7 +199,14 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
@Override
public UB select(final String... selectItems) {
return addQueryOption(QueryOption.SELECT, StringUtils.join(selectItems, ","));
final List<String> values = new ArrayList<String>();
if (queryOptions.containsKey(QueryOption.SELECT.toString())) {
values.add(queryOptions.get(QueryOption.SELECT.toString()));
}
values.addAll(Arrays.asList(selectItems));
return addQueryOption(QueryOption.SELECT, StringUtils.join(values, ","));
}
@Override
@ -271,4 +278,19 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
return build().toASCIIString();
}
protected String buildMultiKeySegment(final Map<String, Object> segmentValues, final boolean escape) {
if (segmentValues == null || segmentValues.isEmpty()) {
return StringUtils.EMPTY;
} else {
final StringBuilder keyBuilder = new StringBuilder().append('(');
for (Map.Entry<String, Object> entry : segmentValues.entrySet()) {
keyBuilder.append(entry.getKey()).append('=').append(
escape ? URIUtils.escape(entry.getValue()) : entry.getValue());
keyBuilder.append(',');
}
keyBuilder.deleteCharAt(keyBuilder.length() - 1).append(')');
return keyBuilder.toString();
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.client.core.uri.v4;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.client.api.uri.SegmentType;
@ -78,11 +79,6 @@ public class URIBuilderImpl extends AbstractURIBuilder<URIBuilder> implements UR
return getThis();
}
@Override
public URIBuilder count(final boolean value) {
return addQueryOption(QueryOption.COUNT, Boolean.toString(value));
}
@Override
public URIBuilder appendAllSegment() {
segments.add(new Segment(SegmentType.ALL, SegmentType.ALL.getValue()));
@ -99,4 +95,13 @@ public class URIBuilderImpl extends AbstractURIBuilder<URIBuilder> implements UR
return addQueryOption(QueryOption.SEARCH, expression);
}
@Override
public URIBuilder count(final boolean value) {
return addQueryOption(QueryOption.COUNT, Boolean.toString(value));
}
@Override
public URIBuilder expandWithOptions(final String expandItem, final Map<String, Object> options) {
return expand(expandItem + buildMultiKeySegment(options, false));
}
}

View File

@ -82,8 +82,8 @@ public class ODataClientImpl extends AbstractODataClient implements ODataClient
@Override
public ODataHeaders getVersionHeaders() {
final ODataHeadersImpl odataHeaders = new ODataHeadersImpl();
odataHeaders.setHeader(HeaderName.maxDataServiceVersion, ODataServiceVersion.V40.toString());
odataHeaders.setHeader(HeaderName.dataServiceVersion, ODataServiceVersion.V40.toString());
odataHeaders.setHeader(HeaderName.odataMaxVersion, ODataServiceVersion.V40.toString());
odataHeaders.setHeader(HeaderName.odataVersion, ODataServiceVersion.V40.toString());
return odataHeaders;
}

View File

@ -30,7 +30,7 @@ import java.util.LinkedHashMap;
import java.util.Set;
import org.apache.http.entity.ContentType;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.header.ODataHeaderValues;
import org.apache.olingo.client.api.communication.header.ODataPreferences;
import org.apache.olingo.client.api.communication.request.UpdateType;
import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
@ -229,11 +229,11 @@ public class EntityCreateTestITCase extends AbstractTestITCase {
final ODataEntityCreateRequest createReq = client.getCUDRequestFactory().getEntityCreateRequest(
client.getURIBuilder(getServiceRoot()).appendEntitySetSegment("Customer").build(), original);
createReq.setPrefer(ODataHeaderValues.preferReturnNoContent);
createReq.setPrefer(new ODataPreferences(client.getServiceVersion()).returnNoContent());
final ODataEntityCreateResponse createRes = createReq.execute();
assertEquals(204, createRes.getStatusCode());
assertEquals(ODataHeaderValues.preferReturnNoContent,
assertEquals(new ODataPreferences(client.getServiceVersion()).returnNoContent(),
createRes.getHeader(HeaderName.preferenceApplied).iterator().next());
try {
@ -260,7 +260,7 @@ public class EntityCreateTestITCase extends AbstractTestITCase {
client.getCUDRequestFactory().getEntityCreateRequest(uriBuilder.build(), original);
createReq.setFormat(ODataPubFormat.JSON_FULL_METADATA);
createReq.setContentType(ContentType.APPLICATION_ATOM_XML.getMimeType());
createReq.setPrefer(ODataHeaderValues.preferReturnContent);
createReq.setPrefer(new ODataPreferences(client.getServiceVersion()).returnContent());
try {
final ODataEntityCreateResponse createRes = createReq.execute();

View File

@ -26,7 +26,7 @@ import java.net.URI;
import java.util.LinkedHashMap;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.header.ODataHeaderValues;
import org.apache.olingo.client.api.communication.header.ODataPreferences;
import org.apache.olingo.client.api.communication.request.UpdateType;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
@ -210,11 +210,11 @@ public class EntityUpdateTestITCase extends AbstractTestITCase {
@Test
public void updateReturnContent() throws EdmPrimitiveTypeException {
final ODataEntityUpdateRequest req = buildMultiKeyUpdateReq(client.getConfiguration().getDefaultPubFormat());
req.setPrefer(ODataHeaderValues.preferReturnContent);
req.setPrefer(new ODataPreferences(client.getServiceVersion()).returnContent());
final ODataEntityUpdateResponse res = req.execute();
assertEquals(200, res.getStatusCode());
assertEquals(ODataHeaderValues.preferReturnContent,
assertEquals(new ODataPreferences(client.getServiceVersion()).returnContent(),
res.getHeader(HeaderName.preferenceApplied).iterator().next());
assertNotNull(res.getBody());
}

View File

@ -100,11 +100,11 @@ public class PropertyValueTestITCase extends AbstractTestITCase {
req.setAccept("application/json");
ODataRetrieveResponse<ODataEntity> res = req.execute();
assertEquals(200, res.getStatusCode());
ODataEntity entitySet = res.getBody();
assertNotNull(entitySet);
ODataEntity entity = res.getBody();
assertNotNull(entity);
assertEquals("fi653p3+MklA/LdoBlhWgnMTUUEo8tEgtbMXnF0a3CUNL9BZxXpSRiD9ebTnmNR0zWPjJ"
+ "VIDx4tdmCnq55XrJh+RW9aI/b34wAogK3kcORw=",
entitySet.getProperties().get(0).getValue().toString());
entity.getProperties().get(0).getValue().toString());
}
@Test(expected = ODataClientErrorException.class)

View File

@ -0,0 +1,280 @@
/*
* 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.
*/
package org.apache.olingo.client.core.it.v4;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataRawRequest;
import org.apache.olingo.client.api.communication.response.ODataRawResponse;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.commons.api.domain.ODataEntity;
import org.apache.olingo.commons.api.domain.ODataEntitySet;
import org.apache.olingo.commons.api.domain.ODataInlineEntity;
import org.apache.olingo.commons.api.domain.ODataInlineEntitySet;
import org.apache.olingo.commons.api.domain.ODataLink;
import org.apache.olingo.commons.api.domain.ODataProperty;
import org.apache.olingo.commons.api.format.ODataPubFormat;
import org.apache.olingo.client.api.uri.CommonURIBuilder;
import org.apache.olingo.commons.core.op.ResourceFactory;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.junit.Ignore;
import org.junit.Test;
/**
* This is the unit test class to check entity retrieve operations.
*/
public class EntityRetrieveTestITCase extends AbstractTestITCase {
protected String getServiceRoot() {
return testStaticServiceRootURL;
}
private void withInlineEntry(final ODataPubFormat format) {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).
appendEntitySetSegment("Customers").appendKeySegment(1).expand("Company");
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(format);
final ODataRetrieveResponse<ODataEntity> res = req.execute();
final ODataEntity entity = res.getBody();
assertNotNull(entity);
assertEquals("#Microsoft.Test.OData.Services.ODataWCFService.Customer", entity.getName());
assertEquals(getServiceRoot() + "/Customers(PersonID=1)", entity.getEditLink().toASCIIString());
assertEquals(3, entity.getNavigationLinks().size());
assertTrue(entity.getAssociationLinks().isEmpty());
boolean found = false;
for (ODataLink link : entity.getNavigationLinks()) {
if (link instanceof ODataInlineEntity) {
final ODataEntity inline = ((ODataInlineEntity) link).getEntity();
assertNotNull(inline);
debugEntry(client.getBinder().getEntry(
inline, ResourceFactory.entryClassForFormat(format == ODataPubFormat.ATOM)), "Just read");
final List<ODataProperty> properties = inline.getProperties();
assertEquals(5, properties.size());
assertTrue(properties.get(0).getName().equals("CompanyID")
|| properties.get(1).getName().equals("CompanyID")
|| properties.get(2).getName().equals("CompanyID")
|| properties.get(3).getName().equals("CompanyID")
|| properties.get(4).getName().equals("CompanyID"));
assertTrue(properties.get(0).getValue().toString().equals("0")
|| properties.get(1).getValue().toString().equals("0")
|| properties.get(2).getValue().toString().equals("0")
|| properties.get(3).getValue().toString().equals("0")
|| properties.get(4).getValue().toString().equals("0"));
found = true;
}
}
assertTrue(found);
}
@Test
public void withInlineEntryFromAtom() {
withInlineEntry(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void withInlineEntryFromJSON() {
// this needs to be full, otherwise there is no mean to recognize links
withInlineEntry(ODataPubFormat.JSON_FULL_METADATA);
}
private void withInlineFeed(final ODataPubFormat format) {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).
appendEntitySetSegment("Customers").appendKeySegment(1).expand("Orders");
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(format);
final ODataRetrieveResponse<ODataEntity> res = req.execute();
final ODataEntity entity = res.getBody();
assertNotNull(entity);
boolean found = false;
for (ODataLink link : entity.getNavigationLinks()) {
if (link instanceof ODataInlineEntitySet) {
final ODataEntitySet inline = ((ODataInlineEntitySet) link).getEntitySet();
assertNotNull(inline);
debugFeed(client.getBinder().getFeed(inline, ResourceFactory.feedClassForFormat(
format == ODataPubFormat.ATOM)), "Just read");
found = true;
}
}
assertTrue(found);
}
@Test
public void withInlineFeedFromAtom() {
withInlineFeed(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void withInlineFeedFromJSON() {
// this needs to be full, otherwise there is no mean to recognize links
withInlineFeed(ODataPubFormat.JSON_FULL_METADATA);
}
private void rawRequest(final ODataPubFormat format) {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).
appendEntitySetSegment("People").appendKeySegment(5);
final ODataRawRequest req = client.getRetrieveRequestFactory().getRawRequest(uriBuilder.build());
req.setFormat(format.toString(client.getServiceVersion()));
final ODataRawResponse res = req.execute();
assertNotNull(res);
final ODataEntitySet entitySet = res.getBodyAs(ODataEntitySet.class);
assertNull(entitySet);
final ODataEntity entity = res.getBodyAs(ODataEntity.class);
assertTrue(entity.getReference().endsWith("/StaticService/V40/Static.svc/People(5)"));
}
@Test
public void rawRequestAsAtom() {
rawRequest(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void rawRequestAsJSON() {
// this needs to be full, otherwise actions will not be provided
rawRequest(ODataPubFormat.JSON_FULL_METADATA);
}
private void multiKey(final ODataPubFormat format) throws EdmPrimitiveTypeException {
final LinkedHashMap<String, Object> multiKey = new LinkedHashMap<String, Object>();
multiKey.put("ProductID", "6");
multiKey.put("ProductDetailID", 1);
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).
appendEntitySetSegment("ProductDetails").appendKeySegment(multiKey);
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(format);
final ODataRetrieveResponse<ODataEntity> res = req.execute();
final ODataEntity entity = res.getBody();
assertNotNull(entity);
assertEquals(Integer.valueOf(1),
entity.getProperty("ProductDetailID").getPrimitiveValue().toCastValue(Integer.class));
}
@Test
public void multiKeyAsAtom() throws EdmPrimitiveTypeException {
multiKey(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void multiKeyAsJSON() throws EdmPrimitiveTypeException {
multiKey(ODataPubFormat.JSON_FULL_METADATA);
}
@Test
public void checkForETagAsATOM() {
checkForETag(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void checkForETagAsJSON() {
checkForETag(ODataPubFormat.JSON_FULL_METADATA);
}
private void checkForETag(final ODataPubFormat format) {
final CommonURIBuilder<?> uriBuilder =
client.getURIBuilder(getServiceRoot()).appendEntitySetSegment("Orders").appendKeySegment(8);
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(format);
final ODataRetrieveResponse<ODataEntity> res = req.execute();
assertEquals(200, res.getStatusCode());
final String etag = res.getEtag();
assertTrue(StringUtils.isNotBlank(etag));
final ODataEntity order = res.getBody();
assertEquals(etag, order.getETag());
}
@Test(expected = IllegalArgumentException.class)
@Ignore
public void issue99() {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).appendEntitySetSegment("Car");
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(ODataPubFormat.JSON);
// this statement should cause an IllegalArgumentException bearing JsonParseException
// since we are attempting to parse an EntitySet as if it was an Entity
req.execute().getBody();
}
@Test
public void retrieveEntityReferenceAsAtom() {
retrieveEntityReference(ODataPubFormat.ATOM);
}
@Test
@Ignore
public void retrieveEntityReferenceAsJSON() {
retrieveEntityReference(ODataPubFormat.JSON_FULL_METADATA);
}
private void retrieveEntityReference(final ODataPubFormat format) {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(getServiceRoot()).
appendEntitySetSegment("Orders").appendKeySegment(8).appendNavigationSegment("CustomerForOrder").
appendRefSegment();
final ODataEntityRequest req = client.getRetrieveRequestFactory().getEntityRequest(uriBuilder.build());
req.setFormat(format);
final ODataRetrieveResponse<ODataEntity> res = req.execute();
assertNotNull(res);
final ODataEntity entity = res.getBody();
assertNotNull(entity);
assertTrue(entity.getReference().endsWith("/StaticService/V40/Static.svc/Customers(PersonID=1)"));
}
}

View File

@ -104,6 +104,8 @@ public class EntitySetTestITCase extends AbstractTestITCase {
assertNotNull(feed);
assertTrue(feed.getContextURL().toASCIIString().endsWith("$metadata#People"));
debugFeed(client.getBinder().getFeed(feed, ResourceFactory.feedClassForFormat(
ODataPubFormat.ATOM == format)), "Just retrieved feed");
@ -151,5 +153,6 @@ public class EntitySetTestITCase extends AbstractTestITCase {
final ODataEntitySet entitySet = res.getBodyAs(ODataEntitySet.class);
assertNotNull(entitySet);
assertTrue(entitySet.getContextURL().toASCIIString().endsWith("$metadata#People"));
}
}

View File

@ -0,0 +1,144 @@
/*
* 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.
*/
package org.apache.olingo.client.core.it.v4;
import static org.junit.Assert.*;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataValueRequest;
import org.apache.olingo.commons.api.format.ODataValueFormat;
import org.apache.olingo.client.api.uri.CommonURIBuilder;
import org.apache.olingo.commons.api.domain.ODataPrimitiveValue;
import org.apache.olingo.commons.api.domain.ODataProperty;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.format.ODataPubFormat;
import org.junit.Test;
public class PropertyValueTestITCase extends AbstractTestITCase {
@Test
public void retrieveIntPropertyValueTest() throws EdmPrimitiveTypeException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PersonID").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
assertEquals("5", req.execute().getBody().toString());
}
@Test
public void retrieveBooleanPropertyValueTest() throws EdmPrimitiveTypeException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("IsRegistered").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
assertEquals("true", req.execute().getBody().toString());
}
@Test
public void retrieveStringPropertyValueTest() throws EdmPrimitiveTypeException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("FirstName").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
assertEquals("Peter", req.execute().getBody().toString());
}
@Test
public void retrieveDatePropertyValueTest() {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("Orders").appendKeySegment(8).appendPropertySegment("OrderDate").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
final ODataPrimitiveValue property = req.execute().getBody();
assertEquals("2011-03-04T16:03:57Z", property.toString());
}
@Test
public void retrieveDecimalPropertyValueTest() throws EdmPrimitiveTypeException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("Height").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
final ODataPrimitiveValue property = req.execute().getBody();
assertEquals("179", property.toString());
}
@Test
public void retrieveBinaryPropertyValueTest() throws IOException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PDC").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
final ODataPrimitiveValue property = req.execute().getBody();
assertEquals("fi653p3+MklA/LdoBlhWgnMTUUEo8tEgtbMXnF0a3CUNL9BZxXpSRiD9ebTnmNR0zWPjJ"
+ "VIDx4tdmCnq55XrJh+RW9aI/b34wAogK3kcORw=", property.toString());
}
@Test(expected = ODataClientErrorException.class)
public void retrieveBinaryPropertyValueTestWithAtom() throws IOException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PDC").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setAccept(ODataPubFormat.ATOM.toString(ODataServiceVersion.V40));
req.execute().getBody();
}
@Test(expected = ODataClientErrorException.class)
public void retrieveBinaryPropertyValueTestWithXML() throws IOException {
final CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("PDC").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setAccept(ODataFormat.XML.toString());
req.execute().getBody();
}
@Test
public void retrieveCollectionPropertyValueTest() {
CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("Numbers");
final ODataPropertyRequest req = client.getRetrieveRequestFactory().getPropertyRequest(uriBuilder.build());
req.setFormat(ODataFormat.XML);
final ODataProperty property = req.execute().getBody();
assertTrue(property.getValue().isCollection());
assertEquals("555-555-5555", property.getCollectionValue().iterator().next().asPrimitive().toString());
}
@Test
public void retrieveNullPropertyValueTest() {
CommonURIBuilder<?> uriBuilder = client.getURIBuilder(testStaticServiceRootURL).
appendEntitySetSegment("People").appendKeySegment(5).appendPropertySegment("MiddleName").
appendValueSegment();
final ODataValueRequest req = client.getRetrieveRequestFactory().getValueRequest(uriBuilder.build());
req.setFormat(ODataValueFormat.TEXT);
final ODataPrimitiveValue property = req.execute().getBody();
assertTrue(StringUtils.isBlank(property.toString()));
}
}

View File

@ -104,7 +104,7 @@ public class URIBuilderTest extends AbstractTest {
public void unboundAction() throws URISyntaxException {
final URIBuilder uriBuilder = getClient().getURIBuilder(SERVICE_ROOT).
appendOperationCallSegment("ProductsByCategoryId",
Collections.<String, Object>singletonMap("categoryId", 2));
Collections.<String, Object>singletonMap("categoryId", 2));
assertEquals(new org.apache.http.client.utils.URIBuilder(
SERVICE_ROOT + "/ProductsByCategoryId(categoryId=2)").build(), uriBuilder.build());
@ -128,4 +128,22 @@ public class URIBuilderTest extends AbstractTest {
assertEquals(new org.apache.http.client.utils.URIBuilder(
SERVICE_ROOT + "/Customers/Model/Namespace.VipCustomer(1)").build(), uriBuilder.build());
}
@Test
public void expandMoreThenOnce() throws URISyntaxException {
URI uri = getClient().getURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Products").appendKeySegment(5).
expand("Orders", "Customers").expand("Info").build();
assertEquals(new org.apache.http.client.utils.URIBuilder(SERVICE_ROOT + "/Products(5)").
addParameter("$expand", "Orders,Customers,Info").build(), uri);
}
@Test
public void selectMoreThenOnce() throws URISyntaxException {
URI uri = getClient().getURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Customers").appendKeySegment(5).
select("Name", "Surname").expand("Info").select("Gender").build();
assertEquals(new org.apache.http.client.utils.URIBuilder(SERVICE_ROOT + "/Customers(5)").
addParameter("$select", "Name,Surname,Gender").addParameter("$expand", "Info").build(), uri);
}
}

View File

@ -20,6 +20,7 @@ package org.apache.olingo.client.core.v4;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import org.apache.olingo.client.api.v4.ODataClient;
import org.apache.olingo.client.api.uri.v4.URIBuilder;
@ -38,6 +39,22 @@ public class URIBuilderTest extends AbstractTest {
return v4Client;
}
@Test
public void expandWithOptions() throws URISyntaxException {
URI uri = getClient().getURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Products").appendKeySegment(5).
expandWithOptions("ProductDetails", new LinkedHashMap<String, Object>() {
private static final long serialVersionUID = 3109256773218160485L;
{
put("$expand", "ProductInfo");
put("$select", "Price");
}
}).expand("Orders", "Customers").build();
assertEquals(new org.apache.http.client.utils.URIBuilder(SERVICE_ROOT + "/Products(5)").
addParameter("$expand", "ProductDetails($expand=ProductInfo,$select=Price),Orders,Customers").build(), uri);
}
@Test
public void count() throws URISyntaxException {
URI uri = getClient().getURIBuilder(SERVICE_ROOT).appendEntitySetSegment("Products").count().build();
@ -132,5 +149,4 @@ public class URIBuilderTest extends AbstractTest {
assertEquals(new org.apache.http.client.utils.URIBuilder(
SERVICE_ROOT + "/Products").addParameter("$search", "blue OR green").build(), uriBuilder.build());
}
}

View File

@ -72,6 +72,8 @@ public interface Constants {
public static final QName QNAME_ATTR_XML_BASE = new QName(XMLConstants.XML_NS_URI, ATTR_XML_BASE);
public static final String CONTEXT = "context";
public static final String ATTR_REL = "rel";
public static final String ATTR_TITLE = "title";
@ -173,7 +175,7 @@ public interface Constants {
public final static String JSON_NULL = "odata.null";
public final static String JSON_VALUE = "value";
public final static String VALUE = "value";
public final static String JSON_URL = "url";
@ -192,6 +194,12 @@ public interface Constants {
// Atom stuff
public final static String ATOM_ELEM_ENTRY = "entry";
public final static String ATOM_ELEM_ENTRY_REF = "ref";
public final static String ATOM_ELEM_ENTRY_REF_ID = "id";
public final static QName QNAME_ATOM_ELEM_ENTRY_REF_ID = new QName(ATOM_ELEM_ENTRY_REF_ID);
public static final QName QNAME_ATOM_ELEM_ENTRY = new QName(NS_ATOM, ATOM_ELEM_ENTRY);
public final static String ATOM_ELEM_FEED = "feed";

View File

@ -38,6 +38,21 @@ public interface Entry {
*/
URI getBaseURI();
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @return context URL.
*/
URI getContextURL();
/**
* Set context URL.
*
* @param contextURL context URL.
*/
void setContextURL(final URI contextURL);
/**
* Gets entry type.
*
@ -53,12 +68,19 @@ public interface Entry {
void setType(String type);
/**
* Gest entry ID.
* Gets entry ID.
*
* @return entry ID.
*/
String getId();
/**
* Sets entry ID.
*
* @param id entry ID.
*/
void setId(String id);
/**
* Gets entry self link.
*

View File

@ -30,6 +30,21 @@ public interface Feed {
*/
URI getBaseURI();
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @return context URL.
*/
URI getContextURL();
/**
* Set context URL.
*
* @param contextURL context URL.
*/
void setContextURL(final URI contextURL);
/**
* Sets number of entries.
*
@ -71,5 +86,4 @@ public interface Feed {
* @param next next link.
*/
void setNext(URI next);
}

View File

@ -18,8 +18,18 @@
*/
package org.apache.olingo.commons.api.data;
import java.net.URI;
public interface Property {
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @return context URL.
*/
URI getContextURL();
String getName();
void setName(String name);

View File

@ -16,30 +16,37 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.client.api.communication.header;
package org.apache.olingo.commons.api.domain;
import java.net.URI;
/**
* Constant header values class.
* OData entity.
*/
public class ODataHeaderValues {
public abstract class AbstractODataPayload extends ODataItem {
private static final long serialVersionUID = -8234709365887433612L;
/**
* <code>Prefer</code> header, return content.
* Context URL.
*/
private URI contextURL;
public AbstractODataPayload(final String name) {
super(name);
}
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @see ODataHeaders.HeaderName#prefer
* @return context URL.
*/
public static final String preferReturnContent = "return-content";
/**
* <code>Prefer</code> header, return no content.
*
* @see ODataHeaders.HeaderName#prefer
*/
public static final String preferReturnNoContent = "return-no-content";
/**
* @see ODataHeaders.HeaderName#dataServiceUrlConventions
*/
public static final String keyAsSegment = "KeyAsSegment";
public URI getContextURL() {
return contextURL;
}
public void setContextURL(final URI contextURL) {
this.contextURL = contextURL;
}
}

View File

@ -26,10 +26,15 @@ import org.apache.commons.lang3.StringUtils;
/**
* OData entity.
*/
public class ODataEntity extends ODataItem implements ODataInvokeResult {
public class ODataEntity extends AbstractODataPayload implements ODataInvokeResult {
private static final long serialVersionUID = 8360640095932811034L;
/**
* Entity reference.
*/
private String reference;
/**
* ETag.
*/
@ -89,6 +94,30 @@ public class ODataEntity extends ODataItem implements ODataInvokeResult {
super(name);
}
/**
* To request entity references in place of the actual entities, the client issues a GET request with /$ref appended
* to the resource path.
* <br />
* If the resource path does not identify an entity or a collection of entities, the service returns 404 Not Found.
* <br />
* If the resource path terminates on a collection, the response MUST be the format-specific representation of a
* collection of entity references pointing to the related entities. If no entities are related, the response is the
* format-specific representation of an empty collection.
* <br />
* If the resource path terminates on a single entity, the response MUST be the format-specific representation of an
* entity reference pointing to the related single entity. If the resource path terminates on a single entity and no
* such entity exists, the service returns 404 Not Found.
*
* @return entity reference.
*/
public String getReference() {
return reference;
}
public void setReference(final String reference) {
this.reference = reference;
}
/**
* Gets ETag.
*

View File

@ -25,7 +25,7 @@ import java.util.List;
/**
* OData entity collection. If pagination was used to get this instance, forward page navigation URI will be available.
*/
public class ODataEntitySet extends ODataItem implements ODataInvokeResult {
public class ODataEntitySet extends AbstractODataPayload implements ODataInvokeResult {
private static final long serialVersionUID = 9039605899821494024L;

View File

@ -39,16 +39,16 @@ public abstract class ODataItem implements Serializable {
*/
protected static final Logger LOG = LoggerFactory.getLogger(ODataItem.class);
/**
* OData item self link.
*/
protected URI link;
/**
* OData entity name/type.
*/
private final String name;
/**
* OData item self link.
*/
protected URI link;
/**
* Constructor.
*
@ -58,6 +58,15 @@ public abstract class ODataItem implements Serializable {
this.name = name;
}
/**
* Returns OData entity name.
*
* @return entity name.
*/
public String getName() {
return name;
}
/**
* Returns self link.
*
@ -76,15 +85,6 @@ public abstract class ODataItem implements Serializable {
this.link = link;
}
/**
* Returns OData entity name.
*
* @return entity name.
*/
public String getName() {
return name;
}
/**
* {@inheritDoc }
*/

View File

@ -98,7 +98,6 @@ public class ODataLink extends ODataItem {
return uri.normalize();
}
/**
* Link type.
*/
@ -186,5 +185,4 @@ public class ODataLink extends ODataItem {
public String getMediaETag() {
return mediaETag;
}
}

View File

@ -49,8 +49,15 @@ abstract class AbstractAtomDealer {
protected final QName countQName;
protected final QName uriQName;
protected final QName nextQName;
protected final QName contextQName;
protected final QName entityRefQName;
protected final QName v4PropertyValueQName;
public AbstractAtomDealer(final ODataServiceVersion version) {
this.version = version;
@ -72,6 +79,12 @@ abstract class AbstractAtomDealer {
new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES), Constants.ELEM_URI);
this.nextQName =
new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES), Constants.NEXT_LINK_REL);
this.contextQName =
new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.CONTEXT);
this.entityRefQName =
new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.ATOM_ELEM_ENTRY_REF);
this.v4PropertyValueQName =
new QName(version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA), Constants.VALUE);
}
protected void namespaces(final XMLStreamWriter writer) throws XMLStreamException {
@ -83,5 +96,4 @@ abstract class AbstractAtomDealer {
writer.writeNamespace(Constants.PREFIX_GML, Constants.NS_GML);
writer.writeNamespace(Constants.PREFIX_GEORSS, Constants.NS_GEORSS);
}
}

View File

@ -31,6 +31,8 @@ abstract class AbstractAtomObject extends AbstractPayloadObject {
private URI baseURI;
private URI contextURL;
private String id;
private String title;
@ -47,10 +49,28 @@ abstract class AbstractAtomObject extends AbstractPayloadObject {
this.baseURI = URI.create(baseURI);
}
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @return context URL.
*/
public URI getContextURL() {
return contextURL;
}
public void setContextURL(final URI contextURL) {
this.contextURL = contextURL;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getTitle() {
return title;
}
@ -74,5 +94,4 @@ abstract class AbstractAtomObject extends AbstractPayloadObject {
this.updated = ISO_DATEFORMAT.parse(value);
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.commons.core.data;
import java.net.URI;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
@ -27,12 +28,29 @@ import org.apache.olingo.commons.api.data.Value;
public abstract class AbstractPropertyImpl implements Property {
private URI contextURL;
private String name;
private String type;
private Value value;
/**
* The context URL describes the content of the payload. It consists of the canonical metadata document URL and a
* fragment identifying the relevant portion of the metadata document.
*
* @return context URL.
*/
@Override
public URI getContextURL() {
return contextURL;
}
public void setContextURL(final URI contextURL) {
this.contextURL = contextURL;
}
@Override
public String getName() {
return name;

View File

@ -168,112 +168,135 @@ public class AtomDeserializer extends AbstractAtomDealer {
}
private AtomEntryImpl entry(final XMLEventReader reader, final StartElement start) throws XMLStreamException {
if (!Constants.QNAME_ATOM_ELEM_ENTRY.equals(start.getName())) {
return null;
}
final AtomEntryImpl entry;
if (entityRefQName.equals(start.getName())) {
entry = entryRef(start);
} else if (Constants.QNAME_ATOM_ELEM_ENTRY.equals(start.getName())) {
entry = new AtomEntryImpl();
final Attribute xmlBase = start.getAttributeByName(Constants.QNAME_ATTR_XML_BASE);
if (xmlBase != null) {
entry.setBaseURI(xmlBase.getValue());
}
final AtomEntryImpl entry = new AtomEntryImpl();
final Attribute xmlBase = start.getAttributeByName(Constants.QNAME_ATTR_XML_BASE);
if (xmlBase != null) {
entry.setBaseURI(xmlBase.getValue());
}
final Attribute etag = start.getAttributeByName(etagQName);
if (etag != null) {
entry.setETag(etag.getValue());
}
entry.setContextURL(retrieveContextURL(start, entry.getBaseURI()));
boolean foundEndEntry = false;
while (reader.hasNext() && !foundEndEntry) {
final XMLEvent event = reader.nextEvent();
final Attribute etag = start.getAttributeByName(etagQName);
if (etag != null) {
entry.setETag(etag.getValue());
}
if (event.isStartElement()) {
if (Constants.QNAME_ATOM_ELEM_ID.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "id");
} else if (Constants.QNAME_ATOM_ELEM_TITLE.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "title");
} else if (Constants.QNAME_ATOM_ELEM_SUMMARY.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "summary");
} else if (Constants.QNAME_ATOM_ELEM_UPDATED.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "updated");
} else if (Constants.QNAME_ATOM_ELEM_CATEGORY.equals(event.asStartElement().getName())) {
final Attribute term = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_TERM));
if (term != null) {
entry.setType(term.getValue());
}
} else if (Constants.QNAME_ATOM_ELEM_LINK.equals(event.asStartElement().getName())) {
final LinkImpl link = new LinkImpl();
final Attribute rel = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_REL));
if (rel != null) {
link.setRel(rel.getValue());
}
final Attribute title = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TITLE));
if (title != null) {
link.setTitle(title.getValue());
}
final Attribute href = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_HREF));
if (href != null) {
link.setHref(href.getValue());
}
final Attribute type = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
if (type != null) {
link.setType(type.getValue());
}
boolean foundEndEntry = false;
while (reader.hasNext() && !foundEndEntry) {
final XMLEvent event = reader.nextEvent();
if (Constants.SELF_LINK_REL.equals(link.getRel())) {
entry.setSelfLink(link);
} else if (Constants.EDIT_LINK_REL.equals(link.getRel())) {
entry.setEditLink(link);
} else if (link.getRel().startsWith(version.getNamespaceMap().get(ODataServiceVersion.NAVIGATION_LINK_REL))) {
entry.getNavigationLinks().add(link);
inline(reader, event.asStartElement(), link);
} else if (link.getRel().startsWith(
version.getNamespaceMap().get(ODataServiceVersion.ASSOCIATION_LINK_REL))) {
entry.getAssociationLinks().add(link);
} else if (link.getRel().startsWith(
version.getNamespaceMap().get(ODataServiceVersion.MEDIA_EDIT_LINK_REL))) {
final Attribute metag = event.asStartElement().getAttributeByName(etagQName);
if (metag != null) {
link.setMediaETag(metag.getValue());
if (event.isStartElement()) {
if (Constants.QNAME_ATOM_ELEM_ID.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "id");
} else if (Constants.QNAME_ATOM_ELEM_TITLE.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "title");
} else if (Constants.QNAME_ATOM_ELEM_SUMMARY.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "summary");
} else if (Constants.QNAME_ATOM_ELEM_UPDATED.equals(event.asStartElement().getName())) {
common(reader, event.asStartElement(), entry, "updated");
} else if (Constants.QNAME_ATOM_ELEM_CATEGORY.equals(event.asStartElement().getName())) {
final Attribute term = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_TERM));
if (term != null) {
entry.setType(term.getValue());
}
entry.getMediaEditLinks().add(link);
}
} else if (actionQName.equals(event.asStartElement().getName())) {
final ODataOperation operation = new ODataOperation();
final Attribute metadata = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_METADATA));
if (metadata != null) {
operation.setMetadataAnchor(metadata.getValue());
}
final Attribute title = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TITLE));
if (title != null) {
operation.setTitle(title.getValue());
}
final Attribute target = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TARGET));
if (target != null) {
operation.setTarget(URI.create(target.getValue()));
}
entry.getOperations().add(operation);
} else if (Constants.QNAME_ATOM_ELEM_CONTENT.equals(event.asStartElement().getName())) {
final Attribute type = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
if (type == null || ContentType.APPLICATION_XML.equals(type.getValue())) {
properties(reader, skipBeforeFirstStartElement(reader), entry);
} else {
entry.setMediaContentType(type.getValue());
final Attribute src = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_SRC));
if (src != null) {
entry.setMediaContentSource(src.getValue());
} else if (Constants.QNAME_ATOM_ELEM_LINK.equals(event.asStartElement().getName())) {
final LinkImpl link = new LinkImpl();
final Attribute rel = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_REL));
if (rel != null) {
link.setRel(rel.getValue());
}
final Attribute title = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TITLE));
if (title != null) {
link.setTitle(title.getValue());
}
final Attribute href = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_HREF));
if (href != null) {
link.setHref(href.getValue());
}
final Attribute type = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
if (type != null) {
link.setType(type.getValue());
}
if (Constants.SELF_LINK_REL.equals(link.getRel())) {
entry.setSelfLink(link);
} else if (Constants.EDIT_LINK_REL.equals(link.getRel())) {
entry.setEditLink(link);
} else if (link.getRel().startsWith(
version.getNamespaceMap().get(ODataServiceVersion.NAVIGATION_LINK_REL))) {
entry.getNavigationLinks().add(link);
inline(reader, event.asStartElement(), link);
} else if (link.getRel().startsWith(
version.getNamespaceMap().get(ODataServiceVersion.ASSOCIATION_LINK_REL))) {
entry.getAssociationLinks().add(link);
} else if (link.getRel().startsWith(
version.getNamespaceMap().get(ODataServiceVersion.MEDIA_EDIT_LINK_REL))) {
final Attribute metag = event.asStartElement().getAttributeByName(etagQName);
if (metag != null) {
link.setMediaETag(metag.getValue());
}
entry.getMediaEditLinks().add(link);
}
} else if (actionQName.equals(event.asStartElement().getName())) {
final ODataOperation operation = new ODataOperation();
final Attribute metadata =
event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_METADATA));
if (metadata != null) {
operation.setMetadataAnchor(metadata.getValue());
}
final Attribute title = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TITLE));
if (title != null) {
operation.setTitle(title.getValue());
}
final Attribute target = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TARGET));
if (target != null) {
operation.setTarget(URI.create(target.getValue()));
}
entry.getOperations().add(operation);
} else if (Constants.QNAME_ATOM_ELEM_CONTENT.equals(event.asStartElement().getName())) {
final Attribute type = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATTR_TYPE));
if (type == null || ContentType.APPLICATION_XML.equals(type.getValue())) {
properties(reader, skipBeforeFirstStartElement(reader), entry);
} else {
entry.setMediaContentType(type.getValue());
final Attribute src = event.asStartElement().getAttributeByName(QName.valueOf(Constants.ATOM_ATTR_SRC));
if (src != null) {
entry.setMediaContentSource(src.getValue());
}
}
} else if (propertiesQName.equals(event.asStartElement().getName())) {
properties(reader, event.asStartElement(), entry);
}
} else if (propertiesQName.equals(event.asStartElement().getName())) {
properties(reader, event.asStartElement(), entry);
}
if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
foundEndEntry = true;
}
}
if (event.isEndElement() && start.getName().equals(event.asEndElement().getName())) {
foundEndEntry = true;
}
return entry;
} else {
entry = null;
}
return entry;
}
private AtomEntryImpl entryRef(final StartElement start) throws XMLStreamException {
final AtomEntryImpl entry = new AtomEntryImpl();
entry.setContextURL(retrieveContextURL(start, null));
final Attribute entryRefId = start.getAttributeByName(Constants.QNAME_ATOM_ELEM_ENTRY_REF_ID);
if (entryRefId != null) {
entry.setId(entryRefId.getValue());
}
return entry;
@ -312,6 +335,8 @@ public class AtomDeserializer extends AbstractAtomDealer {
feed.setBaseURI(xmlBase.getValue());
}
feed.setContextURL(retrieveContextURL(start, feed.getBaseURI()));
boolean foundEndFeed = false;
while (reader.hasNext() && !foundEndFeed) {
final XMLEvent event = reader.nextEvent();
@ -365,4 +390,16 @@ public class AtomDeserializer extends AbstractAtomDealer {
}
return null;
}
private URI retrieveContextURL(final StartElement start, final URI base) {
final Attribute context = start.getAttributeByName(contextQName);
if (context == null) {
return base == null
? null
: URI.create(base.toASCIIString() + "/" + Constants.METADATA);
} else {
return URI.create(context.getValue());
}
}
}

View File

@ -18,6 +18,8 @@
*/
package org.apache.olingo.commons.core.data;
import java.net.URI;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
@ -163,17 +165,29 @@ class AtomPropertyDeserializer extends AbstractAtomDealer {
public AtomPropertyImpl deserialize(final XMLEventReader reader, final StartElement start)
throws XMLStreamException {
final AtomPropertyImpl property = new AtomPropertyImpl();
property.setName(start.getName().getLocalPart());
final Attribute typeAttr = start.getAttributeByName(this.typeQName);
final Attribute context = start.getAttributeByName(contextQName);
property.setContextURL(context == null ? null : URI.create(context.getValue()));
final QName name = start.getName();
if (ODataServiceVersion.V40 == version && v4PropertyValueQName.equals(name)) {
// retrieve name from context
final String contextURL = property.getContextURL().toASCIIString();
property.setName(contextURL.substring(contextURL.lastIndexOf("/") + 1));
} else {
property.setName(name.getLocalPart());
}
final Attribute nullAttr = start.getAttributeByName(this.nullQName);
Value value;
final Attribute nullAttr = start.getAttributeByName(this.nullQName);
final String typeAttrValue = typeAttr == null ? null : typeAttr.getValue();
if (nullAttr == null) {
final Attribute typeAttr = start.getAttributeByName(this.typeQName);
final String typeAttrValue = typeAttr == null ? null : typeAttr.getValue();
final EdmTypeInfo typeInfo = StringUtils.isBlank(typeAttrValue)
? null
: new EdmTypeInfo.Builder().setTypeExpression(typeAttrValue).build();

View File

@ -64,6 +64,14 @@ class AtomPropertySerializer extends AbstractAtomDealer {
writer.writeStartElement(Constants.PREFIX_DATASERVICES, property.getName(),
version.getNamespaceMap().get(ODataServiceVersion.NS_DATASERVICES));
if (version == ODataServiceVersion.V40 && property.getContextURL() != null) {
writer.writeAttribute(
version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
Constants.CONTEXT,
property.getContextURL().toASCIIString());
}
if (standalone) {
namespaces(writer);
}

View File

@ -127,6 +127,13 @@ public class AtomSerializer extends AbstractAtomDealer {
}
private void entry(final XMLStreamWriter writer, final Entry entry) throws XMLStreamException {
if (version == ODataServiceVersion.V40 && entry.getContextURL() != null) {
writer.writeAttribute(
version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
Constants.CONTEXT,
entry.getContextURL().toASCIIString());
}
if (entry.getBaseURI() != null) {
writer.writeAttribute(XMLConstants.XML_NS_URI, Constants.ATTR_XML_BASE, entry.getBaseURI().toASCIIString());
}
@ -184,6 +191,13 @@ public class AtomSerializer extends AbstractAtomDealer {
}
private void feed(final XMLStreamWriter writer, final Feed feed) throws XMLStreamException {
if (version == ODataServiceVersion.V40 && feed.getContextURL() != null) {
writer.writeAttribute(
version.getNamespaceMap().get(ODataServiceVersion.NS_METADATA),
Constants.CONTEXT,
feed.getContextURL().toASCIIString());
}
if (feed.getBaseURI() != null) {
writer.writeAttribute(XMLConstants.XML_NS_URI, Constants.ATTR_XML_BASE, feed.getBaseURI().toASCIIString());
}

View File

@ -23,13 +23,11 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.net.URI;
import java.text.ParseException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
@ -84,14 +82,17 @@ public class JSONEntryDeserializer extends AbstractJsonDeserializer<JSONEntryImp
final ObjectNode tree = (ObjectNode) parser.getCodec().readTree(parser);
if (tree.has(Constants.JSON_VALUE) && tree.get(Constants.JSON_VALUE).isArray()) {
if (tree.has(Constants.VALUE) && tree.get(Constants.VALUE).isArray()) {
throw new JsonParseException("Expected OData Entity, found EntitySet", parser.getCurrentLocation());
}
final JSONEntryImpl entry = new JSONEntryImpl();
if (tree.hasNonNull(Constants.JSON_METADATA)) {
entry.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
entry.setContextURL(URI.create(tree.get(Constants.JSON_CONTEXT).textValue()));
tree.remove(Constants.JSON_CONTEXT);
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
entry.setContextURL(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
tree.remove(Constants.JSON_METADATA);
}
@ -111,11 +112,7 @@ public class JSONEntryDeserializer extends AbstractJsonDeserializer<JSONEntryImp
}
if (tree.hasNonNull(Constants.JSON_ID)) {
try {
entry.setId(tree.get(Constants.JSON_ID).textValue());
} catch (ParseException e) {
throw new JsonMappingException("While parsing Atom entry or feed common elements", e);
}
entry.setId(tree.get(Constants.JSON_ID).textValue());
tree.remove(Constants.JSON_ID);
}

View File

@ -21,7 +21,6 @@ package org.apache.olingo.commons.core.data;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.net.URI;
import java.text.ParseException;
import org.apache.olingo.commons.api.Constants;
/**
@ -33,43 +32,19 @@ public class JSONEntryImpl extends AbstractEntry {
private static final long serialVersionUID = -5275365545400797758L;
private URI metadata;
private String mediaETag;
public void setId(final String id) throws ParseException {
this.setCommonProperty("id", id);
}
@Override
public URI getBaseURI() {
URI baseURI = null;
if (metadata != null) {
final String metadataURI = getMetadata().toASCIIString();
if (getContextURL() != null) {
final String metadataURI = getContextURL().toASCIIString();
baseURI = URI.create(metadataURI.substring(0, metadataURI.indexOf(Constants.METADATA)));
}
return baseURI;
}
/**
* Gets the metadata URI.
*
* @return the metadata URI
*/
public URI getMetadata() {
return metadata;
}
/**
* Sets the metadata URI.
*
* @param metadata metadata URI.
*/
public void setMetadata(final URI metadata) {
this.metadata = metadata;
}
/**
* The odata.mediaEtag annotation MAY be included; its value MUST be the ETag of the binary stream represented by this
* media entity or named stream property.

View File

@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.domain.ODataLinkType;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* Writes out JSON string from an entry.
@ -44,9 +45,12 @@ public class JSONEntrySerializer extends AbstractJsonSerializer<JSONEntryImpl> {
jgen.writeStartObject();
if (entry.getMetadata() != null) {
jgen.writeStringField(Constants.JSON_METADATA, entry.getMetadata().toASCIIString());
if (entry.getContextURL() != null) {
jgen.writeStringField(
version == ODataServiceVersion.V40 ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
entry.getContextURL().toASCIIString());
}
if (entry.getId() != null) {
jgen.writeStringField(Constants.JSON_ID, entry.getId());
}

View File

@ -41,15 +41,20 @@ public class JSONFeedDeserializer extends AbstractJsonDeserializer<JSONFeedImpl>
final ObjectNode tree = (ObjectNode) parser.getCodec().readTree(parser);
if (!tree.has(Constants.JSON_VALUE)) {
if (!tree.has(Constants.VALUE)) {
return null;
}
final JSONFeedImpl feed = new JSONFeedImpl();
if (tree.hasNonNull(Constants.JSON_METADATA)) {
feed.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
feed.setContextURL(URI.create(tree.get(Constants.JSON_CONTEXT).textValue()));
tree.remove(Constants.JSON_CONTEXT);
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
feed.setContextURL(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
tree.remove(Constants.JSON_METADATA);
}
if (tree.hasNonNull(Constants.JSON_COUNT)) {
feed.setCount(tree.get(Constants.JSON_COUNT).asInt());
}
@ -57,8 +62,8 @@ public class JSONFeedDeserializer extends AbstractJsonDeserializer<JSONFeedImpl>
feed.setNext(URI.create(tree.get(Constants.JSON_NEXT_LINK).textValue()));
}
if (tree.hasNonNull(Constants.JSON_VALUE)) {
for (final Iterator<JsonNode> itor = tree.get(Constants.JSON_VALUE).iterator(); itor.hasNext();) {
if (tree.hasNonNull(Constants.VALUE)) {
for (final Iterator<JsonNode> itor = tree.get(Constants.VALUE).iterator(); itor.hasNext();) {
feed.getEntries().add(itor.next().traverse(parser.getCodec()).readValueAs(JSONEntryImpl.class));
}
}

View File

@ -38,9 +38,9 @@ public class JSONFeedImpl extends AbstractPayloadObject implements Feed {
private static final long serialVersionUID = -3576372289800799417L;
private String id;
private URI contextURL;
private URI metadata;
private String id;
private Integer count;
@ -51,8 +51,8 @@ public class JSONFeedImpl extends AbstractPayloadObject implements Feed {
@Override
public URI getBaseURI() {
URI baseURI = null;
if (metadata != null) {
final String metadataURI = getMetadata().toASCIIString();
if (getContextURL() != null) {
final String metadataURI = getContextURL().toASCIIString();
baseURI = URI.create(metadataURI.substring(0, metadataURI.indexOf(Constants.METADATA)));
}
@ -60,21 +60,15 @@ public class JSONFeedImpl extends AbstractPayloadObject implements Feed {
}
/**
* Gets the metadata URI.
*
* @return the metadata URI
* {@inheritDoc}
*/
public URI getMetadata() {
return metadata;
@Override
public URI getContextURL() {
return contextURL;
}
/**
* Sets the metadata URI.
*
* @param metadata metadata URI.
*/
public void setMetadata(final URI metadata) {
this.metadata = metadata;
public void setContextURL(final URI context) {
this.contextURL = context;
}
@Override

View File

@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Entry;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class JSONFeedSerializer extends AbstractJsonSerializer<JSONFeedImpl> {
@ -33,8 +34,10 @@ public class JSONFeedSerializer extends AbstractJsonSerializer<JSONFeedImpl> {
jgen.writeStartObject();
if (feed.getMetadata() != null) {
jgen.writeStringField(Constants.JSON_METADATA, feed.getMetadata().toASCIIString());
if (feed.getContextURL() != null) {
jgen.writeStringField(
version == ODataServiceVersion.V40 ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
feed.getContextURL().toASCIIString());
}
if (feed.getId() != null) {
jgen.writeStringField(Constants.JSON_ID, feed.getId());
@ -46,12 +49,11 @@ public class JSONFeedSerializer extends AbstractJsonSerializer<JSONFeedImpl> {
jgen.writeStringField(Constants.JSON_NEXT_LINK, feed.getNext().toASCIIString());
}
jgen.writeArrayFieldStart(Constants.JSON_VALUE);
jgen.writeArrayFieldStart(Constants.VALUE);
for (Entry entry : feed.getEntries()) {
jgen.writeObject(entry);
}
jgen.writeEndArray();
}
}

View File

@ -41,16 +41,19 @@ public class JSONPropertyDeserializer extends AbstractJsonDeserializer<JSONPrope
final JSONPropertyImpl property = new JSONPropertyImpl();
if (tree.hasNonNull(Constants.JSON_METADATA)) {
property.setMetadata(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
property.setContextURL(URI.create(tree.get(Constants.JSON_CONTEXT).textValue()));
tree.remove(Constants.JSON_CONTEXT);
} else if (tree.hasNonNull(Constants.JSON_METADATA)) {
property.setContextURL(URI.create(tree.get(Constants.JSON_METADATA).textValue()));
tree.remove(Constants.JSON_METADATA);
}
if (property.getMetadata() != null) {
final String metadataURI = property.getMetadata().toASCIIString();
final int dashIdx = metadataURI.lastIndexOf('#');
if (property.getContextURL() != null) {
final String contextURL = property.getContextURL().toASCIIString();
final int dashIdx = contextURL.lastIndexOf('#');
if (dashIdx != -1) {
property.setType(metadataURI.substring(dashIdx + 1));
property.setType(contextURL.substring(dashIdx + 1));
}
}
@ -63,7 +66,7 @@ public class JSONPropertyDeserializer extends AbstractJsonDeserializer<JSONPrope
}
if (property.getValue() == null) {
value(property, tree.has(Constants.JSON_VALUE) ? tree.get(Constants.JSON_VALUE) : tree);
value(property, tree.has(Constants.VALUE) ? tree.get(Constants.VALUE) : tree);
}
return property;

View File

@ -20,7 +20,6 @@ package org.apache.olingo.commons.core.data;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.net.URI;
/**
* A single property (primitive, complex or collection) represented via JSON.
@ -31,23 +30,4 @@ public class JSONPropertyImpl extends AbstractPropertyImpl {
private static final long serialVersionUID = 553414431536637434L;
private URI metadata;
/**
* Gets metadata URI.
*
* @return metadata URI.
*/
public URI getMetadata() {
return metadata;
}
/**
* Sets metadata URI.
*
* @param metadata metadata URI.
*/
public void setMetadata(final URI metadata) {
this.metadata = metadata;
}
}

View File

@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* Writes out JSON string from <tt>JSONPropertyImpl</tt>.
@ -38,16 +39,18 @@ public class JSONPropertySerializer extends AbstractJsonSerializer<JSONPropertyI
jgen.writeStartObject();
if (property.getMetadata() != null) {
jgen.writeStringField(Constants.JSON_METADATA, property.getMetadata().toASCIIString());
if (property.getContextURL() != null) {
jgen.writeStringField(
version == ODataServiceVersion.V40 ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
property.getContextURL().toASCIIString());
}
if (property.getValue().isNull()) {
jgen.writeBooleanField(Constants.JSON_NULL, true);
} else if (property.getValue().isSimple()) {
jgen.writeStringField(Constants.JSON_VALUE, property.getValue().asSimple().get());
jgen.writeStringField(Constants.VALUE, property.getValue().asSimple().get());
} else if (property.getValue().isGeospatial() || property.getValue().isCollection()) {
property(jgen, property, Constants.JSON_VALUE);
property(jgen, property, Constants.VALUE);
} else if (property.getValue().isComplex()) {
for (Property cproperty : property.getValue().asComplex().get()) {
property(jgen, cproperty, cproperty.getName());

View File

@ -96,7 +96,6 @@ public class EdmTypeInfo {
baseType = typeExpression.substring(collStartIdx + 11, collEndIdx);
}
baseType = baseType.replaceAll("^#", "");
final String typeName;