[OLINGO-266] merge

This commit is contained in:
Stephan Klevenz 2014-05-19 14:49:03 +02:00
parent 892ad83956
commit 1591f8742c
11 changed files with 119 additions and 88 deletions

View File

@ -73,7 +73,7 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
super(client, containerHandler);
this.internal = internal;
this.typeRef = typeRef;
this.entityHandler = EntityInvocationHandler.class.cast(this);
this.entityHandler = null;
}
protected AbstractStructuredInvocationHandler(
@ -85,15 +85,21 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
super(client, entityHandler == null ? null : entityHandler.containerHandler);
this.internal = internal;
this.typeRef = typeRef;
this.entityHandler = entityHandler;
// prevent memory leak
this.entityHandler = entityHandler == this ? null : entityHandler;
}
public EntityInvocationHandler getEntityHandler() {
return entityHandler;
return entityHandler == null
? this instanceof EntityInvocationHandler
? EntityInvocationHandler.class.cast(this)
: null
: entityHandler;
}
public void setEntityHandler(EntityInvocationHandler entityHandler) {
this.entityHandler = entityHandler;
// prevent memory leak
this.entityHandler = entityHandler == this ? null : entityHandler;
}
public Class<?> getTypeRef() {
@ -110,14 +116,14 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
return Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {returnType},
OperationInvocationHandler.getInstance(entityHandler));
OperationInvocationHandler.getInstance(getEntityHandler()));
} else if ("factory".equals(method.getName()) && ArrayUtils.isEmpty(args)) {
final Class<?> returnType = method.getReturnType();
return Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {returnType},
ComplexFactoryInvocationHandler.getInstance(entityHandler, this));
ComplexFactoryInvocationHandler.getInstance(getEntityHandler(), this));
} else if (method.getName().startsWith("get")) {
// Assumption: for each getter will always exist a setter and viceversa.
// get method annotation and check if it exists as expected
@ -171,8 +177,8 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
protected void attach() {
if (entityHandler != null && !entityContext.isAttached(entityHandler)) {
entityContext.attach(entityHandler, AttachedEntityStatus.ATTACHED);
if (getEntityHandler() != null && !entityContext.isAttached(getEntityHandler())) {
entityContext.attach(getEntityHandler(), AttachedEntityStatus.ATTACHED);
}
}
@ -181,12 +187,12 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
}
protected void attach(final AttachedEntityStatus status, final boolean override) {
if (entityContext.isAttached(entityHandler)) {
if (entityContext.isAttached(getEntityHandler())) {
if (override) {
entityContext.setStatus(entityHandler, status);
entityContext.setStatus(getEntityHandler(), status);
}
} else {
entityContext.attach(entityHandler, status);
entityContext.attach(getEntityHandler(), status);
}
}
@ -276,8 +282,8 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca
private void setNavigationPropertyValue(final NavigationProperty property, final Object value) {
// 1) attach source entity
if (!entityContext.isAttached(entityHandler)) {
entityContext.attach(entityHandler, AttachedEntityStatus.CHANGED);
if (!entityContext.isAttached(getEntityHandler())) {
entityContext.attach(getEntityHandler(), AttachedEntityStatus.CHANGED);
}
// 2) attach the target entity handlers

View File

@ -99,7 +99,7 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
@Override
protected Object getPropertyValue(final String name, final Type type) {
try {
return CoreUtils.getValueFromProperty(client, getComplex().get(name), type, entityHandler);
return CoreUtils.getValueFromProperty(client, getComplex().get(name), type, getEntityHandler());
} catch (Exception e) {
throw new IllegalArgumentException("Error getting value for property '" + name + "'", e);
}
@ -155,8 +155,8 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
client.getBinder().add(getComplex(), CoreUtils.getODataProperty(client, property.name(), type, toBeAdded));
if (entityHandler != null && !entityContext.isAttached(entityHandler)) {
entityContext.attach(entityHandler, AttachedEntityStatus.CHANGED);
if (getEntityHandler() != null && !entityContext.isAttached(getEntityHandler())) {
entityContext.attach(getEntityHandler(), AttachedEntityStatus.CHANGED);
}
}
@ -181,6 +181,6 @@ public class ComplexInvocationHandler extends AbstractStructuredInvocationHandle
@Override
public boolean isChanged() {
return entityHandler == null ? false : entityHandler.isChanged();
return getEntityHandler() == null ? false : getEntityHandler().isChanged();
}
}

View File

@ -154,7 +154,7 @@ class ContainerImpl implements Container {
EntityContainerFactory.getContext().detachAll();
}
private void batch(
private AttachedEntityStatus batch(
final EntityInvocationHandler handler,
final CommonODataEntity entity,
final ODataChangeset changeset) {
@ -162,20 +162,21 @@ class ContainerImpl implements Container {
switch (EntityContainerFactory.getContext().entityContext().getStatus(handler)) {
case NEW:
batchCreate(handler, entity, changeset);
break;
return AttachedEntityStatus.NEW;
case CHANGED:
batchUpdate(handler, entity, changeset);
break;
return AttachedEntityStatus.CHANGED;
case DELETED:
batchDelete(handler, entity, changeset);
break;
return AttachedEntityStatus.DELETED;
default:
if (handler.isChanged()) {
batchUpdate(handler, entity, changeset);
}
return AttachedEntityStatus.CHANGED;
}
}
@ -239,10 +240,10 @@ class ContainerImpl implements Container {
client.getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) client).getCUDRequestFactory().
getEntityUpdateRequest(handler.getEntityURI(),
org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
: ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) client).getCUDRequestFactory().
getEntityUpdateRequest(handler.getEntityURI(),
org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
req.setPrefer(new ODataPreferences(client.getServiceVersion()).returnContent());
@ -265,10 +266,10 @@ class ContainerImpl implements Container {
client.getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0
? ((org.apache.olingo.client.api.v3.EdmEnabledODataClient) client).getCUDRequestFactory().
getEntityUpdateRequest(uri,
org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
org.apache.olingo.client.api.communication.request.cud.v3.UpdateType.PATCH, changes)
: ((org.apache.olingo.client.api.v4.EdmEnabledODataClient) client).getCUDRequestFactory().
getEntityUpdateRequest(uri,
org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
org.apache.olingo.client.api.communication.request.cud.v4.UpdateType.PATCH, changes);
req.setPrefer(new ODataPreferences(client.getServiceVersion()).returnContent());
@ -371,52 +372,53 @@ class ContainerImpl implements Container {
// insert into the batch
LOG.debug("{}: Insert '{}' into the batch", pos, handler);
batch(handler, entity, changeset);
final AttachedEntityStatus processedStatus = batch(handler, entity, changeset);
items.put(handler, pos);
int startingPos = pos;
if (processedStatus != AttachedEntityStatus.DELETED) {
int startingPos = pos;
if (handler.getEntity().isMediaEntity()) {
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.getServiceRoot(), handler.getEntity().getEditLink().toASCIIString());
batchUpdate(handler, targetURI, entity, changeset);
pos++;
items.put(handler, pos);
}
// update media properties
if (!handler.getPropertyChanges().isEmpty()) {
final URI targetURI = currentStatus == AttachedEntityStatus.NEW
? URI.create("$" + startingPos)
: URIUtils.getURI(factory.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.getServiceRoot(), handler.getEntity().getEditLink().toASCIIString() + "/$value");
batchUpdateMediaEntity(handler, targetURI, handler.getStreamChanges(), changeset);
// update media info (use null key)
pos++;
items.put(null, pos);
}
}
// update media content
if (handler.getStreamChanges() != null) {
for (Map.Entry<String, InputStream> streamedChanges : handler.getStreamedPropertyChanges().entrySet()) {
final URI targetURI = currentStatus == AttachedEntityStatus.NEW
? URI.create("$" + startingPos + "/$value")
: URIUtils.getURI(
factory.getServiceRoot(), handler.getEntity().getEditLink().toASCIIString() + "/$value");
? URI.create("$" + startingPos) : URIUtils.getURI(
factory.getServiceRoot(),
CoreUtils.getMediaEditLink(streamedChanges.getKey(), entity).toASCIIString());
batchUpdateMediaEntity(handler, targetURI, handler.getStreamChanges(), changeset);
batchUpdateMediaResource(handler, targetURI, streamedChanges.getValue(), changeset);
// update media info (use null key)
pos++;
items.put(null, pos);
items.put(handler, pos);
}
}
for (Map.Entry<String, InputStream> streamedChanges : handler.getStreamedPropertyChanges().entrySet()) {
final URI targetURI = currentStatus == AttachedEntityStatus.NEW
? URI.create("$" + startingPos) : URIUtils.getURI(
factory.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;
}

View File

@ -22,6 +22,7 @@ import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.URI;
@ -121,9 +122,9 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
getUUID().getType(),
CoreUtils.getKey(client, typeRef, entity));
this.streamedPropertyChanges.clear();
this.propertyChanges.clear();
this.linkChanges.clear();
this.streamedPropertyChanges.clear();
this.propertiesTag = 0;
this.linksTag = 0;
}
@ -189,20 +190,24 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
@Override
protected Object getPropertyValue(final String name, final Type type) {
try {
final CommonODataProperty property = getEntity().getProperty(name);
Object res;
if (propertyChanges.containsKey(name)) {
res = propertyChanges.get(name);
if (!(type instanceof ParameterizedType) && (Class<?>) type == InputStream.class) {
return getStreamedProperty(name);
} else {
res = CoreUtils.getValueFromProperty(client, property, type, this);
final CommonODataProperty property = getEntity().getProperty(name);
if (res != null) {
addPropertyChanges(name, res);
Object res;
if (propertyChanges.containsKey(name)) {
res = propertyChanges.get(name);
} else {
res = CoreUtils.getValueFromProperty(client, property, type, this);
if (res != null) {
chacheProperty(name, res);
}
}
}
return res;
return res;
}
} catch (Exception e) {
throw new IllegalArgumentException("Error getting value for property '" + name + "'", e);
}
@ -235,7 +240,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
@Override
@SuppressWarnings("unchecked")
protected void setPropertyValue(final Property property, final Object value) {
if (property.type().equalsIgnoreCase(EdmPrimitiveTypeKind.Stream.toString())) {
if (property.type().equalsIgnoreCase("Edm." + EdmPrimitiveTypeKind.Stream.toString())) {
setStreamedProperty(property, (InputStream) value);
} else {
addPropertyChanges(property.name(), value);
@ -306,14 +311,15 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
return this.stream;
}
public Object getStreamedProperty(final Property property) {
InputStream res = streamedPropertyChanges.get(property.name());
public Object getStreamedProperty(final String name) {
InputStream res = streamedPropertyChanges.get(name);
try {
if (res == null) {
final URI link = URIUtils.getURI(
containerHandler.getFactory().getServiceRoot(),
CoreUtils.getMediaEditLink(property.name(), getEntity()).toASCIIString());
CoreUtils.getMediaEditLink(name, getEntity()).toASCIIString());
final ODataMediaRequest req = client.getRetrieveRequestFactory().getMediaRequest(link);
res = req.execute().getBody();
@ -328,7 +334,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
}
private void setStreamedProperty(final Property property, final InputStream input) {
final Object obj = propertyChanges.get(property.name());
final Object obj = streamedPropertyChanges.get(property.name());
if (obj instanceof InputStream) {
IOUtils.closeQuietly((InputStream) obj);
}
@ -347,7 +353,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
}
if (navPropValue != null) {
addLinkChanges(property, navPropValue);
cacheLink(property, navPropValue);
}
return navPropValue;
@ -355,6 +361,10 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
@Override
protected void addPropertyChanges(final String name, final Object value) {
propertyChanges.put(name, value);
}
protected void chacheProperty(final String name, final Object value) {
final int checkpoint = propertyChanges.hashCode();
propertyChanges.put(name, value);
updatePropertiesTag(checkpoint);
@ -362,6 +372,10 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
@Override
protected void addLinkChanges(final NavigationProperty navProp, final Object value) {
linkChanges.put(navProp, value);
}
protected void cacheLink(final NavigationProperty navProp, final Object value) {
final int checkpoint = linkChanges.hashCode();
linkChanges.put(navProp, value);
updateLinksTag(checkpoint);

View File

@ -426,7 +426,7 @@ public final class CoreUtils {
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {getter.getReturnType()},
ComplexInvocationHandler.getInstance(
client, property.getName(), getter.getReturnType(), null));
client, property.getName(), getter.getReturnType(), null));
populate(client, complex, Property.class, property.getValue().asComplex().iterator());
setPropertyValue(bean, getter, complex);
@ -451,7 +451,7 @@ public final class CoreUtils {
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {collItemClass},
ComplexInvocationHandler.getInstance(
client, property.getName(), collItemClass, null));
client, property.getName(), collItemClass, null));
populate(client, collItem, Property.class, value.asComplex().iterator());
collection.add(collItem);
@ -496,7 +496,7 @@ public final class CoreUtils {
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {internalRef},
ComplexInvocationHandler.getInstance(
client, property.getValue().asComplex(), internalRef, entityHandler));
client, property.getValue().asComplex(), internalRef, entityHandler));
} else if (property.hasCollectionValue()) {
final ArrayList<Object> collection = new ArrayList<Object>();
@ -511,7 +511,7 @@ public final class CoreUtils {
Thread.currentThread().getContextClassLoader(),
new Class<?>[] {internalRef},
ComplexInvocationHandler.getInstance(
client, value.asComplex(), internalRef, entityHandler));
client, value.asComplex(), internalRef, entityHandler));
collection.add(collItem);
}
@ -560,8 +560,8 @@ public final class CoreUtils {
if (ns != null && ann != null) {
if (property.getValue().getTypeName().replaceAll("^Collection\\(", "").replaceAll("\\)$", "").equals(
new FullQualifiedName(ns.value(), annType.isAssignableFrom(EnumType.class)
? EnumType.class.cast(ann).name()
: ComplexType.class.cast(ann).name()).toString())) {
? EnumType.class.cast(ann).name()
: ComplexType.class.cast(ann).name()).toString())) {
return clazz;
}
}

View File

@ -116,7 +116,7 @@ public abstract class AbstractServices {
private static final Pattern REQUEST_PATTERN = Pattern.compile("(.*) (http://.*) HTTP/.*");
private static final Pattern BATCH_REQUEST_REF_PATTERN = Pattern.compile("(.*) ([$].*) HTTP/.*");
private static final Pattern BATCH_REQUEST_REF_PATTERN = Pattern.compile("(.*) ([$]\\d+)(.*) HTTP/.*");
private static final Pattern REF_PATTERN = Pattern.compile("([$]\\d+)");
@ -242,7 +242,7 @@ public abstract class AbstractServices {
return xml.createResponse(new ByteArrayInputStream(content.toByteArray()), null, Accept.JSON_FULLMETA);
} catch (Exception e) {
LOG.error("While creating StoredPI", e);
return xml.createFaultResponse(Accept.JSON_FULLMETA.toString(version),e);
return xml.createFaultResponse(Accept.JSON_FULLMETA.toString(version), e);
}
}
@ -284,7 +284,7 @@ public abstract class AbstractServices {
url = matcher.group(2);
method = matcher.group(1);
} else if (matcherRef.find()) {
url = references.get(matcherRef.group(2));
url = references.get(matcherRef.group(2)) + matcherRef.group(3);
method = matcherRef.group(1);
} else {
url = null;

View File

@ -156,7 +156,7 @@ public class V3Services extends AbstractServices {
addChangesetItemIntro(chbos, lastContebtID, cboundary);
res = bodyPartRequest(new MimeBodyPart(part.getInputStream()), references);
if (res.getStatus() >= 400) {
if (res==null || res.getStatus() >= 400) {
throw new Exception("Failure processing changeset");
}

View File

@ -293,7 +293,7 @@ public class V4Services extends AbstractServices {
addChangesetItemIntro(chbos, lastContebtID, cboundary);
res = bodyPartRequest(new MimeBodyPart(part.getInputStream()), references);
if (res.getStatus() >= 400) {
if (res==null || res.getStatus() >= 400) {
throw new Exception("Failure processing changeset");
}
@ -1269,9 +1269,15 @@ public class V4Services extends AbstractServices {
assert "Microsoft.Test.OData.Services.ODataWCFService.Address".equals(entity.getType());
assert entity.getProperty("address").getValue().isComplex();
final ResWrap<AtomPropertyImpl> result = new ResWrap<AtomPropertyImpl>(
URI.create(Constants.get(version, ConstantKey.ODATA_METADATA_PREFIX)
+ "Microsoft.Test.OData.Services.ODataWCFService.Address"),
null,
(AtomPropertyImpl) entity.getProperty("address"));
return xml.createResponse(
null,
xml.writeProperty(acceptType, entity.getProperty("address")),
xml.writeProperty(acceptType, result),
null,
acceptType);
} catch (Exception e) {

View File

@ -49,6 +49,8 @@ public abstract class AbstractTestITCase {
protected static String testStaticServiceRootURL;
protected static String testDemoServiceRootURL;
protected static String testKeyAsSegmentServiceRootURL;
protected static String testActionOverloadingServiceRootURL;
@ -68,6 +70,7 @@ public abstract class AbstractTestITCase {
@BeforeClass
public static void setUpODataServiceRoot() throws IOException {
testStaticServiceRootURL = "http://localhost:9080/stub/StaticService/V40/Static.svc";
testDemoServiceRootURL = "http://localhost:9080/stub/StaticService/V40/Demo.svc";
testKeyAsSegmentServiceRootURL = "http://localhost:9080/stub/StaticService/V40/KeyAsSegment.svc";
testActionOverloadingServiceRootURL = "http://localhost:9080/stub/StaticService/V40/ActionOverloading.svc";
testOpenTypeServiceRootURL = "http://localhost:9080/stub/StaticService/V40/OpenType.svc";

View File

@ -283,7 +283,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
@Override
public ODataProperty getODataProperty(final ResWrap<Property> resource) {
final EdmTypeInfo typeInfo = buildTypeInfo(resource.getContextURL(), resource.getMetadataETag(),
resource.getPayload().getName(), resource.getPayload().getType());
resource.getPayload().getName(), resource.getPayload().getType());
final ODataProperty property = new ODataPropertyImpl(resource.getPayload().getName(),
getODataValue(typeInfo == null