You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by il...@apache.org on 2014/05/27 11:00:45 UTC
[3/3] git commit: [OLINGO-260] Adding option to work
non-transactionally (e.g. without batch)
[OLINGO-260] Adding option to work non-transactionally (e.g. without batch)
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/a66bd98b
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/a66bd98b
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/a66bd98b
Branch: refs/heads/master
Commit: a66bd98b59ace7789d4107601f0be50be3f8e20c
Parents: 0774803
Author: Francesco Chicchiriccò <--global>
Authored: Tue May 27 11:00:32 2014 +0200
Committer: Francesco Chicchiriccò <--global>
Committed: Tue May 27 11:00:32 2014 +0200
----------------------------------------------------------------------
.../ext/proxy/EntityContainerFactory.java | 73 ++-
.../commons/AbstractInvocationHandler.java | 2 +-
.../commons/AbstractPersistenceManager.java | 451 +++++++++++++++
.../AbstractStructuredInvocationHandler.java | 2 +-
.../EntityContainerInvocationHandler.java | 2 +-
.../NonTransactionalPersistenceManagerImpl.java | 60 ++
.../ext/proxy/commons/PersistenceChanges.java | 37 ++
.../proxy/commons/PersistenceManagerImpl.java | 568 -------------------
.../ext/proxy/commons/TransactionItems.java | 81 +++
.../TransactionalPersistenceManagerImpl.java | 108 ++++
.../java/org/apache/olingo/fit/V4Services.java | 57 +-
.../olingo/fit/proxy/v4/AbstractTestITCase.java | 1 +
.../fit/proxy/v4/EntityCreateTestITCase.java | 2 +-
.../fit/proxy/v4/EntityUpdateTestITCase.java | 95 +++-
.../fit/proxy/v4/MediaEntityTestITCase.java | 51 +-
...TransactionalAuthEntityCreateTestITCase.java | 53 ++
.../NonTransactionalEntityCreateTestITCase.java | 50 ++
.../NonTransactionalEntityUpdateTestITCase.java | 49 ++
.../NonTransactionalMediaEntityTestITCase.java | 50 ++
19 files changed, 1159 insertions(+), 633 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
index b2ce911..c36aa77 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
@@ -24,7 +24,10 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.commons.api.format.ODataPubFormat;
+import org.apache.olingo.ext.proxy.api.PersistenceManager;
import org.apache.olingo.ext.proxy.commons.EntityContainerInvocationHandler;
+import org.apache.olingo.ext.proxy.commons.NonTransactionalPersistenceManagerImpl;
+import org.apache.olingo.ext.proxy.commons.TransactionalPersistenceManagerImpl;
import org.apache.olingo.ext.proxy.context.Context;
/**
@@ -40,35 +43,80 @@ public final class EntityContainerFactory<C extends CommonEdmEnabledODataClient<
private final Map<Class<?>, Object> ENTITY_CONTAINERS = new ConcurrentHashMap<Class<?>, Object>();
@SuppressWarnings("unchecked")
- private static <C extends CommonEdmEnabledODataClient<?>> EntityContainerFactory<C> getInstance(final C client) {
+ private static <C extends CommonEdmEnabledODataClient<?>> EntityContainerFactory<C> getInstance(
+ final C client, final boolean transactional) {
+
if (!FACTORY_PER_SERVICEROOT.containsKey(client.getServiceRoot())) {
client.getConfiguration().setDefaultPubFormat(ODataPubFormat.JSON_FULL_METADATA);
- final EntityContainerFactory<C> instance = new EntityContainerFactory<C>(client);
+ final EntityContainerFactory<C> instance = new EntityContainerFactory<C>(client, transactional);
FACTORY_PER_SERVICEROOT.put(client.getServiceRoot(), instance);
}
return (EntityContainerFactory<C>) FACTORY_PER_SERVICEROOT.get(client.getServiceRoot());
}
+ /**
+ * Gives an OData 3.0 instance for given service root, operating in transactions (with batch requests).
+ *
+ * @param serviceRoot OData service root
+ * @return OData 3.0 instance for given service root, operating in transactions (with batch requests)
+ */
public static EntityContainerFactory<org.apache.olingo.client.api.v3.EdmEnabledODataClient> getV3(
final String serviceRoot) {
- return getInstance(ODataClientFactory.getEdmEnabledV3(serviceRoot));
+ return getV3(serviceRoot, true);
+ }
+
+ /**
+ * Gives an OData 3.0 instance for given service root.
+ *
+ * @param serviceRoot OData service root
+ * @param transactional whether operating in transactions (with batch requests) or not
+ * @return OData 3.0 instance for given service root
+ */
+ public static EntityContainerFactory<org.apache.olingo.client.api.v3.EdmEnabledODataClient> getV3(
+ final String serviceRoot, final boolean transactional) {
+
+ return getInstance(ODataClientFactory.getEdmEnabledV3(serviceRoot), transactional);
}
+ /**
+ * Gives an OData 4.0 instance for given service root, operating in transactions (with batch requests).
+ *
+ * @param serviceRoot OData service root
+ * @return OData 4.0 instance for given service root, operating in transactions (with batch requests)
+ */
public static EntityContainerFactory<org.apache.olingo.client.api.v4.EdmEnabledODataClient> getV4(
final String serviceRoot) {
- return getInstance(ODataClientFactory.getEdmEnabledV4(serviceRoot));
+ return getV4(serviceRoot, true);
+ }
+
+ /**
+ * Gives an OData 4.0 instance for given service root.
+ *
+ * @param serviceRoot OData service root
+ * @param transactional whether operating in transactions (with batch requests) or not
+ * @return OData 4.0 instance for given service root
+ */
+ public static EntityContainerFactory<org.apache.olingo.client.api.v4.EdmEnabledODataClient> getV4(
+ final String serviceRoot, final boolean transactional) {
+
+ return getInstance(ODataClientFactory.getEdmEnabledV4(serviceRoot), transactional);
}
private final CommonEdmEnabledODataClient<?> client;
private final Context context;
- private EntityContainerFactory(final CommonEdmEnabledODataClient<?> client) {
+ private final boolean transactional;
+
+ private PersistenceManager persistenceManager;
+
+ private EntityContainerFactory(final CommonEdmEnabledODataClient<?> client, final boolean transactional) {
this.client = client;
this.context = new Context();
+ this.transactional = transactional;
}
@SuppressWarnings("unchecked")
@@ -80,6 +128,21 @@ public final class EntityContainerFactory<C extends CommonEdmEnabledODataClient<
return context;
}
+ public boolean isTransactional() {
+ return transactional;
+ }
+
+ public PersistenceManager getPersistenceManager() {
+ synchronized (this) {
+ if (persistenceManager == null) {
+ persistenceManager = transactional
+ ? new TransactionalPersistenceManagerImpl(this)
+ : new NonTransactionalPersistenceManagerImpl(this);
+ }
+ }
+ return persistenceManager;
+ }
+
/**
* Return an initialized concrete implementation of the passed EntityContainer interface.
*
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
index 2293c39..1728a7a 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractInvocationHandler.java
@@ -210,7 +210,7 @@ abstract class AbstractInvocationHandler implements InvocationHandler {
// 2. IMPORTANT: flush any pending change *before* invoke if this operation is side effecting
if (annotation.type() == OperationType.ACTION) {
- new PersistenceManagerImpl(containerHandler.getFactory()).flush();
+ containerHandler.getFactory().getPersistenceManager().flush();
}
// 3. invoke
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
new file mode 100644
index 0000000..67369ef
--- /dev/null
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
@@ -0,0 +1,451 @@
+/*
+ * 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.ext.proxy.commons;
+
+import java.io.InputStream;
+import java.lang.reflect.Proxy;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.client.api.communication.header.ODataPreferences;
+import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
+import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
+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.domain.CommonODataEntity;
+import org.apache.olingo.commons.api.domain.ODataLink;
+import org.apache.olingo.commons.api.domain.ODataLinkType;
+import org.apache.olingo.commons.api.domain.v4.ODataEntity;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.ODataMediaFormat;
+import org.apache.olingo.ext.proxy.EntityContainerFactory;
+import org.apache.olingo.ext.proxy.api.PersistenceManager;
+import org.apache.olingo.ext.proxy.api.annotations.NavigationProperty;
+import org.apache.olingo.ext.proxy.context.AttachedEntity;
+import org.apache.olingo.ext.proxy.context.AttachedEntityStatus;
+import org.apache.olingo.ext.proxy.context.EntityLinkDesc;
+import org.apache.olingo.ext.proxy.utils.CoreUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractPersistenceManager implements PersistenceManager {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractPersistenceManager.class);
+
+ private static final long serialVersionUID = 2065240290461241515L;
+
+ protected final EntityContainerFactory<?> factory;
+
+ AbstractPersistenceManager(final EntityContainerFactory<?> factory) {
+ this.factory = factory;
+ }
+
+ protected abstract void doFlush(final PersistenceChanges changes, final TransactionItems items);
+
+ @Override
+ public void flush() {
+ final PersistenceChanges changes = new PersistenceChanges();
+ final TransactionItems items = new TransactionItems();
+
+ int pos = 0;
+ final List<EntityLinkDesc> delayedUpdates = new ArrayList<EntityLinkDesc>();
+ for (AttachedEntity attachedEntity : factory.getContext().entityContext()) {
+ final AttachedEntityStatus status = attachedEntity.getStatus();
+ if (((status != AttachedEntityStatus.ATTACHED
+ && status != AttachedEntityStatus.LINKED) || attachedEntity.getEntity().isChanged())
+ && !items.contains(attachedEntity.getEntity())) {
+
+ pos++;
+ pos = processEntityContext(attachedEntity.getEntity(), pos, items, delayedUpdates, changes);
+ }
+ }
+
+ processDelayedUpdates(delayedUpdates, pos, items, changes);
+
+ doFlush(changes, items);
+
+ factory.getContext().detachAll();
+ }
+
+ private ODataLink buildNavigationLink(final String name, final URI uri, final ODataLinkType type) {
+ ODataLink result;
+
+ switch (type) {
+ case ENTITY_NAVIGATION:
+ result = factory.getClient().getObjectFactory().newEntityNavigationLink(name, uri);
+ break;
+
+ case ENTITY_SET_NAVIGATION:
+ result = factory.getClient().getObjectFactory().newEntitySetNavigationLink(name, uri);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Invalid link type " + type.name());
+ }
+
+ return result;
+ }
+
+ protected int processEntityContext(
+ final EntityInvocationHandler handler,
+ int pos,
+ final TransactionItems items,
+ final List<EntityLinkDesc> delayedUpdates,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Process '{}'", handler);
+
+ items.put(handler, null);
+
+ final CommonODataEntity entity = handler.getEntity();
+ entity.getNavigationLinks().clear();
+
+ final AttachedEntityStatus currentStatus = factory.getContext().entityContext().getStatus(handler);
+
+ if (AttachedEntityStatus.DELETED != currentStatus) {
+ entity.getProperties().clear();
+ CoreUtils.addProperties(factory.getClient(), handler.getPropertyChanges(), entity);
+
+ if (entity instanceof ODataEntity) {
+ ((ODataEntity) entity).getAnnotations().clear();
+ CoreUtils.addAnnotations(factory.getClient(), handler.getAnnotations(), (ODataEntity) entity);
+
+ for (Map.Entry<String, AnnotatableInvocationHandler> entry : handler.getPropAnnotatableHandlers().entrySet()) {
+ CoreUtils.addAnnotations(factory.getClient(),
+ entry.getValue().getAnnotations(), ((ODataEntity) entity).getProperty(entry.getKey()));
+ }
+ }
+ }
+
+ for (Map.Entry<NavigationProperty, Object> property : handler.getLinkChanges().entrySet()) {
+ final ODataLinkType type = Collection.class.isAssignableFrom(property.getValue().getClass())
+ ? ODataLinkType.ENTITY_SET_NAVIGATION
+ : ODataLinkType.ENTITY_NAVIGATION;
+
+ final Set<EntityInvocationHandler> toBeLinked = new HashSet<EntityInvocationHandler>();
+ for (Object proxy : type == ODataLinkType.ENTITY_SET_NAVIGATION
+ ? (Collection) property.getValue() : Collections.singleton(property.getValue())) {
+
+ final EntityInvocationHandler target = (EntityInvocationHandler) Proxy.getInvocationHandler(proxy);
+
+ final AttachedEntityStatus status = factory.getContext().entityContext().getStatus(target);
+
+ final URI editLink = target.getEntity().getEditLink();
+
+ if ((status == AttachedEntityStatus.ATTACHED || status == AttachedEntityStatus.LINKED) && !target.isChanged()) {
+ entity.addLink(buildNavigationLink(
+ property.getKey().name(),
+ URIUtils.getURI(factory.getClient().getServiceRoot(), editLink.toASCIIString()), type));
+ } else {
+ if (!items.contains(target)) {
+ pos = processEntityContext(target, pos, items, delayedUpdates, changeset);
+ pos++;
+ }
+
+ final Integer targetPos = items.get(target);
+ if (targetPos == null) {
+ // schedule update for the current object
+ LOG.debug("Schedule '{}' from '{}' to '{}'", type.name(), handler, target);
+ toBeLinked.add(target);
+ } else if (status == AttachedEntityStatus.CHANGED) {
+ entity.addLink(buildNavigationLink(
+ property.getKey().name(),
+ URIUtils.getURI(factory.getClient().getServiceRoot(), editLink.toASCIIString()), type));
+ } else {
+ // create the link for the current object
+ LOG.debug("'{}' from '{}' to (${}) '{}'", type.name(), handler, targetPos, target);
+
+ entity.addLink(buildNavigationLink(property.getKey().name(), URI.create("$" + targetPos), type));
+ }
+ }
+ }
+
+ if (!toBeLinked.isEmpty()) {
+ delayedUpdates.add(new EntityLinkDesc(property.getKey().name(), handler, toBeLinked, type));
+ }
+ }
+
+ if (entity instanceof ODataEntity) {
+ for (Map.Entry<String, AnnotatableInvocationHandler> entry
+ : handler.getNavPropAnnotatableHandlers().entrySet()) {
+
+ CoreUtils.addAnnotations(factory.getClient(),
+ entry.getValue().getAnnotations(),
+ (org.apache.olingo.commons.api.domain.v4.ODataLink) entity.getNavigationLink(entry.getKey()));
+ }
+ }
+
+ // insert into the process queue
+ LOG.debug("{}: Insert '{}' into the process queue", pos, handler);
+ final AttachedEntityStatus processedStatus = queue(handler, entity, changeset);
+
+ items.put(handler, pos);
+
+ if (processedStatus != AttachedEntityStatus.DELETED) {
+ int startingPos = pos;
+
+ if (handler.getEntity().isMediaEntity() && handler.isChanged()) {
+ // update media properties
+ if (!handler.getPropertyChanges().isEmpty()) {
+ final URI targetURI = currentStatus == AttachedEntityStatus.NEW
+ ? URI.create("$" + startingPos)
+ : URIUtils.getURI(
+ factory.getClient().getServiceRoot(), handler.getEntity().getEditLink().toASCIIString());
+ queueUpdate(handler, targetURI, entity, changeset);
+ pos++;
+ items.put(handler, pos);
+ }
+
+ // update media content
+ if (handler.getStreamChanges() != null) {
+ final URI targetURI = currentStatus == AttachedEntityStatus.NEW
+ ? URI.create("$" + startingPos + "/$value")
+ : URIUtils.getURI(
+ factory.getClient().getServiceRoot(),
+ handler.getEntity().getEditLink().toASCIIString() + "/$value");
+
+ queueUpdateMediaEntity(handler, targetURI, handler.getStreamChanges(), changeset);
+
+ // update media info (use null key)
+ pos++;
+ items.put(null, pos);
+ }
+ }
+
+ for (Map.Entry<String, InputStream> streamedChanges : handler.getStreamedPropertyChanges().entrySet()) {
+ final URI targetURI = currentStatus == AttachedEntityStatus.NEW
+ ? URI.create("$" + startingPos) : URIUtils.getURI(
+ factory.getClient().getServiceRoot(),
+ CoreUtils.getMediaEditLink(streamedChanges.getKey(), entity).toASCIIString());
+
+ queueUpdateMediaResource(handler, targetURI, streamedChanges.getValue(), changeset);
+
+ // update media info (use null key)
+ pos++;
+ items.put(handler, pos);
+ }
+ }
+
+ return pos;
+ }
+
+ protected void processDelayedUpdates(
+ final List<EntityLinkDesc> delayedUpdates,
+ int pos,
+ final TransactionItems items,
+ final PersistenceChanges changeset) {
+
+ for (EntityLinkDesc delayedUpdate : delayedUpdates) {
+ pos++;
+ items.put(delayedUpdate.getSource(), pos);
+
+ final CommonODataEntity changes =
+ factory.getClient().getObjectFactory().newEntity(delayedUpdate.getSource().getEntity().getTypeName());
+
+ AttachedEntityStatus status = factory.getContext().entityContext().getStatus(delayedUpdate.getSource());
+
+ final URI sourceURI;
+ if (status == AttachedEntityStatus.CHANGED) {
+ sourceURI = URIUtils.getURI(
+ factory.getClient().getServiceRoot(),
+ delayedUpdate.getSource().getEntity().getEditLink().toASCIIString());
+ } else {
+ int sourcePos = items.get(delayedUpdate.getSource());
+ sourceURI = URI.create("$" + sourcePos);
+ }
+
+ for (EntityInvocationHandler target : delayedUpdate.getTargets()) {
+ status = factory.getContext().entityContext().getStatus(target);
+
+ final URI targetURI;
+ if (status == AttachedEntityStatus.CHANGED) {
+ targetURI = URIUtils.getURI(
+ factory.getClient().getServiceRoot(), target.getEntity().getEditLink().toASCIIString());
+ } else {
+ int targetPos = items.get(target);
+ targetURI = URI.create("$" + targetPos);
+ }
+
+ changes.addLink(delayedUpdate.getType() == ODataLinkType.ENTITY_NAVIGATION
+ ? factory.getClient().getObjectFactory().
+ newEntityNavigationLink(delayedUpdate.getSourceName(), targetURI)
+ : factory.getClient().getObjectFactory().
+ newEntitySetNavigationLink(delayedUpdate.getSourceName(), targetURI));
+
+ LOG.debug("'{}' from {} to {}", delayedUpdate.getType().name(), sourceURI, targetURI);
+ }
+
+ queueUpdate(delayedUpdate.getSource(), sourceURI, changes, changeset);
+ }
+ }
+
+ private AttachedEntityStatus queue(
+ final EntityInvocationHandler handler,
+ final CommonODataEntity entity,
+ final PersistenceChanges changeset) {
+
+ switch (factory.getContext().entityContext().getStatus(handler)) {
+ case NEW:
+ queueCreate(handler, entity, changeset);
+ return AttachedEntityStatus.NEW;
+
+ case CHANGED:
+ queueUpdate(handler, entity, changeset);
+ return AttachedEntityStatus.CHANGED;
+
+ case DELETED:
+ queueDelete(handler, entity, changeset);
+ return AttachedEntityStatus.DELETED;
+
+ default:
+ if (handler.isChanged()) {
+ queueUpdate(handler, entity, changeset);
+ }
+ return AttachedEntityStatus.CHANGED;
+ }
+ }
+
+ private void queueCreate(
+ final EntityInvocationHandler handler,
+ final CommonODataEntity entity,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Create '{}'", handler);
+
+ changeset.addChange(factory.getClient().getCUDRequestFactory().
+ getEntityCreateRequest(handler.getEntitySetURI(), entity), handler);
+ }
+
+ private void queueUpdateMediaEntity(
+ final EntityInvocationHandler handler,
+ final URI uri,
+ final InputStream input,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Update media entity '{}'", uri);
+
+ final ODataMediaEntityUpdateRequest<?> req =
+ factory.getClient().getCUDRequestFactory().getMediaEntityUpdateRequest(uri, input);
+
+ req.setContentType(StringUtils.isBlank(handler.getEntity().getMediaContentType())
+ ? ODataMediaFormat.WILDCARD.toString()
+ : ODataMediaFormat.fromFormat(handler.getEntity().getMediaContentType()).toString());
+
+ if (StringUtils.isNotBlank(handler.getETag())) {
+ req.setIfMatch(handler.getETag());
+ }
+
+ changeset.addChange(req, handler);
+ }
+
+ private void queueUpdateMediaResource(
+ final EntityInvocationHandler handler,
+ final URI uri,
+ final InputStream input,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Update media entity '{}'", uri);
+
+ final ODataStreamUpdateRequest req = factory.getClient().getCUDRequestFactory().getStreamUpdateRequest(uri, input);
+
+ if (StringUtils.isNotBlank(handler.getETag())) {
+ req.setIfMatch(handler.getETag());
+ }
+
+ changeset.addChange(req, handler);
+ }
+
+ private void queueUpdate(
+ final EntityInvocationHandler handler,
+ final CommonODataEntity changes,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Update '{}'", handler.getEntityURI());
+
+ final ODataEntityUpdateRequest<CommonODataEntity> req =
+ factory.getClient().getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
+ ? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
+ getEntityUpdateRequest(handler.getEntityURI(),
+ org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
+ : ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
+ getEntityUpdateRequest(handler.getEntityURI(),
+ org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
+
+ req.setPrefer(new ODataPreferences(factory.getClient().getServiceVersion()).returnContent());
+
+ if (StringUtils.isNotBlank(handler.getETag())) {
+ req.setIfMatch(handler.getETag());
+ }
+
+ changeset.addChange(req, handler);
+ }
+
+ private void queueUpdate(
+ final EntityInvocationHandler handler,
+ final URI uri,
+ final CommonODataEntity changes,
+ final PersistenceChanges changeset) {
+
+ LOG.debug("Update '{}'", uri);
+
+ final ODataEntityUpdateRequest<CommonODataEntity> req =
+ factory.getClient().getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
+ ? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
+ getEntityUpdateRequest(uri,
+ org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
+ : ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
+ getEntityUpdateRequest(uri,
+ org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
+
+ req.setPrefer(new ODataPreferences(factory.getClient().getServiceVersion()).returnContent());
+
+ if (StringUtils.isNotBlank(handler.getETag())) {
+ req.setIfMatch(handler.getETag());
+ }
+
+ changeset.addChange(req, handler);
+ }
+
+ private void queueDelete(
+ final EntityInvocationHandler handler,
+ final CommonODataEntity entity,
+ final PersistenceChanges changeset) {
+
+ final URI deleteURI = handler.getEntityURI() == null ? entity.getEditLink() : handler.getEntityURI();
+ LOG.debug("Delete '{}'", deleteURI);
+
+ final ODataDeleteRequest req = factory.getClient().getCUDRequestFactory().getDeleteRequest(deleteURI);
+
+ if (StringUtils.isNotBlank(handler.getETag())) {
+ req.setIfMatch(handler.getETag());
+ }
+
+ changeset.addChange(req, handler);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
index 9b54380..8b290f2 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java
@@ -268,7 +268,7 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
final ODataRetrieveResponse<CommonODataEntity> res = req.execute();
navPropValue = getEntityProxy(
- uri,
+ null,
res.getBody(),
property.targetContainer(),
getClient().newURIBuilder().appendEntitySetSegment(property.targetEntitySet()).build(),
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
index 5f9433b..56bcc6d 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityContainerInvocationHandler.java
@@ -81,7 +81,7 @@ public final class EntityContainerInvocationHandler extends AbstractInvocationHa
if (isSelfMethod(method, args)) {
return invokeSelfMethod(method, args);
} else if ("flush".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
- new PersistenceManagerImpl(factory).flush();
+ factory.getPersistenceManager().flush();
return ClassUtils.returnVoid();
} else if ("operations".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
final Class<?> returnType = method.getReturnType();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
new file mode 100644
index 0000000..dedd338
--- /dev/null
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/NonTransactionalPersistenceManagerImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ext.proxy.commons;
+
+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.ext.proxy.EntityContainerFactory;
+
+/**
+ * {@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.
+ */
+public class NonTransactionalPersistenceManagerImpl extends AbstractPersistenceManager {
+
+ private static final long serialVersionUID = 5082907388513308752L;
+
+ public NonTransactionalPersistenceManagerImpl(final EntityContainerFactory<?> factory) {
+ super(factory);
+ }
+
+ @Override
+ protected void doFlush(final PersistenceChanges changes, final TransactionItems items) {
+ for (Map.Entry<ODataBatchableRequest, EntityInvocationHandler> entry : changes.getChanges().entrySet()) {
+ try {
+ final ODataResponse response = ((ODataBasicRequest<?, ?>) entry.getKey()).execute();
+
+ if (response instanceof ODataEntityCreateResponse && response.getStatusCode() == 201) {
+ entry.getValue().setEntity(((ODataEntityCreateResponse) response).getBody());
+ LOG.debug("Upgrade created object '{}'", entry.getValue());
+ } else if (response instanceof ODataEntityUpdateResponse && response.getStatusCode() == 200) {
+ entry.getValue().setEntity(((ODataEntityUpdateResponse) response).getBody());
+ LOG.debug("Upgrade updated object '{}'", entry.getValue());
+ }
+ } catch (Exception e) {
+ LOG.error("While performing {}", entry.getKey().getURI(), e);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceChanges.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceChanges.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceChanges.java
new file mode 100644
index 0000000..159d36b
--- /dev/null
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceChanges.java
@@ -0,0 +1,37 @@
+/*
+ * 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.ext.proxy.commons;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
+
+public class PersistenceChanges {
+
+ private final Map<ODataBatchableRequest, EntityInvocationHandler> requests =
+ new LinkedHashMap<ODataBatchableRequest, EntityInvocationHandler>();
+
+ public void addChange(final ODataBatchableRequest request, final EntityInvocationHandler handler) {
+ this.requests.put(request, handler);
+ }
+
+ public Map<ODataBatchableRequest, EntityInvocationHandler> getChanges() {
+ return requests;
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceManagerImpl.java
deleted file mode 100644
index e7ffc57..0000000
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/PersistenceManagerImpl.java
+++ /dev/null
@@ -1,568 +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.ext.proxy.commons;
-
-import java.io.InputStream;
-import java.lang.reflect.Proxy;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.olingo.client.api.communication.header.ODataPreferences;
-import org.apache.olingo.client.api.communication.request.ODataRequest;
-import org.apache.olingo.client.api.communication.request.ODataStreamedRequest;
-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.request.batch.ODataBatchResponseItem;
-import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
-import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
-import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
-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.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.request.batch.ODataChangesetResponseItem;
-import org.apache.olingo.client.core.uri.URIUtils;
-import org.apache.olingo.commons.api.domain.CommonODataEntity;
-import org.apache.olingo.commons.api.domain.ODataLink;
-import org.apache.olingo.commons.api.domain.ODataLinkType;
-import org.apache.olingo.commons.api.domain.v4.ODataEntity;
-import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
-import org.apache.olingo.commons.api.format.ODataMediaFormat;
-import org.apache.olingo.ext.proxy.EntityContainerFactory;
-import org.apache.olingo.ext.proxy.api.PersistenceManager;
-import org.apache.olingo.ext.proxy.api.annotations.NavigationProperty;
-import org.apache.olingo.ext.proxy.context.AttachedEntity;
-import org.apache.olingo.ext.proxy.context.AttachedEntityStatus;
-import org.apache.olingo.ext.proxy.context.EntityLinkDesc;
-import org.apache.olingo.ext.proxy.utils.CoreUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class PersistenceManagerImpl implements PersistenceManager {
-
- private static final long serialVersionUID = -3320312269235907501L;
-
- /**
- * Logger.
- */
- private static final Logger LOG = LoggerFactory.getLogger(PersistenceManagerImpl.class);
-
- private final EntityContainerFactory<?> factory;
-
- PersistenceManagerImpl(final EntityContainerFactory<?> factory) {
- this.factory = factory;
- }
-
- /**
- * Transactional changes commit.
- */
- @Override
- public void flush() {
- final CommonODataBatchRequest request =
- factory.getClient().getBatchRequestFactory().getBatchRequest(factory.getClient().getServiceRoot());
- ((ODataRequest) request).setAccept(factory.getClient().getConfiguration().getDefaultBatchAcceptFormat());
-
- final BatchManager streamManager = (BatchManager) ((ODataStreamedRequest) request).payloadManager();
-
- final ODataChangeset changeset = streamManager.addChangeset();
-
- final TransactionItems items = new TransactionItems();
- final List<EntityLinkDesc> delayedUpdates = new ArrayList<EntityLinkDesc>();
-
- int pos = 0;
-
- for (AttachedEntity attachedEntity : factory.getContext().entityContext()) {
- final AttachedEntityStatus status = attachedEntity.getStatus();
- if (((status != AttachedEntityStatus.ATTACHED
- && status != AttachedEntityStatus.LINKED) || attachedEntity.getEntity().isChanged())
- && !items.contains(attachedEntity.getEntity())) {
- pos++;
- pos = processEntityContext(attachedEntity.getEntity(), pos, items, delayedUpdates, changeset);
- }
- }
-
- processDelayedUpdates(delayedUpdates, pos, items, changeset);
-
- final ODataBatchResponse response = streamManager.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 with this respect.
- if (response.getStatusCode() != 202 && response.getStatusCode() != 200) {
- throw new IllegalStateException("Operation failed");
- }
-
- if (!items.isEmpty()) {
- final Iterator<ODataBatchResponseItem> iter = response.getBody();
- if (!iter.hasNext()) {
- throw new IllegalStateException("Unexpected operation result");
- }
-
- final ODataBatchResponseItem item = iter.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()) {
- LOG.debug("Expected changeset item {}", changesetItemId);
- final ODataResponse res = chgres.next();
- if (res.getStatusCode() >= 400) {
- throw new IllegalStateException("Transaction failed: " + res.getStatusMessage());
- }
-
- final EntityInvocationHandler handler = items.get(changesetItemId);
-
- if (handler != null) {
- if (res instanceof ODataEntityCreateResponse && res.getStatusCode() == 201) {
- handler.setEntity(((ODataEntityCreateResponse) res).getBody());
- LOG.debug("Upgrade created object '{}'", handler);
- } else if (res instanceof ODataEntityUpdateResponse && res.getStatusCode() == 200) {
- handler.setEntity(((ODataEntityUpdateResponse) res).getBody());
- LOG.debug("Upgrade updated object '{}'", handler);
- }
- }
- }
- }
-
- factory.getContext().detachAll();
- }
-
- private AttachedEntityStatus batch(
- final EntityInvocationHandler handler,
- final CommonODataEntity entity,
- final ODataChangeset changeset) {
-
- switch (factory.getContext().entityContext().getStatus(handler)) {
- case NEW:
- batchCreate(handler, entity, changeset);
- return AttachedEntityStatus.NEW;
-
- case CHANGED:
- batchUpdate(handler, entity, changeset);
- return AttachedEntityStatus.CHANGED;
-
- case DELETED:
- batchDelete(handler, entity, changeset);
- return AttachedEntityStatus.DELETED;
-
- default:
- if (handler.isChanged()) {
- batchUpdate(handler, entity, changeset);
- }
- return AttachedEntityStatus.CHANGED;
- }
- }
-
- private void batchCreate(
- final EntityInvocationHandler handler,
- final CommonODataEntity entity,
- final ODataChangeset changeset) {
-
- LOG.debug("Create '{}'", handler);
-
- changeset.addRequest(factory.getClient().getCUDRequestFactory().
- getEntityCreateRequest(handler.getEntitySetURI(), entity));
- }
-
- private void batchUpdateMediaEntity(
- final EntityInvocationHandler handler,
- final URI uri,
- final InputStream input,
- final ODataChangeset changeset) {
-
- LOG.debug("Update media entity '{}'", uri);
-
- final ODataMediaEntityUpdateRequest<?> req =
- factory.getClient().getCUDRequestFactory().getMediaEntityUpdateRequest(uri, input);
-
- req.setContentType(StringUtils.isBlank(handler.getEntity().getMediaContentType())
- ? ODataMediaFormat.WILDCARD.toString()
- : ODataMediaFormat.fromFormat(handler.getEntity().getMediaContentType()).toString());
-
- if (StringUtils.isNotBlank(handler.getETag())) {
- req.setIfMatch(handler.getETag());
- }
-
- changeset.addRequest(req);
- }
-
- private void batchUpdateMediaResource(
- final EntityInvocationHandler handler,
- final URI uri,
- final InputStream input,
- final ODataChangeset changeset) {
-
- LOG.debug("Update media entity '{}'", uri);
-
- final ODataStreamUpdateRequest req = factory.getClient().getCUDRequestFactory().getStreamUpdateRequest(uri, input);
-
- if (StringUtils.isNotBlank(handler.getETag())) {
- req.setIfMatch(handler.getETag());
- }
-
- changeset.addRequest(req);
- }
-
- private void batchUpdate(
- final EntityInvocationHandler handler,
- final CommonODataEntity changes,
- final ODataChangeset changeset) {
-
- LOG.debug("Update '{}'", handler.getEntityURI());
-
- final ODataEntityUpdateRequest<CommonODataEntity> req =
- factory.getClient().getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
- ? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
- getEntityUpdateRequest(handler.getEntityURI(),
- org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
- : ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
- getEntityUpdateRequest(handler.getEntityURI(),
- org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
-
- req.setPrefer(new ODataPreferences(factory.getClient().getServiceVersion()).returnContent());
-
- if (StringUtils.isNotBlank(handler.getETag())) {
- req.setIfMatch(handler.getETag());
- }
-
- changeset.addRequest(req);
- }
-
- private void batchUpdate(
- final EntityInvocationHandler handler,
- final URI uri,
- final CommonODataEntity changes,
- final ODataChangeset changeset) {
-
- LOG.debug("Update '{}'", uri);
-
- final ODataEntityUpdateRequest<CommonODataEntity> req =
- factory.getClient().getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
- ? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
- getEntityUpdateRequest(uri,
- org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
- : ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) factory.getClient()).getCUDRequestFactory().
- getEntityUpdateRequest(uri,
- org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
-
- req.setPrefer(new ODataPreferences(factory.getClient().getServiceVersion()).returnContent());
-
- if (StringUtils.isNotBlank(handler.getETag())) {
- req.setIfMatch(handler.getETag());
- }
-
- changeset.addRequest(req);
- }
-
- private void batchDelete(
- final EntityInvocationHandler handler,
- final CommonODataEntity entity,
- final ODataChangeset changeset) {
-
- final URI deleteURI = handler.getEntityURI() == null ? entity.getEditLink() : handler.getEntityURI();
- LOG.debug("Delete '{}'", deleteURI);
-
- final ODataDeleteRequest req = factory.getClient().getCUDRequestFactory().getDeleteRequest(deleteURI);
-
- if (StringUtils.isNotBlank(handler.getETag())) {
- req.setIfMatch(handler.getETag());
- }
-
- changeset.addRequest(req);
- }
-
- private int processEntityContext(
- final EntityInvocationHandler handler,
- int pos,
- final TransactionItems items,
- final List<EntityLinkDesc> delayedUpdates,
- final ODataChangeset changeset) {
-
- LOG.debug("Process '{}'", handler);
-
- items.put(handler, null);
-
- final CommonODataEntity entity = handler.getEntity();
- entity.getNavigationLinks().clear();
-
- final AttachedEntityStatus currentStatus = factory.getContext().entityContext().getStatus(handler);
-
- if (AttachedEntityStatus.DELETED != currentStatus) {
- entity.getProperties().clear();
- CoreUtils.addProperties(factory.getClient(), handler.getPropertyChanges(), entity);
-
- if (entity instanceof ODataEntity) {
- ((ODataEntity) entity).getAnnotations().clear();
- CoreUtils.addAnnotations(factory.getClient(), handler.getAnnotations(), (ODataEntity) entity);
-
- for (Map.Entry<String, AnnotatableInvocationHandler> entry : handler.getPropAnnotatableHandlers().entrySet()) {
- CoreUtils.addAnnotations(factory.getClient(),
- entry.getValue().getAnnotations(), ((ODataEntity) entity).getProperty(entry.getKey()));
- }
- }
- }
-
- for (Map.Entry<NavigationProperty, Object> property : handler.getLinkChanges().entrySet()) {
- final ODataLinkType type = Collection.class.isAssignableFrom(property.getValue().getClass())
- ? ODataLinkType.ENTITY_SET_NAVIGATION
- : ODataLinkType.ENTITY_NAVIGATION;
-
- final Set<EntityInvocationHandler> toBeLinked = new HashSet<EntityInvocationHandler>();
- for (Object proxy : type == ODataLinkType.ENTITY_SET_NAVIGATION
- ? (Collection) property.getValue() : Collections.singleton(property.getValue())) {
-
- final EntityInvocationHandler target = (EntityInvocationHandler) Proxy.getInvocationHandler(proxy);
-
- final AttachedEntityStatus status = factory.getContext().entityContext().getStatus(target);
-
- final URI editLink = target.getEntity().getEditLink();
-
- if ((status == AttachedEntityStatus.ATTACHED || status == AttachedEntityStatus.LINKED) && !target.isChanged()) {
- entity.addLink(buildNavigationLink(
- property.getKey().name(),
- URIUtils.getURI(factory.getClient().getServiceRoot(), editLink.toASCIIString()), type));
- } else {
- if (!items.contains(target)) {
- pos = processEntityContext(target, pos, items, delayedUpdates, changeset);
- pos++;
- }
-
- final Integer targetPos = items.get(target);
- if (targetPos == null) {
- // schedule update for the current object
- LOG.debug("Schedule '{}' from '{}' to '{}'", type.name(), handler, target);
- toBeLinked.add(target);
- } else if (status == AttachedEntityStatus.CHANGED) {
- entity.addLink(buildNavigationLink(
- property.getKey().name(),
- URIUtils.getURI(factory.getClient().getServiceRoot(), editLink.toASCIIString()), type));
- } else {
- // create the link for the current object
- LOG.debug("'{}' from '{}' to (${}) '{}'", type.name(), handler, targetPos, target);
-
- entity.addLink(buildNavigationLink(property.getKey().name(), URI.create("$" + targetPos), type));
- }
- }
- }
-
- if (!toBeLinked.isEmpty()) {
- delayedUpdates.add(new EntityLinkDesc(property.getKey().name(), handler, toBeLinked, type));
- }
- }
-
- if (entity instanceof ODataEntity) {
- for (Map.Entry<String, AnnotatableInvocationHandler> entry
- : handler.getNavPropAnnotatableHandlers().entrySet()) {
-
- CoreUtils.addAnnotations(factory.getClient(),
- entry.getValue().getAnnotations(),
- (org.apache.olingo.commons.api.domain.v4.ODataLink) entity.getNavigationLink(entry.getKey()));
- }
- }
-
- // insert into the batch
- LOG.debug("{}: Insert '{}' into the batch", pos, handler);
- final AttachedEntityStatus processedStatus = batch(handler, entity, changeset);
-
- items.put(handler, pos);
-
- if (processedStatus != AttachedEntityStatus.DELETED) {
- int startingPos = pos;
-
- if (handler.getEntity().isMediaEntity() && handler.isChanged()) {
- // update media properties
- if (!handler.getPropertyChanges().isEmpty()) {
- final URI targetURI = currentStatus == AttachedEntityStatus.NEW
- ? URI.create("$" + startingPos)
- : URIUtils.getURI(
- factory.getClient().getServiceRoot(), handler.getEntity().getEditLink().toASCIIString());
- batchUpdate(handler, targetURI, entity, changeset);
- pos++;
- items.put(handler, pos);
- }
-
- // update media content
- if (handler.getStreamChanges() != null) {
- final URI targetURI = currentStatus == AttachedEntityStatus.NEW
- ? URI.create("$" + startingPos + "/$value")
- : URIUtils.getURI(
- factory.getClient().getServiceRoot(),
- handler.getEntity().getEditLink().toASCIIString() + "/$value");
-
- batchUpdateMediaEntity(handler, targetURI, handler.getStreamChanges(), changeset);
-
- // update media info (use null key)
- pos++;
- items.put(null, pos);
- }
- }
-
- for (Map.Entry<String, InputStream> streamedChanges : handler.getStreamedPropertyChanges().entrySet()) {
- final URI targetURI = currentStatus == AttachedEntityStatus.NEW
- ? URI.create("$" + startingPos) : URIUtils.getURI(
- factory.getClient().getServiceRoot(),
- CoreUtils.getMediaEditLink(streamedChanges.getKey(), entity).toASCIIString());
-
- batchUpdateMediaResource(handler, targetURI, streamedChanges.getValue(), changeset);
-
- // update media info (use null key)
- pos++;
- items.put(handler, pos);
- }
- }
-
- return pos;
- }
-
- private ODataLink buildNavigationLink(final String name, final URI uri, final ODataLinkType type) {
- ODataLink result;
-
- switch (type) {
- case ENTITY_NAVIGATION:
- result = factory.getClient().getObjectFactory().newEntityNavigationLink(name, uri);
- break;
-
- case ENTITY_SET_NAVIGATION:
- result = factory.getClient().getObjectFactory().newEntitySetNavigationLink(name, uri);
- break;
-
- default:
- throw new IllegalArgumentException("Invalid link type " + type.name());
- }
-
- return result;
- }
-
- private void processDelayedUpdates(
- final List<EntityLinkDesc> delayedUpdates,
- int pos,
- final TransactionItems items,
- final ODataChangeset changeset) {
-
- for (EntityLinkDesc delayedUpdate : delayedUpdates) {
- pos++;
- items.put(delayedUpdate.getSource(), pos);
-
- final CommonODataEntity changes =
- factory.getClient().getObjectFactory().newEntity(delayedUpdate.getSource().getEntity().getTypeName());
-
- AttachedEntityStatus status = factory.getContext().entityContext().getStatus(delayedUpdate.getSource());
-
- final URI sourceURI;
- if (status == AttachedEntityStatus.CHANGED) {
- sourceURI = URIUtils.getURI(
- factory.getClient().getServiceRoot(),
- delayedUpdate.getSource().getEntity().getEditLink().toASCIIString());
- } else {
- int sourcePos = items.get(delayedUpdate.getSource());
- sourceURI = URI.create("$" + sourcePos);
- }
-
- for (EntityInvocationHandler target : delayedUpdate.getTargets()) {
- status = factory.getContext().entityContext().getStatus(target);
-
- final URI targetURI;
- if (status == AttachedEntityStatus.CHANGED) {
- targetURI = URIUtils.getURI(
- factory.getClient().getServiceRoot(), target.getEntity().getEditLink().toASCIIString());
- } else {
- int targetPos = items.get(target);
- targetURI = URI.create("$" + targetPos);
- }
-
- changes.addLink(delayedUpdate.getType() == ODataLinkType.ENTITY_NAVIGATION
- ? factory.getClient().getObjectFactory().
- newEntityNavigationLink(delayedUpdate.getSourceName(), targetURI)
- : factory.getClient().getObjectFactory().
- newEntitySetNavigationLink(delayedUpdate.getSourceName(), targetURI));
-
- LOG.debug("'{}' from {} to {}", delayedUpdate.getType().name(), sourceURI, targetURI);
- }
-
- batchUpdate(delayedUpdate.getSource(), sourceURI, changes, changeset);
- }
- }
-
- private class TransactionItems {
-
- private final List<EntityInvocationHandler> keys = new ArrayList<EntityInvocationHandler>();
-
- private final List<Integer> values = new ArrayList<Integer>();
-
- public EntityInvocationHandler get(final Integer value) {
- if (value != null && values.contains(value)) {
- return keys.get(values.indexOf(value));
- } else {
- return null;
- }
- }
-
- public Integer get(final EntityInvocationHandler key) {
- if (key != null && keys.contains(key)) {
- return values.get(keys.indexOf(key));
- } else {
- return null;
- }
- }
-
- public void remove(final EntityInvocationHandler key) {
- if (keys.contains(key)) {
- values.remove(keys.indexOf(key));
- keys.remove(key);
- }
- }
-
- public void put(final EntityInvocationHandler key, final Integer value) {
- // replace just in case of null current value; otherwise add the new entry
- if (key != null && keys.contains(key) && values.get(keys.indexOf(key)) == null) {
- remove(key);
- }
- keys.add(key);
- values.add(value);
- }
-
- public List<Integer> sortedValues() {
- final List<Integer> sortedValues = new ArrayList<Integer>(values);
- Collections.<Integer>sort(sortedValues);
- return sortedValues;
- }
-
- public boolean contains(final EntityInvocationHandler key) {
- return keys.contains(key);
- }
-
- public int size() {
- return keys.size();
- }
-
- public boolean isEmpty() {
- return keys.isEmpty();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionItems.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionItems.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionItems.java
new file mode 100644
index 0000000..3e5ab6f
--- /dev/null
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionItems.java
@@ -0,0 +1,81 @@
+/*
+ * 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.ext.proxy.commons;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class TransactionItems {
+
+ private final List<EntityInvocationHandler> keys = new ArrayList<EntityInvocationHandler>();
+
+ private final List<Integer> values = new ArrayList<Integer>();
+
+ public EntityInvocationHandler get(final Integer value) {
+ if (value != null && values.contains(value)) {
+ return keys.get(values.indexOf(value));
+ } else {
+ return null;
+ }
+ }
+
+ public Integer get(final EntityInvocationHandler key) {
+ if (key != null && keys.contains(key)) {
+ return values.get(keys.indexOf(key));
+ } else {
+ return null;
+ }
+ }
+
+ public void remove(final EntityInvocationHandler key) {
+ if (keys.contains(key)) {
+ values.remove(keys.indexOf(key));
+ keys.remove(key);
+ }
+ }
+
+ public void put(final EntityInvocationHandler key, final Integer value) {
+ // replace just in case of null current value; otherwise add the new entry
+ if (key != null && keys.contains(key) && values.get(keys.indexOf(key)) == null) {
+ remove(key);
+ }
+ keys.add(key);
+ values.add(value);
+ }
+
+ public List<Integer> sortedValues() {
+ final List<Integer> sortedValues = new ArrayList<Integer>(values);
+ Collections.<Integer>sort(sortedValues);
+ return sortedValues;
+ }
+
+ public boolean contains(final EntityInvocationHandler key) {
+ return keys.contains(key);
+ }
+
+ public int size() {
+ return keys.size();
+ }
+
+ public boolean isEmpty() {
+ return keys.isEmpty();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
new file mode 100644
index 0000000..73a3f29
--- /dev/null
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/TransactionalPersistenceManagerImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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.ext.proxy.commons;
+
+import java.util.Iterator;
+import java.util.Map;
+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;
+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.request.batch.ODataBatchResponseItem;
+import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
+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.request.batch.ODataChangesetResponseItem;
+import org.apache.olingo.ext.proxy.EntityContainerFactory;
+
+/**
+ * {@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
+ * calling <tt>flush()</tt>.
+ */
+public class TransactionalPersistenceManagerImpl extends AbstractPersistenceManager {
+
+ private static final long serialVersionUID = -3320312269235907501L;
+
+ public TransactionalPersistenceManagerImpl(final EntityContainerFactory<?> factory) {
+ super(factory);
+ }
+
+ /**
+ * Transactional changes commit.
+ */
+ @Override
+ protected void doFlush(final PersistenceChanges changes, final TransactionItems items) {
+ final CommonODataBatchRequest request =
+ factory.getClient().getBatchRequestFactory().getBatchRequest(factory.getClient().getServiceRoot());
+ ((ODataRequest) request).setAccept(factory.getClient().getConfiguration().getDefaultBatchAcceptFormat());
+
+ final BatchManager streamManager = (BatchManager) ((ODataStreamedRequest) request).payloadManager();
+
+ final ODataChangeset changeset = streamManager.addChangeset();
+ for (Map.Entry<ODataBatchableRequest, EntityInvocationHandler> entry : changes.getChanges().entrySet()) {
+ changeset.addRequest(entry.getKey());
+ }
+
+ final ODataBatchResponse response = streamManager.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.
+ if (response.getStatusCode() != 202 && response.getStatusCode() != 200) {
+ throw new IllegalStateException("Operation failed");
+ }
+
+ if (!items.isEmpty()) {
+ final Iterator<ODataBatchResponseItem> iter = response.getBody();
+ if (!iter.hasNext()) {
+ throw new IllegalStateException("Unexpected operation result");
+ }
+
+ final ODataBatchResponseItem item = iter.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()) {
+ LOG.debug("Expected changeset item {}", changesetItemId);
+ final ODataResponse res = chgres.next();
+ if (res.getStatusCode() >= 400) {
+ throw new IllegalStateException("Transaction failed: " + res.getStatusMessage());
+ }
+
+ final EntityInvocationHandler handler = items.get(changesetItemId);
+
+ if (handler != null) {
+ if (res instanceof ODataEntityCreateResponse && res.getStatusCode() == 201) {
+ handler.setEntity(((ODataEntityCreateResponse) res).getBody());
+ LOG.debug("Upgrade created object '{}'", handler);
+ } else if (res instanceof ODataEntityUpdateResponse && res.getStatusCode() == 200) {
+ handler.setEntity(((ODataEntityUpdateResponse) res).getBody());
+ LOG.debug("Upgrade updated object '{}'", handler);
+ }
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/fit/src/main/java/org/apache/olingo/fit/V4Services.java
----------------------------------------------------------------------
diff --git a/fit/src/main/java/org/apache/olingo/fit/V4Services.java b/fit/src/main/java/org/apache/olingo/fit/V4Services.java
index e4a2c73..ce4d3ff 100644
--- a/fit/src/main/java/org/apache/olingo/fit/V4Services.java
+++ b/fit/src/main/java/org/apache/olingo/fit/V4Services.java
@@ -374,7 +374,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, true)
+ uriInfo.getRequestUri().toASCIIString(), accept, "People", type, format, null, null, true)
: super.getEntitySet(accept, "People", type)
: super.getEntitySet(uriInfo, accept, "People", top, skip, format, count, filter, orderby, skiptoken);
}
@@ -390,6 +390,43 @@ public class V4Services extends AbstractServices {
uriInfo.getRequestUri().toASCIIString(), accept, "Boss", StringUtils.EMPTY, format, null, null, false);
}
+ @DELETE
+ @Path("/Orders({entityId})/CustomerForOrder")
+ public Response getCustomerForOrder(
+ @Context UriInfo uriInfo,
+ @HeaderParam("Accept") @DefaultValue(StringUtils.EMPTY) String accept,
+ @PathParam("entityId") String entityId,
+ @QueryParam("$format") @DefaultValue(StringUtils.EMPTY) String format) {
+
+ try {
+ final Map.Entry<Accept, AbstractUtilities> utils = getUtilities(accept, format);
+
+ if (utils.getKey() == Accept.XML || utils.getKey() == Accept.TEXT) {
+ throw new UnsupportedMediaTypeException("Unsupported media type");
+ }
+
+ final Map.Entry<String, InputStream> entityInfo =
+ utils.getValue().readEntity("Orders", entityId, Accept.ATOM);
+
+ final InputStream entity = entityInfo.getValue();
+
+ ResWrap<AtomEntityImpl> container = atomDeserializer.read(entity, AtomEntityImpl.class);
+ if (container.getContextURL() == null) {
+ container = new ResWrap<AtomEntityImpl>(URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX)
+ + "Orders" + Constants.get(version, ConstantKey.ODATA_METADATA_ENTITY_SUFFIX)),
+ container.getMetadataETag(), container.getPayload());
+ }
+ final Entity entry = container.getPayload();
+
+ entry.getNavigationLink("CustomerForOrder");
+ } catch (Exception e) {
+
+ }
+
+ return getEntityInternal(
+ uriInfo.getRequestUri().toASCIIString(), accept, "Boss", StringUtils.EMPTY, format, null, null, false);
+ }
+
@GET
@Path("/Company")
public Response getSingletonCompany(
@@ -748,7 +785,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) {
@@ -770,7 +807,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);
@@ -868,8 +905,8 @@ public class V4Services extends AbstractServices {
} else {
final ResWrap<JSONEntityImpl> jcontainer =
mapper.readValue(IOUtils.toInputStream(entity, Constants.ENCODING),
- new TypeReference<JSONEntityImpl>() {
- });
+ new TypeReference<JSONEntityImpl>() {
+ });
entry = dataBinder.toAtomEntity(jcontainer.getPayload());
@@ -967,7 +1004,7 @@ public class V4Services extends AbstractServices {
final ResWrap<JSONEntityImpl> jsonContainer = mapper.readValue(
IOUtils.toInputStream(changes, Constants.ENCODING), new TypeReference<JSONEntityImpl>() {
- });
+ });
jsonContainer.getPayload().setType(typeInfo.getFullQualifiedName().toString());
entryChanges = dataBinder.toAtomEntity(jsonContainer.getPayload());
}
@@ -1001,7 +1038,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<AtomEntityImpl> container = atomDeserializer.read(entry, AtomEntityImpl.class);
// 2. Remove the contained entity
@@ -1247,8 +1284,8 @@ public class V4Services extends AbstractServices {
} else {
final ResWrap<JSONPropertyImpl> paramContainer =
mapper.readValue(IOUtils.toInputStream(param, Constants.ENCODING),
- new TypeReference<JSONPropertyImpl>() {
- });
+ new TypeReference<JSONPropertyImpl>() {
+ });
property = paramContainer.getPayload();
}
@@ -1288,7 +1325,7 @@ public class V4Services extends AbstractServices {
final ResWrap<AtomPropertyImpl> result = new ResWrap<AtomPropertyImpl>(
URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX)
- + "Microsoft.Test.OData.Services.ODataWCFService.Address"),
+ + "Microsoft.Test.OData.Services.ODataWCFService.Address"),
null,
(AtomPropertyImpl) entity.getProperty("address"));
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AbstractTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AbstractTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AbstractTestITCase.java
index 931fcf4..2bfcdf5 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AbstractTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AbstractTestITCase.java
@@ -91,6 +91,7 @@ public abstract class AbstractTestITCase {
protected void createAndDeleteOrder(
final InMemoryEntities container, final EntityContainerFactory<EdmEnabledODataClient> containerFactory) {
+
final Order order = container.getOrders().newOrder();
order.setOrderID(105);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityCreateTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityCreateTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityCreateTestITCase.java
index 3dadd6a..959e62b 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityCreateTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityCreateTestITCase.java
@@ -178,7 +178,7 @@ public class EntityCreateTestITCase extends AbstractTestITCase {
customer.setLastName("Martelli");
customer.setCity("Pescara");
customer.setEmails(Collections.<String>singleton("fabio.martelli@tirasa.net"));
- Address homeAddress = customer.factory().newHomeAddress();
+ final Address homeAddress = customer.factory().newHomeAddress();
homeAddress.setCity("Pescara");
homeAddress.setPostalCode("65100");
homeAddress.setStreet("viale Gabriele D'Annunzio 256");
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityUpdateTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityUpdateTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityUpdateTestITCase.java
index 943eda6..10d9a03 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityUpdateTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/EntityUpdateTestITCase.java
@@ -18,15 +18,22 @@
*/
package org.apache.olingo.fit.proxy.v4;
+import static org.apache.olingo.fit.proxy.v4.AbstractTestITCase.container;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
+import java.util.Calendar;
+import java.util.Collections;
import java.util.UUID;
+import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.client.api.v4.EdmEnabledODataClient;
+import org.apache.olingo.ext.proxy.EntityContainerFactory;
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.Order;
import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.types.OrderCollection;
@@ -43,16 +50,24 @@ import org.junit.Test;
*/
public class EntityUpdateTestITCase extends AbstractTestITCase {
+ protected EntityContainerFactory<EdmEnabledODataClient> getContainerFactory() {
+ return containerFactory;
+ }
+
+ protected InMemoryEntities getContainer() {
+ return container;
+ }
+
@Test
public void update() {
- Person person = container.getPeople().get(1);
+ Person person = getContainer().getPeople().get(1);
final Address address = person.getHomeAddress();
address.setCity("XXX");
- container.flush();
+ getContainer().flush();
- person = container.getPeople().get(1);
+ person = getContainer().getPeople().get(1);
assertEquals("XXX", person.getHomeAddress().getCity());
}
@@ -62,74 +77,106 @@ public class EntityUpdateTestITCase extends AbstractTestITCase {
orderDetailKey.setOrderID(7);
orderDetailKey.setProductID(5);
- OrderDetail orderDetail = container.getOrderDetails().get(orderDetailKey);
+ OrderDetail orderDetail = getContainer().getOrderDetails().get(orderDetailKey);
assertNotNull(orderDetail);
assertEquals(7, orderDetail.getOrderID(), 0);
assertEquals(5, orderDetail.getProductID(), 0);
orderDetail.setQuantity(5);
- container.flush();
+ getContainer().flush();
- orderDetail = container.getOrderDetails().get(orderDetailKey);
+ orderDetail = getContainer().getOrderDetails().get(orderDetailKey);
orderDetail.setQuantity(5);
}
@Test
public void patchLink() {
- Order order = container.getOrders().newOrder();
- order.setOrderID(400);
-
- OrderCollection orders = container.getOrders().newOrderCollection();
+ // 1. create customer
+ Customer customer = getContainer().getCustomers().newCustomer();
+ customer.setPersonID(977);
+ customer.setFirstName("Test");
+ customer.setLastName("Test");
+
+ final Address homeAddress = getContainer().complexFactory().newCompanyAddress();
+ homeAddress.setStreet("V.le Gabriele D'Annunzio");
+ homeAddress.setCity("Pescara");
+ homeAddress.setPostalCode("65127");
+ customer.setHomeAddress(homeAddress);
+
+ customer.setNumbers(Collections.<String>emptyList());
+ customer.setEmails(Collections.<String>emptyList());
+ customer.setCity("Pescara");
+
+ final Calendar birthday = Calendar.getInstance();
+ birthday.clear();
+ birthday.set(1977, 8, 8);
+ customer.setBirthday(birthday);
+
+ customer.setTimeBetweenLastTwoOrders(BigDecimal.valueOf(0.0000002));
+
+ // 2. create order and set it to customer
+ final int orderId = RandomUtils.nextInt(400, 410);
+
+ Order order = getContainer().getOrders().newOrder();
+ order.setOrderID(orderId);
+
+ final OrderCollection orders = getContainer().getOrders().newOrderCollection();
orders.add(order);
- Customer customer = container.getCustomers().get(1);
customer.setOrders(orders);
order.setCustomerForOrder(customer);
- container.flush();
+ getContainer().flush();
- order = container.getOrders().get(400);
- assertEquals(400, order.getOrderID().intValue());
+ // 3. check everything after flush
+ order = getContainer().getOrders().get(orderId);
+ assertEquals(orderId, order.getOrderID(), 0);
- customer = container.getCustomers().get(1);
+ customer = getContainer().getCustomers().get(977);
- assertEquals(2, customer.getOrders().size());
+ //assertEquals(1, customer.getOrders().size());
int count = 0;
for (Order inside : customer.getOrders()) {
- if (inside.getOrderID() == 400) {
+ if (inside.getOrderID() == orderId) {
count++;
}
}
assertEquals(1, count);
- assertEquals(1, order.getCustomerForOrder().getPersonID(), 0);
+ assertEquals(977, order.getCustomerForOrder().getPersonID(), 0);
+
+ // 4. delete customer and order
+ getContainer().getCustomers().delete(977);
+ getContainer().getOrders().delete(orderId);
+
+ getContainer().flush();
}
@Test
public void concurrentModification() {
- Order order = container.getOrders().get(8);
+ Order order = getContainer().getOrders().get(8);
final String etag = ((EntityInvocationHandler) Proxy.getInvocationHandler(order)).getETag();
assertTrue(StringUtils.isNotBlank(etag));
order.setShelfLife(BigDecimal.TEN);
- container.flush();
+ getContainer().flush();
- order = container.getOrders().get(8);
+ order = getContainer().getOrders().get(8);
assertEquals(BigDecimal.TEN, order.getShelfLife());
}
@Test
public void contained() {
- PaymentInstrument instrument = container.getAccounts().get(101).getMyPaymentInstruments().get(101901);
+ PaymentInstrument instrument = getContainer().getAccounts().get(101).getMyPaymentInstruments().get(101901);
final String newName = UUID.randomUUID().toString();
instrument.setFriendlyName(newName);
- container.flush();
+ getContainer().flush();
- instrument = container.getAccounts().get(101).getMyPaymentInstruments().get(101901);
+ instrument = getContainer().getAccounts().get(101).getMyPaymentInstruments().get(101901);
assertEquals(newName, instrument.getFriendlyName());
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a66bd98b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/MediaEntityTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/MediaEntityTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/MediaEntityTestITCase.java
index 60074b0..0ffe48a 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/MediaEntityTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/MediaEntityTestITCase.java
@@ -34,7 +34,6 @@ import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.ext.proxy.EntityContainerFactory;
import org.apache.olingo.fit.proxy.v4.demo.odatademo.DemoService;
import org.apache.olingo.fit.proxy.v4.demo.odatademo.types.Advertisement;
-import org.junit.BeforeClass;
import org.junit.Test;
/**
@@ -42,22 +41,30 @@ import org.junit.Test;
*/
public class MediaEntityTestITCase extends AbstractTestITCase {
- private static DemoService dcontainer;
+ private EntityContainerFactory<EdmEnabledODataClient> ecf;
- @BeforeClass
- public static void initContainer() {
- final EntityContainerFactory<EdmEnabledODataClient> otcontainerFactory =
- EntityContainerFactory.getV4(testDemoServiceRootURL);
- otcontainerFactory.getClient().getConfiguration().setDefaultBatchAcceptFormat(ContentType.APPLICATION_OCTET_STREAM);
- dcontainer = otcontainerFactory.getEntityContainer(DemoService.class);
- assertNotNull(dcontainer);
+ private DemoService ime;
+
+ protected EntityContainerFactory<EdmEnabledODataClient> getContainerFactory() {
+ if (ecf == null) {
+ ecf = EntityContainerFactory.getV4(testDemoServiceRootURL);
+ ecf.getClient().getConfiguration().setDefaultBatchAcceptFormat(ContentType.APPLICATION_OCTET_STREAM);
+ }
+ return ecf;
+ }
+
+ protected DemoService getContainer() {
+ if (ime == null) {
+ ime = getContainerFactory().getEntityContainer(DemoService.class);
+ }
+ return ime;
}
@Test
public void read() throws IOException {
final UUID uuid = UUID.fromString("f89dee73-af9f-4cd4-b330-db93c25ff3c7");
- final Advertisement adv = dcontainer.getAdvertisements().get(uuid);
+ final Advertisement adv = getContainer().getAdvertisements().get(uuid);
assertTrue(adv.getAirDate() instanceof Calendar);
final InputStream is = adv.getStream();
@@ -69,38 +76,38 @@ public class MediaEntityTestITCase extends AbstractTestITCase {
public void update() throws IOException {
final UUID uuid = UUID.fromString("f89dee73-af9f-4cd4-b330-db93c25ff3c7");
- final Advertisement adv = dcontainer.getAdvertisements().get(uuid);
+ final Advertisement adv = getContainer().getAdvertisements().get(uuid);
assertNotNull(adv);
final String random = RandomStringUtils.random(124, "abcdefghijklmnopqrstuvwxyz");
adv.setStream(IOUtils.toInputStream(random));
- dcontainer.flush();
+ getContainer().flush();
- assertEquals(random, IOUtils.toString(dcontainer.getAdvertisements().get(uuid).getStream()));
+ assertEquals(random, IOUtils.toString(getContainer().getAdvertisements().get(uuid).getStream()));
}
@Test
public void create() throws IOException {
final String random = RandomStringUtils.random(124, "abcdefghijklmnopqrstuvwxyz");
- final Advertisement adv = dcontainer.getAdvertisements().newAdvertisement();
+ final Advertisement adv = getContainer().getAdvertisements().newAdvertisement();
adv.setStream(IOUtils.toInputStream(random));
adv.setAirDate(Calendar.getInstance());
- dcontainer.flush();
+ getContainer().flush();
final UUID uuid = adv.getID();
- containerFactory.getContext().detachAll();
-
- assertEquals(random, IOUtils.toString(dcontainer.getAdvertisements().get(uuid).getStream()));
+ getContainerFactory().getContext().detachAll();
+
+ assertEquals(random, IOUtils.toString(getContainer().getAdvertisements().get(uuid).getStream()));
- containerFactory.getContext().detachAll();
+ getContainerFactory().getContext().detachAll();
- dcontainer.getAdvertisements().delete(uuid);
- dcontainer.flush();
+ getContainer().getAdvertisements().delete(uuid);
+ getContainer().flush();
- assertNull(dcontainer.getAdvertisements().get(uuid));
+ assertNull(getContainer().getAdvertisements().get(uuid));
}
}