[OLINGO-175, OLINGO-205, OLINGO-246] provided v4 batch test including outside update; still missing asyncronous execution

This commit is contained in:
fmartelli 2014-04-19 12:42:51 +02:00
parent 6dfdee2ef2
commit 9fa8fbc31f
36 changed files with 986 additions and 350 deletions

View File

@ -38,12 +38,10 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Header;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
@ -118,7 +116,7 @@ public abstract class AbstractServices {
private static final Pattern BATCH_REQUEST_REF_PATTERN = Pattern.compile("(.*) ([$].*) HTTP/.*");
private static final String BOUNDARY = "batch_243234_25424_ef_892u748";
protected static final String BOUNDARY = "batch_243234_25424_ef_892u748";
protected final ODataServiceVersion version;
@ -205,16 +203,16 @@ public abstract class AbstractServices {
@POST
@Path("/$batch")
@Consumes("multipart/mixed")
@Produces("application/octet-stream; boundary=" + BOUNDARY)
@Consumes(ContentType.MULTIPART_MIXED)
@Produces(ContentType.APPLICATION_OCTET_STREAM + ";boundary=" + BOUNDARY)
public Response batch(
@HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
final @Multipart MultipartBody attachment) {
try {
final boolean continueOnError = prefer.contains("odata.continue-on-error");
return xml.createBatchResponse(
exploreMultipart(attachment.getAllAttachments(), BOUNDARY, continueOnError),
exploreMultipart(attachment.getAllAttachments(), BOUNDARY, continueOnError),
BOUNDARY);
} catch (IOException e) {
return xml.createFaultResponse(Accept.XML.toString(version), e);
@ -244,6 +242,8 @@ public abstract class AbstractServices {
headers.putSingle(header.getName(), header.getValue());
}
final Response res;
if (matcher.find()) {
String method = matcher.group(1);
if ("PATCH".equals(method) || "MERGE".equals(method)) {
@ -255,8 +255,8 @@ public abstract class AbstractServices {
final WebClient client = WebClient.create(url);
client.headers(headers);
return client.invoke(method, body.getDataHandler().getInputStream());
res = client.invoke(method, body.getDataHandler().getInputStream());
client.close();
} else if (matcherRef.find()) {
String method = matcherRef.group(1);
if ("PATCH".equals(method) || "MERGE".equals(method)) {
@ -269,14 +269,17 @@ public abstract class AbstractServices {
final WebClient client = WebClient.create(references.get(url));
client.headers(headers);
return client.invoke(method, body.getDataHandler().getInputStream());
res = client.invoke(method, body.getDataHandler().getInputStream());
client.close();
} else {
return null;
res = null;
}
return res;
}
protected abstract InputStream exploreMultipart(
final List<Attachment> attachments, final String boundary, final boolean continueOnError)
final List<Attachment> attachments, final String boundary, final boolean continueOnError)
throws IOException;
protected void addItemIntro(final ByteArrayOutputStream bos) throws IOException {
@ -417,7 +420,7 @@ public abstract class AbstractServices {
} else {
final Container<JSONEntryImpl> jcont =
mapper.readValue(IOUtils.toInputStream(changes), new TypeReference<JSONEntryImpl>() {
});
});
entryChanges = dataBinder.getAtomEntry(jcont.getObject());
}
@ -555,7 +558,6 @@ public abstract class AbstractServices {
@HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) String prefer,
@PathParam("entitySetName") String entitySetName,
final String entity) {
// default
AbstractUtilities utils = xml;
try {
@ -608,7 +610,7 @@ public abstract class AbstractServices {
} else {
final Container<JSONEntryImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity), new TypeReference<JSONEntryImpl>() {
});
});
entry = dataBinder.getAtomEntry(jcontainer.getObject());
@ -635,7 +637,7 @@ public abstract class AbstractServices {
Container<AtomEntryImpl> result = atomDeserializer.read(serialization, AtomEntryImpl.class);
result = new Container<AtomEntryImpl>(
URI.create(Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL)
+ "$metadata#" + entitySetName + "/$entity"), null, result.getObject());
+ "$metadata#" + entitySetName + "/$entity"), null, result.getObject());
final String path = Commons.getEntityBasePath(entitySetName, entityKey);
FSManager.instance(version).putInMemory(
@ -697,13 +699,13 @@ public abstract class AbstractServices {
replaceAll("\"Salary\":[0-9]*,", "\"Salary\":0,").
replaceAll("\"Title\":\".*\"", "\"Title\":\"[Sacked]\"").
replaceAll("\\<d:Salary m:type=\"Edm.Int32\"\\>.*\\</d:Salary\\>",
"<d:Salary m:type=\"Edm.Int32\">0</d:Salary>").
"<d:Salary m:type=\"Edm.Int32\">0</d:Salary>").
replaceAll("\\<d:Title\\>.*\\</d:Title\\>", "<d:Title>[Sacked]</d:Title>");
final FSManager fsManager = FSManager.instance(version);
fsManager.putInMemory(IOUtils.toInputStream(newContent, "UTF-8"),
fsManager.getAbsolutePath(Commons.getEntityBasePath("Person", entityId) + Constants.get(version,
ConstantKey.ENTITY), utils.getKey()));
ConstantKey.ENTITY), utils.getKey()));
return utils.getValue().createResponse(null, null, null, utils.getKey(), Response.Status.NO_CONTENT);
} catch (Exception e) {
@ -755,9 +757,9 @@ public abstract class AbstractServices {
final Long newSalary = Long.valueOf(salaryMatcher.group(1)) + n;
newContent = newContent.
replaceAll("\"Salary\":" + salaryMatcher.group(1) + ",",
"\"Salary\":" + newSalary + ",").
"\"Salary\":" + newSalary + ",").
replaceAll("\\<d:Salary m:type=\"Edm.Int32\"\\>" + salaryMatcher.group(1) + "</d:Salary\\>",
"<d:Salary m:type=\"Edm.Int32\">" + newSalary + "</d:Salary>");
"<d:Salary m:type=\"Edm.Int32\">" + newSalary + "</d:Salary>");
}
FSManager.instance(version).putInMemory(IOUtils.toInputStream(newContent, "UTF-8"),
@ -887,7 +889,7 @@ public abstract class AbstractServices {
} else {
mapper.writeValue(
writer, new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(), container.getMetadataETag(),
dataBinder.getJsonFeed(container.getObject())));
dataBinder.getJsonFeed(container.getObject())));
}
return xml.createResponse(
@ -1502,8 +1504,8 @@ public abstract class AbstractServices {
mapper.writeValue(
writer,
new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(),
container.getMetadataETag(),
dataBinder.getJsonFeed((AtomFeedImpl) container.getObject())));
container.getMetadataETag(),
dataBinder.getJsonFeed((AtomFeedImpl) container.getObject())));
}
} else {
final Container<Entry> container = atomDeserializer.<Entry, AtomEntryImpl>read(stream, AtomEntryImpl.class);
@ -1515,8 +1517,8 @@ public abstract class AbstractServices {
mapper.writeValue(
writer,
new JsonEntryContainer<JSONEntryImpl>(container.getContextURL(),
container.getMetadataETag(),
dataBinder.getJsonEntry((AtomEntryImpl) container.getObject())));
container.getMetadataETag(),
dataBinder.getJsonEntry((AtomEntryImpl) container.getObject())));
}
}

View File

@ -196,7 +196,7 @@ public class V4Services extends AbstractServices {
return utils.getValue().createResponse(
FSManager.instance(version).readFile(Constants.get(version, ConstantKey.REF)
+ File.separatorChar + filename, utils.getKey()),
+ File.separatorChar + filename, utils.getKey()),
null,
utils.getKey());
} catch (Exception e) {
@ -218,7 +218,7 @@ public class V4Services extends AbstractServices {
final Response response =
getEntityInternal(uriInfo.getRequestUri().toASCIIString(),
accept, entitySetName, entityId, accept, StringUtils.EMPTY, StringUtils.EMPTY, false);
accept, entitySetName, entityId, accept, StringUtils.EMPTY, StringUtils.EMPTY, false);
return response.getStatus() >= 400
? postNewEntity(uriInfo, accept, contentType, prefer, entitySetName, changes)
: super.patchEntity(uriInfo, accept, contentType, prefer, ifMatch, entitySetName, entityId, changes);
@ -242,7 +242,7 @@ public class V4Services extends AbstractServices {
return postNewEntity(uriInfo, accept, contentType, prefer, entitySetName, entityId);
}
}
private StringBuilder containedPath(final String entityId, final String containedEntitySetName) {
return new StringBuilder("Accounts").append(File.separatorChar).
append(entityId).append(File.separatorChar).
@ -272,7 +272,7 @@ public class V4Services extends AbstractServices {
final InputStream entry = FSManager.instance(version).
readFile(containedPath(entityId, containedEntitySetName).
append('(').append(containedEntityId).append(')').toString(), Accept.ATOM);
append('(').append(containedEntityId).append(')').toString(), Accept.ATOM);
final Container<AtomEntryImpl> container = atomDeserializer.read(entry, AtomEntryImpl.class);
@ -315,7 +315,7 @@ public class V4Services extends AbstractServices {
} else {
final Container<JSONEntryImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity), new TypeReference<JSONEntryImpl>() {
});
});
entry = dataBinder.getAtomEntry(jcontainer.getObject());
@ -413,7 +413,7 @@ public class V4Services extends AbstractServices {
final Container<JSONEntryImpl> jsonContainer = mapper.readValue(IOUtils.toInputStream(changes),
new TypeReference<JSONEntryImpl>() {
});
});
jsonContainer.getObject().setType(typeInfo.getFullQualifiedName().toString());
entryChanges = dataBinder.getAtomEntry(jsonContainer.getObject());
}
@ -446,9 +446,9 @@ public class V4Services extends AbstractServices {
// 1. Fetch the contained entity to be removed
final InputStream entry = FSManager.instance(version).
readFile(containedPath(entityId, containedEntitySetName).
append('(').append(containedEntityId).append(')').toString(), Accept.ATOM);
append('(').append(containedEntityId).append(')').toString(), Accept.ATOM);
final Container<AtomEntryImpl> container = atomDeserializer.read(entry, AtomEntryImpl.class);
// 2. Remove the contained entity
final String atomEntryRelativePath = containedPath(entityId, containedEntitySetName).
append('(').append(containedEntityId).append(')').toString();
@ -457,7 +457,7 @@ public class V4Services extends AbstractServices {
// 3. Update the contained entity set
final String atomFeedRelativePath = containedPath(entityId, containedEntitySetName).toString();
final InputStream feedIS = FSManager.instance(version).readFile(atomFeedRelativePath, Accept.ATOM);
final Container<AtomFeedImpl> feedContainer = atomDeserializer.read(feedIS, AtomFeedImpl.class);
final Container<AtomFeedImpl> feedContainer = atomDeserializer.read(feedIS, AtomFeedImpl.class);
feedContainer.getObject().getEntries().remove(container.getObject());
final ByteArrayOutputStream content = new ByteArrayOutputStream();
@ -510,7 +510,7 @@ public class V4Services extends AbstractServices {
} else {
mapper.writeValue(
writer, new JsonFeedContainer<JSONFeedImpl>(container.getContextURL(), container.getMetadataETag(),
dataBinder.getJsonFeed(container.getObject())));
dataBinder.getJsonFeed(container.getObject())));
}
return xml.createResponse(
@ -522,5 +522,4 @@ public class V4Services extends AbstractServices {
return xml.createFaultResponse(accept, e);
}
}
}

View File

@ -23,11 +23,6 @@ package org.apache.olingo.client.api;
*/
public class ODataBatchConstants {
/**
* Batch/Changeset content type.
*/
public static final String MULTIPART_CONTENT_TYPE = "multipart/mixed";
/**
* Batch item content type.
*/

View File

@ -18,7 +18,7 @@
*/
package org.apache.olingo.client.api.communication.request;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
/**
* Object request that can be sent embedded into a batch request.
@ -32,7 +32,7 @@ public interface ODataBatchableRequest extends ODataRequest {
*
* @param req destination batch request.
*/
void batch(final ODataBatchRequest req);
void batch(final CommonODataBatchRequest req);
/**
* Writes (and consume) the request onto the given batch stream.
@ -42,5 +42,5 @@ public interface ODataBatchableRequest extends ODataRequest {
* @param req destination batch request.
* @param contentId ContentId header value to be added to the serialization. Use this in case of changeset items.
*/
void batch(final ODataBatchRequest req, final String contentId);
void batch(final CommonODataBatchRequest req, final String contentId);
}

View File

@ -24,12 +24,4 @@ import java.io.Serializable;
* OData batch request factory class.
*/
public interface CommonBatchRequestFactory extends Serializable {
/**
* Gets a batch request object instance.
*
* @param serviceRoot service root.
* @return new ODataBatchRequest instance.
*/
ODataBatchRequest getBatchRequest(String serviceRoot);
}

View File

@ -20,13 +20,11 @@ package org.apache.olingo.client.api.communication.request.batch;
import java.io.IOException;
import java.io.PipedOutputStream;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
/**
* This class implements a batch request.
*/
public interface ODataBatchRequest extends ODataStreamedRequest<ODataBatchResponse, BatchStreamManager> {
public interface CommonODataBatchRequest {
/**
* Gets piped stream to be used to stream batch items.
@ -42,7 +40,7 @@ public interface ODataBatchRequest extends ODataStreamedRequest<ODataBatchRespon
* @return the current batch request.
* @throws IOException in case of write errors.
*/
ODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException;
CommonODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException;
/**
* Appends the given byte array to the payload.
@ -53,5 +51,5 @@ public interface ODataBatchRequest extends ODataStreamedRequest<ODataBatchRespon
* @return the current batch request.
* @throws IOException in case of write errors.
*/
ODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException;
CommonODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException;
}

View File

@ -21,4 +21,12 @@ package org.apache.olingo.client.api.communication.request.batch.v3;
import org.apache.olingo.client.api.communication.request.batch.CommonBatchRequestFactory;
public interface BatchRequestFactory extends CommonBatchRequestFactory {
/**
* Gets a batch request object instance.
*
* @param serviceRoot service root.
* @return new ODataBatchRequest instance.
*/
ODataBatchRequest getBatchRequest(String serviceRoot);
}

View File

@ -0,0 +1,26 @@
/*
* 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.request.batch.v3;
/**
* Batch request payload management.
*/
public interface BatchStreamManager
extends org.apache.olingo.client.api.communication.request.batch.BatchStreamManager {
}

View File

@ -0,0 +1,30 @@
/*
* 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.request.batch.v3;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
/**
* This class implements a batch request.
*/
public interface ODataBatchRequest
extends CommonODataBatchRequest, ODataStreamedRequest<ODataBatchResponse, BatchStreamManager> {
}

View File

@ -21,4 +21,12 @@ package org.apache.olingo.client.api.communication.request.batch.v4;
import org.apache.olingo.client.api.communication.request.batch.CommonBatchRequestFactory;
public interface BatchRequestFactory extends CommonBatchRequestFactory {
/**
* Gets a batch request object instance.
*
* @param serviceRoot service root.
* @return new ODataBatchRequest instance.
*/
ODataBatchRequest getBatchRequest(String serviceRoot);
}

View File

@ -0,0 +1,34 @@
/*
* 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.request.batch.v4;
/**
* Batch request payload management.
*/
public interface BatchStreamManager
extends org.apache.olingo.client.api.communication.request.batch.BatchStreamManager {
/**
* Gets an outside update batch item instance. An outside update item can be submitted embedded into a batch request
* only.
*
* @return ODataOutsideUpdate instance.
*/
ODataOutsideUpdate addOutsideUpdate();
}

View File

@ -0,0 +1,30 @@
/*
* 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.request.batch.v4;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
/**
* This class implements a batch request.
*/
public interface ODataBatchRequest
extends CommonODataBatchRequest, ODataStreamedRequest<ODataBatchResponse, BatchStreamManager> {
}

View File

@ -0,0 +1,38 @@
/*
* 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.request.batch.v4;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequestItem;
/**
* Retrieve request wrapper for the corresponding batch item.
*/
public interface ODataOutsideUpdate extends ODataBatchRequestItem {
/**
* Serialize and send the given request.
* <p>
* An IllegalArgumentException is thrown in case of no GET request.
*
* @param request request to be serialized.
* @return current item instance.
*/
ODataOutsideUpdate setRequest(final ODataBatchableRequest request);
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.client.api.communication.request.streamed;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.response.ODataMediaEntityCreateResponse;
import org.apache.olingo.commons.api.domain.CommonODataEntity;
@ -27,5 +28,6 @@ import org.apache.olingo.commons.api.domain.CommonODataEntity;
* @param <E> concrete ODataEntity implementation
*/
public interface ODataMediaEntityCreateRequest<E extends CommonODataEntity>
extends ODataStreamedEntityRequest<ODataMediaEntityCreateResponse<E>, MediaEntityCreateStreamManager<E>> {
extends ODataStreamedEntityRequest<ODataMediaEntityCreateResponse<E>, MediaEntityCreateStreamManager<E>>,
ODataBatchableRequest{
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.client.api.communication.request.streamed;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.response.ODataMediaEntityUpdateResponse;
import org.apache.olingo.commons.api.domain.CommonODataEntity;
@ -27,5 +28,6 @@ import org.apache.olingo.commons.api.domain.CommonODataEntity;
* @param <E> concrete ODataEntity implementation
*/
public interface ODataMediaEntityUpdateRequest<E extends CommonODataEntity>
extends ODataStreamedEntityRequest<ODataMediaEntityUpdateResponse<E>, MediaEntityUpdateStreamManager<E>> {
extends ODataStreamedEntityRequest<ODataMediaEntityUpdateResponse<E>, MediaEntityUpdateStreamManager<E>>,
ODataBatchableRequest {
}

View File

@ -29,7 +29,7 @@ import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataBasicRequest;
import org.apache.olingo.client.api.communication.request.ODataStreamer;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.commons.api.format.Format;
import org.apache.olingo.client.api.http.HttpMethod;
@ -94,7 +94,7 @@ public abstract class AbstractODataBasicRequest<V extends ODataResponse, T exten
*
* @param req destination batch request.
*/
public void batch(final ODataBatchRequest req) {
public void batch(final CommonODataBatchRequest req) {
batch(req, null);
}
@ -106,7 +106,7 @@ public abstract class AbstractODataBasicRequest<V extends ODataResponse, T exten
* @param req destination batch request.
* @param contentId contentId of the changeset item.
*/
public void batch(final ODataBatchRequest req, final String contentId) {
public void batch(final CommonODataBatchRequest req, final String contentId) {
try {
req.rawAppend(toByteArray());
if (StringUtils.isNotBlank(contentId)) {

View File

@ -14,7 +14,6 @@ package org.apache.olingo.client.core.communication.request.batch;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.batch.CommonBatchRequestFactory;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
/**
* OData batch request factory class.
@ -28,9 +27,4 @@ public abstract class AbstractBatchRequestFactory implements CommonBatchRequestF
protected AbstractBatchRequestFactory(final CommonODataClient client) {
this.client = client;
}
@Override
public ODataBatchRequest getBatchRequest(final String serviceRoot) {
return new ODataBatchRequestImpl(client, client.getURIBuilder(serviceRoot).appendBatchSegment().build());
}
}

View File

@ -0,0 +1,138 @@
/*
* 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.communication.request.batch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequestItem;
import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
import org.apache.olingo.client.api.communication.request.batch.ODataRetrieve;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.core.communication.request.AbstractODataStreamManager;
import org.apache.olingo.client.core.communication.request.Wrapper;
/**
* Batch request payload management.
*/
public abstract class AbstractBatchStreamManager extends AbstractODataStreamManager<ODataBatchResponse> {
/**
* Batch request current item.
*/
protected ODataBatchRequestItem currentItem = null;
/**
* batch request reference.
*/
protected final CommonODataBatchRequest req;
/**
* Private constructor.
*
* @param req batch request reference.
*/
protected AbstractBatchStreamManager(
final CommonODataBatchRequest req, final Wrapper<Future<HttpResponse>> futureWrap) {
super(futureWrap);
this.req = req;
}
/**
* Gets a changeset batch item instance. A changeset can be submitted embedded into a batch request only.
*
* @return ODataChangeset instance.
*/
public ODataChangeset addChangeset() {
closeCurrentItem();
// stream dash boundary
streamDashBoundary();
final ODataChangesetResponseItem expectedResItem = new ODataChangesetResponseItem();
((AbstractODataBatchRequest) req).expectedResItems.add(expectedResItem);
currentItem = new ODataChangesetImpl(req, expectedResItem);
return (ODataChangeset) currentItem;
}
/**
* Gets a retrieve batch item instance. A retrieve item can be submitted embedded into a batch request only.
*
* @return ODataRetrieve instance.
*/
public ODataRetrieve addRetrieve() {
closeCurrentItem();
// stream dash boundary
streamDashBoundary();
final ODataRetrieveResponseItem expectedResItem = new ODataRetrieveResponseItem();
currentItem = new ODataRetrieveImpl(req, expectedResItem);
((AbstractODataBatchRequest) req).expectedResItems.add(expectedResItem);
return (ODataRetrieve) currentItem;
}
/**
* Close the current streamed item.
*/
protected void closeCurrentItem() {
if (currentItem != null) {
currentItem.close();
}
}
/**
* {@inheritDoc }
*/
@Override
protected ODataBatchResponse getResponse(final long timeout, final TimeUnit unit) {
closeCurrentItem();
streamCloseDelimiter();
finalizeBody();
return getResponseInstance(timeout, unit);
}
protected abstract ODataBatchResponse getResponseInstance(final long timeout, final TimeUnit unit);
/**
* Streams dash boundary.
*/
protected void streamDashBoundary() {
// preamble
newLine();
// stream batch-boundary
stream(("--" + ((AbstractODataBatchRequest) req).boundary).getBytes());
newLine();
}
/**
* Streams close delimiter.
*/
protected void streamCloseDelimiter() {
// stream close-delimiter
newLine();
stream(("--" + ((AbstractODataBatchRequest) req).boundary + "--").getBytes());
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.communication.request.batch;
import java.io.PipedOutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataStreamManager;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.core.communication.request.streamed.AbstractODataStreamedRequest;
import org.apache.olingo.commons.api.format.ContentType;
/**
* This class implements a batch request.
*/
public abstract class AbstractODataBatchRequest<V extends ODataResponse, T extends ODataStreamManager<V>>
extends AbstractODataStreamedRequest<V, T> {
/**
* Batch request boundary.
*/
protected final String boundary;
/**
* Expected batch response items.
*/
protected final List<ODataBatchResponseItem> expectedResItems = new ArrayList<ODataBatchResponseItem>();
/**
* Constructor.
*
* @param odataClient client instance getting this request
* @param uri batch request URI (http://serviceRoot/$batch)
*/
protected AbstractODataBatchRequest(final CommonODataClient odataClient, final URI uri) {
super(odataClient, HttpMethod.POST, uri);
// create a random UUID value for boundary
boundary = "batch_" + UUID.randomUUID().toString();
// specify the contentType header
setContentType(ContentType.MULTIPART_MIXED + ";" + ODataBatchConstants.BOUNDARY + "=" + boundary);
}
/**
* {@inheritDoc }
*/
public PipedOutputStream getOutputStream() {
return getStreamManager().getBodyStreamWriter();
}
/**
* {@inheritDoc}
* <p>
* This operation is unsupported by a batch request.
*/
@Override
public void batch(CommonODataBatchRequest req) {
throw new UnsupportedOperationException("A batch request is not batchable");
}
}

View File

@ -20,7 +20,7 @@ package org.apache.olingo.client.core.communication.request.batch;
import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequestItem;
import org.apache.olingo.client.core.communication.request.AbstractODataStreamer;
@ -43,14 +43,14 @@ public abstract class AbstractODataBatchRequestItem extends AbstractODataStreame
/**
* OData batch request.
*/
protected ODataBatchRequest req;
protected CommonODataBatchRequest req;
/**
* Constructor.
*
* @param req OData batch request.
*/
public AbstractODataBatchRequestItem(final ODataBatchRequest req) {
public AbstractODataBatchRequestItem(final CommonODataBatchRequest req) {
super(req.getOutputStream());
this.open = true;
this.req = req;
@ -81,7 +81,7 @@ public abstract class AbstractODataBatchRequestItem extends AbstractODataStreame
* @param request request to be batched.
* @param contentId changeset item id.
*/
protected void streamRequestHeader(final ODataBatchableRequest request, final int contentId) {
protected void streamRequestHeader(final ODataBatchableRequest request, final String contentId) {
//stream batch content type
stream(ODataBatchConstants.ITEM_CONTENT_TYPE_LINE.getBytes());
newLine();

View File

@ -1,258 +0,0 @@
/*
* 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.communication.request.batch;
import java.io.IOException;
import java.io.PipedOutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.batch.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequestItem;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
import org.apache.olingo.client.api.communication.request.batch.ODataRetrieve;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.core.communication.request.AbstractODataStreamManager;
import org.apache.olingo.client.core.communication.request.streamed.AbstractODataStreamedRequest;
import org.apache.olingo.client.core.communication.response.AbstractODataResponse;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchResponseManager;
/**
* This class implements a batch request.
*/
public class ODataBatchRequestImpl extends AbstractODataStreamedRequest<ODataBatchResponse, BatchStreamManager>
implements ODataBatchRequest {
/**
* Batch request boundary.
*/
private final String boundary;
/**
* Expected batch response items.
*/
private final List<ODataBatchResponseItem> expectedResItems = new ArrayList<ODataBatchResponseItem>();
/**
* Constructor.
*
* @param odataClient client instance getting this request
* @param uri batch request URI (http://serviceRoot/$batch)
*/
ODataBatchRequestImpl(final CommonODataClient odataClient, final URI uri) {
super(odataClient, HttpMethod.POST, uri);
// create a random UUID value for boundary
boundary = "batch_" + UUID.randomUUID().toString();
// specify the contentType header
setContentType(ODataBatchConstants.MULTIPART_CONTENT_TYPE + ";" + ODataBatchConstants.BOUNDARY + "=" + boundary);
}
/**
* {@inheritDoc }
*/
@Override
protected BatchStreamManager getStreamManager() {
if (streamManager == null) {
streamManager = new BatchStreamManagerImpl(this);
}
return (BatchStreamManager) streamManager;
}
/**
* {@inheritDoc }
*/
@Override
public PipedOutputStream getOutputStream() {
return getStreamManager().getBodyStreamWriter();
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequestImpl rawAppend(final byte[] toBeStreamed) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed);
return this;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequestImpl rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed, off, len);
return this;
}
/**
* {@inheritDoc}
* <p>
* This operation is unsupported by a batch request.
*/
@Override
public void batch(ODataBatchRequest req) {
throw new UnsupportedOperationException("A batch request is not batchable");
}
/**
* This class implements a response to a batch request.
*
* @see org.apache.olingo.client.core.communication.request.ODataBatchRequest
*/
private class ODataBatchResponseImpl extends AbstractODataResponse implements ODataBatchResponse {
/**
* Constructor.
*
* @param client HTTP client.
* @param res HTTP response.
*/
private ODataBatchResponseImpl(final HttpClient client, final HttpResponse res) {
super(client, res);
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<ODataBatchResponseItem> getBody() {
return new ODataBatchResponseManager(this, expectedResItems);
}
}
/**
* Batch request payload management.
*/
public class BatchStreamManagerImpl extends AbstractODataStreamManager<ODataBatchResponse>
implements BatchStreamManager {
/**
* Batch request current item.
*/
private ODataBatchRequestItem currentItem = null;
/**
* batch request reference.
*/
private final ODataBatchRequest req;
/**
* Private constructor.
*
* @param req batch request reference.
*/
private BatchStreamManagerImpl(final ODataBatchRequest req) {
super(ODataBatchRequestImpl.this.futureWrapper);
this.req = req;
}
/**
* Gets a changeset batch item instance. A changeset can be submitted embedded into a batch request only.
*
* @return ODataChangeset instance.
*/
@Override
public ODataChangeset addChangeset() {
closeCurrentItem();
// stream dash boundary
streamDashBoundary();
final ODataChangesetResponseItem expectedResItem = new ODataChangesetResponseItem();
expectedResItems.add(expectedResItem);
currentItem = new ODataChangesetImpl(req, expectedResItem);
return (ODataChangeset) currentItem;
}
/**
* Gets a retrieve batch item instance. A retrieve item can be submitted embedded into a batch request only.
*
* @return ODataRetrieve instance.
*/
@Override
public ODataRetrieve addRetrieve() {
closeCurrentItem();
// stream dash boundary
streamDashBoundary();
final ODataRetrieveResponseItem expectedResItem = new ODataRetrieveResponseItem();
currentItem = new ODataRetrieveImpl(req, expectedResItem);
expectedResItems.add(expectedResItem);
return (ODataRetrieve) currentItem;
}
/**
* Close the current streamed item.
*/
private void closeCurrentItem() {
if (currentItem != null) {
currentItem.close();
}
}
/**
* {@inheritDoc }
*/
@Override
protected ODataBatchResponse getResponse(final long timeout, final TimeUnit unit) {
closeCurrentItem();
streamCloseDelimiter();
finalizeBody();
return new ODataBatchResponseImpl(httpClient, getHttpResponse(timeout, unit));
}
/**
* Streams dash boundary.
*/
private void streamDashBoundary() {
// preamble
newLine();
// stream batch-boundary
stream(("--" + boundary).getBytes());
newLine();
}
/**
* Streams close delimiter.
*/
private void streamCloseDelimiter() {
// stream close-delimiter
newLine();
stream(("--" + boundary + "--").getBytes());
}
}
}

View File

@ -37,6 +37,7 @@ import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.request.ODataStreamer;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchLineIterator;
import org.apache.olingo.commons.api.format.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -301,7 +302,7 @@ public class ODataBatchUtilities {
final String contentType = headers.containsKey(HeaderName.contentType.toString())
? headers.get(HeaderName.contentType.toString()).toString() : StringUtils.EMPTY;
if (contentType.contains(ODataBatchConstants.MULTIPART_CONTENT_TYPE)) {
if (contentType.contains(ContentType.MULTIPART_MIXED)) {
nextItemType = BatchItemType.CHANGESET;
} else if (contentType.contains(ODataBatchConstants.ITEM_CONTENT_TYPE)) {
nextItemType = BatchItemType.RETRIEVE;

View File

@ -19,13 +19,13 @@
package org.apache.olingo.client.core.communication.request.batch;
import java.util.UUID;
import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.core.communication.request.ODataRequestImpl;
import org.apache.olingo.commons.api.format.ContentType;
/**
* Changeset wrapper for the corresponding batch item.
@ -54,7 +54,7 @@ public class ODataChangesetImpl extends AbstractODataBatchRequestItem
* @param req batch request.
* @param expectedResItem expected OData response items.
*/
ODataChangesetImpl(final ODataBatchRequest req, final ODataChangesetResponseItem expectedResItem) {
ODataChangesetImpl(final CommonODataBatchRequest req, final ODataChangesetResponseItem expectedResItem) {
super(req);
this.expectedResItem = expectedResItem;
@ -99,7 +99,7 @@ public class ODataChangesetImpl extends AbstractODataBatchRequestItem
if (!hasStreamedSomething) {
stream((HeaderName.contentType.toString() + ": "
+ ODataBatchConstants.MULTIPART_CONTENT_TYPE + ";boundary=" + boundary).getBytes());
+ ContentType.MULTIPART_MIXED + ";boundary=" + boundary).getBytes());
newLine();
newLine();
@ -117,7 +117,7 @@ public class ODataChangesetImpl extends AbstractODataBatchRequestItem
newLine();
// stream the request
streamRequestHeader(request, contentId);
streamRequestHeader(request, String.valueOf(contentId));
request.batch(req, String.valueOf(contentId));

View File

@ -19,7 +19,7 @@
package org.apache.olingo.client.core.communication.request.batch;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataRetrieve;
import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.core.communication.request.ODataRequestImpl;
@ -38,7 +38,7 @@ public class ODataRetrieveImpl extends AbstractODataBatchRequestItem
* @param req batch request.
* @param expectedResItem expected batch response item.
*/
ODataRetrieveImpl(final ODataBatchRequest req, final ODataRetrieveResponseItem expectedResItem) {
ODataRetrieveImpl(final CommonODataBatchRequest req, final ODataRetrieveResponseItem expectedResItem) {
super(req);
this.expectedResItem = expectedResItem;
}

View File

@ -20,6 +20,7 @@ package org.apache.olingo.client.core.communication.request.batch.v3;
import org.apache.olingo.client.api.v3.ODataClient;
import org.apache.olingo.client.api.communication.request.batch.v3.BatchRequestFactory;
import org.apache.olingo.client.api.communication.request.batch.v3.ODataBatchRequest;
import org.apache.olingo.client.core.communication.request.batch.AbstractBatchRequestFactory;
public class BatchRequestFactoryImpl extends AbstractBatchRequestFactory
@ -30,4 +31,9 @@ public class BatchRequestFactoryImpl extends AbstractBatchRequestFactory
public BatchRequestFactoryImpl(final ODataClient client) {
super(client);
}
@Override
public ODataBatchRequest getBatchRequest(final String serviceRoot) {
return new ODataBatchRequestImpl(client, client.getURIBuilder(serviceRoot).appendBatchSegment().build());
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.communication.request.batch.v3;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.batch.v3.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.v3.ODataBatchRequest;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.core.communication.request.batch.AbstractBatchStreamManager;
import org.apache.olingo.client.core.communication.request.batch.AbstractODataBatchRequest;
import org.apache.olingo.client.core.communication.request.batch.v3.ODataBatchRequestImpl.BatchStreamManagerImpl;
import org.apache.olingo.client.core.communication.request.batch.v3.ODataBatchRequestImpl.ODataBatchResponseImpl;
import org.apache.olingo.client.core.communication.response.AbstractODataResponse;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchResponseManager;
/**
* This class implements a batch request.
*/
public class ODataBatchRequestImpl
extends AbstractODataBatchRequest<ODataBatchResponse, BatchStreamManager>
implements ODataBatchRequest, ODataStreamedRequest<ODataBatchResponse, BatchStreamManager> {
public ODataBatchRequestImpl(final CommonODataClient odataClient, final URI uri) {
super(odataClient, uri);
}
@Override
protected BatchStreamManager getStreamManager() {
if (streamManager == null) {
streamManager = new BatchStreamManagerImpl(this);
}
return (BatchStreamManager) streamManager;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed);
return this;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed, off, len);
return this;
}
/**
* Batch request payload management.
*/
public class BatchStreamManagerImpl extends AbstractBatchStreamManager implements BatchStreamManager {
public BatchStreamManagerImpl(final ODataBatchRequest req) {
super(req, ODataBatchRequestImpl.this.futureWrapper);
}
@Override
protected ODataBatchResponse getResponseInstance(final long timeout, final TimeUnit unit) {
return new ODataBatchResponseImpl(httpClient, getHttpResponse(timeout, unit));
}
}
/**
* This class implements a response to a batch request.
*
* @see org.apache.olingo.client.core.communication.request.ODataBatchRequest
*/
protected class ODataBatchResponseImpl extends AbstractODataResponse implements ODataBatchResponse {
/**
* Constructor.
*
* @param client HTTP client.
* @param res HTTP response.
*/
protected ODataBatchResponseImpl(final HttpClient client, final HttpResponse res) {
super(client, res);
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<ODataBatchResponseItem> getBody() {
return new ODataBatchResponseManager(this, expectedResItems);
}
}
}

View File

@ -20,6 +20,7 @@ package org.apache.olingo.client.core.communication.request.batch.v4;
import org.apache.olingo.client.api.v4.ODataClient;
import org.apache.olingo.client.api.communication.request.batch.v4.BatchRequestFactory;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataBatchRequest;
import org.apache.olingo.client.core.communication.request.batch.AbstractBatchRequestFactory;
public class BatchRequestFactoryImpl extends AbstractBatchRequestFactory
@ -30,4 +31,9 @@ public class BatchRequestFactoryImpl extends AbstractBatchRequestFactory
public BatchRequestFactoryImpl(final ODataClient client) {
super(client);
}
@Override
public ODataBatchRequest getBatchRequest(final String serviceRoot) {
return new ODataBatchRequestImpl(client, client.getURIBuilder(serviceRoot).appendBatchSegment().build());
}
}

View File

@ -0,0 +1,132 @@
/*
* 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.communication.request.batch.v4;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.batch.v4.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataOutsideUpdate;
import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.core.communication.request.batch.AbstractBatchStreamManager;
import org.apache.olingo.client.core.communication.request.batch.AbstractODataBatchRequest;
import org.apache.olingo.client.core.communication.response.AbstractODataResponse;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchResponseManager;
import org.apache.olingo.commons.api.format.ContentType;
/**
* This class implements a batch request.
*/
public class ODataBatchRequestImpl
extends AbstractODataBatchRequest<ODataBatchResponse, BatchStreamManager>
implements ODataBatchRequest {
public ODataBatchRequestImpl(final CommonODataClient odataClient, final URI uri) {
super(odataClient, uri);
setAccept(ContentType.MULTIPART_MIXED);
}
@Override
protected BatchStreamManager getStreamManager() {
if (streamManager == null) {
streamManager = new BatchStreamManagerImpl(this);
}
return (BatchStreamManager) streamManager;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed);
return this;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException {
getStreamManager().getBodyStreamWriter().write(toBeStreamed, off, len);
return this;
}
/**
* Batch request payload management.
*/
public class BatchStreamManagerImpl extends AbstractBatchStreamManager implements BatchStreamManager {
public BatchStreamManagerImpl(final ODataBatchRequest req) {
super(req, ODataBatchRequestImpl.this.futureWrapper);
}
@Override
protected ODataBatchResponse getResponseInstance(final long timeout, final TimeUnit unit) {
return new ODataBatchResponseImpl(httpClient, getHttpResponse(timeout, unit));
}
@Override
public ODataOutsideUpdate addOutsideUpdate() {
closeCurrentItem();
// stream dash boundary
streamDashBoundary();
final ODataOutsideUpdateResponseItem expectedResItem = new ODataOutsideUpdateResponseItem();
currentItem = new ODataOutsideUpdateImpl(req, expectedResItem);
((ODataBatchRequestImpl) req).expectedResItems.add(expectedResItem);
return (ODataOutsideUpdate) currentItem;
}
}
/**
* This class implements a response to a batch request.
*
* @see org.apache.olingo.client.core.communication.request.ODataBatchRequest
*/
protected class ODataBatchResponseImpl extends AbstractODataResponse implements ODataBatchResponse {
/**
* Constructor.
*
* @param client HTTP client.
* @param res HTTP response.
*/
protected ODataBatchResponseImpl(final HttpClient client, final HttpResponse res) {
super(client, res);
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<ODataBatchResponseItem> getBody() {
return new ODataBatchResponseManager(this, expectedResItems);
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.communication.request.batch.v4;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataOutsideUpdate;
import org.apache.olingo.client.api.http.HttpMethod;
import org.apache.olingo.client.core.communication.request.ODataRequestImpl;
import org.apache.olingo.client.core.communication.request.batch.AbstractODataBatchRequestItem;
/**
* Retrieve request wrapper for the corresponding batch item.
*/
public class ODataOutsideUpdateImpl extends AbstractODataBatchRequestItem
implements ODataOutsideUpdate {
private final ODataOutsideUpdateResponseItem expectedResItem;
/**
* Constructor.
*
* @param req batch request.
* @param expectedResItem expected batch response item.
*/
ODataOutsideUpdateImpl(final CommonODataBatchRequest req, final ODataOutsideUpdateResponseItem expectedResItem) {
super(req);
this.expectedResItem = expectedResItem;
}
/**
* Close item.
*/
@Override
protected void closeItem() {
// nop
}
/**
* {@inheritDoc }
*/
@Override
public ODataOutsideUpdate setRequest(final ODataBatchableRequest request) {
if (!isOpen()) {
throw new IllegalStateException("Current batch item is closed");
}
if (((ODataRequestImpl) request).getMethod() == HttpMethod.GET) {
throw new IllegalArgumentException("Invalid request. Use ODataRetrieve for GET method");
}
hasStreamedSomething = true;
// stream the request
streamRequestHeader(request, ODataOutsideUpdateResponseItem.OUTSIDE_CONTENT_ID);
request.batch(req, ODataOutsideUpdateResponseItem.OUTSIDE_CONTENT_ID);
// close before in order to avoid any further setRequest calls.
close();
// add request to the list
expectedResItem.addResponse(
ODataOutsideUpdateResponseItem.OUTSIDE_CONTENT_ID, ((ODataRequestImpl) request).getResponseTemplate());
return this;
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.communication.request.batch.v4;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.core.communication.request.batch.AbstractODataBatchResponseItem;
import org.apache.olingo.client.core.communication.request.batch.ODataBatchUtilities;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchErrorResponse;
/**
* Retrieve response wrapper for the corresponding batch item.
*/
public class ODataOutsideUpdateResponseItem extends AbstractODataBatchResponseItem {
public static final String OUTSIDE_CONTENT_ID = "__OUTSIDEUPDATE__";
/**
* Constructor.
*/
public ODataOutsideUpdateResponseItem() {
super(false);
}
/**
* {@inheritDoc }
*/
@Override
public ODataResponse next() {
if (closed) {
throw new IllegalStateException("Invalid request - the item has been closed");
}
final Map.Entry<Integer, String> responseLine = ODataBatchUtilities.readResponseLine(batchLineIterator);
LOG.debug("Retrieved item response {}", responseLine);
final Map<String, Collection<String>> headers = ODataBatchUtilities.readHeaders(batchLineIterator);
LOG.debug("Retrieved item headers {}", headers);
final ODataResponse res;
if (responseLine.getKey() >= 400) {
// generate error response
res = new ODataBatchErrorResponse(responseLine, headers, batchLineIterator, boundary);
} else {
if (!hasNext()) {
throw new NoSuchElementException("No item found");
}
res = expectedItemsIterator.next().initFromBatch(responseLine, headers, batchLineIterator, boundary);
}
return res;
}
/**
* Unsupported operation.
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Operation not supported.");
}
}

View File

@ -32,7 +32,7 @@ import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataStreamManager;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
import org.apache.olingo.client.api.communication.request.ODataStreamer;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.CommonODataBatchRequest;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.commons.api.format.ODataMediaFormat;
import org.apache.olingo.client.api.http.HttpMethod;
@ -112,7 +112,7 @@ public abstract class AbstractODataStreamedRequest<V extends ODataResponse, T ex
*
* @param req destination batch request.
*/
public void batch(final ODataBatchRequest req) {
public void batch(final CommonODataBatchRequest req) {
batch(req, null);
}
@ -124,7 +124,7 @@ public abstract class AbstractODataStreamedRequest<V extends ODataResponse, T ex
* @param req destination batch request.
* @param contentId ContentId header value to be added to the serialization. Use this in case of changeset items.
*/
public void batch(final ODataBatchRequest req, final String contentId) {
public void batch(final CommonODataBatchRequest req, final String contentId) {
final InputStream input = getStreamManager().getBody();
try {

View File

@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.streamed.MediaEntityCreateStreamManager;
import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityCreateRequest;
import org.apache.olingo.client.api.communication.response.ODataMediaEntityCreateResponse;
@ -42,7 +41,7 @@ import org.apache.olingo.commons.api.data.Entry;
*/
public class ODataMediaEntityCreateRequestImpl<E extends CommonODataEntity>
extends AbstractODataStreamedEntityRequest<ODataMediaEntityCreateResponse<E>, MediaEntityCreateStreamManager<E>>
implements ODataMediaEntityCreateRequest<E>, ODataBatchableRequest {
implements ODataMediaEntityCreateRequest<E> {
private final InputStream media;

View File

@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.streamed.MediaEntityUpdateStreamManager;
import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityUpdateRequest;
import org.apache.olingo.client.api.communication.response.ODataMediaEntityUpdateResponse;
@ -42,7 +41,7 @@ import org.apache.olingo.commons.api.data.Entry;
*/
public class ODataMediaEntityUpdateRequestImpl<E extends CommonODataEntity>
extends AbstractODataStreamedEntityRequest<ODataMediaEntityUpdateResponse<E>, MediaEntityUpdateStreamManager<E>>
implements ODataMediaEntityUpdateRequest<E>, ODataBatchableRequest {
implements ODataMediaEntityUpdateRequest<E> {
private final InputStream media;

View File

@ -32,10 +32,10 @@ import org.apache.http.HttpResponse;
import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.request.ODataStreamManager;
import org.apache.olingo.client.api.communication.request.batch.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
import org.apache.olingo.client.api.communication.request.batch.ODataRetrieve;
import org.apache.olingo.client.api.communication.request.batch.v3.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.cud.v3.UpdateType;

View File

@ -18,8 +18,6 @@
*/
package org.apache.olingo.client.core.it.v4;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
@ -35,11 +33,12 @@ import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.header.HeaderName;
import org.apache.olingo.client.api.communication.header.ODataPreferences;
import org.apache.olingo.client.api.communication.request.ODataStreamManager;
import org.apache.olingo.client.api.communication.request.batch.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
import org.apache.olingo.client.api.communication.request.batch.ODataRetrieve;
import org.apache.olingo.client.api.communication.request.batch.v4.BatchStreamManager;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataBatchRequest;
import org.apache.olingo.client.api.communication.request.batch.v4.ODataOutsideUpdate;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.cud.v4.UpdateType;
@ -54,15 +53,20 @@ import org.apache.olingo.client.core.communication.request.AbstractODataStreamMa
import org.apache.olingo.client.core.communication.request.Wrapper;
import org.apache.olingo.client.core.communication.request.batch.ODataChangesetResponseItem;
import org.apache.olingo.client.core.communication.request.batch.ODataRetrieveResponseItem;
import org.apache.olingo.client.core.communication.request.batch.v4.ODataOutsideUpdateResponseItem;
import org.apache.olingo.client.core.communication.request.retrieve.ODataEntityRequestImpl;
import org.apache.olingo.client.core.communication.request.retrieve.ODataEntityRequestImpl.ODataEntityResponseImpl;
import static org.apache.olingo.client.core.it.v4.AbstractTestITCase.client;
import org.apache.olingo.client.core.uri.URIUtils;
import org.apache.olingo.commons.api.domain.v4.ODataEntity;
import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.format.ODataPubFormat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class BatchTestITCase extends AbstractTestITCase {
@ -73,6 +77,14 @@ public class BatchTestITCase extends AbstractTestITCase {
private static final int MAX = 10000;
// ------------------------
// Uncomment to performe check externally ...
// ------------------------
// private final static String testStaticServiceRootURL= "http://odatae2etest.azurewebsites.net/javatest/DefaultService/";
// private final static String ACCEPT = ContentType.MULTIPART_MIXED;
// ------------------------
private final static String ACCEPT = ContentType.APPLICATION_OCTET_STREAM;
@Test
public void stringStreaming() {
final TestStreamManager streaming = new TestStreamManager();
@ -93,6 +105,7 @@ public class BatchTestITCase extends AbstractTestITCase {
public void emptyBatchRequest() {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
final BatchStreamManager payload = request.execute();
final ODataBatchResponse response = payload.getResponse();
@ -108,6 +121,7 @@ public class BatchTestITCase extends AbstractTestITCase {
public void changesetWithError() {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
final BatchStreamManager payload = request.execute();
final ODataChangeset changeset = payload.addChangeset();
@ -164,6 +178,7 @@ public class BatchTestITCase extends AbstractTestITCase {
private void continueOnError(final boolean continueOnError) {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
if (continueOnError) {
request.addCustomHeader(HeaderName.prefer, new ODataPreferences(client.getServiceVersion()).continueOnError());
@ -232,6 +247,7 @@ public class BatchTestITCase extends AbstractTestITCase {
public void changesetWithReference() throws EdmPrimitiveTypeException {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
final BatchStreamManager streamManager = request.execute();
final ODataChangeset changeset = streamManager.addChangeset();
@ -310,11 +326,83 @@ public class BatchTestITCase extends AbstractTestITCase {
}
}
@Test
@SuppressWarnings("unchecked")
public void batchRequestWithOutsideUpdates() throws EdmPrimitiveTypeException {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
final BatchStreamManager streamManager = request.execute();
// -------------------------------------------
// Add retrieve item
// -------------------------------------------
ODataRetrieve retrieve = streamManager.addRetrieve();
// prepare URI
URIBuilder targetURI = client.getURIBuilder(testStaticServiceRootURL);
targetURI.appendEntitySetSegment("Customers").appendKeySegment(1).
expand("Orders").select("PersonID,Orders/OrderID");
// create new request
ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build());
queryReq.setFormat(ODataPubFormat.ATOM);
retrieve.setRequest(queryReq);
// -------------------------------------------
// -------------------------------------------
// Add new order with outside item
// -------------------------------------------
final ODataOutsideUpdate outside = streamManager.addOutsideUpdate();
// prepare URI
targetURI = client.getURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("Orders");
final ODataEntity original = newOrder(2000);
final ODataEntityCreateRequest<ODataEntity> createReq =
client.getCUDRequestFactory().getEntityCreateRequest(targetURI.build(), original);
createReq.setFormat(ODataPubFormat.ATOM);
outside.setRequest(createReq);
// -------------------------------------------
final ODataBatchResponse response = streamManager.getResponse();
assertEquals(200, response.getStatusCode());
assertEquals("OK", response.getStatusMessage());
final Iterator<ODataBatchResponseItem> iter = response.getBody();
// retrieve the first item (ODataRetrieve)
ODataBatchResponseItem item = iter.next();
assertTrue(item instanceof ODataRetrieveResponseItem);
ODataRetrieveResponseItem retitem = (ODataRetrieveResponseItem) item;
ODataResponse res = retitem.next();
assertTrue(res instanceof ODataEntityResponseImpl);
assertEquals(200, res.getStatusCode());
assertEquals("OK", res.getStatusMessage());
// retrieve the second item (ODataChangeset)
item = iter.next();
assertTrue(item instanceof ODataOutsideUpdateResponseItem);
final ODataOutsideUpdateResponseItem outitem = (ODataOutsideUpdateResponseItem) item;
res = outitem.next();
assertTrue(res instanceof ODataEntityCreateResponse);
assertEquals(201, res.getStatusCode());
assertEquals("Created", res.getStatusMessage());
final ODataEntityCreateResponse<ODataEntity> entres = (ODataEntityCreateResponse<ODataEntity>) res;
final ODataEntity entity = entres.getBody();
assertEquals(2000, entity.getProperty("OrderID").getPrimitiveValue().toCastValue(Integer.class).intValue());
assertFalse(iter.hasNext());
}
@Test
@SuppressWarnings("unchecked")
public void batchRequest() throws EdmPrimitiveTypeException {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
final BatchStreamManager streamManager = request.execute();

View File

@ -33,6 +33,8 @@ public abstract class ContentType {
public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
public static final String MULTIPART_MIXED = "multipart/mixed";
public static final String APPLICATION_SVG_XML = "application/svg+xml";
public static final String APPLICATION_XHTML_XML = "application/xhtml+xml";