[OLINGO-1155]Delta support in Json format
This commit is contained in:
parent
f6dd0deacc
commit
f7e5a5c716
|
@ -319,4 +319,18 @@ public interface Constants {
|
|||
String ASSOCIATION_LINK_TYPE = ContentType.APPLICATION_XML.toContentTypeString();
|
||||
String ENTITY_COLLECTION_BINDING_LINK_TYPE = ContentType.APPLICATION_XML.toContentTypeString();
|
||||
String ENTITY_BINDING_LINK_TYPE = ContentType.APPLICATION_XML.toContentTypeString();
|
||||
|
||||
//For v4.01 Delta
|
||||
|
||||
String LINK = "/$link";
|
||||
String DELETEDLINK = "/$deletedLink";
|
||||
String DELTA = "/$delta";
|
||||
String DELTAVALUE = "delta";
|
||||
String AT = "@";
|
||||
String DELETEDENTITY = "/$deletedEntity";
|
||||
String DELTALINK = "@deltaLink";
|
||||
String HASH = "#";
|
||||
String REMOVED = "removed";
|
||||
String ENTITY = "/$entity";
|
||||
String REASON = "Reason";
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.net.URI;
|
|||
/**
|
||||
* A deleted entity contains the reason for deletion and the id.
|
||||
*/
|
||||
public class DeletedEntity {
|
||||
public class DeletedEntity extends Entity{
|
||||
|
||||
/**
|
||||
* Reason of the removal from the list
|
||||
|
|
|
@ -40,7 +40,12 @@ public enum ODataServiceVersion {
|
|||
/**
|
||||
* OData Version 4.0
|
||||
*/
|
||||
V40("4.0");
|
||||
V40("4.0"),
|
||||
/**
|
||||
* OData Version 4.01
|
||||
*/
|
||||
V401("4.01");
|
||||
|
||||
|
||||
private static final Pattern DATASERVICEVERSIONPATTERN = Pattern.compile("(\\p{Digit}+\\.\\p{Digit}+)(:?;.*)?");
|
||||
|
||||
|
@ -57,7 +62,8 @@ public enum ODataServiceVersion {
|
|||
return V10.toString().equals(possibleDataServiceVersion)
|
||||
|| V20.toString().equals(possibleDataServiceVersion)
|
||||
|| V30.toString().equals(possibleDataServiceVersion)
|
||||
|| V40.toString().equals(possibleDataServiceVersion);
|
||||
|| V40.toString().equals(possibleDataServiceVersion)
|
||||
|| V401.toString().equals(possibleDataServiceVersion);
|
||||
} else {
|
||||
throw new IllegalArgumentException(version);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public enum PreferenceName {
|
|||
INCLUDE_ANNOTATIONS("odata.include-annotations"),
|
||||
MAX_PAGE_SIZE("odata.maxpagesize"),
|
||||
TRACK_CHANGES("odata.track-changes"),
|
||||
TRACK_CHANGES_PREF("track-changes"),
|
||||
RETURN("return"),
|
||||
RESPOND_ASYNC("respond-async"),
|
||||
WAIT("wait"),
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.olingo.server.api.etag.ETagHelper;
|
|||
import org.apache.olingo.server.api.etag.ServiceMetadataETagSupport;
|
||||
import org.apache.olingo.server.api.prefer.Preferences;
|
||||
import org.apache.olingo.server.api.serializer.EdmAssistedSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
|
@ -184,4 +185,13 @@ public abstract class OData {
|
|||
*/
|
||||
public abstract EdmAssistedSerializer createEdmAssistedSerializer(final ContentType contentType)
|
||||
throws SerializerException;
|
||||
|
||||
/**
|
||||
* Creates a new serializer object capable of working without EDM information
|
||||
* for rendering delta content in the specified format.
|
||||
* @param contentType a content type supported by Olingo
|
||||
* @param version versions supported by Olingo
|
||||
*/
|
||||
public abstract EdmDeltaSerializer createEdmDeltaSerializer(final ContentType contentType,
|
||||
final List<String> versions) throws SerializerException;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.server.api.serializer;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
|
||||
public interface EdmDeltaSerializer {
|
||||
|
||||
/**
|
||||
* Writes collection of delta-response into an InputStream.
|
||||
* Information from the EDM is used in addition to information from the data and preferred,
|
||||
* but the serializer works without any EDM information as well.
|
||||
* Linked data is always written as expanded items (so closed reference loops have to be avoided).
|
||||
* @param metadata metadata for the service
|
||||
* @param referencedEntityType the {@link EdmEntityType} or <code>null</code> if not available
|
||||
* @param delta the delta data as entity collection
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
SerializerResult entityCollection(ServiceMetadata metadata, EdmEntityType referencedEntityType,
|
||||
Delta delta, EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
|
||||
}
|
|
@ -41,6 +41,8 @@ public class SerializerException extends ODataLibraryException {
|
|||
INCONSISTENT_PROPERTY_TYPE,
|
||||
/** parameter: property name */
|
||||
MISSING_PROPERTY,
|
||||
/** parameter: Delta property name */
|
||||
MISSING_DELTA_PROPERTY,
|
||||
/** parameter: - */
|
||||
MISSING_ID,
|
||||
/** parameters: property name, property value */
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SkipOption;
|
||||
|
@ -68,4 +69,9 @@ public interface UriInfoAll {
|
|||
* @return Object containing information of the $top option
|
||||
*/
|
||||
TopOption getTopOption();
|
||||
|
||||
/**
|
||||
* @return Object containing information of the $deltatoken option
|
||||
*/
|
||||
DeltaTokenOption getDeltaTokenOption();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.olingo.server.api.uri;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
|
@ -91,4 +92,9 @@ public interface UriInfoCrossjoin {
|
|||
* @return Object containing information of the $top option
|
||||
*/
|
||||
TopOption getTopOption();
|
||||
|
||||
/**
|
||||
* @return Object containing information of the $deltatoken option
|
||||
*/
|
||||
DeltaTokenOption getDeltaTokenOption();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
|
@ -69,7 +70,12 @@ public interface UriInfoResource {
|
|||
* @return Object containing information of the $count option
|
||||
*/
|
||||
CountOption getCountOption();
|
||||
|
||||
|
||||
/**
|
||||
* @return Object containing information of the $deltatoken option
|
||||
*/
|
||||
DeltaTokenOption getDeltaTokenOption();
|
||||
|
||||
/**
|
||||
* @return Object containing information of the $orderby option
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.server.api.uri.queryoption;
|
||||
|
||||
public interface DeltaTokenOption extends SystemQueryOption {
|
||||
|
||||
/**
|
||||
* @return Value of $deltatoken
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
}
|
|
@ -83,7 +83,12 @@ public enum SystemQueryOptionKind {
|
|||
* @see LevelsExpandOption
|
||||
*/
|
||||
LEVELS("$levels"),
|
||||
|
||||
|
||||
/**
|
||||
* @see deltaTokenOption
|
||||
*/
|
||||
DELTATOKEN("$deltatoken"),
|
||||
|
||||
/**
|
||||
* @see ApplyOption
|
||||
*/
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.apache.olingo.server.api.uri.UriResourceRoot;
|
|||
import org.apache.olingo.server.api.uri.UriResourceSingleton;
|
||||
import org.apache.olingo.server.api.uri.UriResourceValue;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
|
@ -259,7 +260,10 @@ public class RequestURLHierarchyVisitor implements RequestURLVisitor {
|
|||
if (info.getSkipTokenOption() != null) {
|
||||
visit(info.getSkipTokenOption());
|
||||
}
|
||||
|
||||
|
||||
if (info.getDeltaTokenOption() != null) {
|
||||
visit(info.getDeltaTokenOption());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -313,7 +317,11 @@ public class RequestURLHierarchyVisitor implements RequestURLVisitor {
|
|||
@Override
|
||||
public void visit(UriResourceRef info) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(DeltaTokenOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceRoot info) {
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.olingo.server.api.uri.UriResourceRoot;
|
|||
import org.apache.olingo.server.api.uri.UriResourceSingleton;
|
||||
import org.apache.olingo.server.api.uri.UriResourceValue;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
|
@ -96,7 +97,9 @@ public interface RequestURLVisitor {
|
|||
void visit(TopOption option);
|
||||
|
||||
void visit(UriResourceCount option);
|
||||
|
||||
|
||||
void visit(DeltaTokenOption option);
|
||||
|
||||
void visit(UriResourceRef info);
|
||||
|
||||
void visit(UriResourceRoot info);
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.olingo.server.api.etag.ETagHelper;
|
|||
import org.apache.olingo.server.api.etag.ServiceMetadataETagSupport;
|
||||
import org.apache.olingo.server.api.prefer.Preferences;
|
||||
import org.apache.olingo.server.api.serializer.EdmAssistedSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
|
@ -53,6 +54,8 @@ import org.apache.olingo.server.core.prefer.PreferencesImpl;
|
|||
import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl;
|
||||
import org.apache.olingo.server.core.serializer.json.EdmAssistedJsonSerializer;
|
||||
import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
|
||||
import org.apache.olingo.server.core.serializer.json.JsonDeltaSerializer;
|
||||
import org.apache.olingo.server.core.serializer.json.JsonDeltaSerializerWithNavigations;
|
||||
import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializer;
|
||||
import org.apache.olingo.server.core.uri.UriHelperImpl;
|
||||
|
||||
|
@ -96,6 +99,33 @@ public class ODataImpl extends OData {
|
|||
throw new SerializerException("Unsupported format: " + contentType.toContentTypeString(),
|
||||
SerializerException.MessageKeys.UNSUPPORTED_FORMAT, contentType.toContentTypeString());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EdmDeltaSerializer createEdmDeltaSerializer(final ContentType contentType, final List<String> versions)
|
||||
throws SerializerException {
|
||||
if (contentType.isCompatible(ContentType.APPLICATION_JSON)) {
|
||||
if(versions!=null && versions.size()>0){
|
||||
return getMaxVersion(versions)>4 ? new JsonDeltaSerializerWithNavigations(contentType):
|
||||
new JsonDeltaSerializer(contentType);
|
||||
}
|
||||
return new JsonDeltaSerializerWithNavigations(contentType);
|
||||
}
|
||||
throw new SerializerException("Unsupported format: " + contentType.toContentTypeString(),
|
||||
SerializerException.MessageKeys.UNSUPPORTED_FORMAT, contentType.toContentTypeString());
|
||||
}
|
||||
|
||||
private float getMaxVersion(List<String> versions) {
|
||||
Float versionValue [] = new Float [versions.size()];
|
||||
int i=0;
|
||||
Float max=new Float(0);
|
||||
for(String version:versions){
|
||||
Float ver = Float.valueOf(version);
|
||||
versionValue[i++] = ver;
|
||||
max = max > ver ? max : ver ;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ODataHttpHandler createHandler(final ServiceMetadata serviceMetadata) {
|
||||
|
|
|
@ -105,7 +105,11 @@ public class DebugTabUri implements DebugTab {
|
|||
} else if (uriInfo.getKind() == UriInfoKind.entityId) {
|
||||
appendType(gen, "typeCast", uriInfo.asUriInfoEntityId().getEntityTypeCast());
|
||||
}
|
||||
|
||||
|
||||
if (uriInfo.getDeltaTokenOption() != null) {
|
||||
gen.writeStringField("deltatoken", uriInfo.getDeltaTokenOption().getValue());
|
||||
}
|
||||
|
||||
if (uriInfo.getFormatOption() != null) {
|
||||
gen.writeStringField("format", uriInfo.getFormatOption().getFormat());
|
||||
}
|
||||
|
|
|
@ -78,7 +78,8 @@ public class PreferencesImpl implements Preferences {
|
|||
|
||||
@Override
|
||||
public boolean hasTrackChanges() {
|
||||
return preferences.containsKey(PreferenceName.TRACK_CHANGES.getName());
|
||||
return (preferences.containsKey(PreferenceName.TRACK_CHANGES.getName())
|
||||
||preferences.containsKey(PreferenceName.TRACK_CHANGES_PREF.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* 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.server.core.serializer.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.olingo.commons.api.Constants;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmStructuredType;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.serializer.SerializerResultImpl;
|
||||
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
|
||||
import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
|
||||
import org.apache.olingo.server.core.uri.UriHelperImpl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
public class JsonDeltaSerializer implements EdmDeltaSerializer {
|
||||
|
||||
private static final String LINK = "/$link";
|
||||
private static final String DELETEDLINK = "/$deletedLink";
|
||||
private static final String DELTA = "/$delta";
|
||||
private static final String HASH = "#";
|
||||
private static final String DELETEDENTITY = "/$deletedEntity";
|
||||
private static final String ENTITY = "/$entity";
|
||||
private static final String REASON = "Reason";
|
||||
private static final String IO_EXCEPTION_TEXT = "An I/O exception occurred.";
|
||||
private final boolean isIEEE754Compatible;
|
||||
private final boolean isODataMetadataNone;
|
||||
private final boolean isODataMetadataFull;
|
||||
|
||||
public JsonDeltaSerializer(final ContentType contentType) {
|
||||
isIEEE754Compatible = ContentTypeHelper.isODataIEEE754Compatible(contentType);
|
||||
isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType);
|
||||
isODataMetadataFull = ContentTypeHelper.isODataMetadataFull(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerResult entityCollection(ServiceMetadata metadata, EdmEntityType referencedEntityType, Delta delta,
|
||||
EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
try {
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
outputStream = buffer.getOutputStream();
|
||||
JsonGenerator json = new JsonFactory().createGenerator(outputStream);
|
||||
boolean pagination = false;
|
||||
json.writeStartObject();
|
||||
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
writeContextURL(contextURL, json);
|
||||
|
||||
if (options != null && options.getCount() != null && options.getCount().getValue()) {
|
||||
writeInlineCount(delta.getCount(), json);
|
||||
}
|
||||
json.writeFieldName(Constants.VALUE);
|
||||
writeEntitySet(metadata, referencedEntityType, delta, options, json);
|
||||
|
||||
pagination = writeNextLink(delta, json);
|
||||
writeDeltaLink(delta, json, pagination);
|
||||
|
||||
json.close();
|
||||
outputStream.close();
|
||||
return SerializerResultImpl.with().content(buffer.getInputStream()).build();
|
||||
} catch (final IOException e) {
|
||||
cachedException =
|
||||
new SerializerException(IO_EXCEPTION_TEXT, e, SerializerException.MessageKeys.IO_EXCEPTION);
|
||||
throw cachedException;
|
||||
} finally {
|
||||
closeCircleStreamBufferOutput(outputStream, cachedException);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Delta entitySet, final EntityCollectionSerializerOptions options,
|
||||
final JsonGenerator json) throws IOException,
|
||||
SerializerException {
|
||||
json.writeStartArray();
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
writeAddedUpdatedEntity(metadata, entityType, entity, options.getExpand(),
|
||||
options.getSelect(), options.getContextURL(), false, options.getContextURL()
|
||||
.getEntitySetOrSingletonOrType(), json);
|
||||
}
|
||||
for (final DeletedEntity deletedEntity : entitySet.getDeletedEntities()) {
|
||||
writeDeletedEntity(deletedEntity, options, json);
|
||||
}
|
||||
for (final DeltaLink addedLink : entitySet.getAddedLinks()) {
|
||||
writeLink(addedLink, options, json, true);
|
||||
}
|
||||
for (final DeltaLink deletedLink : entitySet.getDeletedLinks()) {
|
||||
writeLink(deletedLink, options, json, false);
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writeLink(DeltaLink link, EntityCollectionSerializerOptions options,
|
||||
JsonGenerator json, boolean isAdded) throws IOException, SerializerException {
|
||||
try {
|
||||
json.writeStartObject();
|
||||
String entityId = options.getContextURL().getEntitySetOrSingletonOrType();
|
||||
String operation = isAdded ? LINK : DELETEDLINK;
|
||||
json.writeStringField(Constants.JSON_CONTEXT, HASH + entityId + operation);
|
||||
if (link != null) {
|
||||
if (link.getSource() != null) {
|
||||
json.writeStringField(Constants.ATTR_SOURCE, link.getSource().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink source is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Source");
|
||||
}
|
||||
if (link.getRelationship() != null) {
|
||||
json.writeStringField(Constants.ATTR_RELATIONSHIP, link.getRelationship().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink relationship is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Relationship");
|
||||
}
|
||||
if (link.getTarget() != null) {
|
||||
json.writeStringField(Constants.ERROR_TARGET, link.getTarget().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink target is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Target");
|
||||
}
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Delta Link");
|
||||
}
|
||||
json.writeEndObject();
|
||||
} catch (IOException e) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDeletedEntity(DeletedEntity deletedEntity,
|
||||
EntityCollectionSerializerOptions options, JsonGenerator json) throws IOException, SerializerException {
|
||||
if (deletedEntity.getId() == null) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
if (deletedEntity.getReason() == null) {
|
||||
throw new SerializerException("DeletedEntity reason is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, REASON);
|
||||
}
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.JSON_CONTEXT, HASH + deletedEntity.getId().toASCIIString() + DELETEDENTITY);
|
||||
json.writeStringField(Constants.JSON_ID, deletedEntity.getId().toASCIIString());
|
||||
json.writeStringField(Constants.ELEM_REASON, deletedEntity.getReason().name());
|
||||
json.writeEndObject();
|
||||
|
||||
}
|
||||
|
||||
public void writeAddedUpdatedEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final ExpandOption expand, final SelectOption select, final ContextURL url,
|
||||
final boolean onlyReference, String name, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
if (entity.getId() != null && url != null) {
|
||||
String entityId = entity.getId().toString();
|
||||
name = url.getEntitySetOrSingletonOrType();
|
||||
if (!entityId.contains(name)) {
|
||||
String entityName = entityId.substring(0, entityId.indexOf("("));
|
||||
if (!entityName.equals(name)) {
|
||||
json.writeStringField(Constants.JSON_CONTEXT, HASH + entityName + ENTITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
json.writeStringField(Constants.JSON_ID, getEntityId(entity, entityType, name));
|
||||
writeProperties(metadata, entityType, entity.getProperties(), select, json);
|
||||
json.writeEndObject();
|
||||
|
||||
}
|
||||
|
||||
private Property findProperty(final String propertyName, final List<Property> properties) {
|
||||
for (final Property property : properties) {
|
||||
if (propertyName.equals(property.getName())) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void writeProperty(final ServiceMetadata metadata,
|
||||
final EdmProperty edmProperty, final Property property,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
boolean isStreamProperty = isStreamProperty(edmProperty);
|
||||
if (property != null) {
|
||||
if (!isStreamProperty) {
|
||||
json.writeFieldName(edmProperty.getName());
|
||||
}
|
||||
writePropertyValue(metadata, edmProperty, property, selectedPaths, json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isStreamProperty(EdmProperty edmProperty) {
|
||||
final EdmType type = edmProperty.getType();
|
||||
return (edmProperty.isPrimitive() && type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream));
|
||||
}
|
||||
|
||||
private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
|
||||
final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
final EdmType type = edmProperty.getType();
|
||||
try {
|
||||
if (edmProperty.isPrimitive()
|
||||
|| type.getKind() == EdmTypeKind.ENUM || type.getKind() == EdmTypeKind.DEFINITION) {
|
||||
if (edmProperty.isCollection()) {
|
||||
writePrimitiveCollection((EdmPrimitiveType) type, property,
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), json);
|
||||
} else {
|
||||
writePrimitive((EdmPrimitiveType) type, property,
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), json);
|
||||
}
|
||||
} else if (property.isComplex()) {
|
||||
if (edmProperty.isCollection()) {
|
||||
writeComplexCollection(metadata, (EdmComplexType) type, property, selectedPaths, json);
|
||||
} else {
|
||||
writeComplex(metadata, (EdmComplexType) type, property, selectedPaths, json);
|
||||
}
|
||||
} else {
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
|
||||
}
|
||||
} catch (final EdmPrimitiveTypeException e) {
|
||||
throw new SerializerException("Wrong value for property!", e,
|
||||
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
|
||||
edmProperty.getName(), property.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected EdmComplexType resolveComplexType(final ServiceMetadata metadata, final EdmComplexType baseType,
|
||||
final String derivedTypeName) throws SerializerException {
|
||||
|
||||
String fullQualifiedName = baseType.getFullQualifiedName().getFullQualifiedNameAsString();
|
||||
if (derivedTypeName == null ||
|
||||
fullQualifiedName.equals(derivedTypeName)) {
|
||||
return baseType;
|
||||
}
|
||||
EdmComplexType derivedType = metadata.getEdm().getComplexType(new FullQualifiedName(derivedTypeName));
|
||||
if (derivedType == null) {
|
||||
throw new SerializerException("Complex Type not found",
|
||||
SerializerException.MessageKeys.UNKNOWN_TYPE, derivedTypeName);
|
||||
}
|
||||
EdmComplexType type = derivedType.getBaseType();
|
||||
while (type != null) {
|
||||
if (type.getFullQualifiedName().equals(baseType.getFullQualifiedName())) {
|
||||
return derivedType;
|
||||
}
|
||||
type = type.getBaseType();
|
||||
}
|
||||
throw new SerializerException("Wrong base type",
|
||||
SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName,
|
||||
baseType.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
|
||||
private void writeComplex(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
String derivedName = property.getType();
|
||||
final EdmComplexType resolvedType = resolveComplexType(metadata, (EdmComplexType) type, derivedName);
|
||||
if (!isODataMetadataNone && !resolvedType.equals(type) || isODataMetadataFull) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#" + property.getType());
|
||||
}
|
||||
writeComplexValue(metadata, resolvedType, property.asComplex().getValue(), selectedPaths,
|
||||
json);
|
||||
json.writeEndObject();
|
||||
}
|
||||
|
||||
private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartArray();
|
||||
for (Object value : property.asCollection()) {
|
||||
switch (property.getValueType()) {
|
||||
case COLLECTION_PRIMITIVE:
|
||||
case COLLECTION_ENUM:
|
||||
try {
|
||||
writePrimitiveValue(property.getName(), type, value, isNullable,
|
||||
maxLength, precision, scale, isUnicode, json);
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new SerializerException("Wrong value for property!", e,
|
||||
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
|
||||
property.getName(), property.getValue().toString());
|
||||
}
|
||||
break;
|
||||
case COLLECTION_GEOSPATIAL:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
default:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartArray();
|
||||
for (Object value : property.asCollection()) {
|
||||
switch (property.getValueType()) {
|
||||
case COLLECTION_COMPLEX:
|
||||
json.writeStartObject();
|
||||
if (isODataMetadataFull) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#" +
|
||||
type.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
writeComplexValue(metadata, type, ((ComplexValue) value).getValue(), selectedPaths, json);
|
||||
json.writeEndObject();
|
||||
break;
|
||||
default:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writePrimitive(final EdmPrimitiveType type, final Property property,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json)
|
||||
throws EdmPrimitiveTypeException, IOException, SerializerException {
|
||||
if (property.isPrimitive()) {
|
||||
writePrimitiveValue(property.getName(), type, property.asPrimitive(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
} else if (property.isGeospatial()) {
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
} else if (property.isEnum()) {
|
||||
writePrimitiveValue(property.getName(), type, property.asEnum(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
} else {
|
||||
throw new SerializerException("Inconsistent property type!",
|
||||
SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void writePrimitiveValue(final String name, final EdmPrimitiveType type, final Object primitiveValue,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json) throws EdmPrimitiveTypeException, IOException {
|
||||
final String value = type.valueToString(primitiveValue,
|
||||
isNullable, maxLength, precision, scale, isUnicode);
|
||||
if (value == null) {
|
||||
json.writeNull();
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
|
||||
json.writeBoolean(Boolean.parseBoolean(value));
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int32)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single)
|
||||
|| (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64))
|
||||
&& !isIEEE754Compatible) {
|
||||
json.writeNumber(value);
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream)) {
|
||||
if (primitiveValue instanceof Link) {
|
||||
Link stream = (Link) primitiveValue;
|
||||
if (!isODataMetadataNone) {
|
||||
if (stream.getMediaETag() != null) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_ETAG, stream.getMediaETag());
|
||||
}
|
||||
if (stream.getType() != null) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_CONTENT_TYPE, stream.getType());
|
||||
}
|
||||
}
|
||||
if (isODataMetadataFull) {
|
||||
if (stream.getRel() != null && stream.getRel().equals(Constants.NS_MEDIA_READ_LINK_REL)) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_READ_LINK, stream.getHref());
|
||||
}
|
||||
if (stream.getRel() == null || stream.getRel().equals(Constants.NS_MEDIA_EDIT_LINK_REL)) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_EDIT_LINK, stream.getHref());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
json.writeString(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeComplexValue(final ServiceMetadata metadata,
|
||||
final EdmComplexType type, final List<Property> properties,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
|
||||
for (final String propertyName : type.getPropertyNames()) {
|
||||
final Property property = findProperty(propertyName, properties);
|
||||
if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
|
||||
writeProperty(metadata, (EdmProperty) type.getProperty(propertyName), property,
|
||||
selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
|
||||
json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
|
||||
final List<Property> properties,
|
||||
final SelectOption select, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
final boolean all = ExpandSelectHelper.isAll(select);
|
||||
final Set<String> selected = all ? new HashSet<String>() : ExpandSelectHelper.getSelectedPropertyNames(select
|
||||
.getSelectItems());
|
||||
for (final String propertyName : type.getPropertyNames()) {
|
||||
if (all || selected.contains(propertyName)) {
|
||||
final EdmProperty edmProperty = type.getStructuralProperty(propertyName);
|
||||
final Property property = findProperty(propertyName, properties);
|
||||
final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null : ExpandSelectHelper
|
||||
.getSelectedPaths(select.getSelectItems(), propertyName);
|
||||
writeProperty(metadata, edmProperty, property, selectedPaths, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ascii representation of the entity id
|
||||
* or thrown an {@link SerializerException} if id is <code>null</code>.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return ascii representation of the entity id
|
||||
*/
|
||||
private String getEntityId(Entity entity, EdmEntityType entityType, String name) throws SerializerException {
|
||||
try {
|
||||
if (entity != null) {
|
||||
if (entity.getId() == null) {
|
||||
if (entityType == null || entityType.getKeyPredicateNames() == null
|
||||
|| name == null) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
} else {
|
||||
final UriHelper uriHelper = new UriHelperImpl();
|
||||
entity.setId(URI.create(name + '(' + uriHelper.buildKeyPredicate(entityType, entity) + ')'));
|
||||
return entity.getId().toASCIIString();
|
||||
}
|
||||
} else {
|
||||
return entity.getId().toASCIIString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
}
|
||||
|
||||
void writeInlineCount(final Integer count, final JsonGenerator json)
|
||||
throws IOException {
|
||||
if (count != null) {
|
||||
String countValue = isIEEE754Compatible ? String.valueOf(count) : String.valueOf(count);
|
||||
json.writeStringField(Constants.JSON_COUNT, countValue);
|
||||
}
|
||||
}
|
||||
|
||||
ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
|
||||
if (isODataMetadataNone) {
|
||||
return null;
|
||||
} else if (contextURL == null) {
|
||||
throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
|
||||
}
|
||||
return contextURL;
|
||||
}
|
||||
|
||||
void writeContextURL(final ContextURL contextURL, final JsonGenerator json) throws IOException {
|
||||
if (!isODataMetadataNone && contextURL != null) {
|
||||
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString() + DELTA);
|
||||
}
|
||||
}
|
||||
|
||||
boolean writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json)
|
||||
throws IOException {
|
||||
if (entitySet.getNext() != null) {
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void writeDeltaLink(final AbstractEntityCollection entitySet, final JsonGenerator json, boolean pagination)
|
||||
throws IOException {
|
||||
if (entitySet.getDeltaLink() != null && !pagination) {
|
||||
json.writeStringField(Constants.JSON_DELTA_LINK, entitySet.getDeltaLink().toASCIIString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void closeCircleStreamBufferOutput(final OutputStream outputStream,
|
||||
final SerializerException cachedException)
|
||||
throws SerializerException {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
if (cachedException != null) {
|
||||
throw cachedException;
|
||||
} else {
|
||||
throw new SerializerException(IO_EXCEPTION_TEXT, e,
|
||||
SerializerException.MessageKeys.IO_EXCEPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,655 @@
|
|||
/*
|
||||
* 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.server.core.serializer.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.olingo.commons.api.Constants;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Annotation;
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Linked;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmStructuredType;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.serializer.SerializerResultImpl;
|
||||
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
|
||||
import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
|
||||
import org.apache.olingo.server.core.uri.UriHelperImpl;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
public class JsonDeltaSerializerWithNavigations implements EdmDeltaSerializer {
|
||||
private static final String IO_EXCEPTION_TEXT = "An I/O exception occurred.";
|
||||
private final boolean isIEEE754Compatible;
|
||||
private final boolean isODataMetadataNone;
|
||||
private final boolean isODataMetadataFull;
|
||||
|
||||
public JsonDeltaSerializerWithNavigations(final ContentType contentType) {
|
||||
isIEEE754Compatible = ContentTypeHelper.isODataIEEE754Compatible(contentType);
|
||||
isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType);
|
||||
isODataMetadataFull = ContentTypeHelper.isODataMetadataFull(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerResult entityCollection(ServiceMetadata metadata, EdmEntityType referencedEntityType, Delta delta,
|
||||
EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
boolean pagination = false;
|
||||
try {
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
outputStream = buffer.getOutputStream();
|
||||
JsonGenerator json = new JsonFactory().createGenerator(outputStream);
|
||||
json.writeStartObject();
|
||||
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
writeContextURL(contextURL, json);
|
||||
|
||||
if (options != null && options.getCount() != null && options.getCount().getValue()) {
|
||||
writeInlineCount(delta.getCount(), json);
|
||||
}
|
||||
json.writeFieldName(Constants.VALUE);
|
||||
writeEntitySet(metadata, referencedEntityType, delta, options, json);
|
||||
|
||||
pagination = writeNextLink(delta, json);
|
||||
writeDeltaLink(delta, json, pagination);
|
||||
|
||||
json.close();
|
||||
outputStream.close();
|
||||
return SerializerResultImpl.with().content(buffer.getInputStream()).build();
|
||||
} catch (final IOException e) {
|
||||
cachedException =
|
||||
new SerializerException(IO_EXCEPTION_TEXT, e, SerializerException.MessageKeys.IO_EXCEPTION);
|
||||
throw cachedException;
|
||||
} finally {
|
||||
closeCircleStreamBufferOutput(outputStream, cachedException);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void closeCircleStreamBufferOutput(final OutputStream outputStream,
|
||||
final SerializerException cachedException)
|
||||
throws SerializerException {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
if (cachedException != null) {
|
||||
throw cachedException;
|
||||
} else {
|
||||
throw new SerializerException(IO_EXCEPTION_TEXT, e,
|
||||
SerializerException.MessageKeys.IO_EXCEPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Delta entitySet, final EntityCollectionSerializerOptions options,
|
||||
final JsonGenerator json) throws IOException,
|
||||
SerializerException {
|
||||
json.writeStartArray();
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
writeAddedUpdatedEntity(metadata, entityType, entity, options.getExpand(), options.getSelect(),
|
||||
options.getContextURL(), false, options.getContextURL().getEntitySetOrSingletonOrType(), json);
|
||||
}
|
||||
for (final DeletedEntity deletedEntity : entitySet.getDeletedEntities()) {
|
||||
writeDeletedEntity(deletedEntity, json);
|
||||
}
|
||||
for (final DeltaLink addedLink : entitySet.getAddedLinks()) {
|
||||
writeLink(addedLink, options, json, true);
|
||||
}
|
||||
for (final DeltaLink deletedLink : entitySet.getDeletedLinks()) {
|
||||
writeLink(deletedLink, options, json, false);
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writeLink(DeltaLink link, EntityCollectionSerializerOptions options,
|
||||
JsonGenerator json, boolean isAdded) throws IOException, SerializerException {
|
||||
try {
|
||||
json.writeStartObject();
|
||||
String entityId = options.getContextURL().getEntitySetOrSingletonOrType();// throw error if not set id
|
||||
String operation = isAdded ? Constants.LINK : Constants.DELETEDLINK;
|
||||
json.writeStringField(Constants.AT + Constants.CONTEXT, Constants.HASH + entityId + operation);
|
||||
if (link != null) {
|
||||
if (link.getSource() != null) {
|
||||
json.writeStringField(Constants.ATTR_SOURCE, link.getSource().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink source is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Source");
|
||||
}
|
||||
if (link.getRelationship() != null) {
|
||||
json.writeStringField(Constants.ATTR_RELATIONSHIP, link.getRelationship().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink relationship is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Relationship");
|
||||
}
|
||||
if (link.getTarget() != null) {
|
||||
json.writeStringField(Constants.ERROR_TARGET, link.getTarget().toString());
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink target is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Target");
|
||||
}
|
||||
} else {
|
||||
throw new SerializerException("DeltaLink is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, "Delta Link");
|
||||
}
|
||||
json.writeEndObject();
|
||||
} catch (IOException e) {
|
||||
throw new SerializerException("Entity id is null.",
|
||||
SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDeletedEntity(Entity deletedEntity,
|
||||
JsonGenerator json) throws IOException, SerializerException {
|
||||
if (deletedEntity.getId() == null) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
json.writeStartObject();
|
||||
if (isODataMetadataFull) {
|
||||
|
||||
json.writeStringField(Constants.AT + Constants.CONTEXT, Constants.HASH + deletedEntity.getId().toASCIIString()
|
||||
+ Constants.DELETEDENTITY);
|
||||
}
|
||||
if (((DeletedEntity) deletedEntity).getReason() == null) {
|
||||
throw new SerializerException("DeletedEntity reason is null.",
|
||||
SerializerException.MessageKeys.MISSING_DELTA_PROPERTY, Constants.REASON);
|
||||
}
|
||||
json.writeFieldName(Constants.AT + Constants.REMOVED);
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.ELEM_REASON,
|
||||
((DeletedEntity) deletedEntity).getReason().name());
|
||||
List<Annotation> annotations = deletedEntity.getAnnotations();
|
||||
if (annotations != null && annotations.size() > 0) {
|
||||
for (Annotation annotation : annotations) {
|
||||
json.writeStringField(Constants.AT + annotation.getTerm(), annotation.getValue().toString());
|
||||
}
|
||||
}
|
||||
json.writeEndObject();
|
||||
List<Property> properties = deletedEntity.getProperties();
|
||||
if (properties != null && properties.size() > 0) {
|
||||
for (Property property : properties) {
|
||||
json.writeStringField(property.getName(), property.getValue().toString());
|
||||
}
|
||||
}
|
||||
json.writeStringField(Constants.AT + Constants.ATOM_ATTR_ID, deletedEntity.getId().toASCIIString());
|
||||
json.writeEndObject();
|
||||
|
||||
}
|
||||
|
||||
public void writeAddedUpdatedEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final ExpandOption expand, final SelectOption select, final ContextURL url,
|
||||
final boolean onlyReference, String name, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
if (entity.getId() != null && url != null) {
|
||||
name = url.getEntitySetOrSingletonOrType();
|
||||
String entityId = entity.getId().toString();
|
||||
if (!entityId.contains(name)) {
|
||||
String entityName = entityId.substring(0, entityId.indexOf("("));
|
||||
if (!entityName.equals(name)) {
|
||||
json.writeStringField(Constants.AT + Constants.CONTEXT, Constants.HASH + entityName
|
||||
+ Constants.ENTITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
json.writeStringField(Constants.AT + Constants.ATOM_ATTR_ID, getEntityId(entity, entityType, name));
|
||||
writeProperties(metadata, entityType, entity.getProperties(), select, json);
|
||||
writeNavigationProperties(metadata, entityType, entity, expand, name, json);
|
||||
json.writeEndObject();
|
||||
|
||||
}
|
||||
|
||||
private Property findProperty(final String propertyName, final List<Property> properties) {
|
||||
for (final Property property : properties) {
|
||||
if (propertyName.equals(property.getName())) {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void writeProperty(final ServiceMetadata metadata,
|
||||
final EdmProperty edmProperty, final Property property,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
boolean isStreamProperty = isStreamProperty(edmProperty);
|
||||
if (property != null) {
|
||||
if (!isStreamProperty) {
|
||||
json.writeFieldName(edmProperty.getName());
|
||||
}
|
||||
writePropertyValue(metadata, edmProperty, property, selectedPaths, json);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStreamProperty(EdmProperty edmProperty) {
|
||||
final EdmType type = edmProperty.getType();
|
||||
return (edmProperty.isPrimitive() && type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream));
|
||||
}
|
||||
|
||||
private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
|
||||
final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
final EdmType type = edmProperty.getType();
|
||||
try {
|
||||
if (edmProperty.isPrimitive()
|
||||
|| type.getKind() == EdmTypeKind.ENUM || type.getKind() == EdmTypeKind.DEFINITION) {
|
||||
if (edmProperty.isCollection()) {
|
||||
writePrimitiveCollection((EdmPrimitiveType) type, property,
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), json);
|
||||
} else {
|
||||
writePrimitive((EdmPrimitiveType) type, property,
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), json);
|
||||
}
|
||||
} else if (property.isComplex()) {
|
||||
if (edmProperty.isCollection()) {
|
||||
writeComplexCollection(metadata, (EdmComplexType) type, property, selectedPaths, json);
|
||||
} else {
|
||||
writeComplex(metadata, (EdmComplexType) type, property, selectedPaths, json);
|
||||
}
|
||||
} else {
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
|
||||
}
|
||||
} catch (final EdmPrimitiveTypeException e) {
|
||||
throw new SerializerException("Wrong value for property!", e,
|
||||
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
|
||||
edmProperty.getName(), property.getValue().toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected EdmComplexType resolveComplexType(final ServiceMetadata metadata, final EdmComplexType baseType,
|
||||
final String derivedTypeName) throws SerializerException {
|
||||
|
||||
String fullQualifiedName = baseType.getFullQualifiedName().getFullQualifiedNameAsString();
|
||||
if (derivedTypeName == null ||
|
||||
fullQualifiedName.equals(derivedTypeName)) {
|
||||
return baseType;
|
||||
}
|
||||
EdmComplexType derivedType = metadata.getEdm().getComplexType(new FullQualifiedName(derivedTypeName));
|
||||
if (derivedType == null) {
|
||||
throw new SerializerException("Complex Type not found",
|
||||
SerializerException.MessageKeys.UNKNOWN_TYPE, derivedTypeName);
|
||||
}
|
||||
EdmComplexType type = derivedType.getBaseType();
|
||||
while (type != null) {
|
||||
if (type.getFullQualifiedName().equals(baseType.getFullQualifiedName())) {
|
||||
return derivedType;
|
||||
}
|
||||
type = type.getBaseType();
|
||||
}
|
||||
throw new SerializerException("Wrong base type",
|
||||
SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName,
|
||||
baseType.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
|
||||
private void writeComplex(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
String derivedName = property.getType();
|
||||
final EdmComplexType resolvedType = resolveComplexType(metadata, (EdmComplexType) type, derivedName);
|
||||
if (!isODataMetadataNone && !resolvedType.equals(type) || isODataMetadataFull) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#" + property.getType());
|
||||
}
|
||||
writeComplexValue(metadata, resolvedType, property.asComplex().getValue(), selectedPaths,
|
||||
json);
|
||||
json.writeEndObject();
|
||||
}
|
||||
|
||||
private void writePrimitiveCollection(final EdmPrimitiveType type, final Property property,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartArray();
|
||||
for (Object value : property.asCollection()) {
|
||||
switch (property.getValueType()) {
|
||||
case COLLECTION_PRIMITIVE:
|
||||
case COLLECTION_ENUM:
|
||||
try {
|
||||
writePrimitiveValue(property.getName(), type, value, isNullable,
|
||||
maxLength, precision, scale, isUnicode, json);
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new SerializerException("Wrong value for property!", e,
|
||||
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
|
||||
property.getName(), property.getValue().toString());
|
||||
}
|
||||
break;
|
||||
case COLLECTION_GEOSPATIAL:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
default:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartArray();
|
||||
for (Object value : property.asCollection()) {
|
||||
switch (property.getValueType()) {
|
||||
case COLLECTION_COMPLEX:
|
||||
json.writeStartObject();
|
||||
if (isODataMetadataFull) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#" +
|
||||
type.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
writeComplexValue(metadata, type, ((ComplexValue) value).getValue(), selectedPaths, json);
|
||||
json.writeEndObject();
|
||||
break;
|
||||
default:
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
private void writePrimitive(final EdmPrimitiveType type, final Property property,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json)
|
||||
throws EdmPrimitiveTypeException, IOException, SerializerException {
|
||||
if (property.isPrimitive()) {
|
||||
writePrimitiveValue(property.getName(), type, property.asPrimitive(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
} else if (property.isGeospatial()) {
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
|
||||
} else if (property.isEnum()) {
|
||||
writePrimitiveValue(property.getName(), type, property.asEnum(),
|
||||
isNullable, maxLength, precision, scale, isUnicode, json);
|
||||
} else {
|
||||
throw new SerializerException("Inconsistent property type!",
|
||||
SerializerException.MessageKeys.INCONSISTENT_PROPERTY_TYPE, property.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void writePrimitiveValue(final String name, final EdmPrimitiveType type, final Object primitiveValue,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
|
||||
final Boolean isUnicode, final JsonGenerator json) throws EdmPrimitiveTypeException, IOException {
|
||||
final String value = type.valueToString(primitiveValue,
|
||||
isNullable, maxLength, precision, scale, isUnicode);
|
||||
if (value == null) {
|
||||
json.writeNull();
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
|
||||
json.writeBoolean(Boolean.parseBoolean(value));
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int32)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single)
|
||||
|| (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
|
||||
|| type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64))
|
||||
&& !isIEEE754Compatible) {
|
||||
json.writeNumber(value);
|
||||
} else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream)) {
|
||||
if (primitiveValue instanceof Link) {
|
||||
Link stream = (Link) primitiveValue;
|
||||
if (!isODataMetadataNone) {
|
||||
if (stream.getMediaETag() != null) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_ETAG, stream.getMediaETag());
|
||||
}
|
||||
if (stream.getType() != null) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_CONTENT_TYPE, stream.getType());
|
||||
}
|
||||
}
|
||||
if (isODataMetadataFull) {
|
||||
if (stream.getRel() != null && stream.getRel().equals(Constants.NS_MEDIA_READ_LINK_REL)) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_READ_LINK, stream.getHref());
|
||||
}
|
||||
if (stream.getRel() == null || stream.getRel().equals(Constants.NS_MEDIA_EDIT_LINK_REL)) {
|
||||
json.writeStringField(name + Constants.JSON_MEDIA_EDIT_LINK, stream.getHref());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
json.writeString(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeComplexValue(final ServiceMetadata metadata,
|
||||
final EdmComplexType type, final List<Property> properties,
|
||||
final Set<List<String>> selectedPaths, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
|
||||
for (final String propertyName : type.getPropertyNames()) {
|
||||
final Property property = findProperty(propertyName, properties);
|
||||
if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
|
||||
writeProperty(metadata, (EdmProperty) type.getProperty(propertyName), property,
|
||||
selectedPaths == null ? null : ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
|
||||
json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
|
||||
final List<Property> properties,
|
||||
final SelectOption select, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
final boolean all = ExpandSelectHelper.isAll(select);
|
||||
final Set<String> selected = all ? new HashSet<String>() : ExpandSelectHelper.getSelectedPropertyNames(select
|
||||
.getSelectItems());
|
||||
for (final String propertyName : type.getPropertyNames()) {
|
||||
if ((all || selected.contains(propertyName)) && properties.size() > 0) {
|
||||
final EdmProperty edmProperty = type.getStructuralProperty(propertyName);
|
||||
final Property property = findProperty(propertyName, properties);
|
||||
final Set<List<String>> selectedPaths = all || edmProperty.isPrimitive() ? null : ExpandSelectHelper
|
||||
.getSelectedPaths(select.getSelectItems(), propertyName);
|
||||
writeProperty(metadata, edmProperty, property, selectedPaths, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeNavigationProperties(final ServiceMetadata metadata,
|
||||
final EdmStructuredType type, final Linked linked, final ExpandOption expand,
|
||||
final String name, final JsonGenerator json) throws SerializerException, IOException {
|
||||
if (ExpandSelectHelper.hasExpand(expand)) {
|
||||
final boolean expandAll = ExpandSelectHelper.getExpandAll(expand) != null;
|
||||
final Set<String> expanded = expandAll ? new HashSet<String>() : ExpandSelectHelper.getExpandedPropertyNames(
|
||||
expand.getExpandItems());
|
||||
for (final String propertyName : type.getNavigationPropertyNames()) {
|
||||
if (expandAll || expanded.contains(propertyName)) {
|
||||
final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
|
||||
final Link navigationLink = linked.getNavigationLink(property.getName());
|
||||
final ExpandItem innerOptions = expandAll ? null : ExpandSelectHelper.getExpandItem(expand.getExpandItems(),
|
||||
propertyName);
|
||||
if (innerOptions != null && innerOptions.getLevelsOption() != null) {
|
||||
throw new SerializerException("Expand option $levels is not supported.",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
if (navigationLink != null) {
|
||||
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
||||
innerOptions == null ? null : innerOptions.getExpandOption(),
|
||||
innerOptions == null ? null : innerOptions.getSelectOption(),
|
||||
innerOptions == null ? null : innerOptions.getCountOption(),
|
||||
innerOptions == null ? false : innerOptions.hasCountPath(),
|
||||
innerOptions == null ? false : innerOptions.isRef(),
|
||||
name, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final boolean onlyReference, String name, final JsonGenerator json) throws IOException,
|
||||
SerializerException {
|
||||
json.writeStartArray();
|
||||
for (final Entity entity : entitySet) {
|
||||
if (onlyReference) {
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.JSON_ID, getEntityId(entity, entityType, null));
|
||||
json.writeEndObject();
|
||||
} else {
|
||||
if (entity instanceof DeletedEntity) {
|
||||
writeDeletedEntity(entity, json);
|
||||
} else {
|
||||
writeAddedUpdatedEntity(metadata, entityType, entity, expand, select, null, false, name, json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
protected void writeExpandedNavigationProperty(
|
||||
final ServiceMetadata metadata, final EdmNavigationProperty property,
|
||||
final Link navigationLink, final ExpandOption innerExpand,
|
||||
final SelectOption innerSelect, final CountOption innerCount,
|
||||
final boolean writeOnlyCount, final boolean writeOnlyRef, final String name,
|
||||
final JsonGenerator json) throws IOException, SerializerException {
|
||||
|
||||
if (property.isCollection()) {
|
||||
if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
|
||||
json.writeFieldName(property.getName() + Constants.AT + Constants.DELTAVALUE);
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, writeOnlyRef, name, json);
|
||||
}
|
||||
|
||||
} else {
|
||||
json.writeFieldName(property.getName()+ Constants.AT + Constants.DELTAVALUE);
|
||||
if (navigationLink != null && navigationLink.getInlineEntity() != null) {
|
||||
if (navigationLink.getInlineEntity() instanceof DeletedEntity) {
|
||||
writeDeletedEntity(navigationLink.getInlineEntity(), json);
|
||||
} else {
|
||||
writeAddedUpdatedEntity(metadata, property.getType(), navigationLink.getInlineEntity(),
|
||||
innerExpand, innerSelect, null, writeOnlyRef, name, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ascii representation of the entity id
|
||||
* or thrown an {@link SerializerException} if id is <code>null</code>.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @return ascii representation of the entity id
|
||||
*/
|
||||
private String getEntityId(Entity entity, EdmEntityType entityType, String name) throws SerializerException {
|
||||
try {
|
||||
if (entity != null) {
|
||||
if (entity.getId() == null) {
|
||||
if (entityType == null || entityType.getKeyPredicateNames() == null
|
||||
|| name == null) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
} else {
|
||||
final UriHelper uriHelper = new UriHelperImpl();
|
||||
entity.setId(URI.create(name + '(' + uriHelper.buildKeyPredicate(entityType, entity) + ')'));
|
||||
return entity.getId().toASCIIString();
|
||||
}
|
||||
} else {
|
||||
return entity.getId().toASCIIString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new SerializerException("Entity id is null.", SerializerException.MessageKeys.MISSING_ID);
|
||||
}
|
||||
}
|
||||
|
||||
void writeInlineCount(final Integer count, final JsonGenerator json)
|
||||
throws IOException {
|
||||
if (count != null) {
|
||||
String countValue = isIEEE754Compatible ? String.valueOf(count) : String.valueOf(count);
|
||||
json.writeStringField(Constants.AT + Constants.ATOM_ELEM_COUNT, countValue);
|
||||
}
|
||||
}
|
||||
|
||||
ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
|
||||
if (isODataMetadataNone) {
|
||||
return null;
|
||||
} else if (contextURL == null) {
|
||||
throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
|
||||
}
|
||||
return contextURL;
|
||||
}
|
||||
|
||||
void writeContextURL(final ContextURL contextURL, final JsonGenerator json) throws IOException {
|
||||
if (!isODataMetadataNone && contextURL != null) {
|
||||
String context = Constants.AT + Constants.CONTEXT;
|
||||
json.writeStringField(context, ContextURLBuilder.create(contextURL).toASCIIString() + Constants.DELTA);
|
||||
}
|
||||
}
|
||||
|
||||
boolean writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json)
|
||||
throws IOException {
|
||||
if (entitySet.getNext() != null) {
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void writeDeltaLink(final AbstractEntityCollection entitySet, final JsonGenerator json,
|
||||
final boolean pagination)
|
||||
throws IOException {
|
||||
if (entitySet.getDeltaLink() != null && !pagination) {
|
||||
json.writeStringField(Constants.DELTALINK, entitySet.getDeltaLink().toASCIIString());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -174,6 +174,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
final EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
boolean pagination = false;
|
||||
try {
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
outputStream = buffer.getOutputStream();
|
||||
|
@ -197,7 +198,8 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
writeEntitySet(metadata, entityType, entitySet,
|
||||
options.getExpand(), null, options.getSelect(), options.getWriteOnlyReferences(), null, name, json);
|
||||
}
|
||||
writeNextLink(entitySet, json);
|
||||
writeNextLink(entitySet, json, pagination);
|
||||
writeDeltaLink(entitySet, json, pagination);
|
||||
|
||||
json.close();
|
||||
outputStream.close();
|
||||
|
@ -224,6 +226,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
throws SerializerException {
|
||||
|
||||
SerializerException cachedException;
|
||||
boolean pagination = false;
|
||||
try {
|
||||
JsonGenerator json = new JsonFactory().createGenerator(outputStream);
|
||||
json.writeStartObject();
|
||||
|
@ -245,7 +248,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
options.getExpand(), null, options.getSelect(), options.getWriteOnlyReferences(), null, name, json);
|
||||
}
|
||||
// next link support for streaming results
|
||||
writeNextLink(entitySet, json);
|
||||
writeNextLink(entitySet, json, pagination);
|
||||
|
||||
json.close();
|
||||
} catch (final IOException e) {
|
||||
|
@ -1165,6 +1168,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
boolean pagination = false ;
|
||||
|
||||
try {
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
|
@ -1187,7 +1191,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
json.writeEndArray();
|
||||
|
||||
writeNextLink(entityCollection, json);
|
||||
writeNextLink(entityCollection, json, pagination);
|
||||
|
||||
json.writeEndObject();
|
||||
|
||||
|
@ -1231,9 +1235,20 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
void writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json) throws IOException {
|
||||
void writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json, boolean pagination)
|
||||
throws IOException {
|
||||
if (entitySet.getNext() != null) {
|
||||
pagination = true;
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
}else{
|
||||
pagination = false;
|
||||
}
|
||||
}
|
||||
|
||||
void writeDeltaLink(final AbstractEntityCollection entitySet, final JsonGenerator json, boolean pagination)
|
||||
throws IOException {
|
||||
if (entitySet.getDeltaLink() != null && !pagination) {
|
||||
json.writeStringField(Constants.JSON_DELTA_LINK, entitySet.getDeltaLink().toASCIIString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.apache.olingo.server.api.uri.UriResource;
|
|||
import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
|
@ -189,6 +190,7 @@ public class UriInfoImpl implements UriInfo {
|
|||
case SELECT:
|
||||
case SKIP:
|
||||
case SKIPTOKEN:
|
||||
case DELTATOKEN:
|
||||
case TOP:
|
||||
case LEVELS:
|
||||
case APPLY:
|
||||
|
@ -310,4 +312,9 @@ public class UriInfoImpl implements UriInfo {
|
|||
public String getFragment() {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeltaTokenOption getDeltaTokenOption() {
|
||||
return (DeltaTokenOption) systemQueryOptions.get(SystemQueryOptionKind.DELTATOKEN);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.apache.olingo.server.core.uri.parser.search.SearchParser;
|
|||
import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.ApplyOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.DeltaTokenOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
|
||||
|
@ -332,6 +333,14 @@ public class Parser {
|
|||
}
|
||||
systemOption = new SkipTokenOptionImpl().setValue(optionValue);
|
||||
break;
|
||||
case DELTATOKEN:
|
||||
if (optionValue.isEmpty()) {
|
||||
throw new UriParserSyntaxException("Illegal value of $deltatoken option!",
|
||||
UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
|
||||
optionName, optionValue);
|
||||
}
|
||||
systemOption = new DeltaTokenOptionImpl().setValue(optionValue);
|
||||
break;
|
||||
case TOP:
|
||||
systemOption = new TopOptionImpl()
|
||||
.setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.server.core.uri.queryoption;
|
||||
|
||||
import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
|
||||
|
||||
public class DeltaTokenOptionImpl extends SystemQueryOptionImpl implements DeltaTokenOption {
|
||||
|
||||
public DeltaTokenOptionImpl() {
|
||||
setKind(SystemQueryOptionKind.DELTATOKEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
public DeltaTokenOptionImpl setValue(final String deltaTokenValue) {
|
||||
setText(deltaTokenValue);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -45,27 +45,27 @@ public class UriValidator {
|
|||
//CHECKSTYLE:OFF (Maven checkstyle)
|
||||
private static final boolean[][] decisionMatrix =
|
||||
{
|
||||
/* 0-FILTER 1-FORMAT 2-EXPAND 3-ID 4-COUNT 5-ORDERBY 6-SEARCH 7-SELECT 8-SKIP 9-SKIPTOKEN 10-TOP 11-APPLY */
|
||||
/* all 0 */ { true , true , true , false, true , true , true , true , true , true , true , true },
|
||||
/* batch 1 */ { false, false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* crossjoin 2 */ { true , true , true , false, true , true , true , true , true , true , true , true },
|
||||
/* entityId 3 */ { false, true , true , true , false, false, false, true , false, false, false, false },
|
||||
/* metadata 4 */ { false, true , false, false, false, false, false, false, false, false, false, false },
|
||||
/* service 5 */ { false, true , false, false, false, false, false, false, false, false, false, false },
|
||||
/* entitySet 6 */ { true , true , true , false, true , true , true , true , true , true , true , true },
|
||||
/* entitySetCount 7 */ { true , false, false, false, false, false, true , false, false, false, false, true },
|
||||
/* entity 8 */ { false, true , true , false, false, false, false, true , false, false, false, false },
|
||||
/* mediaStream 9 */ { false, false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* references 10 */ { true , true , false, false, true , true , true , false, true , true , true , false },
|
||||
/* reference 11 */ { false, true , false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyComplex 12 */ { false, true , true , false, false, false, false, true , false, false, false, false },
|
||||
/* propertyComplexCollection 13 */ { true , true , true , false, true , true , false, true , true , true , true , true },
|
||||
/* propertyComplexCollectionCount 14 */ { true , false, false, false, false, false, false, false, false, false, false, true },
|
||||
/* propertyPrimitive 15 */ { false, true , false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyPrimitiveCollection 16 */ { true , true , false, false, true , true , false, false, true , true , true , false },
|
||||
/* propertyPrimitiveCollectionCount 17 */ { true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyPrimitiveValue 18 */ { false, true , false, false, false, false, false, false, false, false, false, false },
|
||||
/* none 19 */ { false, true , false, false, false, false, false, false, false, false, false, false }
|
||||
/* 0-FILTER 1-FORMAT 2-EXPAND 3-ID 4-COUNT 5-ORDERBY 6-SEARCH 7-SELECT 8-SKIP 9-SKIPTOKEN 10-TOP 11-APPLY 12-DELTATOKEN */
|
||||
/* all 0 */ { true , true , true , false, true , true , true , true , true , true , true , true, true },
|
||||
/* batch 1 */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* crossjoin 2 */ { true , true , true , false, true , true , true , true , true , true , true , true, true },
|
||||
/* entityId 3 */ { false, true , true , true , false, false, false, true , false, false, false, false, false },
|
||||
/* metadata 4 */ { false, true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* service 5 */ { false, true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* entitySet 6 */ { true , true , true , false, true , true , true , true , true , true , true , true, true },
|
||||
/* entitySetCount 7 */ { true , false, false, false, false, false, true , false, false, false, false, true, true },
|
||||
/* entity 8 */ { false, true , true , false, false, false, false, true , false, false, false, false, false },
|
||||
/* mediaStream 9 */ { false, false, false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* references 10 */ { true , true , false, false, true , true , true , false, true , true , true , false, true },
|
||||
/* reference 11 */ { false, true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyComplex 12 */ { false, true , true , false, false, false, false, true , false, false, false, false, false },
|
||||
/* propertyComplexCollection 13 */ { true , true , true , false, true , true , false, true , true , true , true , true , true },
|
||||
/* propertyComplexCollectionCount 14 */ { true , false, false, false, false, false, false, false, false, false, false, true , false },
|
||||
/* propertyPrimitive 15 */ { false, true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyPrimitiveCollection 16 */ { true , true , false, false, true , true , false, false, true , true , true , false, true },
|
||||
/* propertyPrimitiveCollectionCount 17 */ { true , false, false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* propertyPrimitiveValue 18 */ { false, true , false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* none 19 */ { false, true , false, false, false, false, false, false, false, false, false, false, false }
|
||||
};
|
||||
//CHECKSTYLE:ON
|
||||
//@formatter:on
|
||||
|
@ -119,6 +119,7 @@ public class UriValidator {
|
|||
temp.put(SystemQueryOptionKind.SKIPTOKEN, 9);
|
||||
temp.put(SystemQueryOptionKind.TOP, 10);
|
||||
temp.put(SystemQueryOptionKind.APPLY, 11);
|
||||
temp.put(SystemQueryOptionKind.DELTATOKEN, 12);
|
||||
OPTION_INDEX = Collections.unmodifiableMap(temp);
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ SerializerException.IO_EXCEPTION=An I/O exception occurred.
|
|||
SerializerException.NULL_INPUT=The input 'null' is not allowed here.
|
||||
SerializerException.NO_CONTEXT_URL=No context URL has been provided.
|
||||
SerializerException.UNSUPPORTED_PROPERTY_TYPE=The type of the property '%1$s' is not yet supported.
|
||||
SerializerException.MISSING_DELTA_PROPERTY=The delta property '%1$s' is missing.
|
||||
SerializerException.INCONSISTENT_PROPERTY_TYPE=An inconsistency has been detected in the type definition of property '%1$s'.
|
||||
SerializerException.MISSING_PROPERTY=The non-nullable property '%1$s' is missing.
|
||||
SerializerException.MISSING_ID=The entity id value is missing.
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
|
|||
import org.apache.olingo.server.core.uri.queryoption.ApplyOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.DeltaTokenOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
|
||||
|
@ -121,7 +122,8 @@ public class UriInfoImplTest {
|
|||
final QueryOption skipToken = new SkipTokenOptionImpl().setName("");
|
||||
final QueryOption top = new TopOptionImpl().setName("");
|
||||
final QueryOption levels = new LevelsOptionImpl().setName("");
|
||||
|
||||
final QueryOption deltaToken = new DeltaTokenOptionImpl().setName("");
|
||||
|
||||
final QueryOption customOption0 = new CustomQueryOptionImpl().setName("0").setText("A");
|
||||
final QueryOption customOption1 = new CustomQueryOptionImpl().setName("1").setText("B");
|
||||
|
||||
|
@ -146,9 +148,10 @@ public class UriInfoImplTest {
|
|||
.setQueryOption(customOption1)
|
||||
.setQueryOption(levels)
|
||||
.setQueryOption(initialQueryOption)
|
||||
.setQueryOption(alias);
|
||||
.setQueryOption(alias)
|
||||
.setQueryOption(deltaToken);
|
||||
|
||||
assertEquals(13, uriInfo.getSystemQueryOptions().size());
|
||||
assertEquals(14, uriInfo.getSystemQueryOptions().size());
|
||||
assertEquals(apply, uriInfo.getApplyOption());
|
||||
assertEquals(expand, uriInfo.getExpandOption());
|
||||
assertEquals(filter, uriInfo.getFilterOption());
|
||||
|
@ -161,6 +164,7 @@ public class UriInfoImplTest {
|
|||
assertEquals(skip, uriInfo.getSkipOption());
|
||||
assertEquals(skipToken, uriInfo.getSkipTokenOption());
|
||||
assertEquals(top, uriInfo.getTopOption());
|
||||
assertEquals(deltaToken, uriInfo.getDeltaTokenOption());
|
||||
|
||||
assertArrayEquals(new QueryOption[] { alias }, uriInfo.getAliases().toArray());
|
||||
assertEquals("C", uriInfo.getValueForAlias("alias"));
|
||||
|
|
|
@ -94,7 +94,8 @@ public class DataCreator {
|
|||
data.put("ESCompCollDerived", createESCompCollDerived(edm, odata));
|
||||
data.put("ESTwoPrimDerived", createESTwoPrimDerived(edm, odata));
|
||||
data.put("ESAllPrimDerived", createESAllPrimDerived(edm, odata));
|
||||
|
||||
data.put("ESDelta", createESDelta(edm, odata));
|
||||
|
||||
linkSINav(data);
|
||||
linkESTwoPrim(data);
|
||||
linkESAllPrim(data);
|
||||
|
@ -102,6 +103,34 @@ public class DataCreator {
|
|||
linkESKeyNav(data);
|
||||
linkESTwoKeyNav(data);
|
||||
linkESPeople(data);
|
||||
linkESDelta(data);
|
||||
}
|
||||
|
||||
|
||||
private EntityCollection createESDelta(final Edm edm, final OData odata) {
|
||||
EntityCollection entityCollection = new EntityCollection();
|
||||
|
||||
entityCollection.getEntities().add(new Entity()
|
||||
.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + Short.MAX_VALUE)));
|
||||
entityCollection.getEntities().add(new Entity()
|
||||
.addProperty(createPrimitive("PropertyInt16", Short.MIN_VALUE))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + Short.MIN_VALUE)));
|
||||
entityCollection.getEntities().add(new Entity()
|
||||
.addProperty(createPrimitive("PropertyInt16", 0))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + 0)));
|
||||
entityCollection.getEntities().add(new Entity()
|
||||
.addProperty(createPrimitive("PropertyInt16", 100))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + 100)));
|
||||
entityCollection.getEntities().add(new Entity()
|
||||
.addProperty(createPrimitive("PropertyInt16", -1))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + -1)));
|
||||
|
||||
|
||||
setEntityType(entityCollection, edm.getEntityType(EntityTypeProvider.nameETDelta));
|
||||
createEntityId(edm, odata, "ESDelta", entityCollection);
|
||||
createOperations("ESDelta", entityCollection, EntityTypeProvider.nameETDelta);
|
||||
return entityCollection;
|
||||
}
|
||||
|
||||
private EntityCollection createSINav(Edm edm, OData odata) {
|
||||
|
@ -1511,6 +1540,16 @@ public class DataCreator {
|
|||
+ " <g stroke=\"darkmagenta\" stroke-width=\"16\" fill=\"" + color + "\">\n"
|
||||
+ " <circle cx=\"50\" cy=\"50\" r=\"42\"/>\n" + " </g>\n" + "</svg>\n").getBytes(Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
|
||||
private void linkESDelta(final Map<String, EntityCollection> data) {
|
||||
final EntityCollection entityCollection = data.get("ESDelta");
|
||||
final List<Entity> targetEntities = data.get("ESAllPrim").getEntities();
|
||||
|
||||
setLinks(entityCollection.getEntities().get(0), "NavPropertyETAllPrimMany", targetEntities.get(1),
|
||||
targetEntities.get(2));
|
||||
setLink(entityCollection.getEntities().get(3), "NavPropertyETAllPrimOne", targetEntities.get(0));
|
||||
}
|
||||
|
||||
private void linkESPeople(final Map<String, EntityCollection> data) {
|
||||
final EntityCollection entityCollection = data.get("ESPeople");
|
||||
|
|
|
@ -32,6 +32,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity.Reason;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
|
@ -563,7 +566,54 @@ public class DataProvider {
|
|||
entity.setMediaContentType(type);
|
||||
entity.setMediaETag("W/\"" + UUID.randomUUID() + "\"");
|
||||
}
|
||||
|
||||
|
||||
public List<DeletedEntity> readDeletedEntities(final EdmEntitySet edmEntitySet) throws DataProviderException {
|
||||
EntityCollection entityCollection = data.get(edmEntitySet.getName());
|
||||
List<DeletedEntity> listOfDeletedEntities = new ArrayList<DeletedEntity>();
|
||||
DeletedEntity entitySetDeleted = new DeletedEntity();
|
||||
if (entityCollection.getEntities().size() > 1) {
|
||||
entitySetDeleted.setId(entityCollection.getEntities().get(0).getId());
|
||||
entitySetDeleted.setReason(Reason.changed);
|
||||
listOfDeletedEntities.add(entitySetDeleted);
|
||||
entitySetDeleted = new DeletedEntity();
|
||||
entitySetDeleted.setId(entityCollection.getEntities().get(1).getId());
|
||||
entitySetDeleted.setReason(Reason.deleted);
|
||||
}
|
||||
listOfDeletedEntities.add(entitySetDeleted);
|
||||
return listOfDeletedEntities;
|
||||
}
|
||||
|
||||
public List<DeltaLink> readAddedLinks(final EdmEntitySet edmEntitySet) throws DataProviderException {
|
||||
EntityCollection entityCollection = data.get(edmEntitySet.getName());
|
||||
List<DeltaLink> listOfAddedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link = new DeltaLink();
|
||||
if (entityCollection.getEntities().size() > 0) {
|
||||
link.setSource(entityCollection.getEntities().get(0).getId());
|
||||
link.setRelationship("NavPropertyETAllPrimOne");
|
||||
link.setTarget(data.get("ESAllPrim").getEntities().get(1).getId());
|
||||
}
|
||||
listOfAddedLinks.add(link);
|
||||
return listOfAddedLinks;
|
||||
}
|
||||
|
||||
public List<DeltaLink> readDeletedLinks(final EdmEntitySet edmEntitySet) throws DataProviderException {
|
||||
EntityCollection entityCollection = data.get(edmEntitySet.getName());
|
||||
List<DeltaLink> listOfDeletedLinks = new ArrayList<DeltaLink>();
|
||||
if (entityCollection.getEntities().size() > 1) {
|
||||
DeltaLink link = new DeltaLink();
|
||||
link.setSource(entityCollection.getEntities().get(0).getId());
|
||||
link.setRelationship("NavPropertyETAllPrimOne");
|
||||
link.setTarget(data.get("ESAllPrim").getEntities().get(0).getId());
|
||||
listOfDeletedLinks.add(link);
|
||||
link = new DeltaLink();
|
||||
link.setSource(entityCollection.getEntities().get(1).getId());
|
||||
link.setRelationship("NavPropertyETAllPrimOne");
|
||||
link.setTarget(data.get("ESAllPrim").getEntities().get(1).getId());
|
||||
listOfDeletedLinks.add(link);
|
||||
}
|
||||
return listOfDeletedLinks;
|
||||
}
|
||||
|
||||
public EntityCollection readFunctionEntityCollection(final EdmFunction function, final List<UriParameter> parameters,
|
||||
final UriInfoResource uriInfo) throws DataProviderException {
|
||||
return FunctionData.entityCollectionFunction(function.getName(),
|
||||
|
@ -713,6 +763,42 @@ public class DataProvider {
|
|||
}
|
||||
}
|
||||
|
||||
public List<Entity> readNavigationEntities(EdmEntitySet entitySet) {
|
||||
|
||||
EntityCollection entityCollection = data.get(entitySet.getName());
|
||||
List<Entity> entities = new ArrayList<Entity>();
|
||||
Entity otherEntity = entitySet.getName() == "ESAllPrim" ? data.get("ESDelta").getEntities().get(0) :
|
||||
data.get("ESAllPrim").getEntities().get(0);
|
||||
EntityCollection ec1=new EntityCollection();
|
||||
Entity entity1 = new Entity();
|
||||
entity1.setId(entityCollection.getEntities().get(0).getId());//added navigation
|
||||
entity1.addProperty(entityCollection.getEntities().get(0).getProperty(edm.getEntityContainer()
|
||||
.getEntitySet(entitySet.getName()).getEntityType().getPropertyNames().get(0)));
|
||||
Link link = new Link();
|
||||
Entity entity2 = new Entity();
|
||||
entity2.setId(otherEntity.getId());
|
||||
ec1.getEntities().add(entity2);
|
||||
link.setInlineEntitySet(ec1);
|
||||
link.setTitle("NavPropertyETAllPrimMany");
|
||||
entity1.getNavigationLinks().add(link);
|
||||
|
||||
Entity entity3 = new Entity();
|
||||
EntityCollection ec2=new EntityCollection();
|
||||
entity3.setId(entityCollection.getEntities().get(0).getId());//added navigation
|
||||
DeletedEntity delentity = new DeletedEntity();
|
||||
delentity.setId(otherEntity.getId());
|
||||
delentity.setReason(Reason.deleted);
|
||||
ec2.getEntities().add(delentity);
|
||||
Link delLink = new Link();
|
||||
delLink.setInlineEntitySet(ec2);
|
||||
delLink.setTitle("NavPropertyETAllPrimMany");
|
||||
entity3.getNavigationLinks().add(delLink);
|
||||
entities.add(otherEntity);
|
||||
entities.add(entity1);
|
||||
entities.add(entity3);
|
||||
return entities;
|
||||
}
|
||||
|
||||
public Entity read(EdmSingleton singleton) {
|
||||
if (data.containsKey(singleton.getName())) {
|
||||
EntityCollection entitySet = data.get(singleton.getName());
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
package org.apache.olingo.server.tecsvc.processor;
|
||||
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -28,6 +30,9 @@ import org.apache.olingo.commons.api.data.ComplexValue;
|
|||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.ContextURL.Builder;
|
||||
import org.apache.olingo.commons.api.data.ContextURL.Suffix;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
|
@ -62,6 +67,7 @@ import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
|
|||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.serializer.SerializerStreamResult;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
|
||||
|
@ -70,12 +76,14 @@ import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
|||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.IdOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
|
||||
import org.apache.olingo.server.tecsvc.async.AsyncProcessor;
|
||||
import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
|
||||
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
||||
import org.apache.olingo.server.tecsvc.data.RequestValidator;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.ExpandSystemQueryOptionHandler;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.CountHandler;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.DeltaTokenHandler;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.FilterHandler;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.OrderByHandler;
|
||||
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.SearchHandler;
|
||||
|
@ -91,6 +99,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
implements EntityCollectionProcessor, CountEntityCollectionProcessor, EntityProcessor, MediaEntityProcessor,
|
||||
ReferenceCollectionProcessor, ReferenceProcessor {
|
||||
|
||||
private static final String DELTATOKEN = "deltatoken";
|
||||
|
||||
public TechnicalEntityProcessor(final DataProvider dataProvider, final ServiceMetadata serviceMetadata) {
|
||||
super(dataProvider, serviceMetadata);
|
||||
}
|
||||
|
@ -110,15 +120,28 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
getEdmEntitySet(uriInfo); // including checks
|
||||
final EntityCollection entitySetInitial = readEntityCollection(uriInfo);
|
||||
EntityCollection entitySet = new EntityCollection();
|
||||
|
||||
entitySet.getEntities().addAll(entitySetInitial.getEntities());
|
||||
FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, uriInfo, serviceMetadata.getEdm());
|
||||
response.setContent(odata.createFixedFormatSerializer().count(
|
||||
entitySet.getEntities().size()));
|
||||
int count = entitySet.getEntities().size();
|
||||
for (SystemQueryOption systemQueryOption : uriInfo.getSystemQueryOptions()) {
|
||||
if (systemQueryOption.getName().contains(DELTATOKEN)) {
|
||||
count = count + getDeltaCount(uriInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
response.setContent(odata.createFixedFormatSerializer().count(count));
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.TEXT_PLAIN.toContentTypeString());
|
||||
}
|
||||
|
||||
private int getDeltaCount(UriInfo uriInfo) throws ODataApplicationException {
|
||||
List<DeletedEntity> deletedEntity = readDeletedEntities(uriInfo);
|
||||
List<DeltaLink> addedLink = readAddedLinks(uriInfo);
|
||||
List<DeltaLink> deletedLink = readDeletedLinks(uriInfo);
|
||||
List<Entity> listofNavigationEntities = readNavigationEntities(uriInfo);
|
||||
return deletedEntity.size() + addedLink.size() + deletedLink.size() + listofNavigationEntities.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
|
||||
final ContentType requestedContentType) throws ODataApplicationException, ODataLibraryException {
|
||||
|
@ -513,6 +536,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
edmEntitySet.getEntityType();
|
||||
|
||||
EntityCollection entitySetInitial = readEntityCollection(uriInfo);
|
||||
Delta delta = null;
|
||||
if (entitySetInitial == null) {
|
||||
entitySetInitial = new EntityCollection();
|
||||
}
|
||||
|
@ -553,7 +577,35 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand, uriInfo,
|
||||
serviceMetadata.getEdm());
|
||||
final CountOption countOption = uriInfo.getCountOption();
|
||||
|
||||
final List<SystemQueryOption> systemQueryOptions = uriInfo.getSystemQueryOptions();
|
||||
String deltaToken = null;
|
||||
for (SystemQueryOption systemQueryOption : systemQueryOptions) {
|
||||
if (systemQueryOption.getName().contains(DELTATOKEN)) {
|
||||
deltaToken = systemQueryOption.getText();
|
||||
delta = new Delta();
|
||||
Integer count = 0;
|
||||
if (deltaToken != null) {
|
||||
String deltaTokenValue = generateDeltaToken();
|
||||
List<DeletedEntity> listOfDeletedEntities = readDeletedEntities(uriInfo);
|
||||
List<DeltaLink> listOfAddedLinks = readAddedLinks(uriInfo);
|
||||
List<DeltaLink> listOfDeletedLinks = readDeletedLinks(uriInfo);
|
||||
List<Entity> listofNavigationEntities = readNavigationEntities(uriInfo);
|
||||
delta.getDeletedEntities().addAll(listOfDeletedEntities);
|
||||
delta.getAddedLinks().addAll(listOfAddedLinks);
|
||||
delta.getDeletedLinks().addAll(listOfDeletedLinks);
|
||||
delta.getEntities().addAll(listofNavigationEntities);
|
||||
count = listOfDeletedLinks.size()+listOfAddedLinks.size()+listOfDeletedEntities.size();
|
||||
delta.setDeltaLink(DeltaTokenHandler.createDeltaLink(
|
||||
request.getRawRequestUri(),
|
||||
deltaTokenValue));
|
||||
}
|
||||
|
||||
delta.getEntities().addAll(entitySetSerialization.getEntities());
|
||||
count = count + delta.getEntities().size();
|
||||
delta.setCount(count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
String id;
|
||||
if (edmEntitySet == null) {
|
||||
// Used for functions, function imports etc.
|
||||
|
@ -561,7 +613,12 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
} else {
|
||||
id = request.getRawBaseUri() + edmEntitySet.getName();
|
||||
}
|
||||
|
||||
if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasTrackChanges()) {
|
||||
String deltaTokenValue = generateDeltaToken();
|
||||
entitySetSerialization.setDeltaLink(DeltaTokenHandler.createDeltaLink(
|
||||
request.getRawRequestUri(),
|
||||
deltaTokenValue));
|
||||
}
|
||||
if(isReference) {
|
||||
final SerializerResult serializerResult =
|
||||
serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption);
|
||||
|
@ -573,6 +630,12 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
expand, select, countOption, id);
|
||||
|
||||
response.setODataContent(serializerResult.getODataContent());
|
||||
} else if(delta != null){
|
||||
final SerializerResult serializerResult =
|
||||
serializeDeltaPayloads(request,
|
||||
delta, edmEntitySet, edmEntityType, requestedContentType,
|
||||
expand, select, countOption, id);
|
||||
response.setContent(serializerResult.getContent());
|
||||
} else {
|
||||
final SerializerResult serializerResult =
|
||||
serializeEntityCollection(request,
|
||||
|
@ -587,8 +650,44 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
if (pageSize != null) {
|
||||
response.setHeader(HttpHeader.PREFERENCE_APPLIED,
|
||||
PreferencesApplied.with().maxPageSize(serverPageSize).build().toValueString());
|
||||
}else if (odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasTrackChanges()) {
|
||||
response.setHeader(HttpHeader.PREFERENCE_APPLIED,
|
||||
PreferencesApplied.with().trackChanges().build().toValueString());
|
||||
}
|
||||
if(delta!=null){
|
||||
response.setHeader(HttpHeader.ODATA_VERSION,request.getHeaders(HttpHeader.ODATA_MAX_VERSION).get(0));
|
||||
}
|
||||
}
|
||||
private List<Entity> readNavigationEntities(final UriInfo uriInfo) {
|
||||
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
return dataProvider.readNavigationEntities(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet());
|
||||
}
|
||||
|
||||
private String generateDeltaToken() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.000");
|
||||
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
return dateFormat.format(date);
|
||||
}
|
||||
|
||||
private SerializerResult serializeDeltaPayloads(final ODataRequest request, final Delta delta,
|
||||
final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
|
||||
final ContentType requestedFormat, final ExpandOption expand, final SelectOption select,
|
||||
final CountOption countOption, String id) throws ODataLibraryException {
|
||||
|
||||
return odata.createEdmDeltaSerializer(requestedFormat, request.getHeaders(HttpHeader.ODATA_VERSION))
|
||||
.entityCollection(serviceMetadata,
|
||||
edmEntityType, delta,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(isODataMetadataNone(requestedFormat) ? null :
|
||||
getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand, select))
|
||||
.count(countOption)
|
||||
.expand(expand).select(select)
|
||||
.id(id)
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is streaming is enabled for this entity set in combination with the given content type.
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.apache.olingo.server.tecsvc.processor;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
|
@ -231,6 +233,23 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
return entitySet;
|
||||
}
|
||||
|
||||
protected List<DeletedEntity> readDeletedEntities(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
return dataProvider.readDeletedEntities(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet());
|
||||
}
|
||||
|
||||
|
||||
protected List<DeltaLink> readAddedLinks(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
return dataProvider.readAddedLinks(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet());
|
||||
}
|
||||
|
||||
protected List<DeltaLink> readDeletedLinks(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
return dataProvider.readDeletedLinks(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet());
|
||||
}
|
||||
|
||||
|
||||
protected EntityCollection readEntityCollection(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
if (resourcePaths.size() > 1 && resourcePaths.get(1) instanceof UriResourceNavigation) {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.server.tecsvc.processor.queryoptions.options;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
|
||||
|
||||
public class DeltaTokenHandler {
|
||||
|
||||
public static URI createDeltaLink(final String rawRequestUri, String deltaToken)
|
||||
throws ODataApplicationException {
|
||||
// Remove a maybe existing skiptoken, making sure that the query part is not empty.
|
||||
String deltalink = rawRequestUri.contains("?") ?
|
||||
rawRequestUri.replaceAll("(\\$|%24)deltatoken=.+&?", "").replaceAll("(\\?|&)$", "") :
|
||||
rawRequestUri;
|
||||
|
||||
// Add a question mark or an ampersand, depending on the current query part.
|
||||
deltalink += deltalink.contains("?") ? '&' : '?';
|
||||
deltaToken = deltaToken.substring(0, 4);
|
||||
// Append the new skiptoken.
|
||||
deltalink += SystemQueryOptionKind.DELTATOKEN.toString().replace("$", "%24") // poor man's percent encoding
|
||||
+ '='
|
||||
+ "%2A" +deltaToken ; // "%2A" is a percent-encoded asterisk
|
||||
|
||||
try {
|
||||
return new URI(deltalink);
|
||||
} catch (final URISyntaxException e) {
|
||||
throw new ODataApplicationException("Exception while constructing delta link",
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -109,6 +109,7 @@ public class ContainerProvider {
|
|||
entitySets.add(prov.getEntitySet(ContainerProvider.nameContainer, "ESPeople"));
|
||||
entitySets.add(prov.getEntitySet(ContainerProvider.nameContainer, "ESTwoPrimDerived"));
|
||||
entitySets.add(prov.getEntitySet(ContainerProvider.nameContainer, "ESAllPrimDerived"));
|
||||
entitySets.add(prov.getEntitySet(ContainerProvider.nameContainer, "ESDelta"));
|
||||
|
||||
// Singletons
|
||||
List<CsdlSingleton> singletons = new ArrayList<CsdlSingleton>();
|
||||
|
@ -678,7 +679,7 @@ public class ContainerProvider {
|
|||
new CsdlAnnotation().setTerm(TermProvider.TERM_DATA.getFullQualifiedNameAsString()).setExpression(
|
||||
new CsdlConstantExpression(CsdlConstantExpression.ConstantExpressionType.Bool, "true"))));
|
||||
|
||||
}else if (name.equals("ESAllPrimDerived")) {
|
||||
} else if (name.equals("ESAllPrimDerived")) {
|
||||
return new CsdlEntitySet()
|
||||
.setName("ESAllPrimDerived")
|
||||
.setType(EntityTypeProvider.nameETAllPrim)
|
||||
|
@ -692,6 +693,17 @@ public class ContainerProvider {
|
|||
new CsdlAnnotation().setTerm(TermProvider.TERM_DATA.getFullQualifiedNameAsString()).setExpression(
|
||||
new CsdlConstantExpression(CsdlConstantExpression.ConstantExpressionType.Bool, "true"))
|
||||
));
|
||||
} else if (name.equals("ESDelta")) {
|
||||
return new CsdlEntitySet()
|
||||
.setName("ESDelta")
|
||||
.setType(EntityTypeProvider.nameETTwoPrim)
|
||||
.setNavigationPropertyBindings(Arrays.asList(
|
||||
new CsdlNavigationPropertyBinding()
|
||||
.setPath("NavPropertyETAllPrimOne")
|
||||
.setTarget("ESAllPrim"),
|
||||
new CsdlNavigationPropertyBinding()
|
||||
.setPath("NavPropertyETAllPrimMany")
|
||||
.setTarget("ESAllPrim")));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ public class EntityTypeProvider {
|
|||
"ETMixEnumDefCollComp");
|
||||
public static final FullQualifiedName nameETStream = new FullQualifiedName(SchemaProvider.NAMESPACE,
|
||||
"ETWithStream");
|
||||
public static final FullQualifiedName nameETDelta =
|
||||
new FullQualifiedName(SchemaProvider.NAMESPACE, "ETDelta");
|
||||
|
||||
public static final FullQualifiedName nameETPeople = new FullQualifiedName(SchemaProvider.NAMESPACE, "ETPeople");
|
||||
|
||||
|
@ -503,7 +505,16 @@ public class EntityTypeProvider {
|
|||
PropertyProvider.propertyId,
|
||||
PropertyProvider.propertyName))
|
||||
.setNavigationProperties(Arrays.asList(PropertyProvider.navPropertyFriends));
|
||||
}
|
||||
} else if (entityTypeName.equals(nameETDelta)) {
|
||||
return new CsdlEntityType()
|
||||
.setName("ETDelta")
|
||||
.setBaseType(nameETTwoPrim)
|
||||
.setProperties(Arrays.asList(
|
||||
PropertyProvider.propertyInt16_NotNullable, PropertyProvider.propertyString))
|
||||
.setNavigationProperties(
|
||||
Arrays.asList(PropertyProvider.navPropertyETAllPrimOne_ETAllPrim,
|
||||
PropertyProvider.collectionNavPropertyETAllPrimMany_ETAllPrim));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ public class SchemaProvider {
|
|||
entityTypes.add(prov.getEntityType(EntityTypeProvider.nameETCompMixPrimCollComp));
|
||||
entityTypes.add(prov.getEntityType(EntityTypeProvider.nameETKeyPrimNav));
|
||||
entityTypes.add(prov.getEntityType(EntityTypeProvider.nameETStream));
|
||||
entityTypes.add(prov.getEntityType(EntityTypeProvider.nameETDelta));
|
||||
|
||||
// ComplexTypes
|
||||
List<CsdlComplexType> complexTypes = new ArrayList<CsdlComplexType>();
|
||||
|
|
|
@ -0,0 +1,731 @@
|
|||
/*
|
||||
* 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.server.core.serializer.json;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity;
|
||||
import org.apache.olingo.commons.api.data.DeletedEntity.Reason;
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.data.DeltaLink;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.ContextURL.Suffix;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.serializer.ExpandSelectMock;
|
||||
import org.apache.olingo.server.tecsvc.MetadataETagSupport;
|
||||
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
||||
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class JsonDeltaSerializerTest {
|
||||
|
||||
final EdmDeltaSerializer ser;
|
||||
private static final OData odata = OData.newInstance();
|
||||
private static final ServiceMetadata metadata = odata.createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList(), new MetadataETagSupport("W/\"metadataETag\""));
|
||||
private static final EdmEntityContainer entityContainer = metadata.getEdm().getEntityContainer();
|
||||
private final DataProvider data = new DataProvider(odata, metadata.getEdm());
|
||||
|
||||
|
||||
public JsonDeltaSerializerTest() throws SerializerException {
|
||||
List<String> versions = new ArrayList<String>();
|
||||
versions.add("4.0");
|
||||
ser = OData.newInstance().createEdmDeltaSerializer(ContentType.JSON, versions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addedDeltaLink() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deletedDeltaLink() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> deletedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
deletedLinks.add(link1 );
|
||||
delta.getDeletedLinks().addAll(deletedLinks);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$deletedLink\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deletedEntity() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeletedEntity> deletedEntity = new ArrayList<DeletedEntity>();
|
||||
DeletedEntity entity1 = new DeletedEntity();
|
||||
entity1.setId(new URI("ESDelta(100)"));
|
||||
entity1.setReason(Reason.deleted);
|
||||
DeletedEntity entity2 = new DeletedEntity();
|
||||
entity2.setId(new URI("ESDelta(-32768)"));
|
||||
entity2.setReason(Reason.changed);
|
||||
deletedEntity.add(entity1);
|
||||
deletedEntity.add(entity2);
|
||||
delta.getDeletedEntities().addAll(deletedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+"\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta(100)/$deletedEntity\","
|
||||
+ "\"@odata.id\":\"ESDelta(100)\",\"reason\":\"deleted\"},{"
|
||||
+ "\"@odata.context\":\"#ESDelta(-32768)/$deletedEntity\","
|
||||
+ "\"@odata.id\":\"ESDelta(-32768)\",\"reason\":\"changed\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void addedChangedDeltaEntity() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(1);
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
Entity changedEntity = new Entity();
|
||||
changedEntity.setId(entity2.getId());
|
||||
changedEntity.addProperty(entity2.getProperty("PropertyString"));
|
||||
addedEntity.add(entity);
|
||||
addedEntity.add(changedEntity);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.id\":\"ESDelta(32767)\",\"PropertyInt16\":32767,"
|
||||
+ "\"PropertyString\":\"Number:32767\"},{\"@odata.id\":\"ESDelta(-32768)\","
|
||||
+ "\"PropertyString\":\"Number:-32768\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
@Test
|
||||
public void basicDeltaTest() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
|
||||
List<DeltaLink> deletedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink delLink = new DeltaLink();
|
||||
delLink.setRelationship("NavPropertyETAllPrimOne");
|
||||
delLink.setSource(new URI("ESDelta(100)"));
|
||||
delLink.setTarget(new URI("ESAllPrim(0)"));
|
||||
deletedLinks.add(delLink );
|
||||
delta.getDeletedLinks().addAll(deletedLinks);
|
||||
|
||||
List<DeletedEntity> deletedEntity = new ArrayList<DeletedEntity>();
|
||||
DeletedEntity delEntity1 = new DeletedEntity();
|
||||
delEntity1.setId(new URI("ESDelta(100)"));
|
||||
delEntity1.setReason(Reason.deleted);
|
||||
DeletedEntity delEntity2 = new DeletedEntity();
|
||||
delEntity2.setId(new URI("ESDelta(-32768)"));
|
||||
delEntity2.setReason(Reason.changed);
|
||||
deletedEntity.add(delEntity1);
|
||||
deletedEntity.add(delEntity2);
|
||||
delta.getDeletedEntities().addAll(deletedEntity);
|
||||
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(1);
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
Entity changedEntity = new Entity();
|
||||
changedEntity.setId(entity2.getId());
|
||||
changedEntity.addProperty(entity2.getProperty("PropertyString"));
|
||||
addedEntity.add(entity);
|
||||
addedEntity.add(changedEntity);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+"\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.id\":\"ESDelta(32767)\",\"PropertyInt16\":32767,"
|
||||
+ "\"PropertyString\":\"Number:32767\"},{\"@odata.id\":\"ESDelta(-32768)\","
|
||||
+ "\"PropertyString\":\"Number:-32768\"},{\"@odata.context\":\"#ESDelta(100)/$deletedEntity\","
|
||||
+ "\"@odata.id\":\"ESDelta(100)\",\"reason\":\"deleted\"},"
|
||||
+ "{\"@odata.context\":\"#ESDelta(-32768)/$deletedEntity\",\"@odata.id\":\"ESDelta(-32768)\","
|
||||
+ "\"reason\":\"changed\"},{\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\",\"target\":\"ESAllPrim(0)\"},{\"@odata.context\":"
|
||||
+ "\"#ESDelta/$deletedLink\",\"source\":\"ESDelta(100)\",\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addedDifferentdDeltaEntity() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
final EdmEntitySet edmEntitySet2 = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
addedEntity.add(entity);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet2.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet2).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+"\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESAllPrim/$entity\",\"@odata.id\":\"ESAllPrim(32767)\","
|
||||
+ "\"PropertyInt16\":32767,\"PropertyString\":\"First Resource - positive values\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeltaToken() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.setDeltaLink(new URI("23042017"));
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}],"
|
||||
+ "\"@odata.deltaLink\":\"23042017\""
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipToken() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.setNext(new URI("23042017"));
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}],"
|
||||
+ "\"@odata.nextLink\":\"23042017\""
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipDeltaToken() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.setNext(new URI("23042017"));
|
||||
delta.setDeltaLink(new URI("02052017"));
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}],"
|
||||
+ "\"@odata.nextLink\":\"23042017\""
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeltaCount() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
CountOption countOption = Mockito.mock(CountOption.class);
|
||||
Mockito.when(countOption.getValue()).thenReturn(true);
|
||||
Delta delta = new Delta();
|
||||
delta.setCount(1);
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.setDeltaLink(new URI("23042017"));
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.count(countOption)
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\","
|
||||
+ "\"@odata.count\":\"1\","
|
||||
+ "\"value\":[{"
|
||||
+ "\"@odata.context\":\"#ESDelta/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}],"
|
||||
+ "\"@odata.deltaLink\":\"23042017\""
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
@Test
|
||||
public void testEmptyDelta() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":[]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeltaForStream() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESWithStream");
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESWithStream/$delta\","
|
||||
+ "\"value\":[{\"@odata.context\":\"#ESWithStream/$link\","
|
||||
+ "\"source\":\"ESDelta(100)\",\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selectInDelta() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
final EdmEntityType entityType = edmEntitySet.getEntityType();
|
||||
final UriHelper helper = odata.createUriHelper();
|
||||
final SelectOption select = ExpandSelectMock.mockSelectOption(Collections.singletonList(
|
||||
ExpandSelectMock.mockSelectItem(entityContainer.getEntitySet("ESAllPrim"), "PropertyString")));
|
||||
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(1);
|
||||
|
||||
Delta delta = new Delta();
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
Entity changedEntity = new Entity();
|
||||
changedEntity.setId(entity2.getId());
|
||||
changedEntity.addProperty(entity2.getProperty("PropertyString"));
|
||||
changedEntity.addProperty(entity2.getProperty("PropertyInt16"));
|
||||
addedEntity.add(entity);
|
||||
addedEntity.add(changedEntity);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, null, select))
|
||||
.suffix(Suffix.ENTITY).build())
|
||||
.select(select).build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
Assert.assertEquals("{"
|
||||
+"\"@odata.context\":\"$metadata#ESDelta(PropertyString)/$entity/$delta\","
|
||||
+ "\"value\":[{\"@odata.id\":\"ESDelta(32767)\",\"PropertyString\":\"Number:32767\"},"
|
||||
+ "{\"@odata.id\":\"ESDelta(-32768)\",\"PropertyString\":\"Number:-32768\"}]}",
|
||||
jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollPropertyInDelta() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
List<Entity> addedEntities = new ArrayList<Entity>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
addedEntities.add(entity);
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.getEntities().addAll(addedEntities);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESCollAllPrim/$delta\","
|
||||
+ "\"value\":[{\"@odata.id\":\"ESCollAllPrim(1)\",\"PropertyInt16\":1,"
|
||||
+ "\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\","
|
||||
+ "\"Employee3@company.example\"],\"CollPropertyBoolean\":[true,false,true],"
|
||||
+ "\"CollPropertyByte\":[50,200,249],\"CollPropertySByte\":[-120,120,126],\"CollPropertyInt16\":"
|
||||
+ "[1000,2000,30112],\"CollPropertyInt32\":[23232323,11223355,10000001],\"CollPropertyInt64\":"
|
||||
+ "[929292929292,333333333333,444444444444],\"CollPropertySingle\":[1790.0,26600.0,3210.0],"
|
||||
+ "\"CollPropertyDouble\":[-17900.0,-2.78E7,3210.0],\"CollPropertyDecimal\":"
|
||||
+ "[12,-2,1234],\"CollPropertyBinary\":"
|
||||
+ "[\"q83v\",\"ASNF\",\"VGeJ\"],\"CollPropertyDate\":[\"1958-12-03\",\"1999-08-05\",\"2013-06-25\"],"
|
||||
+ "\"CollPropertyDateTimeOffset\":[\"2015-08-12T03:08:34Z\",\"1970-03-28T12:11:10Z\","
|
||||
+ "\"1948-02-17T09:09:09Z\"],"
|
||||
+ "\"CollPropertyDuration\":[\"PT13S\",\"PT5H28M0S\",\"PT1H0S\"],\"CollPropertyGuid\":"
|
||||
+ "[\"ffffff67-89ab-cdef-0123-456789aaaaaa\",\"eeeeee67-89ab-cdef-0123-456789bbbbbb\","
|
||||
+ "\"cccccc67-89ab-cdef-0123-456789cccccc\"],\"CollPropertyTimeOfDay\":[\"04:14:13\",\"23:59:59\","
|
||||
+ "\"01:12:33\"]},{\"@odata.context\":\"#ESCollAllPrim/$link\",\"source\":\"ESDelta(100)\",\"relationship\":"
|
||||
+ "\"NavPropertyETAllPrimOne\",\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexCollPropertyInDelta() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESKeyNav");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
Delta delta = new Delta();
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
List<Entity> addedEntities = new ArrayList<Entity>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
addedEntities.add(entity);
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
delta.getEntities().addAll(addedEntities);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+"\"@odata.context\":\"$metadata#ESKeyNav/$delta\","
|
||||
+ "\"value\":[{\"@odata.id\":\"ESKeyNav(1)\",\"PropertyInt16\":1,"
|
||||
+ "\"PropertyString\":\"I am String Property 1\",\"PropertyCompNav\":"
|
||||
+ "{\"PropertyInt16\":1},\"PropertyCompAllPrim\":{\"PropertyString\":"
|
||||
+ "\"First Resource - positive values\",\"PropertyBinary\":"
|
||||
+ "\"ASNFZ4mrze8=\",\"PropertyBoolean\":true,\"PropertyByte\":"
|
||||
+ "255,\"PropertyDate\":\"2012-12-03\",\"PropertyDateTimeOffset\":"
|
||||
+ "\"2012-12-03T07:16:23Z\",\"PropertyDecimal\":"
|
||||
+ "34,\"PropertySingle\":1.79E20,\"PropertyDouble\":-1.79E20,\"PropertyDuration\":\"PT6S\",\"PropertyGuid\":"
|
||||
+ "\"01234567-89ab-cdef-0123-456789abcdef\",\"PropertyInt16\":32767,"
|
||||
+ "\"PropertyInt32\":2147483647,\"PropertyInt64\":"
|
||||
+ "9223372036854775807,\"PropertySByte\":127,\"PropertyTimeOfDay\":\"21:05:59\"},\"PropertyCompTwoPrim\":"
|
||||
+ "{\"PropertyInt16\":16,\"PropertyString\":\"Test123\"},\"CollPropertyString\":"
|
||||
+ "[\"Employee1@company.example\","
|
||||
+ "\"Employee2@company.example\",\"Employee3@company.example\"],\"CollPropertyInt16\":[1000,2000,30112],"
|
||||
+ "\"CollPropertyComp\":[{\"PropertyInt16\":1,\"PropertyComp\":{\"PropertyString\":"
|
||||
+ "\"First Resource - positive values\","
|
||||
+ "\"PropertyBinary\":\"ASNFZ4mrze8=\",\"PropertyBoolean\":true,\"PropertyByte\":"
|
||||
+ "255,\"PropertyDate\":\"2012-12-03\","
|
||||
+ "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\",\"PropertyDecimal\":34,\"PropertySingle\":1.79E20,"
|
||||
+ "\"PropertyDouble\":-1.79E20,\"PropertyDuration\":\"PT6S\",\"PropertyGuid\":"
|
||||
+ "\"01234567-89ab-cdef-0123-456789abcdef\","
|
||||
+ "\"PropertyInt16\":32767,\"PropertyInt32\":2147483647,\"PropertyInt64\":"
|
||||
+ "9223372036854775807,\"PropertySByte\":127,"
|
||||
+ "\"PropertyTimeOfDay\":\"21:05:59\"}},{\"PropertyInt16\":2,\"PropertyComp\":{\"PropertyString\":"
|
||||
+ "\"First Resource - positive values\",\"PropertyBinary\":\"ASNFZ4mrze8=\",\"PropertyBoolean\":true,"
|
||||
+ "\"PropertyByte\":255,\"PropertyDate\":\"2012-12-03\",\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
|
||||
+ "\"PropertyDecimal\":34,\"PropertySingle\":1.79E20,\"PropertyDouble\":-1.79E20,"
|
||||
+ "\"PropertyDuration\":\"PT6S\","
|
||||
+ "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
|
||||
+ "\"PropertyInt16\":32767,\"PropertyInt32\":2147483647,"
|
||||
+ "\"PropertyInt64\":9223372036854775807,\"PropertySByte\":127,"
|
||||
+ "\"PropertyTimeOfDay\":\"21:05:59\"}},{\"PropertyInt16\":3,"
|
||||
+ "\"PropertyComp\":{\"PropertyString\":\"First Resource - positive values\","
|
||||
+ "\"PropertyBinary\":\"ASNFZ4mrze8=\","
|
||||
+ "\"PropertyBoolean\":true,\"PropertyByte\":255,\"PropertyDate\":\"2012-12-03\",\"PropertyDateTimeOffset\":"
|
||||
+ "\"2012-12-03T07:16:23Z\",\"PropertyDecimal\":34,\"PropertySingle\":1.79E20,\"PropertyDouble\":-1.79E20,"
|
||||
+ "\"PropertyDuration\":\"PT6S\",\"PropertyGuid\":"
|
||||
+ "\"01234567-89ab-cdef-0123-456789abcdef\",\"PropertyInt16\":32767,"
|
||||
+ "\"PropertyInt32\":2147483647,\"PropertyInt64\":9223372036854775807,"
|
||||
+ "\"PropertySByte\":127,\"PropertyTimeOfDay\":"
|
||||
+ "\"21:05:59\"}}],\"PropertyCompCompNav\":{\"PropertyString\":\"1\","
|
||||
+ "\"PropertyCompNav\":{\"PropertyInt16\":1}}},"
|
||||
+ "{\"@odata.context\":\"#ESKeyNav/$link\",\"source\":\"ESDelta(100)\","
|
||||
+ "\"relationship\":\"NavPropertyETAllPrimOne\","
|
||||
+ "\"target\":\"ESAllPrim(0)\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void navigationEntityInDeltaEntity() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(3);
|
||||
final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
|
||||
ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
Entity changedEntity = new Entity();
|
||||
changedEntity.setId(entity.getId());
|
||||
changedEntity.addProperty(entity.getProperty("PropertyString"));
|
||||
addedEntity.add(entity);
|
||||
addedEntity.add(entity2);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
|
||||
.build()).getContent();
|
||||
String jsonString = IOUtils.toString(stream);
|
||||
final String expectedResult = "{"
|
||||
+ "\"@odata.context\":\"$metadata#ESDelta/$delta\",\"value\":"
|
||||
+ "[{\"@odata.id\":\"ESDelta(32767)\",\"PropertyInt16\":32767,\"PropertyString\":"
|
||||
+ "\"Number:32767\"},{\"@odata.id\":\"ESDelta(100)\",\"PropertyInt16\":100,"
|
||||
+ "\"PropertyString\":\"Number:100\"}]"
|
||||
+ "}";
|
||||
Assert.assertNotNull(jsonString);
|
||||
Assert.assertEquals(expectedResult, jsonString);
|
||||
}
|
||||
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeDeltaEntityTest() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(1);
|
||||
List<Entity> addedEntity = new ArrayList<Entity>();
|
||||
Entity changedEntity = new Entity();
|
||||
changedEntity.addProperty(entity2.getProperty("PropertyString"));
|
||||
addedEntity.add(changedEntity);
|
||||
delta.getEntities().addAll(addedEntity);
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeLinkDeltaTest1() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
}
|
||||
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeLinkDeltaTest2() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setTarget(new URI("ESAllPrim(0)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
}
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeLinkDeltaTest3() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = new DeltaLink();
|
||||
link1.setRelationship("NavPropertyETAllPrimOne");
|
||||
link1.setSource(new URI("ESDelta(100)"));
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
}
|
||||
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeLinkDeltaTest4() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeltaLink> addedLinks = new ArrayList<DeltaLink>();
|
||||
DeltaLink link1 = null;
|
||||
addedLinks.add(link1 );
|
||||
delta.getAddedLinks().addAll(addedLinks );
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
}
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeDeltaDeletedEntityTest1() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeletedEntity> deletedEntity = new ArrayList<DeletedEntity>();
|
||||
DeletedEntity delEntity1 = new DeletedEntity();
|
||||
delEntity1.setReason(Reason.deleted);
|
||||
|
||||
deletedEntity.add(delEntity1);
|
||||
delta.getDeletedEntities().addAll(deletedEntity);
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = SerializerException.class)
|
||||
public void negativeDeltaDeletedEntityTest2() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
|
||||
Delta delta = new Delta();
|
||||
|
||||
List<DeletedEntity> deletedEntity = new ArrayList<DeletedEntity>();
|
||||
DeletedEntity delEntity1 = new DeletedEntity();
|
||||
delEntity1.setId(new URI("ESDelta(100)"));
|
||||
|
||||
deletedEntity.add(delEntity1);
|
||||
delta.getDeletedEntities().addAll(deletedEntity);
|
||||
|
||||
ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getContent();
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue