[OLINGO-369] continue-on-error behavior implemented for both transactional and non-transactional persistence

This commit is contained in:
Francesco Chicchiriccò 2014-07-17 14:18:21 +02:00
parent 31e4913950
commit 23789e100b
29 changed files with 455 additions and 251 deletions

View File

@ -19,6 +19,8 @@
package org.apache.olingo.ext.proxy.api;
import java.io.Serializable;
import java.util.List;
import org.apache.olingo.commons.api.ODataRuntimeException;
/**
* Interface for container operations.
@ -27,6 +29,9 @@ public interface PersistenceManager extends Serializable {
/**
* Flushes all pending changes to the OData service.
*
* @return a list where n-th item is either null (if corresponding request went out successfully) or the exception
* bearing the error returned from the service.
*/
void flush();
List<ODataRuntimeException> flush();
}

View File

@ -25,6 +25,7 @@ import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateR
import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.streamed.ODataStreamUpdateRequest;
import org.apache.olingo.client.core.uri.URIUtils;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.domain.CommonODataEntity;
import org.apache.olingo.commons.api.domain.ODataLink;
import org.apache.olingo.commons.api.domain.ODataLinkType;
@ -67,10 +68,10 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
this.factory = factory;
}
protected abstract void doFlush(final PersistenceChanges changes, final TransactionItems items);
protected abstract List<ODataRuntimeException> doFlush(PersistenceChanges changes, TransactionItems items);
@Override
public void flush() {
public List<ODataRuntimeException> flush() {
final PersistenceChanges changes = new PersistenceChanges();
final TransactionItems items = new TransactionItems();
@ -89,9 +90,11 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
processDelayedUpdates(delayedUpdates, pos, items, changes);
doFlush(changes, items);
final List<ODataRuntimeException> result = doFlush(changes, items);
factory.getContext().detachAll();
return result;
}
private ODataLink buildNavigationLink(final String name, final URI uri, final ODataLinkType type) {

View File

@ -23,8 +23,6 @@ import org.apache.olingo.ext.proxy.Service;
import org.apache.olingo.ext.proxy.api.annotations.EntityContainer;
import org.apache.olingo.ext.proxy.api.annotations.EntitySet;
import org.apache.olingo.ext.proxy.api.annotations.Singleton;
import org.apache.olingo.ext.proxy.utils.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@ -82,8 +80,7 @@ public final class EntityContainerInvocationHandler extends AbstractInvocationHa
if (isSelfMethod(method, args)) {
return invokeSelfMethod(method, args);
} else if ("flush".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
factory.getPersistenceManager().flush();
return ClassUtils.returnVoid();
return factory.getPersistenceManager().flush();
} else if ("operations".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
final Class<?> returnType = method.getReturnType();

View File

@ -18,19 +18,21 @@
*/
package org.apache.olingo.ext.proxy.commons;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.olingo.client.api.communication.request.ODataBasicRequest;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.ext.proxy.Service;
import java.util.Map;
/**
* {@link org.apache.olingo.ext.proxy.api.PersistenceManager} implementation not using OData batch requests: any
* read-write operation will be sent separately to the OData service when calling <tt>flush()</tt>; any intermediate
* error will be logged and ignored.
* read-write operation will be sent separately to the OData service when calling <tt>flush()</tt>.
*/
public class NonTransactionalPersistenceManagerImpl extends AbstractPersistenceManager {
@ -41,8 +43,13 @@ public class NonTransactionalPersistenceManagerImpl extends AbstractPersistenceM
}
@Override
protected void doFlush(final PersistenceChanges changes, final TransactionItems items) {
for (Map.Entry<ODataBatchableRequest, EntityInvocationHandler> entry : changes.getChanges().entrySet()) {
protected List<ODataRuntimeException> doFlush(final PersistenceChanges changes, final TransactionItems items) {
final List<ODataRuntimeException> result = new ArrayList<ODataRuntimeException>();
for (final Iterator<Map.Entry<ODataBatchableRequest, EntityInvocationHandler>> itor =
changes.getChanges().entrySet().iterator(); itor.hasNext();) {
final Map.Entry<ODataBatchableRequest, EntityInvocationHandler> entry = itor.next();
try {
final ODataResponse response = ((ODataBasicRequest<?>) entry.getKey()).execute();
@ -53,9 +60,19 @@ public class NonTransactionalPersistenceManagerImpl extends AbstractPersistenceM
entry.getValue().setEntity(((ODataEntityUpdateResponse<?>) response).getBody());
LOG.debug("Upgrade updated object '{}'", entry.getValue());
}
} catch (Exception e) {
result.add(null);
} catch (ODataRuntimeException e) {
LOG.error("While performing {}", entry.getKey().getURI(), e);
if (factory.getClient().getConfiguration().isContinueOnError()) {
result.add(e);
} else {
throw e;
}
}
}
return result;
}
}

View File

@ -18,6 +18,12 @@
*/
package org.apache.olingo.ext.proxy.commons;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
import org.apache.olingo.client.api.communication.request.ODataRequest;
import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
@ -29,12 +35,11 @@ import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.core.communication.header.ODataErrorResponseChecker;
import org.apache.olingo.client.core.communication.request.batch.ODataChangesetResponseItem;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.ext.proxy.Service;
import java.util.Iterator;
import java.util.Map;
/**
* {@link org.apache.olingo.ext.proxy.api.PersistenceManager} implementation using OData batch requests to implement
* high-level user transactions: all read-write operations will be packed in a batch request to the OData service when
@ -52,20 +57,20 @@ public class TransactionalPersistenceManagerImpl extends AbstractPersistenceMana
* Transactional changes commit.
*/
@Override
protected void doFlush(final PersistenceChanges changes, final TransactionItems items) {
protected List<ODataRuntimeException> doFlush(final PersistenceChanges changes, final TransactionItems items) {
final CommonODataBatchRequest request =
factory.getClient().getBatchRequestFactory().getBatchRequest(factory.getClient().getServiceRoot());
((ODataRequest) request).setAccept(
factory.getClient().getConfiguration().getDefaultBatchAcceptFormat().toContentTypeString());
final BatchManager streamManager = (BatchManager) ((ODataStreamedRequest) request).payloadManager();
final BatchManager batchManager = (BatchManager) ((ODataStreamedRequest) request).payloadManager();
final ODataChangeset changeset = streamManager.addChangeset();
final ODataChangeset changeset = batchManager.addChangeset();
for (Map.Entry<ODataBatchableRequest, EntityInvocationHandler> entry : changes.getChanges().entrySet()) {
changeset.addRequest(entry.getKey());
}
final ODataBatchResponse response = streamManager.getResponse();
final ODataBatchResponse response = batchManager.getResponse();
// This should be 202 for service version <= 3.0 and 200 for service version >= 4.0 but it seems that
// many service implementations are not fully compliant in this respect.
@ -73,24 +78,54 @@ public class TransactionalPersistenceManagerImpl extends AbstractPersistenceMana
throw new IllegalStateException("Operation failed");
}
final List<ODataRuntimeException> result = new ArrayList<ODataRuntimeException>();
if (!items.isEmpty()) {
final Iterator<ODataBatchResponseItem> iter = response.getBody();
if (!iter.hasNext()) {
final Iterator<ODataBatchResponseItem> batchResItor = response.getBody();
if (!batchResItor.hasNext()) {
throw new IllegalStateException("Unexpected operation result");
}
final ODataBatchResponseItem item = iter.next();
final ODataBatchResponseItem item = batchResItor.next();
if (!(item instanceof ODataChangesetResponseItem)) {
throw new IllegalStateException("Unexpected batch response item " + item.getClass().getSimpleName());
}
final ODataChangesetResponseItem chgres = (ODataChangesetResponseItem) item;
for (Integer changesetItemId : items.sortedValues()) {
for (final Iterator<Integer> itor = items.sortedValues().iterator(); itor.hasNext();) {
final Integer changesetItemId = itor.next();
LOG.debug("Expected changeset item {}", changesetItemId);
final ODataResponse res = chgres.next();
if (res.getStatusCode() >= 400) {
throw new IllegalStateException("Transaction failed: " + res.getStatusMessage());
if (factory.getClient().getConfiguration().isContinueOnError()) {
result.add(ODataErrorResponseChecker.checkResponse(
factory.getClient(),
new StatusLine() {
@Override
public ProtocolVersion getProtocolVersion() {
return null;
}
@Override
public int getStatusCode() {
return res.getStatusCode();
}
@Override
public String getReasonPhrase() {
return res.getStatusMessage();
}
},
res.getRawResponse(),
((ODataRequest) request).getAccept()));
} else {
throw new IllegalStateException("Transaction failed: " + res.getStatusMessage());
}
} else {
result.add(null);
}
final EntityInvocationHandler handler = items.get(changesetItemId);
@ -107,5 +142,7 @@ public class TransactionalPersistenceManagerImpl extends AbstractPersistenceMana
}
}
response.close();
return result;
}
}

View File

@ -85,6 +85,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.ws.rs.BadRequestException;
@Service
@Path("/V40/Static.svc")
@ -301,7 +302,7 @@ public class V4Services extends AbstractServices {
addChangesetItemIntro(chbos, lastContebtID, cboundary);
res = bodyPartRequest(new MimeBodyPart(part.getInputStream()), references);
if (res == null || res.getStatus() >= 400) {
if (!continueOnError && (res == null || res.getStatus() >= 400)) {
throw new Exception("Failure processing changeset");
}
@ -372,7 +373,7 @@ public class V4Services extends AbstractServices {
return StringUtils.isBlank(filter) && StringUtils.isBlank(search)
? NumberUtils.isNumber(type)
? super.getEntityInternal(
uriInfo.getRequestUri().toASCIIString(), accept, "People", type, format, null, null)
uriInfo.getRequestUri().toASCIIString(), accept, "People", type, format, null, null)
: super.getEntitySet(accept, "People", type)
: super.getEntitySet(uriInfo, accept, "People", top, skip, format, count, filter, orderby, skiptoken);
}
@ -555,7 +556,7 @@ public class V4Services extends AbstractServices {
final Link link = new LinkImpl();
link.setRel("edit");
link.setHref(URI.create(
Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL)
Constants.get(version, ConstantKey.DEFAULT_SERVICE_URL)
+ "ProductDetails(ProductID=6,ProductDetailID=1)").toASCIIString());
entry.setEditLink(link);
@ -753,7 +754,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) {
@ -762,6 +763,24 @@ public class V4Services extends AbstractServices {
}
}
@POST
@Path("/People")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM})
public Response postPeople(
@Context final UriInfo uriInfo,
@HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) final String accept,
@HeaderParam("Content-Type") @DefaultValue(StringUtils.EMPTY) final String contentType,
@HeaderParam("Prefer") @DefaultValue(StringUtils.EMPTY) final String prefer,
final String entity) {
if ("{\"@odata.type\":\"#Microsoft.Test.OData.Services.ODataWCFService.Person\"}".equals(entity)) {
return xml.createFaultResponse(accept, new BadRequestException());
}
return super.postNewEntity(uriInfo, accept, contentType, prefer, "People", entity);
}
@Override
public Response patchEntity(
final UriInfo uriInfo,
@ -775,9 +794,9 @@ public class V4Services extends AbstractServices {
final Response response =
getEntityInternal(uriInfo.getRequestUri().toASCIIString(),
accept, entitySetName, entityId, accept, StringUtils.EMPTY, StringUtils.EMPTY);
accept, entitySetName, entityId, accept, StringUtils.EMPTY, StringUtils.EMPTY);
return response.getStatus() >= 400
? postNewEntity(uriInfo, accept, contentType, prefer, entitySetName, changes)
? super.postNewEntity(uriInfo, accept, contentType, prefer, entitySetName, changes)
: super.patchEntity(uriInfo, accept, contentType, prefer, ifMatch, entitySetName, entityId, changes);
}
@ -1001,7 +1020,7 @@ 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 ResWrap<Entity> container = atomDeserializer.toEntity(entry);
// 2. Remove the contained entity
@ -1275,7 +1294,7 @@ public class V4Services extends AbstractServices {
final ResWrap<Property> result = new ResWrap<Property>(
URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX)
+ "Microsoft.Test.OData.Services.ODataWCFService.Address"),
+ "Microsoft.Test.OData.Services.ODataWCFService.Address"),
null,
entity.getProperty("address"));

View File

@ -322,7 +322,6 @@ public class ContextTestITCase extends AbstractTestITCase {
final Login login = container.getLogin().newLogin();
final EntityInvocationHandler handler = (EntityInvocationHandler) Proxy.getInvocationHandler(login);
assertTrue(service.getContext().entityContext().isAttached(handler));
try {
@ -356,7 +355,7 @@ public class ContextTestITCase extends AbstractTestITCase {
@Test
public void flushTest() {
Customer customer = container.getCustomer().newCustomer();
final Customer customer = container.getCustomer().newCustomer();
customer.setCustomerId(300);
customer.setName("samplename");

View File

@ -48,7 +48,7 @@ import static org.junit.Assert.fail;
public class APIBasicDesignTestITCase extends AbstractTestITCase {
protected Service<EdmEnabledODataClient> getContainerFactory() {
return containerFactory;
return service;
}
protected InMemoryEntities getContainer() {
@ -133,7 +133,7 @@ public class APIBasicDesignTestITCase extends AbstractTestITCase {
assertEquals(BigDecimal.ZERO, actual.getShelfLife());
assertEquals(2, actual.getOrderShelfLifes().size());
containerFactory.getContext().detachAll();
service.getContext().detachAll();
// Delete order ...
container.getOrders().delete(container.getOrders().getByKey(1105));
@ -142,7 +142,7 @@ public class APIBasicDesignTestITCase extends AbstractTestITCase {
container.flush();
containerFactory.getContext().detachAll();
service.getContext().detachAll();
try {
container.getOrders().getByKey(105).load();
fail();

View File

@ -63,7 +63,7 @@ public abstract class AbstractTestITCase {
protected static String testAuthServiceRootURL;
protected static Service<EdmEnabledODataClient> containerFactory;
protected static Service<EdmEnabledODataClient> service;
protected static InMemoryEntities container;
@ -77,11 +77,11 @@ public abstract class AbstractTestITCase {
testLargeModelServiceRootURL = "http://localhost:9080/stub/StaticService/V40/Static.svc/large";
testAuthServiceRootURL = "http://localhost:9080/stub/DefaultService.svc/V40/Static.svc";
containerFactory = Service.getV4(testStaticServiceRootURL);
containerFactory.getClient().getConfiguration().setDefaultBatchAcceptFormat(ContentType.APPLICATION_OCTET_STREAM);
container = containerFactory.getEntityContainer(InMemoryEntities.class);
service = Service.getV4(testStaticServiceRootURL);
service.getClient().getConfiguration().setDefaultBatchAcceptFormat(ContentType.APPLICATION_OCTET_STREAM);
container = service.getEntityContainer(InMemoryEntities.class);
assertNotNull(container);
containerFactory.getContext().detachAll();
service.getContext().detachAll();
}
protected Customer readCustomer(final InMemoryEntities container, final int id) {

View File

@ -41,7 +41,7 @@ public class AsyncTestITCase extends AbstractTestITCase {
@Test
public void retrieveEntitySet() throws InterruptedException, ExecutionException {
final Future<CustomerCollection> futureCustomers =
new AsyncCall<CustomerCollection>(containerFactory.getClient().getConfiguration()) {
new AsyncCall<CustomerCollection>(service.getClient().getConfiguration()) {
@Override
public CustomerCollection call() {
@ -69,7 +69,7 @@ public class AsyncTestITCase extends AbstractTestITCase {
Person person = container.getPeople().getByKey(1);
person.setFirstName(randomFirstName);
final Future<Void> futureFlush = new AsyncCall<Void>(containerFactory.getClient().getConfiguration()) {
final Future<Void> futureFlush = new AsyncCall<Void>(service.getClient().getConfiguration()) {
@Override
public Void call() {
@ -83,7 +83,7 @@ public class AsyncTestITCase extends AbstractTestITCase {
Thread.sleep(1000L);
}
new AsyncCall<Person>(containerFactory.getClient().getConfiguration()) {
new AsyncCall<Person>(service.getClient().getConfiguration()) {
@Override
public Person call() {

View File

@ -0,0 +1,91 @@
/*
* 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.fit.proxy.v4;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Proxy;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.v4.EdmEnabledODataClient;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.ext.proxy.Service;
import org.apache.olingo.ext.proxy.commons.EntityInvocationHandler;
import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.InMemoryEntities;
import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Address;
import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Employee;
import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.Person;
import org.junit.Test;
public class ContextTestITCase extends AbstractTestITCase {
private void continueOnError(final Service<EdmEnabledODataClient> service, final InMemoryEntities container) {
final Person person = container.getPeople().newPerson();
final EntityInvocationHandler handler = (EntityInvocationHandler) Proxy.getInvocationHandler(person);
assertTrue(service.getContext().entityContext().isAttached(handler));
final Employee employee = container.getPeople().newEmployee();
employee.setPersonID(199);
employee.setFirstName("Fabio");
employee.setLastName("Martelli");
employee.setEmails(Collections.<String>singleton("fabio.martelli@tirasa.net"));
final Calendar date = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
date.clear();
date.set(2011, 3, 4, 9, 0, 0);
employee.setDateHired(new Timestamp(date.getTimeInMillis()));
final Address homeAddress = employee.factory().newHomeAddress();
homeAddress.setCity("Pescara");
homeAddress.setPostalCode("65100");
homeAddress.setStreet("viale Gabriele D'Annunzio 256");
employee.setHomeAddress(homeAddress);
employee.setNumbers(Arrays.asList(new String[] {"3204725072", "08569930"}));
final List<ODataRuntimeException> result = container.flush();
assertEquals(2, result.size());
assertTrue(result.get(0) instanceof ODataClientErrorException);
assertNull(result.get(1));
}
@Test
public void transactionalContinueOnError() {
service.getClient().getConfiguration().setContinueOnError(true);
continueOnError(service, container);
service.getClient().getConfiguration().setContinueOnError(false);
}
@Test
public void nonTransactionalContinueOnError() {
final Service<EdmEnabledODataClient> _service = Service.getV4(testStaticServiceRootURL, false);
_service.getClient().getConfiguration().setDefaultBatchAcceptFormat(ContentType.APPLICATION_OCTET_STREAM);
_service.getClient().getConfiguration().setContinueOnError(true);
final InMemoryEntities _container = _service.getEntityContainer(InMemoryEntities.class);
continueOnError(_service, _container);
}
}

View File

@ -62,7 +62,7 @@ import static org.junit.Assert.fail;
public class EntityCreateTestITCase extends AbstractTestITCase {
protected Service<EdmEnabledODataClient> getContainerFactory() {
return containerFactory;
return service;
}
protected InMemoryEntities getContainer() {

View File

@ -55,7 +55,7 @@ import static org.junit.Assert.assertTrue;
public class EntityUpdateTestITCase extends AbstractTestITCase {
protected Service<EdmEnabledODataClient> getContainerFactory() {
return containerFactory;
return service;
}
protected InMemoryEntities getContainer() {

View File

@ -44,7 +44,7 @@ public class FilterTestITCase extends AbstractTestITCase {
final People people = container.getPeople();
PersonCollection result =
people.filter(containerFactory.getClient().getFilterFactory().lt("PersonID", 3)).execute();
people.filter(service.getClient().getFilterFactory().lt("PersonID", 3)).execute();
// 1. check that result looks as expected
assertEquals(2, result.size());
@ -77,9 +77,9 @@ public class FilterTestITCase extends AbstractTestITCase {
@Test
public void search() {
final Search<Person, PersonCollection> search = container.getPeople().createSearch().setSearch(
containerFactory.getClient().getSearchFactory().or(
containerFactory.getClient().getSearchFactory().literal("Bob"),
containerFactory.getClient().getSearchFactory().literal("Jill")));
service.getClient().getSearchFactory().or(
service.getClient().getSearchFactory().literal("Bob"),
service.getClient().getSearchFactory().literal("Jill")));
final PersonCollection result = search.getResult();
assertFalse(result.isEmpty());

View File

@ -51,7 +51,7 @@ public class OperationImportInvokeTestITCase extends AbstractTestITCase {
@Test
public void getPerson() {
final Address address = container.getPeople().newPerson().factory().newHomeAddress();
final Address address = container.getPeople().getByKey(1).factory().newHomeAddress();
address.setStreet("1 Microsoft Way");
address.setPostalCode("98052");
address.setCity("London");
@ -80,7 +80,7 @@ public class OperationImportInvokeTestITCase extends AbstractTestITCase {
@Test
public void resetBossAddress() {
final Address address = container.getPeople().newPerson().factory().newHomeAddress();
final Address address = container.getPeople().getByKey(1).factory().newHomeAddress();
address.setStreet("Via Le Mani Dal Naso, 123");
address.setPostalCode("Tollo");
address.setCity("66010");

View File

@ -49,7 +49,7 @@ public class PropertyTestITCase extends AbstractTestITCase {
fail();
} catch (IllegalStateException e) {
// ignore and detach all
containerFactory.getContext().detachAll();
service.getContext().detachAll();
}
}
}

View File

@ -158,7 +158,7 @@ public class BatchTestITCase extends AbstractTestITCase {
assertEquals(404, res.getStatusCode());
assertEquals("Not Found", res.getStatusMessage());
assertEquals(Integer.valueOf(3), Integer.valueOf(
res.getHeader(ODataBatchConstants.CHANGESET_CONTENT_ID_NAME).iterator().next()));
res.getHeader(ODataBatchConstants.CHANGESET_CONTENT_ID_NAME).iterator().next()));
assertFalse(retitem.hasNext());
assertFalse(iter.hasNext());
@ -175,10 +175,12 @@ public class BatchTestITCase extends AbstractTestITCase {
}
private void continueOnError(final boolean continueOnError) {
final boolean preContinueOnError = client.getConfiguration().isContinueOnError();
client.getConfiguration().setContinueOnError(continueOnError);
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
request.setAccept(ACCEPT);
request.continueOnError();
final BatchManager streamManager = request.payloadManager();
@ -187,7 +189,7 @@ public class BatchTestITCase extends AbstractTestITCase {
// -------------------------------------------
// prepare URI
URIBuilder targetURI = client.newURIBuilder(testStaticServiceRootURL);
targetURI.appendEntitySetSegment("UnexistinfEntitySet").appendKeySegment(1);
targetURI.appendEntitySetSegment("UnexistingEntitySet").appendKeySegment(1);
// create new request
ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build());
@ -232,6 +234,8 @@ public class BatchTestITCase extends AbstractTestITCase {
assertEquals(200, res.getStatusCode());
assertEquals("OK", res.getStatusMessage());
}
client.getConfiguration().setContinueOnError(preContinueOnError);
}
@Test
@ -249,7 +253,7 @@ public class BatchTestITCase extends AbstractTestITCase {
// add create request
final ODataEntityCreateRequest<ODataEntity> createReq =
client.getCUDRequestFactory().getEntityCreateRequest(uriBuilder.build(), order);
client.getCUDRequestFactory().getEntityCreateRequest(uriBuilder.build(), order);
changeset.addRequest(createReq);
@ -259,8 +263,8 @@ public class BatchTestITCase extends AbstractTestITCase {
// add update request: link CustomerInfo(17) to the new customer
final ODataEntity customerChanges = client.getObjectFactory().newEntity(order.getTypeName());
customerChanges.addLink(client.getObjectFactory().newEntitySetNavigationLink(
"OrderDetails",
client.newURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("OrderDetails").
"OrderDetails",
client.newURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("OrderDetails").
appendKeySegment(new HashMap<String, Object>() {
private static final long serialVersionUID = 3109256773218160485L;
@ -271,7 +275,7 @@ public class BatchTestITCase extends AbstractTestITCase {
}).build()));
final ODataEntityUpdateRequest<ODataEntity> updateReq = client.getCUDRequestFactory().getEntityUpdateRequest(
URI.create("$" + createRequestRef), UpdateType.PATCH, customerChanges);
URI.create("$" + createRequestRef), UpdateType.PATCH, customerChanges);
changeset.addRequest(updateReq);
@ -293,10 +297,10 @@ public class BatchTestITCase extends AbstractTestITCase {
order = ((ODataEntityCreateResponse<ODataEntity>) res).getBody();
final ODataEntitySetRequest<ODataEntitySet> req = client.getRetrieveRequestFactory().getEntitySetRequest(
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString() + "/OrderDetails"));
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString() + "/OrderDetails"));
assertEquals(Integer.valueOf(7),
req.execute().getBody().getEntities().get(0).getProperty("OrderID").getPrimitiveValue().
req.execute().getBody().getEntities().get(0).getProperty("OrderID").getPrimitiveValue().
toCastValue(Integer.class));
res = chgitem.next();
@ -305,13 +309,13 @@ public class BatchTestITCase extends AbstractTestITCase {
// clean ...
assertEquals(204, client.getCUDRequestFactory().getDeleteRequest(
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString())).execute().
getStatusCode());
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString())).execute().
getStatusCode());
try {
client.getRetrieveRequestFactory().getEntityRequest(
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString())).
execute().getBody();
URIUtils.getURI(testStaticServiceRootURL, order.getEditLink().toASCIIString())).
execute().getBody();
fail();
} catch (Exception e) {
// ignore
@ -332,7 +336,7 @@ public class BatchTestITCase extends AbstractTestITCase {
// prepare URI
URIBuilder targetURI = client.newURIBuilder(testStaticServiceRootURL);
targetURI.appendEntitySetSegment("Customers").appendKeySegment(1).
expand("Orders").select("PersonID,Orders/OrderID");
expand("Orders").select("PersonID,Orders/OrderID");
// create new request
ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build());
@ -348,7 +352,7 @@ public class BatchTestITCase extends AbstractTestITCase {
targetURI = client.newURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("Orders");
final ODataEntity original = newOrder(2000);
final ODataEntityCreateRequest<ODataEntity> createReq =
client.getCUDRequestFactory().getEntityCreateRequest(targetURI.build(), original);
client.getCUDRequestFactory().getEntityCreateRequest(targetURI.build(), original);
createReq.setFormat(ODataFormat.JSON);
streamManager.addRequest(createReq);
// -------------------------------------------
@ -386,7 +390,7 @@ public class BatchTestITCase extends AbstractTestITCase {
}
@Test
@SuppressWarnings({ "unchecked" })
@SuppressWarnings({"unchecked"})
public void batchRequest() throws EdmPrimitiveTypeException {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(testStaticServiceRootURL);
@ -418,15 +422,15 @@ public class BatchTestITCase extends AbstractTestITCase {
final URI editLink = targetURI.build();
final ODataEntity patch = client.getObjectFactory().newEntity(
new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Customer"));
new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Customer"));
patch.setEditLink(editLink);
patch.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
"LastName",
client.getObjectFactory().newPrimitiveValueBuilder().buildString("new last name")));
"LastName",
client.getObjectFactory().newPrimitiveValueBuilder().buildString("new last name")));
final ODataEntityUpdateRequest<ODataEntity> changeReq =
client.getCUDRequestFactory().getEntityUpdateRequest(UpdateType.PATCH, patch);
client.getCUDRequestFactory().getEntityUpdateRequest(UpdateType.PATCH, patch);
changeReq.setFormat(ODataFormat.JSON_FULL_METADATA);
changeset.addRequest(changeReq);
@ -435,7 +439,7 @@ public class BatchTestITCase extends AbstractTestITCase {
targetURI = client.newURIBuilder(testStaticServiceRootURL).appendEntitySetSegment("Orders");
final ODataEntity original = newOrder(1000);
final ODataEntityCreateRequest<ODataEntity> createReq =
client.getCUDRequestFactory().getEntityCreateRequest(targetURI.build(), original);
client.getCUDRequestFactory().getEntityCreateRequest(targetURI.build(), original);
createReq.setFormat(ODataFormat.JSON);
changeset.addRequest(createReq);
// -------------------------------------------
@ -468,7 +472,7 @@ public class BatchTestITCase extends AbstractTestITCase {
assertEquals("OK", res.getStatusMessage());
ODataEntityRequestImpl<ODataEntity>.ODataEntityResponseImpl entres =
(ODataEntityRequestImpl.ODataEntityResponseImpl) res;
(ODataEntityRequestImpl.ODataEntityResponseImpl) res;
ODataEntity entity = entres.getBody();
assertEquals(1, entity.getProperty("PersonID").getPrimitiveValue().toCastValue(Integer.class), 0);
@ -513,7 +517,7 @@ public class BatchTestITCase extends AbstractTestITCase {
public void async() {
// create your request
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(
URI.create(testStaticServiceRootURL + "/async/").normalize().toASCIIString());
URI.create(testStaticServiceRootURL + "/async/").normalize().toASCIIString());
request.setAccept(ACCEPT);
final AsyncBatchRequestWrapper async = client.getAsyncRequestFactory().getAsyncBatchRequestWrapper(request);
@ -556,17 +560,17 @@ public class BatchTestITCase extends AbstractTestITCase {
final Iterator<ODataBatchResponseItem> iter = response.getBody();
// retrieve the first item (ODataRetrieve)
ODataBatchResponseItem item = iter.next();
final ODataBatchResponseItem item = iter.next();
assertTrue(item instanceof ODataSingleResponseItem);
// The service return interim results to an asynchronously executing batch.
ODataSingleResponseItem retitem = (ODataSingleResponseItem) item;
ODataResponse res = retitem.next();
final ODataSingleResponseItem retitem = (ODataSingleResponseItem) item;
final ODataResponse res = retitem.next();
assertTrue(res instanceof AsyncResponse);
assertEquals(202, res.getStatusCode());
assertEquals("Accepted", res.getStatusMessage());
Collection<String> newMonitorLocation = res.getHeader(HeaderName.location);
final Collection<String> newMonitorLocation = res.getHeader(HeaderName.location);
if (newMonitorLocation != null && !newMonitorLocation.isEmpty()) {
responseWrapper.forceNextMonitorCheck(URI.create(newMonitorLocation.iterator().next()));
// .... now you can start again with isDone() and getODataResponse().
@ -634,20 +638,20 @@ public class BatchTestITCase extends AbstractTestITCase {
private ODataEntity newOrder(final int id) {
final ODataEntity order = getClient().getObjectFactory().
newEntity(new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Order"));
newEntity(new FullQualifiedName("Microsoft.Test.OData.Services.ODataWCFService.Order"));
order.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("OrderID",
getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt32(id)));
getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt32(id)));
order.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("OrderDate",
getClient().getObjectFactory().newPrimitiveValueBuilder().
getClient().getObjectFactory().newPrimitiveValueBuilder().
setType(EdmPrimitiveTypeKind.DateTimeOffset).setValue(Calendar.getInstance()).build()));
order.getProperties().add(getClient().getObjectFactory().newPrimitiveProperty("ShelfLife",
getClient().getObjectFactory().newPrimitiveValueBuilder().
getClient().getObjectFactory().newPrimitiveValueBuilder().
setType(EdmPrimitiveTypeKind.Duration).setValue(new BigDecimal("0.0000002")).build()));
order.getProperties().add(getClient().getObjectFactory().newCollectionProperty("OrderShelfLifes",
getClient().getObjectFactory().newCollectionValue(EdmPrimitiveTypeKind.Duration.name()).add(
getClient().getObjectFactory().newPrimitiveValueBuilder().setType(EdmPrimitiveTypeKind.Duration).
setValue(new BigDecimal("0.0000002")).build())));
getClient().getObjectFactory().newCollectionValue(EdmPrimitiveTypeKind.Duration.name()).add(
getClient().getObjectFactory().newPrimitiveValueBuilder().setType(EdmPrimitiveTypeKind.Duration).
setValue(new BigDecimal("0.0000002")).build())));
return order;
}

View File

@ -32,16 +32,18 @@ public interface Configuration {
/**
* Gets the configured default <tt>Accept</tt> header value format for a batch request.
*
* @return configured default <tt>Accept</tt> header value for a batch request.
*/
ContentType getDefaultBatchAcceptFormat();
/**
* Set the default <tt>Accept</tt> header value format for a batch request.
*
* @param contentType default <tt>Accept</tt> header value.
*/
void setDefaultBatchAcceptFormat(ContentType contentType);
/**
* Gets the configured OData format for AtomPub exchanges. If this configuration parameter doesn't exist the
* JSON_FULL_METADATA format will be used as default.
@ -197,52 +199,62 @@ public interface Configuration {
void setKeyAsSegment(boolean value);
/**
* Gets whether query URIs in request should contain fully qualified type name.
* - OData Intermediate Conformance Level:
* MUST support casting to a derived type according to [OData-URL] if derived types are present in the model.
* Gets whether query URIs in request should contain fully qualified type name. - OData Intermediate Conformance
* Level: MUST support casting to a derived type according to [OData-URL] if derived types are present in the model.
* <br/>
* Example: http://host/service/Customers/Model.VipCustomer(102) or
* http://host/service/Customers/Model.VipCustomer
* Example: http://host/service/Customers/Model.VipCustomer(102) or http://host/service/Customers/Model.VipCustomer
*
* @return whether query URIs in request should contain fully qualified type name.
* segment.
* @return whether query URIs in request should contain fully qualified type name. segment.
*/
boolean isAddressingDerivedTypes() ;
boolean isAddressingDerivedTypes();
/**
* Sets whether query URIs in request should contain fully qualified type name. - OData Intermediate Conformance
* Level: MUST support casting to a derived type according to [OData-URL] if derived types are present in the model.
* <br/>
* Example: http://host/service/Customers/Model.VipCustomer(102) or http://host/service/Customers/Model.VipCustomer
*
* @param value 'TRUE' to use this feature.
*/
void setAddressingDerivedTypes(boolean value);
/**
* Checks whether operation name in request URI should be fully qualified name, which is required by OData V4
* protocol, but some service may still choose to support shorter name.
* <br/>
* Example: http://host/service/Customers(2)/NS1.Model.IncreaseSalary VS
* http://host/service/Customers(2)/IncreaseSalary
*
* @return wheter operation name in request URI should be fully qualified name. segment.
*/
boolean isUseUrlOperationFQN();
/**
* Sets whether operation name in request URI should be fully qualified name, which is required by OData V4 protocol,
* but some service may still choose to support shorter name.
* <br/>
* Example: http://host/service/Customers(2)/NS1.Model.IncreaseSalary VS
* Example: http://host/service/Customers(2)/NS1.Model.IncreaseSalary VS
* http://host/service/Customers(2)/IncreaseSalary
*
* @param value 'TRUE' to use this feature.
*/
void setUseUrlOperationFQN(final boolean value);
/**
* Sets whether operation name in request URI should be fully qualified name, which is required by OData V4 protocol,
* but some service may still choose to support shorter name.
* <br/>
* Example: http://host/service/Customers(2)/NS1.Model.IncreaseSalary VS
* http://host/service/Customers(2)/IncreaseSalary
*
* @return whether whether operation name in request URI should be fully qualified name.
* segment.
*/
boolean isUseUrlOperationFQN() ;
void setUseUrlOperationFQN(boolean value);
/**
* Sets whether query URIs in request should contain fully qualified type name.
* - OData Intermediate Conformance Level:
* MUST support casting to a derived type according to [OData-URL] if derived types are present in the model.
* <br/>
* Example: http://host/service/Customers/Model.VipCustomer(102) or
* http://host/service/Customers/Model.VipCustomer
* When processing a set of requests (in batch requests, for example), checks if the execution will be aborted after
* first error encountered or not.
*
* @return whether execution of a set of requests will be aborted after first error
*/
boolean isContinueOnError();
/**
* When processing a set of requests (in batch requests, for example), sets if the execution will be aborted after
* first error encountered or not.
*
* @param value 'TRUE' to use this feature.
*/
void setAddressingDerivedTypes(final boolean value);
void setContinueOnError(boolean value);
/**
* Retrieves request executor service.

View File

@ -20,6 +20,7 @@ package org.apache.olingo.client.api.communication;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.StatusLine;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.domain.ODataError;
/**
@ -27,7 +28,7 @@ import org.apache.olingo.commons.api.domain.ODataError;
*
* @see ODataError
*/
public class ODataClientErrorException extends RuntimeException {
public class ODataClientErrorException extends ODataRuntimeException {
private static final long serialVersionUID = -2551523202755268162L;

View File

@ -19,11 +19,12 @@
package org.apache.olingo.client.api.communication;
import org.apache.http.StatusLine;
import org.apache.olingo.commons.api.ODataRuntimeException;
/**
* Represents a server error in OData.
*/
public class ODataServerErrorException extends RuntimeException {
public class ODataServerErrorException extends ODataRuntimeException {
private static final long serialVersionUID = -6423014532618680135L;

View File

@ -23,11 +23,7 @@ import org.apache.olingo.client.api.communication.request.batch.BatchManager;
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, BatchManager> {
ODataBatchRequest continueOnError();
}

View File

@ -57,6 +57,8 @@ public class ConfigurationImpl implements Configuration {
private static final String CHUNKING = "chunking";
private static final String CONTINUE_ON_ERROR = "continueOnError";
private final Map<String, Object> CONF = new HashMap<String, Object>();
private transient ExecutorService executor = Executors.newFixedThreadPool(10);
@ -105,7 +107,7 @@ public class ConfigurationImpl implements Configuration {
@Override
public ODataFormat getDefaultFormat() {
ODataFormat format = getDefaultPubFormat();
final ODataFormat format = getDefaultPubFormat();
return format == ODataFormat.ATOM ? ODataFormat.XML : format;
}
@ -209,6 +211,16 @@ public class ConfigurationImpl implements Configuration {
setProperty(USE_OPERATION_FQN_IN_URL, value);
}
@Override
public boolean isContinueOnError() {
return (Boolean) getProperty(CONTINUE_ON_ERROR, false);
}
@Override
public void setContinueOnError(final boolean value) {
setProperty(CONTINUE_ON_ERROR, value);
}
@Override
public ExecutorService getExecutor() {
return executor;

View File

@ -0,0 +1,85 @@
/*
* 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.header;
import java.io.InputStream;
import org.apache.http.StatusLine;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.ODataServerErrorException;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.domain.ODataError;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.serialization.ODataDeserializerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ODataErrorResponseChecker {
protected static final Logger LOG = LoggerFactory.getLogger(ODataErrorResponseChecker.class);
private static ODataError getGenericError(final int code, final String errorMsg) {
final ODataError error = new ODataError();
error.setCode(String.valueOf(code));
error.setMessage(errorMsg);
return error;
}
public static ODataRuntimeException checkResponse(
final CommonODataClient<?> odataClient, final StatusLine statusLine, final InputStream entity,
final String accept) {
ODataRuntimeException result = null;
if (statusLine.getStatusCode() >= 400) {
if (entity == null) {
result = new ODataClientErrorException(statusLine);
} else {
final ODataFormat format = accept.contains("xml") ? ODataFormat.XML : ODataFormat.JSON;
ODataError error;
try {
error = odataClient.getReader().readError(entity, format);
} catch (final RuntimeException e) {
LOG.warn("Error deserializing error response", e);
error = getGenericError(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
} catch (final ODataDeserializerException e) {
LOG.warn("Error deserializing error response", e);
error = getGenericError(
statusLine.getStatusCode(),
statusLine.getReasonPhrase());
}
if (statusLine.getStatusCode() >= 500) {
result = new ODataServerErrorException(statusLine);
} else {
result = new ODataClientErrorException(statusLine, error);
}
}
}
return result;
}
private ODataErrorResponseChecker() {
// private constructor for static utility class
}
}

View File

@ -15,20 +15,14 @@
*/
package org.apache.olingo.client.core.communication.request;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.ODataServerErrorException;
import org.apache.olingo.client.api.http.HttpClientException;
import org.apache.olingo.commons.api.domain.ODataError;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.serialization.ODataDeserializerException;
import org.apache.olingo.client.core.communication.header.ODataErrorResponseChecker;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public abstract class AbstractRequest {
@ -38,13 +32,6 @@ public abstract class AbstractRequest {
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractRequest.class);
private ODataError getGenericError(final int code, final String errorMsg) {
final ODataError error = new ODataError();
error.setCode(String.valueOf(code));
error.setMessage(errorMsg);
return error;
}
protected void checkRequest(final CommonODataClient<?> odataClient, final HttpUriRequest request) {
// If using and Edm enabled client, checks that the cached service root matches the request URI
if (odataClient instanceof CommonEdmEnabledODataClient
@ -61,39 +48,18 @@ public abstract class AbstractRequest {
protected void checkResponse(
final CommonODataClient<?> odataClient, final HttpResponse response, final String accept) {
if (response.getStatusLine().getStatusCode() >= 400) {
try {
final HttpEntity httpEntity = response.getEntity();
if (httpEntity == null) {
throw new ODataClientErrorException(response.getStatusLine());
} else {
final ODataFormat format = accept.contains("xml") ? ODataFormat.XML : ODataFormat.JSON;
ODataError error;
try {
error = odataClient.getReader().readError(httpEntity.getContent(), format);
} catch (final RuntimeException e) {
LOG.warn("Error deserializing error response", e);
error = getGenericError(
response.getStatusLine().getStatusCode(),
response.getStatusLine().getReasonPhrase());
} catch (final ODataDeserializerException e) {
LOG.warn("Error deserializing error response", e);
error = getGenericError(
response.getStatusLine().getStatusCode(),
response.getStatusLine().getReasonPhrase());
}
if (response.getStatusLine().getStatusCode() >= 500) {
throw new ODataServerErrorException(response.getStatusLine());
} else {
throw new ODataClientErrorException(response.getStatusLine(), error);
}
}
} catch (IOException e) {
throw new HttpClientException(
"Received '" + response.getStatusLine() + "' but could not extract error body", e);
try {
final ODataRuntimeException exception = ODataErrorResponseChecker.
checkResponse(odataClient,
response.getStatusLine(),
response.getEntity() == null ? null : response.getEntity().getContent(),
accept);
if (exception != null) {
throw exception;
}
} catch (IOException e) {
throw new ODataRuntimeException(
"Received '" + response.getStatusLine() + "' but could not extract error body", e);
}
}
}

View File

@ -27,7 +27,6 @@ import org.apache.olingo.client.api.communication.request.batch.ODataSingleReque
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;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@ -36,6 +35,8 @@ import java.util.concurrent.TimeUnit;
*/
public abstract class AbstractBatchManager extends AbstractODataStreamManager<ODataBatchResponse> {
protected final boolean continueOnError;
/**
* Batch request current item.
*/
@ -46,15 +47,12 @@ public abstract class AbstractBatchManager extends AbstractODataStreamManager<OD
*/
protected final CommonODataBatchRequest req;
/**
* Private constructor.
*
* @param req batch request reference.
*/
protected AbstractBatchManager(
final CommonODataBatchRequest req, final Wrapper<Future<HttpResponse>> futureWrap) {
protected AbstractBatchManager(final CommonODataBatchRequest req,
final Wrapper<Future<HttpResponse>> futureWrap, final boolean continueOnError) {
super(futureWrap);
this.req = req;
this.continueOnError = continueOnError;
}
/**
@ -68,7 +66,7 @@ public abstract class AbstractBatchManager extends AbstractODataStreamManager<OD
// stream dash boundary
streamDashBoundary();
final ODataChangesetResponseItem expectedResItem = new ODataChangesetResponseItem();
final ODataChangesetResponseItem expectedResItem = new ODataChangesetResponseItem(continueOnError);
((AbstractODataBatchRequest) req).addExpectedResItem(expectedResItem);
currentItem = new ODataChangesetImpl(req, expectedResItem);
@ -83,7 +81,7 @@ public abstract class AbstractBatchManager extends AbstractODataStreamManager<OD
*/
public void addRequest(final ODataBatchableRequest request) {
validateSingleRequest(request);
closeCurrentItem();
// stream dash boundary
@ -106,9 +104,6 @@ public abstract class AbstractBatchManager extends AbstractODataStreamManager<OD
}
}
/**
* {@inheritDoc }
*/
@Override
protected ODataBatchResponse getResponse(final long timeout, final TimeUnit unit) {
closeCurrentItem();
@ -140,5 +135,5 @@ public abstract class AbstractBatchManager extends AbstractODataStreamManager<OD
stream(("--" + ((AbstractODataBatchRequest) req).boundary + "--").getBytes());
}
protected abstract void validateSingleRequest(final ODataBatchableRequest request);
protected abstract void validateSingleRequest(ODataBatchableRequest request);
}

View File

@ -22,7 +22,6 @@ import org.apache.olingo.client.api.ODataBatchConstants;
import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchErrorResponse;
import org.apache.olingo.client.core.communication.response.v4.AsyncResponseImpl;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
@ -32,22 +31,19 @@ import java.util.NoSuchElementException;
*/
public class ODataChangesetResponseItem extends AbstractODataBatchResponseItem {
private final boolean continueOnError;
private boolean unexpected = false;
/**
* Constructor.
*/
public ODataChangesetResponseItem() {
public ODataChangesetResponseItem(final boolean continueOnError) {
super(true);
this.continueOnError = continueOnError;
}
public void setUnexpected() {
this.unexpected = true;
}
/**
* {@inheritDoc }
*/
@Override
public ODataResponse next() {
if (current != null) {
@ -105,7 +101,7 @@ public class ODataChangesetResponseItem extends AbstractODataBatchResponseItem {
current.initFromBatch(responseLine, headers, batchLineIterator, boundary);
if (current.getStatusCode() >= 400) {
if (current.getStatusCode() >= 400 && !continueOnError) {
// found error ....
breaking = true;
}

View File

@ -34,15 +34,11 @@ import org.apache.olingo.client.core.communication.request.batch.AbstractBatchMa
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 java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
/**
* This class implements a batch request.
*/
public class ODataBatchRequestImpl
extends AbstractODataBatchRequest<ODataBatchResponse, BatchManager>
implements ODataBatchRequest, ODataStreamedRequest<ODataBatchResponse, BatchManager> {
@ -60,20 +56,14 @@ public class ODataBatchRequestImpl
return (BatchManager) payloadManager;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException {
getPayloadManager().getBodyStreamWriter().write(toBeStreamed);
return this;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException {
public ODataBatchRequest rawAppend(final byte[] toBeStreamed, final int off, final int len) throws IOException {
getPayloadManager().getBodyStreamWriter().write(toBeStreamed, off, len);
return this;
}
@ -84,7 +74,7 @@ public class ODataBatchRequestImpl
public class BatchManagerImpl extends AbstractBatchManager implements BatchManager {
public BatchManagerImpl(final ODataBatchRequest req) {
super(req, ODataBatchRequestImpl.this.futureWrapper);
super(req, ODataBatchRequestImpl.this.futureWrapper, odataClient.getConfiguration().isContinueOnError());
}
@Override
@ -100,11 +90,6 @@ public class ODataBatchRequestImpl
}
}
/**
* 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 {
protected ODataBatchResponseImpl(final CommonODataClient<?> odataClient, final HttpClient httpClient,

View File

@ -18,6 +18,10 @@
*/
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;
@ -34,20 +38,10 @@ import org.apache.olingo.client.core.communication.request.batch.AbstractODataBa
import org.apache.olingo.client.core.communication.response.AbstractODataResponse;
import org.apache.olingo.client.core.communication.response.batch.ODataBatchResponseManager;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
/**
* This class implements a batch request.
*/
public class ODataBatchRequestImpl
extends AbstractODataBatchRequest<ODataBatchResponse, BatchManager>
implements ODataBatchRequest {
private boolean continueOnError = false;
public ODataBatchRequestImpl(final ODataClient odataClient, final URI uri) {
super(odataClient, uri);
setAccept(odataClient.getConfiguration().getDefaultBatchAcceptFormat().toContentTypeString());
@ -61,18 +55,12 @@ public class ODataBatchRequestImpl
return (BatchManager) payloadManager;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed) throws IOException {
getPayloadManager().getBodyStreamWriter().write(toBeStreamed);
return this;
}
/**
* {@inheritDoc }
*/
@Override
public ODataBatchRequest rawAppend(final byte[] toBeStreamed, int off, int len) throws IOException {
getPayloadManager().getBodyStreamWriter().write(toBeStreamed, off, len);
@ -80,10 +68,12 @@ public class ODataBatchRequestImpl
}
@Override
public ODataBatchRequest continueOnError() {
addCustomHeader(HeaderName.prefer, new ODataPreferences(odataClient.getServiceVersion()).continueOnError());
continueOnError = true;
return this;
protected HttpResponse doExecute() {
if (odataClient.getConfiguration().isContinueOnError()) {
addCustomHeader(HeaderName.prefer, new ODataPreferences(odataClient.getServiceVersion()).continueOnError());
}
return super.doExecute();
}
/**
@ -92,7 +82,8 @@ public class ODataBatchRequestImpl
public class BatchManagerImpl extends AbstractBatchManager implements BatchManager {
public BatchManagerImpl(final ODataBatchRequest req) {
super(req, ODataBatchRequestImpl.this.futureWrapper);
super(req, ODataBatchRequestImpl.this.futureWrapper,
ODataBatchRequestImpl.this.odataClient.getConfiguration().isContinueOnError());
}
@Override
@ -105,11 +96,6 @@ public class ODataBatchRequestImpl
}
}
/**
* 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 {
protected ODataBatchResponseImpl(
@ -118,12 +104,9 @@ public class ODataBatchRequestImpl
super(odataClient, httpClient, res);
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<ODataBatchResponseItem> getBody() {
return new ODataBatchResponseManager(this, expectedResItems, continueOnError);
return new ODataBatchResponseManager(this, expectedResItems, odataClient.getConfiguration().isContinueOnError());
}
@Override

View File

@ -20,18 +20,18 @@ package org.apache.olingo.commons.api;
public class ODataRuntimeException extends RuntimeException {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 5492375572049190883L;
public ODataRuntimeException(final String msg) {
super(msg);
}
public ODataRuntimeException(final String msg, final Exception e) {
super(msg, e);
public ODataRuntimeException(final String msg, final Exception cause) {
super(msg, cause);
}
public ODataRuntimeException(final Exception e) {
super(e);
public ODataRuntimeException(final Exception cause) {
super(cause);
}
}