OLINGO-175 provided update (PUT) and X-HTTP-METHOD header management
This commit is contained in:
parent
e624815544
commit
1e4d761b03
|
@ -44,6 +44,10 @@ public class EntityUpdateTestITCase extends AbstractTestITCase {
|
|||
protected String getServiceRoot() {
|
||||
return testDefaultServiceRootURL;
|
||||
}
|
||||
|
||||
protected String getStaticServiceRoot() {
|
||||
return testStaticServiceRootURL;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeAsAtom() {
|
||||
|
@ -92,7 +96,7 @@ public class EntityUpdateTestITCase extends AbstractTestITCase {
|
|||
@Test
|
||||
public void replaceAsAtom() {
|
||||
final ODataPubFormat format = ODataPubFormat.ATOM;
|
||||
final ODataEntity changes = read(format, client.getURIBuilder(getServiceRoot()).
|
||||
final ODataEntity changes = read(format, client.getURIBuilder(getStaticServiceRoot()).
|
||||
appendEntityTypeSegment("Car").appendKeySegment(14).build());
|
||||
updateEntityDescription(format, changes, UpdateType.REPLACE);
|
||||
}
|
||||
|
@ -100,7 +104,7 @@ public class EntityUpdateTestITCase extends AbstractTestITCase {
|
|||
@Test
|
||||
public void replaceAsJSON() {
|
||||
final ODataPubFormat format = ODataPubFormat.JSON_FULL_METADATA;
|
||||
final ODataEntity changes = read(format, client.getURIBuilder(getServiceRoot()).
|
||||
final ODataEntity changes = read(format, client.getURIBuilder(getStaticServiceRoot()).
|
||||
appendEntityTypeSegment("Car").appendKeySegment(14).build());
|
||||
updateEntityDescription(format, changes, UpdateType.REPLACE);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.msopentech.odatajclient.testservice.utils.ODataVersion;
|
|||
import com.msopentech.odatajclient.testservice.utils.FSManager;
|
||||
|
||||
import static com.msopentech.odatajclient.testservice.utils.Constants.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
|
@ -38,6 +39,7 @@ import javax.ws.rs.GET;
|
|||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
|
@ -122,14 +124,42 @@ public abstract class AbstractServices {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample failing entity POST.
|
||||
*
|
||||
* @param accept Accept header.
|
||||
* @param format format query option.
|
||||
* @param entitySetName entity set name.
|
||||
* @return fault response.
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{entitySetName}({entityId})")
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
|
||||
@Consumes({ MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
|
||||
public Response putNewEntity(
|
||||
@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
|
||||
@HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
|
||||
@PathParam("entitySetName") String entitySetName,
|
||||
@PathParam("entityId") String entityId,
|
||||
final String entity) {
|
||||
try {
|
||||
|
||||
final Accept acceptType = Accept.parse(accept, getVersion());
|
||||
|
||||
if (acceptType == Accept.XML || acceptType == Accept.TEXT) {
|
||||
throw new UnsupportedMediaTypeException("Unsupported media type");
|
||||
}
|
||||
|
||||
final InputStream res;
|
||||
if (acceptType == Accept.ATOM) {
|
||||
res = atom.saveSingleEntity(entityId, entitySetName, IOUtils.toInputStream(entity));
|
||||
} else {
|
||||
res = json.saveSingleEntity(entityId, entitySetName, IOUtils.toInputStream(entity));
|
||||
}
|
||||
|
||||
res.close();
|
||||
|
||||
final Response response = atom.createResponse(null, null, acceptType, Response.Status.NO_CONTENT);
|
||||
response.getHeaders().put("Preference-Applied", Collections.<Object>singletonList(prefer));
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return atom.createFaultResponse(accept, e);
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{entitySetName}")
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON })
|
||||
|
@ -150,11 +180,9 @@ public abstract class AbstractServices {
|
|||
|
||||
final InputStream res;
|
||||
if (acceptType == Accept.ATOM) {
|
||||
res = atom.createEntity(
|
||||
null, null, ENTITY, IOUtils.toInputStream(entity), entitySetName, acceptType);
|
||||
res = atom.createEntity(entitySetName, IOUtils.toInputStream(entity));
|
||||
} else {
|
||||
res = json.createEntity(
|
||||
null, null, ENTITY, IOUtils.toInputStream(entity), entitySetName, acceptType);
|
||||
res = json.createEntity(entitySetName, IOUtils.toInputStream(entity));
|
||||
}
|
||||
|
||||
if (prefer.equalsIgnoreCase("return-no-content")) {
|
||||
|
|
|
@ -19,9 +19,12 @@
|
|||
package com.msopentech.odatajclient.testservice;
|
||||
|
||||
import com.msopentech.odatajclient.testservice.utils.ODataVersion;
|
||||
import com.msopentech.odatajclient.testservice.utils.XHTTPMethodInterceptor;
|
||||
import javax.ws.rs.Path;
|
||||
import org.apache.cxf.interceptor.InInterceptors;
|
||||
|
||||
@Path("/V3/Static.svc")
|
||||
@InInterceptors(classes = XHTTPMethodInterceptor.class)
|
||||
public class V3Services extends AbstractServices {
|
||||
|
||||
public V3Services() throws Exception {
|
||||
|
|
|
@ -19,9 +19,12 @@
|
|||
package com.msopentech.odatajclient.testservice;
|
||||
|
||||
import com.msopentech.odatajclient.testservice.utils.ODataVersion;
|
||||
import com.msopentech.odatajclient.testservice.utils.XHTTPMethodInterceptor;
|
||||
import javax.ws.rs.Path;
|
||||
import org.apache.cxf.interceptor.InInterceptors;
|
||||
|
||||
@Path("/V4/Static.svc")
|
||||
@InInterceptors(classes = XHTTPMethodInterceptor.class)
|
||||
public class V4Services extends AbstractServices {
|
||||
|
||||
public V4Services() throws Exception {
|
||||
|
|
|
@ -146,13 +146,51 @@ public abstract class AbstractUtilities {
|
|||
final String entitySetName, final String entityKey, final InputStream is, final NavigationLinks links)
|
||||
throws Exception;
|
||||
|
||||
public InputStream saveSingleEntity(
|
||||
final String key,
|
||||
final String entitySetName,
|
||||
final InputStream is) throws Exception {
|
||||
return saveSingleEntity(key, entitySetName, is, null);
|
||||
}
|
||||
|
||||
public InputStream saveSingleEntity(
|
||||
final String key,
|
||||
final String entitySetName,
|
||||
final InputStream is,
|
||||
final NavigationLinks links) throws Exception {
|
||||
|
||||
// -----------------------------------------
|
||||
// 0. Get the path
|
||||
// -----------------------------------------
|
||||
final String path =
|
||||
entitySetName + File.separatorChar + Commons.getEntityKey(key) + File.separatorChar + ENTITY;
|
||||
// -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
// 1. Normalize navigation info; edit link; ...
|
||||
// -----------------------------------------
|
||||
final InputStream normalized = normalizeLinks(entitySetName, key, is, links);
|
||||
// -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
// 2. save the entity
|
||||
// -----------------------------------------
|
||||
final FileObject fo = fsManager.putInMemory(normalized, fsManager.getAbsolutePath(path, getDefaultFormat()));
|
||||
// -----------------------------------------
|
||||
|
||||
return fo.getContent().getInputStream();
|
||||
}
|
||||
|
||||
public InputStream createEntity(
|
||||
final String entitySetName, final InputStream is) throws Exception {
|
||||
return createEntity(null, entitySetName, is);
|
||||
}
|
||||
|
||||
public InputStream createEntity(
|
||||
final String key,
|
||||
final String basePath,
|
||||
final String relativePath,
|
||||
final InputStream is,
|
||||
final String entitySetName,
|
||||
final Accept accept) throws Exception {
|
||||
final InputStream is) throws Exception {
|
||||
|
||||
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
IOUtils.copy(is, bos);
|
||||
|
@ -162,9 +200,9 @@ public abstract class AbstractUtilities {
|
|||
// 0. Get default entry key and path (N.B. operation will consume/close the stream; use a copy instead)
|
||||
// -----------------------------------------
|
||||
final String entityKey = key == null ? getDefaultEntryKey(
|
||||
entitySetName, new ByteArrayInputStream(bos.toByteArray()), accept) : key;
|
||||
final String path = StringUtils.isBlank(basePath)
|
||||
? entitySetName + File.separatorChar + Commons.getEntityKey(entityKey) + File.separatorChar : basePath;
|
||||
entitySetName, new ByteArrayInputStream(bos.toByteArray()), getDefaultFormat()) : key;
|
||||
|
||||
final String path = entitySetName + File.separatorChar + Commons.getEntityKey(entityKey) + File.separatorChar;
|
||||
// -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
|
@ -175,21 +213,21 @@ public abstract class AbstractUtilities {
|
|||
// -----------------------------------------
|
||||
|
||||
// -----------------------------------------
|
||||
// 2. Retrieve navigation info
|
||||
// 2. Normalize navigation info; edit link; ... and save entity ....
|
||||
// -----------------------------------------
|
||||
final InputStream normalized =
|
||||
normalizeLinks(entitySetName, entityKey, new ByteArrayInputStream(bos.toByteArray()), links);
|
||||
final InputStream createdEntity =
|
||||
saveSingleEntity(entityKey, entitySetName, new ByteArrayInputStream(bos.toByteArray()), links);
|
||||
// -----------------------------------------
|
||||
|
||||
bos.reset();
|
||||
IOUtils.copy(normalized, bos);
|
||||
IOUtils.copy(createdEntity, bos);
|
||||
|
||||
// -----------------------------------------
|
||||
// 2. save the entity
|
||||
// 3. save the entity
|
||||
// -----------------------------------------
|
||||
final FileObject fo = fsManager.putInMemory(
|
||||
new ByteArrayInputStream(bos.toByteArray()),
|
||||
fsManager.getAbsolutePath(path + relativePath, accept));
|
||||
fsManager.getAbsolutePath(path + ENTITY, getDefaultFormat()));
|
||||
IOUtils.closeQuietly(bos);
|
||||
// -----------------------------------------
|
||||
|
||||
|
@ -211,15 +249,12 @@ public abstract class AbstractUtilities {
|
|||
IOUtils.closeQuietly(stream);
|
||||
|
||||
final String inlineEntryKey = getDefaultEntryKey(
|
||||
inlineEntitySetName, new ByteArrayInputStream(inlineBos.toByteArray()), accept);
|
||||
inlineEntitySetName, new ByteArrayInputStream(inlineBos.toByteArray()), getDefaultFormat());
|
||||
|
||||
createEntity(
|
||||
inlineEntryKey,
|
||||
null,
|
||||
ENTITY,
|
||||
new ByteArrayInputStream(inlineBos.toByteArray()),
|
||||
inlineEntitySetName,
|
||||
accept);
|
||||
new ByteArrayInputStream(inlineBos.toByteArray()));
|
||||
|
||||
hrefs.add(inlineEntitySetName + "(" + inlineEntryKey + ")");
|
||||
}
|
||||
|
@ -492,4 +527,6 @@ public abstract class AbstractUtilities {
|
|||
final InputStream toBeChanged, final String linkName, final InputStream replacement) throws Exception;
|
||||
|
||||
public abstract InputStream selectEntity(final InputStream entity, final String[] propertyNames) throws Exception;
|
||||
|
||||
protected abstract Accept getDefaultFormat();
|
||||
}
|
||||
|
|
|
@ -84,4 +84,6 @@ public class Constants {
|
|||
|
||||
public final static String JSON_EDITLINK_NAME = "odata.editLink";
|
||||
|
||||
public final static String XHTTP_HEADER_NAME = "X-HTTP-METHOD";
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,11 @@ public class JSONUtilities extends AbstractUtilities {
|
|||
super(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Accept getDefaultFormat() {
|
||||
return Accept.JSON_FULLMETA;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc }
|
||||
*/
|
||||
|
@ -94,26 +99,28 @@ public class JSONUtilities extends AbstractUtilities {
|
|||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final ObjectNode srcNode = (ObjectNode) mapper.readTree(is);
|
||||
|
||||
for (String linkTitle : links.getLinkNames()) {
|
||||
// normalize link
|
||||
srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
|
||||
srcNode.set(
|
||||
linkTitle + JSON_NAVIGATION_SUFFIX,
|
||||
new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
|
||||
}
|
||||
if (links != null) {
|
||||
for (String linkTitle : links.getLinkNames()) {
|
||||
// normalize link
|
||||
srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
|
||||
srcNode.set(
|
||||
linkTitle + JSON_NAVIGATION_SUFFIX,
|
||||
new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
|
||||
}
|
||||
|
||||
for (String linkTitle : links.getInlineNames()) {
|
||||
// normalize link if exist; declare a new one if missing
|
||||
srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
|
||||
srcNode.set(
|
||||
linkTitle + JSON_NAVIGATION_SUFFIX,
|
||||
new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
|
||||
for (String linkTitle : links.getInlineNames()) {
|
||||
// normalize link if exist; declare a new one if missing
|
||||
srcNode.remove(linkTitle + JSON_NAVIGATION_BIND_SUFFIX);
|
||||
srcNode.set(
|
||||
linkTitle + JSON_NAVIGATION_SUFFIX,
|
||||
new TextNode(String.format("%s(%s)/%s", entitySetName, entityKey, linkTitle)));
|
||||
|
||||
// remove inline
|
||||
srcNode.remove(linkTitle);
|
||||
// remove inline
|
||||
srcNode.remove(linkTitle);
|
||||
|
||||
// remove from links
|
||||
links.removeLink(linkTitle);
|
||||
// remove from links
|
||||
links.removeLink(linkTitle);
|
||||
}
|
||||
}
|
||||
|
||||
srcNode.set(
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* 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 com.msopentech.odatajclient.testservice.utils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.cxf.interceptor.Fault;
|
||||
import org.apache.cxf.message.Message;
|
||||
import org.apache.cxf.phase.AbstractPhaseInterceptor;
|
||||
import org.apache.cxf.phase.Phase;
|
||||
|
||||
public class XHTTPMethodInterceptor extends AbstractPhaseInterceptor<Message> {
|
||||
|
||||
public XHTTPMethodInterceptor() {
|
||||
super(Phase.PRE_PROTOCOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final Message message) throws Fault {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, List<String>> headers = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
|
||||
|
||||
if (headers.containsKey(Constants.XHTTP_HEADER_NAME)) {
|
||||
message.put(Message.HTTP_REQUEST_METHOD, headers.get(Constants.XHTTP_HEADER_NAME).iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,11 @@ public class XMLUtilities extends AbstractUtilities {
|
|||
super(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Accept getDefaultFormat() {
|
||||
return Accept.ATOM;
|
||||
}
|
||||
|
||||
protected static XMLEventReader getEventReader(final InputStream is) throws XMLStreamException {
|
||||
if (factory == null) {
|
||||
factory = XMLInputFactory.newInstance();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"odata.metadata": "http://localhost:${cargo.servlet.port}/StaticService/V3/Static.svc/$metadata#Car/@Element",
|
||||
"odata.type": "Microsoft.Test.OData.Services.AstoriaDefaultService.Car",
|
||||
"odata.id": "http://localhost:${cargo.servlet.port}/StaticService/V3/Static.svc/Car(14)",
|
||||
"odata.editLink": "Car(14)",
|
||||
"odata.mediaEditLink": "Car(14)/$value",
|
||||
"odata.mediaReadLink": "Car(14)/$value",
|
||||
"odata.mediaContentType": "*/*",
|
||||
"Photo@odata.mediaEditLink": "Car(14)/Photo",
|
||||
"Video@odata.mediaEditLink": "Car(14)/Video",
|
||||
"VIN": 14,
|
||||
"Description": "畚チびンぁあяまぴひタバァンぴ歹チ歹歹ァまマぞ珱暦ぼ歹グ珱ボチタびゼソゼたグёま畚a畚歹匚畚ァゼ匚Я欲匚チチボびソァぴ暦ぺポソチバЯゼ黑ダ匚マび暦ダソク歹まあa裹ソハ歹暦弌aバ暦ぽネ"
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?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/V3/Static.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
|
||||
<id>http://localhost:${cargo.servlet.port}/StaticService/V3/Static.svc/Car(14)</id>
|
||||
<category term="Microsoft.Test.OData.Services.AstoriaDefaultService.Car" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
|
||||
<link rel="edit" title="Car" href="Car(14)" />
|
||||
<title />
|
||||
<updated>2014-03-07T15:15:31Z</updated>
|
||||
<author>
|
||||
<name />
|
||||
</author>
|
||||
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media/Photo" title="Photo" href="Car(14)/Photo" />
|
||||
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media/Video" title="Video" href="Car(14)/Video" />
|
||||
<link rel="edit-media" title="Car" href="Car(14)/$value" />
|
||||
<content type="*/*" src="Car(14)/$value" />
|
||||
<m:properties>
|
||||
<d:VIN m:type="Edm.Int32">14</d:VIN>
|
||||
<d:Description>畚チびンぁあяまぴひタバァンぴ歹チ歹歹ァまマぞ珱暦ぼ歹グ珱ボチタびゼソゼたグёま畚a畚歹匚畚ァゼ匚Я欲匚チチボびソァぴ暦ぺポソチバЯゼ黑ダ匚マび暦ダソク歹まあa裹ソハ歹暦弌aバ暦ぽネ</d:Description>
|
||||
</m:properties>
|
||||
</entry>
|
Loading…
Reference in New Issue