OLINGO-573: New processing framework on server side with single interface with TripPin as example
This commit is contained in:
parent
3e8c50646e
commit
2b73abcce0
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -18,13 +18,13 @@
|
|||
******************************************************************************/
|
||||
package org.apache.olingo.commons.core;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class DecoderTest {
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -18,16 +18,16 @@
|
|||
******************************************************************************/
|
||||
package org.apache.olingo.commons.core;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for percent-encoding.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class EncoderTest {
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<module>client-core</module>
|
||||
<module>server-api</module>
|
||||
<module>server-core</module>
|
||||
<module>server-core-ext</module>
|
||||
<module>server-tecsvc</module>
|
||||
<module>server-test</module>
|
||||
</modules>
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -19,13 +19,16 @@
|
|||
package org.apache.olingo.server.api.deserializer;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.Parameter;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmAction;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
|
||||
/**
|
||||
* Deserializer on OData server side.
|
||||
|
@ -34,7 +37,7 @@ public interface ODataDeserializer {
|
|||
|
||||
/**
|
||||
* Deserializes an entity stream into an {@link Entity} object.
|
||||
* Validates: property types, no double properties, correct json types
|
||||
* Validates: property types, no double properties, correct json types
|
||||
* @param stream
|
||||
* @param edmEntityType
|
||||
* @return deserialized {@link Entity} object
|
||||
|
@ -50,7 +53,7 @@ public interface ODataDeserializer {
|
|||
* @throws DeserializerException
|
||||
*/
|
||||
EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes an action-parameters stream into an {@link Entity} object.
|
||||
* Validates: parameter types, no double parameters, correct json types.
|
||||
|
@ -60,4 +63,22 @@ public interface ODataDeserializer {
|
|||
* @throws DeserializerException
|
||||
*/
|
||||
List<Parameter> actionParameters(InputStream stream, EdmAction edmAction) throws DeserializerException;
|
||||
|
||||
/**
|
||||
* Deserializes the Property or collections of properties (primitive & complex)
|
||||
* @param stream
|
||||
* @param edmProperty
|
||||
* @return deserialized {@link Property}
|
||||
* @throws DeserializerException
|
||||
*/
|
||||
Property property(InputStream stream, EdmProperty edmProperty) throws DeserializerException;
|
||||
|
||||
/**
|
||||
* Read entity references from the provided document
|
||||
* @param stream
|
||||
* @param keys
|
||||
* @return
|
||||
* @throws DeserializerException
|
||||
*/
|
||||
List<URI> entityReferences(InputStream stream) throws DeserializerException;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -30,6 +30,7 @@ public class EntityCollectionSerializerOptions {
|
|||
private CountOption count;
|
||||
private ExpandOption expand;
|
||||
private SelectOption select;
|
||||
private boolean onlyReferences;
|
||||
|
||||
/** Gets the {@link ContextURL}. */
|
||||
public ContextURL getContextURL() {
|
||||
|
@ -51,6 +52,11 @@ public class EntityCollectionSerializerOptions {
|
|||
return select;
|
||||
}
|
||||
|
||||
/** only writes the references of the entities*/
|
||||
public boolean onlyReferences() {
|
||||
return onlyReferences;
|
||||
}
|
||||
|
||||
/** Initializes the options builder. */
|
||||
public static Builder with() {
|
||||
return new Builder();
|
||||
|
@ -59,7 +65,7 @@ public class EntityCollectionSerializerOptions {
|
|||
/** Builder of OData serializer options. */
|
||||
public static final class Builder {
|
||||
|
||||
private EntityCollectionSerializerOptions options;
|
||||
private final EntityCollectionSerializerOptions options;
|
||||
|
||||
private Builder() {
|
||||
options = new EntityCollectionSerializerOptions();
|
||||
|
@ -89,6 +95,12 @@ public class EntityCollectionSerializerOptions {
|
|||
return this;
|
||||
}
|
||||
|
||||
/** Sets to serialize only references */
|
||||
public Builder setWriteOnlyReferences(final boolean ref) {
|
||||
options.onlyReferences = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds the OData serializer options. */
|
||||
public EntityCollectionSerializerOptions build() {
|
||||
return options;
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -27,6 +27,7 @@ public class EntitySerializerOptions {
|
|||
private ContextURL contextURL;
|
||||
private ExpandOption expand;
|
||||
private SelectOption select;
|
||||
private boolean onlyReferences;
|
||||
|
||||
/** Gets the {@link ContextURL}. */
|
||||
public ContextURL getContextURL() {
|
||||
|
@ -43,6 +44,11 @@ public class EntitySerializerOptions {
|
|||
return select;
|
||||
}
|
||||
|
||||
/** only writes the references of the entities*/
|
||||
public boolean onlyReferences() {
|
||||
return onlyReferences;
|
||||
}
|
||||
|
||||
private EntitySerializerOptions() {}
|
||||
|
||||
/** Initializes the options builder. */
|
||||
|
@ -53,7 +59,7 @@ public class EntitySerializerOptions {
|
|||
/** Builder of OData serializer options. */
|
||||
public static final class Builder {
|
||||
|
||||
private EntitySerializerOptions options;
|
||||
private final EntitySerializerOptions options;
|
||||
|
||||
private Builder() {
|
||||
options = new EntitySerializerOptions();
|
||||
|
@ -77,6 +83,12 @@ public class EntitySerializerOptions {
|
|||
return this;
|
||||
}
|
||||
|
||||
/** Sets to serialize only references */
|
||||
public Builder setWriteOnlyReferences(final boolean ref) {
|
||||
options.onlyReferences = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds the OData serializer options. */
|
||||
public EntitySerializerOptions build() {
|
||||
return options;
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -39,7 +39,7 @@ public interface ODataSerializer {
|
|||
/**
|
||||
* Writes the service document into an InputStream.
|
||||
* @param edm the Entity Data Model
|
||||
* @param serviceRoot the service-root URI of this OData service
|
||||
* @param serviceRoot the service-root URI of this OData service
|
||||
*/
|
||||
InputStream serviceDocument(Edm edm, String serviceRoot) throws SerializerException;
|
||||
|
||||
|
@ -58,21 +58,23 @@ public interface ODataSerializer {
|
|||
|
||||
/**
|
||||
* Writes entity-collection data into an InputStream.
|
||||
* @param metadata Metadata for the service
|
||||
* @param entityType the {@link EdmEntityType}
|
||||
* @param entitySet the data of the entity set
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
InputStream entityCollection(EdmEntityType entityType, EntitySet entitySet,
|
||||
EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
InputStream entityCollection(ServiceMetadata metadata, EdmEntityType entityType,
|
||||
EntitySet entitySet, EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
|
||||
/**
|
||||
* Writes entity data into an InputStream.
|
||||
* @param metadata Metadata for the service
|
||||
* @param entityType the {@link EdmEntityType}
|
||||
* @param entity the data of the entity
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
InputStream entity(EdmEntityType entityType, Entity entity, EntitySerializerOptions options)
|
||||
throws SerializerException;
|
||||
InputStream entity(ServiceMetadata metadata, EdmEntityType entityType, Entity entity,
|
||||
EntitySerializerOptions options) throws SerializerException;
|
||||
|
||||
/**
|
||||
* Writes primitive-type instance data into an InputStream.
|
||||
|
@ -85,12 +87,13 @@ public interface ODataSerializer {
|
|||
|
||||
/**
|
||||
* Writes complex-type instance data into an InputStream.
|
||||
* @param metadata Metadata for the service
|
||||
* @param type complex type
|
||||
* @param property property value
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
InputStream complex(EdmComplexType type, Property property, ComplexSerializerOptions options)
|
||||
throws SerializerException;
|
||||
InputStream complex(ServiceMetadata metadata, EdmComplexType type, Property property,
|
||||
ComplexSerializerOptions options) throws SerializerException;
|
||||
|
||||
/**
|
||||
* Writes data of a collection of primitive-type instances into an InputStream.
|
||||
|
@ -103,10 +106,11 @@ public interface ODataSerializer {
|
|||
|
||||
/**
|
||||
* Writes data of a collection of complex-type instances into an InputStream.
|
||||
* @param metadata Metadata for the service
|
||||
* @param type complex type
|
||||
* @param property property value
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
InputStream complexCollection(EdmComplexType type, Property property, ComplexSerializerOptions options)
|
||||
throws SerializerException;
|
||||
InputStream complexCollection(ServiceMetadata metadata, EdmComplexType type, Property property,
|
||||
ComplexSerializerOptions options) throws SerializerException;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -37,7 +37,9 @@ public class SerializerException extends ODataTranslatedException {
|
|||
/** parameter: property name */ INCONSISTENT_PROPERTY_TYPE,
|
||||
/** parameter: property name */ MISSING_PROPERTY,
|
||||
/** parameters: property name, property value */ WRONG_PROPERTY_VALUE,
|
||||
/** parameters: primitive-type name, value */ WRONG_PRIMITIVE_VALUE;
|
||||
/** parameters: primitive-type name, value */ WRONG_PRIMITIVE_VALUE,
|
||||
UNKNOWN_TYPE,
|
||||
WRONG_BASE_TYPE;
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>odata-server-core-ext</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.olingo</groupId>
|
||||
<artifactId>odata-lib</artifactId>
|
||||
<version>4.0.0-beta-03-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
<jetty-version>9.2.7.v20150116</jetty-version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.olingo</groupId>
|
||||
<artifactId>odata-server-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.olingo</groupId>
|
||||
<artifactId>odata-server-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.olingo</groupId>
|
||||
<artifactId>odata-commons-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.stream</groupId>
|
||||
<artifactId>stax-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${jetty-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${jetty-version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${jetty-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>${jetty-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataServerError;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.RepresentationType;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
|
||||
public class ErrorHandler {
|
||||
private final OData odata;
|
||||
private final ServiceMetadata metadata;
|
||||
private final CustomContentTypeSupport customContent;
|
||||
|
||||
public ErrorHandler(OData odata, ServiceMetadata metadata, CustomContentTypeSupport customContent) {
|
||||
this.odata = odata;
|
||||
this.metadata = metadata;
|
||||
this.customContent = customContent;
|
||||
}
|
||||
|
||||
public void handleException(Exception e, ODataRequest request, ODataResponse response) {
|
||||
if (e instanceof UriValidationException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriValidationException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof UriParserSemanticException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserSemanticException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof UriParserSyntaxException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserSyntaxException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof UriParserException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof ContentNegotiatorException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((ContentNegotiatorException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof SerializerException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((SerializerException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof BatchDeserializerException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((BatchDeserializerException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof DeserializerException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((DeserializerException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else if(e instanceof ODataHandlerException) {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((ODataHandlerException)e, null);
|
||||
handleServerError(request, response, serverError);
|
||||
} else {
|
||||
ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
|
||||
handleServerError(request, response, serverError);
|
||||
}
|
||||
}
|
||||
|
||||
void handleServerError(final ODataRequest request, final ODataResponse response,
|
||||
final ODataServerError serverError) {
|
||||
ContentType requestedContentType;
|
||||
try {
|
||||
UriInfo uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(),
|
||||
null, this.metadata.getEdm());
|
||||
requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
|
||||
request, this.customContent, RepresentationType.ERROR);
|
||||
} catch (final ContentNegotiatorException e) {
|
||||
requestedContentType = ODataFormat.JSON.getContentType();
|
||||
} catch (UriParserException e) {
|
||||
requestedContentType = ODataFormat.JSON.getContentType();
|
||||
}
|
||||
processError(response, serverError, requestedContentType);
|
||||
}
|
||||
|
||||
void processError(ODataResponse response, ODataServerError serverError,
|
||||
ContentType requestedContentType) {
|
||||
try {
|
||||
ODataSerializer serializer = this.odata.createSerializer(ODataFormat
|
||||
.fromContentType(requestedContentType));
|
||||
response.setContent(serializer.error(serverError));
|
||||
response.setStatusCode(serverError.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
|
||||
} catch (Exception e) {
|
||||
// This should never happen but to be sure we have this catch here
|
||||
// to prevent sending a stacktrace to a client.
|
||||
String responseContent = "{\"error\":{\"code\":null,\"message\":\"An unexpected exception occurred during "
|
||||
+ "error processing with message: " + e.getMessage() + "\"}}"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
response.setContent(new ByteArrayInputStream(responseContent.getBytes()));
|
||||
response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE,
|
||||
ContentType.APPLICATION_JSON.toContentTypeString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.events.Attribute;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.provider.Action;
|
||||
import org.apache.olingo.commons.api.edm.provider.ActionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.ComplexType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EnumMember;
|
||||
import org.apache.olingo.commons.api.edm.provider.EnumType;
|
||||
import org.apache.olingo.commons.api.edm.provider.Function;
|
||||
import org.apache.olingo.commons.api.edm.provider.FunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.NavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.NavigationPropertyBinding;
|
||||
import org.apache.olingo.commons.api.edm.provider.OnDelete;
|
||||
import org.apache.olingo.commons.api.edm.provider.OnDeleteAction;
|
||||
import org.apache.olingo.commons.api.edm.provider.Operation;
|
||||
import org.apache.olingo.commons.api.edm.provider.Parameter;
|
||||
import org.apache.olingo.commons.api.edm.provider.Property;
|
||||
import org.apache.olingo.commons.api.edm.provider.PropertyRef;
|
||||
import org.apache.olingo.commons.api.edm.provider.ReferentialConstraint;
|
||||
import org.apache.olingo.commons.api.edm.provider.ReturnType;
|
||||
import org.apache.olingo.commons.api.edm.provider.Schema;
|
||||
import org.apache.olingo.commons.api.edm.provider.Singleton;
|
||||
import org.apache.olingo.commons.api.edm.provider.Term;
|
||||
import org.apache.olingo.commons.api.edm.provider.TypeDefinition;
|
||||
|
||||
/**
|
||||
* This class can convert a CSDL document into EDMProvider object
|
||||
*/
|
||||
public class MetadataParser {
|
||||
|
||||
public EdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||
|
||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
||||
new ElementReader<SchemaBasedEdmProvider>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||
String name) throws XMLStreamException {
|
||||
String version = attr(element, "Version");
|
||||
if (version.equals("4.0")) {
|
||||
readDataServicesAndReference(reader, element, provider);
|
||||
}
|
||||
}
|
||||
}.read(reader, null, provider, "Edmx");
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private void readDataServicesAndReference(XMLEventReader reader, StartElement element,
|
||||
SchemaBasedEdmProvider provider) throws XMLStreamException {
|
||||
new ElementReader<SchemaBasedEdmProvider>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||
String name) throws XMLStreamException {
|
||||
if (name.equals("DataServices")) {
|
||||
readSchema(reader, element, provider);
|
||||
} else if (name.equals("Reference")) {
|
||||
readReference(reader, element, provider, "Reference");
|
||||
}
|
||||
}
|
||||
}.read(reader, element, provider, "DataServices", "Reference");
|
||||
}
|
||||
|
||||
private void readReference(XMLEventReader reader, StartElement element,
|
||||
SchemaBasedEdmProvider provider, String name) throws XMLStreamException {
|
||||
new ElementReader<SchemaBasedEdmProvider>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider t, String name)
|
||||
throws XMLStreamException {
|
||||
// TODO:
|
||||
}
|
||||
}.read(reader, element, provider, name);
|
||||
}
|
||||
|
||||
private void readSchema(XMLEventReader reader, StartElement element,
|
||||
SchemaBasedEdmProvider provider) throws XMLStreamException {
|
||||
|
||||
Schema schema = new Schema();
|
||||
schema.setComplexTypes(new ArrayList<ComplexType>());
|
||||
schema.setActions(new ArrayList<Action>());
|
||||
schema.setEntityTypes(new ArrayList<EntityType>());
|
||||
schema.setEnumTypes(new ArrayList<EnumType>());
|
||||
schema.setFunctions(new ArrayList<Function>());
|
||||
schema.setTerms(new ArrayList<Term>());
|
||||
schema.setTypeDefinitions(new ArrayList<TypeDefinition>());
|
||||
|
||||
new ElementReader<Schema>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, Schema schema, String name)
|
||||
throws XMLStreamException {
|
||||
schema.setNamespace(attr(element, "Namespace"));
|
||||
schema.setAlias(attr(element, "Alias"));
|
||||
readSchemaContents(reader, schema);
|
||||
}
|
||||
}.read(reader, element, schema, "Schema");
|
||||
provider.addSchema(schema);
|
||||
}
|
||||
|
||||
private void readSchemaContents(XMLEventReader reader, Schema schema) throws XMLStreamException {
|
||||
new ElementReader<Schema>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, Schema schema, String name)
|
||||
throws XMLStreamException {
|
||||
if (name.equals("Action")) {
|
||||
readAction(reader, element, schema);
|
||||
} else if (name.equals("Annotations")) {
|
||||
// TODO:
|
||||
} else if (name.equals("Annotation")) {
|
||||
// TODO:
|
||||
} else if (name.equals("ComplexType")) {
|
||||
readComplexType(reader, element, schema);
|
||||
} else if (name.equals("EntityContainer")) {
|
||||
readEntityContainer(reader, element, schema);
|
||||
} else if (name.equals("EntityType")) {
|
||||
readEntityType(reader, element, schema);
|
||||
} else if (name.equals("EnumType")) {
|
||||
readEnumType(reader, element, schema);
|
||||
} else if (name.equals("Function")) {
|
||||
readFunction(reader, element, schema);
|
||||
} else if (name.equals("Term")) {
|
||||
schema.getTerms().add(readTerm(element));
|
||||
} else if (name.equals("TypeDefinition")) {
|
||||
schema.getTypeDefinitions().add(readTypeDefinition(element));
|
||||
}
|
||||
}
|
||||
}.read(reader, null, schema, "Action", "Annotations", "Annotation", "ComplexType",
|
||||
"EntityContainer", "EntityType", "EnumType", "Function", "Term", "TypeDefinition");
|
||||
}
|
||||
|
||||
private void readAction(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
|
||||
Action action = new Action();
|
||||
action.setParameters(new ArrayList<Parameter>());
|
||||
action.setName(attr(element, "Name"));
|
||||
action.setBound(Boolean.parseBoolean(attr(element, "IsBound")));
|
||||
String entitySetPath = attr(element, "EntitySetPath");
|
||||
if (entitySetPath != null) {
|
||||
// TODO: need to parse into binding and path.
|
||||
action.setEntitySetPath(entitySetPath);
|
||||
}
|
||||
readOperationParameters(reader, action);
|
||||
schema.getActions().add(action);
|
||||
}
|
||||
|
||||
private FullQualifiedName readType(StartElement element) {
|
||||
String type = attr(element, "Type");
|
||||
if (type.startsWith("Collection(") && type.endsWith(")")) {
|
||||
return new FullQualifiedName(type.substring(11, type.length() - 1));
|
||||
}
|
||||
return new FullQualifiedName(type);
|
||||
}
|
||||
|
||||
private boolean isCollectionType(StartElement element) {
|
||||
String type = attr(element, "Type");
|
||||
if (type.startsWith("Collection(") && type.endsWith(")")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void readReturnType(StartElement element, Operation operation) {
|
||||
ReturnType returnType = new ReturnType();
|
||||
returnType.setType(readType(element));
|
||||
returnType.setCollection(isCollectionType(element));
|
||||
returnType.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
|
||||
|
||||
String maxLength = attr(element, "MaxLength");
|
||||
if (maxLength != null) {
|
||||
returnType.setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
String precision = attr(element, "Precision");
|
||||
if (precision != null) {
|
||||
returnType.setPrecision(Integer.parseInt(precision));
|
||||
}
|
||||
String scale = attr(element, "Scale");
|
||||
if (scale != null) {
|
||||
returnType.setScale(Integer.parseInt(scale));
|
||||
}
|
||||
String srid = attr(element, "SRID");
|
||||
if (srid != null) {
|
||||
// TODO: no olingo support yet.
|
||||
}
|
||||
operation.setReturnType(returnType);
|
||||
}
|
||||
|
||||
private void readParameter(StartElement element, Operation operation) {
|
||||
Parameter parameter = new Parameter();
|
||||
parameter.setName(attr(element, "Name"));
|
||||
parameter.setType(readType(element));
|
||||
parameter.setCollection(isCollectionType(element));
|
||||
parameter.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
|
||||
|
||||
String maxLength = attr(element, "MaxLength");
|
||||
if (maxLength != null) {
|
||||
parameter.setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
String precision = attr(element, "Precision");
|
||||
if (precision != null) {
|
||||
parameter.setPrecision(Integer.parseInt(precision));
|
||||
}
|
||||
String scale = attr(element, "Scale");
|
||||
if (scale != null) {
|
||||
parameter.setScale(Integer.parseInt(scale));
|
||||
}
|
||||
String srid = attr(element, "SRID");
|
||||
if (srid != null) {
|
||||
// TODO: no olingo support yet.
|
||||
}
|
||||
operation.getParameters().add(parameter);
|
||||
}
|
||||
|
||||
private TypeDefinition readTypeDefinition(StartElement element) {
|
||||
TypeDefinition td = new TypeDefinition();
|
||||
td.setName(attr(element, "Name"));
|
||||
td.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
|
||||
td.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
||||
|
||||
String maxLength = attr(element, "MaxLength");
|
||||
if (maxLength != null) {
|
||||
td.setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
String precision = attr(element, "Precision");
|
||||
if (precision != null) {
|
||||
td.setPrecision(Integer.parseInt(precision));
|
||||
}
|
||||
String scale = attr(element, "Scale");
|
||||
if (scale != null) {
|
||||
td.setScale(Integer.parseInt(scale));
|
||||
}
|
||||
String srid = attr(element, "SRID");
|
||||
if (srid != null) {
|
||||
// TODO: no olingo support yet.
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
private Term readTerm(StartElement element) {
|
||||
Term term = new Term();
|
||||
term.setName(attr(element, "Name"));
|
||||
term.setType(attr(element, "Type"));
|
||||
if (attr(element, "BaseTerm") != null) {
|
||||
term.setBaseTerm(attr(element, "BaseTerm"));
|
||||
}
|
||||
if (attr(element, "DefaultValue") != null) {
|
||||
term.setDefaultValue(attr(element, "DefaultValue"));
|
||||
}
|
||||
if (attr(element, "AppliesTo") != null) {
|
||||
term.setAppliesTo(Arrays.asList(attr(element, "AppliesTo")));
|
||||
}
|
||||
term.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
|
||||
String maxLength = attr(element, "MaxLength");
|
||||
if (maxLength != null) {
|
||||
term.setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
String precision = attr(element, "Precision");
|
||||
if (precision != null) {
|
||||
term.setPrecision(Integer.parseInt(precision));
|
||||
}
|
||||
String scale = attr(element, "Scale");
|
||||
if (scale != null) {
|
||||
term.setScale(Integer.parseInt(scale));
|
||||
}
|
||||
String srid = attr(element, "SRID");
|
||||
if (srid != null) {
|
||||
// TODO: no olingo support yet.
|
||||
}
|
||||
return term;
|
||||
}
|
||||
|
||||
private void readFunction(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
Function function = new Function();
|
||||
function.setParameters(new ArrayList<Parameter>());
|
||||
function.setName(attr(element, "Name"));
|
||||
function.setBound(Boolean.parseBoolean(attr(element, "IsBound")));
|
||||
function.setComposable(Boolean.parseBoolean(attr(element, "IsComposable")));
|
||||
String entitySetPath = attr(element, "EntitySetPath");
|
||||
if (entitySetPath != null) {
|
||||
// TODO: need to parse into binding and path.
|
||||
function.setEntitySetPath(entitySetPath);
|
||||
}
|
||||
readOperationParameters(reader, function);
|
||||
schema.getFunctions().add(function);
|
||||
}
|
||||
|
||||
private void readOperationParameters(XMLEventReader reader, final Operation operation)
|
||||
throws XMLStreamException {
|
||||
new ElementReader<Operation>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, Operation operation, String name)
|
||||
throws XMLStreamException {
|
||||
if (name.equals("Parameter")) {
|
||||
readParameter(element, operation);
|
||||
} else if (name.equals("ReturnType")) {
|
||||
readReturnType(element, operation);
|
||||
}
|
||||
}
|
||||
}.read(reader, null, operation, "Parameter", "ReturnType");
|
||||
}
|
||||
|
||||
private void readEnumType(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
EnumType type = new EnumType();
|
||||
type.setMembers(new ArrayList<EnumMember>());
|
||||
type.setName(attr(element, "Name"));
|
||||
if (attr(element, "UnderlyingType") != null) {
|
||||
type.setUnderlyingType(new FullQualifiedName(attr(element, "UnderlyingType")));
|
||||
}
|
||||
type.setFlags(Boolean.parseBoolean(attr(element, "IsFlags")));
|
||||
|
||||
readEnumMembers(reader, element, type);
|
||||
schema.getEnumTypes().add(type);
|
||||
}
|
||||
|
||||
private void readEnumMembers(XMLEventReader reader, StartElement element, EnumType type)
|
||||
throws XMLStreamException {
|
||||
new ElementReader<EnumType>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, EnumType type, String name)
|
||||
throws XMLStreamException {
|
||||
EnumMember member = new EnumMember();
|
||||
member.setName(attr(element, "Name"));
|
||||
member.setValue(attr(element, "Value"));
|
||||
type.getMembers().add(member);
|
||||
}
|
||||
}.read(reader, element, type, "Member");
|
||||
}
|
||||
|
||||
private void readEntityType(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
EntityType entityType = new EntityType();
|
||||
entityType.setProperties(new ArrayList<Property>());
|
||||
entityType.setNavigationProperties(new ArrayList<NavigationProperty>());
|
||||
entityType.setKey(new ArrayList<PropertyRef>());
|
||||
entityType.setName(attr(element, "Name"));
|
||||
if (attr(element, "BaseType") != null) {
|
||||
entityType.setBaseType(new FullQualifiedName(attr(element, "BaseType")));
|
||||
}
|
||||
entityType.setAbstract(Boolean.parseBoolean(attr(element, "Abstract")));
|
||||
entityType.setOpenType(Boolean.parseBoolean(attr(element, "OpenType")));
|
||||
entityType.setHasStream(Boolean.parseBoolean(attr(element, "HasStream")));
|
||||
readEntityProperties(reader, entityType);
|
||||
schema.getEntityTypes().add(entityType);
|
||||
}
|
||||
|
||||
private void readEntityProperties(XMLEventReader reader, EntityType entityType)
|
||||
throws XMLStreamException {
|
||||
new ElementReader<EntityType>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, EntityType entityType, String name)
|
||||
throws XMLStreamException {
|
||||
if (name.equals("Property")) {
|
||||
entityType.getProperties().add(readProperty(element));
|
||||
} else if (name.equals("NavigationProperty")) {
|
||||
entityType.getNavigationProperties().add(readNavigationProperty(reader, element));
|
||||
} else if (name.equals("Key")) {
|
||||
readKey(reader, element, entityType);
|
||||
}
|
||||
}
|
||||
}.read(reader, null, entityType, "Property", "NavigationProperty", "Key");
|
||||
}
|
||||
|
||||
private void readKey(XMLEventReader reader, StartElement element, EntityType entityType)
|
||||
throws XMLStreamException {
|
||||
new ElementReader<EntityType>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, EntityType entityType, String name)
|
||||
throws XMLStreamException {
|
||||
PropertyRef ref = new PropertyRef();
|
||||
ref.setName(attr(element, "Name"));
|
||||
ref.setAlias(attr(element, "Alias"));
|
||||
entityType.getKey().add(ref);
|
||||
}
|
||||
}.read(reader, element, entityType, "PropertyRef");
|
||||
}
|
||||
|
||||
private NavigationProperty readNavigationProperty(XMLEventReader reader, StartElement element)
|
||||
throws XMLStreamException {
|
||||
NavigationProperty property = new NavigationProperty();
|
||||
property.setReferentialConstraints(new ArrayList<ReferentialConstraint>());
|
||||
|
||||
property.setName(attr(element, "Name"));
|
||||
property.setType(readType(element));
|
||||
property.setCollection(isCollectionType(element));
|
||||
property.setNullable(Boolean.parseBoolean(attr(element, "Nullable")));
|
||||
property.setPartner(attr(element, "Partner"));
|
||||
property.setContainsTarget(Boolean.parseBoolean(attr(element, "ContainsTarget")));
|
||||
|
||||
new ElementReader<NavigationProperty>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, NavigationProperty property,
|
||||
String name) throws XMLStreamException {
|
||||
if (name.equals("ReferentialConstraint")) {
|
||||
ReferentialConstraint constraint = new ReferentialConstraint();
|
||||
constraint.setProperty(attr(element, "Property"));
|
||||
constraint.setReferencedProperty(attr(element, "ReferencedProperty"));
|
||||
property.getReferentialConstraints().add(constraint);
|
||||
} else if (name.equals("OnDelete")) {
|
||||
property.setOnDelete(new OnDelete().setAction(OnDeleteAction.valueOf(attr(element, "Action"))));
|
||||
}
|
||||
}
|
||||
}.read(reader, element, property, "ReferentialConstraint", "OnDelete");
|
||||
return property;
|
||||
}
|
||||
|
||||
private String attr(StartElement element, String name) {
|
||||
Attribute attr = element.getAttributeByName(new QName(name));
|
||||
if (attr != null) {
|
||||
return attr.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Property readProperty(StartElement element) {
|
||||
Property property = new Property();
|
||||
property.setName(attr(element, "Name"));
|
||||
property.setType(readType(element));
|
||||
property.setCollection(isCollectionType(element));
|
||||
property.setNullable(Boolean.parseBoolean(attr(element, "Nullable") == null ? "true" : attr(
|
||||
element, "Nullable")));
|
||||
property.setUnicode(Boolean.parseBoolean(attr(element, "Unicode")));
|
||||
|
||||
String maxLength = attr(element, "MaxLength");
|
||||
if (maxLength != null) {
|
||||
property.setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
String precision = attr(element, "Precision");
|
||||
if (precision != null) {
|
||||
property.setPrecision(Integer.parseInt(precision));
|
||||
}
|
||||
String scale = attr(element, "Scale");
|
||||
if (scale != null) {
|
||||
property.setScale(Integer.parseInt(scale));
|
||||
}
|
||||
String srid = attr(element, "SRID");
|
||||
if (srid != null) {
|
||||
// TODO: no olingo support yet.
|
||||
}
|
||||
String defaultValue = attr(element, "DefaultValue");
|
||||
if (defaultValue != null) {
|
||||
property.setDefaultValue(defaultValue);
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
private void readEntityContainer(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
final EntityContainer container = new EntityContainer();
|
||||
container.setName(attr(element, "Name"));
|
||||
if (attr(element, "Extends") != null) {
|
||||
container.setExtendsContainer(attr(element, "Extends"));
|
||||
}
|
||||
container.setActionImports(new ArrayList<ActionImport>());
|
||||
container.setFunctionImports(new ArrayList<FunctionImport>());
|
||||
container.setEntitySets(new ArrayList<EntitySet>());
|
||||
container.setSingletons(new ArrayList<Singleton>());
|
||||
|
||||
new ElementReader<Schema>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, Schema schema, String name)
|
||||
throws XMLStreamException {
|
||||
if (name.equals("EntitySet")) {
|
||||
readEntitySet(reader, element, container);
|
||||
} else if (name.equals("Singleton")) {
|
||||
readSingleton(reader, element, container);
|
||||
} else if (name.equals("ActionImport")) {
|
||||
readActionImport(element, container);
|
||||
} else if (name.equals("FunctionImport")) {
|
||||
readFunctionImport(element, container);
|
||||
}
|
||||
}
|
||||
|
||||
private void readFunctionImport(StartElement element, EntityContainer container) {
|
||||
FunctionImport functionImport = new FunctionImport();
|
||||
functionImport.setName(attr(element, "Name"));
|
||||
functionImport.setFunction(new FullQualifiedName(attr(element, "Function")));
|
||||
functionImport.setIncludeInServiceDocument(Boolean.parseBoolean(attr(element,
|
||||
"IncludeInServiceDocument")));
|
||||
|
||||
String entitySet = attr(element, "EntitySet");
|
||||
if (entitySet != null) {
|
||||
functionImport.setEntitySet(entitySet);
|
||||
}
|
||||
container.getFunctionImports().add(functionImport);
|
||||
}
|
||||
|
||||
private void readActionImport(StartElement element, EntityContainer container) {
|
||||
ActionImport actionImport = new ActionImport();
|
||||
actionImport.setName(attr(element, "Name"));
|
||||
actionImport.setAction(new FullQualifiedName(attr(element, "Action")));
|
||||
|
||||
String entitySet = attr(element, "EntitySet");
|
||||
if (entitySet != null) {
|
||||
actionImport.setEntitySet(entitySet);
|
||||
}
|
||||
container.getActionImports().add(actionImport);
|
||||
}
|
||||
|
||||
private void readSingleton(XMLEventReader reader, StartElement element,
|
||||
EntityContainer container) throws XMLStreamException {
|
||||
Singleton singleton = new Singleton();
|
||||
singleton.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
|
||||
singleton.setName(attr(element, "Name"));
|
||||
singleton.setType(new FullQualifiedName(attr(element, "Type")));
|
||||
singleton.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
|
||||
readNavigationPropertyBindings(reader, element, singleton.getNavigationPropertyBindings());
|
||||
container.getSingletons().add(singleton);
|
||||
}
|
||||
|
||||
private void readEntitySet(XMLEventReader reader, StartElement element,
|
||||
EntityContainer container) throws XMLStreamException {
|
||||
EntitySet entitySet = new EntitySet();
|
||||
entitySet.setName(attr(element, "Name"));
|
||||
entitySet.setType(new FullQualifiedName(attr(element, "EntityType")));
|
||||
entitySet.setIncludeInServiceDocument(Boolean.parseBoolean(attr(element,
|
||||
"IncludeInServiceDocument")));
|
||||
entitySet.setNavigationPropertyBindings(new ArrayList<NavigationPropertyBinding>());
|
||||
readNavigationPropertyBindings(reader, element, entitySet.getNavigationPropertyBindings());
|
||||
container.getEntitySets().add(entitySet);
|
||||
}
|
||||
|
||||
private void readNavigationPropertyBindings(XMLEventReader reader, StartElement element,
|
||||
List<NavigationPropertyBinding> bindings) throws XMLStreamException {
|
||||
new ElementReader<List<NavigationPropertyBinding>>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element,
|
||||
List<NavigationPropertyBinding> bindings, String name) throws XMLStreamException {
|
||||
NavigationPropertyBinding binding = new NavigationPropertyBinding();
|
||||
binding.setPath(attr(element, "Path"));
|
||||
binding.setTarget(attr(element, "Target"));
|
||||
bindings.add(binding);
|
||||
}
|
||||
|
||||
}.read(reader, element, bindings, "NavigationPropertyBinding");
|
||||
;
|
||||
}
|
||||
}.read(reader, element, schema, "EntitySet", "Singleton", "ActionImport", "FunctionImport");
|
||||
schema.setEntityContainer(container);
|
||||
}
|
||||
|
||||
private void readComplexType(XMLEventReader reader, StartElement element, Schema schema)
|
||||
throws XMLStreamException {
|
||||
ComplexType complexType = new ComplexType();
|
||||
complexType.setProperties(new ArrayList<Property>());
|
||||
complexType.setNavigationProperties(new ArrayList<NavigationProperty>());
|
||||
complexType.setName(attr(element, "Name"));
|
||||
if (attr(element, "BaseType") != null) {
|
||||
complexType.setBaseType(new FullQualifiedName(attr(element, "BaseType")));
|
||||
}
|
||||
complexType.setAbstract(Boolean.parseBoolean(attr(element, "Abstract")));
|
||||
complexType.setOpenType(Boolean.parseBoolean(attr(element, "OpenType")));
|
||||
readProperties(reader, complexType);
|
||||
|
||||
schema.getComplexTypes().add(complexType);
|
||||
}
|
||||
|
||||
private void readProperties(XMLEventReader reader, ComplexType complexType)
|
||||
throws XMLStreamException {
|
||||
new ElementReader<ComplexType>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, ComplexType complexType, String name)
|
||||
throws XMLStreamException {
|
||||
if (name.equals("Property")) {
|
||||
complexType.getProperties().add(readProperty(element));
|
||||
} else if (name.equals("NavigationProperty")) {
|
||||
complexType.getNavigationProperties().add(readNavigationProperty(reader, element));
|
||||
}
|
||||
}
|
||||
}.read(reader, null, complexType, "Property", "NavigationProperty");
|
||||
}
|
||||
|
||||
abstract class ElementReader<T> {
|
||||
void read(XMLEventReader reader, StartElement element, T t, String... names)
|
||||
throws XMLStreamException {
|
||||
while (reader.hasNext()) {
|
||||
XMLEvent event = reader.peek();
|
||||
|
||||
event = skipAnnotations(reader, event);
|
||||
|
||||
if (!event.isStartElement() && !event.isEndElement()) {
|
||||
reader.nextEvent();
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean hit = false;
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (event.isStartElement()) {
|
||||
element = event.asStartElement();
|
||||
if (element.getName().getLocalPart().equals(names[i])) {
|
||||
reader.nextEvent(); // advance cursor
|
||||
// System.out.println("reading = "+names[i]);
|
||||
build(reader, element, t, names[i]);
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
if (event.isEndElement()) {
|
||||
EndElement e = event.asEndElement();
|
||||
if (e.getName().getLocalPart().equals(names[i])) {
|
||||
reader.nextEvent(); // advance cursor
|
||||
// System.out.println("done reading = "+names[i]);
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XMLEvent skipAnnotations(XMLEventReader reader, XMLEvent event)
|
||||
throws XMLStreamException {
|
||||
boolean skip = false;
|
||||
|
||||
while (reader.hasNext()) {
|
||||
if (event.isStartElement()) {
|
||||
StartElement element = event.asStartElement();
|
||||
if (element.getName().getLocalPart().equals("Annotation")) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
if (event.isEndElement()) {
|
||||
EndElement element = event.asEndElement();
|
||||
if (element.getName().getLocalPart().equals("Annotation")) {
|
||||
return reader.peek();
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
event = reader.nextEvent();
|
||||
} else {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
abstract void build(XMLEventReader reader, StartElement element, T t, String name)
|
||||
throws XMLStreamException;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.processor.Processor;
|
||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.legacy.ProcessorServiceHandler;
|
||||
|
||||
public class OData4HttpHandler extends ODataHttpHandlerImpl {
|
||||
private ServiceHandler handler;
|
||||
private final ServiceMetadata serviceMetadata;
|
||||
private final OData odata;
|
||||
private CustomContentTypeSupport customContentTypeSupport;
|
||||
|
||||
|
||||
public OData4HttpHandler(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
this.odata = odata;
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
// this is support old interfaces
|
||||
this.handler = new ProcessorServiceHandler();
|
||||
this.handler.init(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
|
||||
ODataRequest request = null;
|
||||
ODataResponse response = new ODataResponse();
|
||||
|
||||
try {
|
||||
request = createODataRequest(httpRequest, 0);
|
||||
validateODataVersion(request, response);
|
||||
|
||||
ServiceDispatcher dispatcher = new ServiceDispatcher(this.odata, this.serviceMetadata,
|
||||
handler, this.customContentTypeSupport);
|
||||
dispatcher.execute(request, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
ErrorHandler handler = new ErrorHandler(this.odata, this.serviceMetadata,
|
||||
this.customContentTypeSupport);
|
||||
handler.handleException(e, request, response);
|
||||
}
|
||||
convertToHttp(httpResponse, response);
|
||||
}
|
||||
|
||||
|
||||
ODataRequest createODataRequest(final HttpServletRequest httpRequest, final int split)
|
||||
throws ODataTranslatedException {
|
||||
try {
|
||||
ODataRequest odRequest = new ODataRequest();
|
||||
|
||||
odRequest.setBody(httpRequest.getInputStream());
|
||||
extractHeaders(odRequest, httpRequest);
|
||||
extractMethod(odRequest, httpRequest);
|
||||
extractUri(odRequest, httpRequest, split);
|
||||
|
||||
return odRequest;
|
||||
} catch (final IOException e) {
|
||||
throw new SerializerException(
|
||||
"An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
void validateODataVersion(final ODataRequest request, final ODataResponse response)
|
||||
throws ODataHandlerException {
|
||||
final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
|
||||
response.setHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
|
||||
|
||||
if (maxVersion != null) {
|
||||
if (ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), maxVersion)) {
|
||||
throw new ODataHandlerException("ODataVersion not supported: " + maxVersion, //$NON-NLS-1$
|
||||
ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final Processor processor) {
|
||||
|
||||
if (processor instanceof ServiceHandler) {
|
||||
this.handler = (ServiceHandler) processor;
|
||||
this.handler.init(this.odata, this.serviceMetadata);
|
||||
}
|
||||
|
||||
if (this.handler instanceof ProcessorServiceHandler) {
|
||||
((ProcessorServiceHandler)this.handler).register(processor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final CustomContentTypeSupport customContentTypeSupport) {
|
||||
this.customContentTypeSupport = customContentTypeSupport;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.olingo.commons.api.ODataRuntimeException;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
|
||||
public class OData4Impl extends ODataImpl {
|
||||
|
||||
public static OData newInstance() {
|
||||
try {
|
||||
final Class<?> clazz = Class.forName(OData4Impl.class.getName());
|
||||
final Object object = clazz.newInstance();
|
||||
return (OData) object;
|
||||
} catch (final Exception e) {
|
||||
throw new ODataRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private OData4Impl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ODataHttpHandler createHandler(final ServiceMetadata edm) {
|
||||
return new OData4HttpHandler(this, edm);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoAll;
|
||||
import org.apache.olingo.server.api.uri.UriInfoBatch;
|
||||
import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
|
||||
import org.apache.olingo.server.api.uri.UriInfoEntityId;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriInfoMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriInfoService;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceCount;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceIt;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceRef;
|
||||
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.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.IdOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SkipOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SkipTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.TopOption;
|
||||
|
||||
public class RequestURLHierarchyVisitor implements RequestURLVisitor {
|
||||
|
||||
private UriInfo uriInfo;
|
||||
|
||||
public UriInfo getUriInfo() {
|
||||
return this.uriInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfo info) {
|
||||
this.uriInfo = info;
|
||||
|
||||
UriInfoKind kind = info.getKind();
|
||||
switch (kind) {
|
||||
case all:
|
||||
visit(info.asUriInfoAll());
|
||||
break;
|
||||
case batch:
|
||||
visit(info.asUriInfoBatch());
|
||||
break;
|
||||
case crossjoin:
|
||||
visit(info.asUriInfoCrossjoin());
|
||||
break;
|
||||
case entityId:
|
||||
visit(info.asUriInfoEntityId());
|
||||
break;
|
||||
case metadata:
|
||||
visit(info.asUriInfoMetadata());
|
||||
break;
|
||||
case resource:
|
||||
visit(info.asUriInfoResource());
|
||||
break;
|
||||
case service:
|
||||
visit(info.asUriInfoService());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoService info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoAll info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoBatch info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoCrossjoin info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoEntityId info) {
|
||||
visit(info.getSelectOption());
|
||||
|
||||
if (info.getExpandOption() != null) {
|
||||
visit(info.getExpandOption());
|
||||
}
|
||||
if (info.getFormatOption() != null) {
|
||||
visit(info.getFormatOption());
|
||||
}
|
||||
if (info.getIdOption() != null) {
|
||||
visit(info.getIdOption(), info.getEntityTypeCast());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoMetadata info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoResource info) {
|
||||
List<UriResource> parts = info.getUriResourceParts();
|
||||
for (UriResource resource : parts) {
|
||||
switch (resource.getKind()) {
|
||||
case action:
|
||||
visit((UriResourceAction) resource);
|
||||
break;
|
||||
case complexProperty:
|
||||
visit((UriResourceComplexProperty) resource);
|
||||
break;
|
||||
case count:
|
||||
visit((UriResourceCount) resource);
|
||||
break;
|
||||
case entitySet:
|
||||
visit((UriResourceEntitySet) resource);
|
||||
break;
|
||||
case function:
|
||||
visit((UriResourceFunction) resource);
|
||||
break;
|
||||
case it:
|
||||
visit((UriResourceIt) resource);
|
||||
break;
|
||||
case lambdaAll:
|
||||
visit((UriResourceLambdaAll) resource);
|
||||
break;
|
||||
case lambdaAny:
|
||||
visit((UriResourceLambdaAny) resource);
|
||||
break;
|
||||
case lambdaVariable:
|
||||
visit((UriResourceLambdaVariable) resource);
|
||||
break;
|
||||
case navigationProperty:
|
||||
visit((UriResourceNavigation) resource);
|
||||
break;
|
||||
case ref:
|
||||
visit((UriResourceRef) resource);
|
||||
break;
|
||||
case root:
|
||||
visit((UriResourceRoot) resource);
|
||||
break;
|
||||
case primitiveProperty:
|
||||
visit((UriResourcePrimitiveProperty) resource);
|
||||
break;
|
||||
case singleton:
|
||||
visit((UriResourceSingleton) resource);
|
||||
break;
|
||||
case value:
|
||||
visit((UriResourceValue) resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html#_Toc372793682
|
||||
if (info.getSearchOption() != null) {
|
||||
visit(info.getSearchOption());
|
||||
}
|
||||
|
||||
if (info.getFilterOption() != null) {
|
||||
visit(info.getFilterOption());
|
||||
}
|
||||
|
||||
if (info.getCountOption() != null) {
|
||||
visit(info.getCountOption());
|
||||
}
|
||||
|
||||
visit(info.getOrderByOption());
|
||||
|
||||
if (info.getSkipOption() != null) {
|
||||
visit(info.getSkipOption());
|
||||
}
|
||||
|
||||
if (info.getTopOption() != null) {
|
||||
visit(info.getTopOption());
|
||||
}
|
||||
|
||||
if (info.getExpandOption() != null) {
|
||||
visit(info.getExpandOption());
|
||||
}
|
||||
|
||||
visit(info.getSelectOption());
|
||||
|
||||
if (info.getFormatOption() != null) {
|
||||
visit(info.getFormatOption());
|
||||
}
|
||||
|
||||
if (info.getIdOption() != null) {
|
||||
visit(info.getIdOption(), null);
|
||||
}
|
||||
|
||||
if (info.getSkipTokenOption() != null) {
|
||||
visit(info.getSkipTokenOption());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpandOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FilterOption info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FormatOption info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IdOption info, EdmEntityType type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CountOption info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(OrderByOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SearchOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SelectOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SkipOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SkipTokenOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(TopOption option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceCount option) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceRef info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceRoot info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceValue info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceAction info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceEntitySet info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceFunction info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceIt info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceLambdaAll info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceLambdaAny info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceLambdaVariable info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceNavigation info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceSingleton info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceComplexProperty info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourcePrimitiveProperty info) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoAll;
|
||||
import org.apache.olingo.server.api.uri.UriInfoBatch;
|
||||
import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
|
||||
import org.apache.olingo.server.api.uri.UriInfoEntityId;
|
||||
import org.apache.olingo.server.api.uri.UriInfoMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriInfoService;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceCount;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceIt;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
|
||||
import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceRef;
|
||||
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.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FormatOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.IdOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SkipOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SkipTokenOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.TopOption;
|
||||
|
||||
public interface RequestURLVisitor {
|
||||
|
||||
void visit(UriInfo info);
|
||||
|
||||
void visit(UriInfoService info);
|
||||
|
||||
void visit(UriInfoAll info);
|
||||
|
||||
void visit(UriInfoBatch info);
|
||||
|
||||
void visit(UriInfoCrossjoin info);
|
||||
|
||||
void visit(UriInfoEntityId info);
|
||||
|
||||
void visit(UriInfoMetadata info);
|
||||
|
||||
void visit(UriInfoResource info);
|
||||
|
||||
// Walk UriInfoResource
|
||||
void visit(ExpandOption option);
|
||||
|
||||
void visit(FilterOption info);
|
||||
|
||||
void visit(FormatOption info);
|
||||
|
||||
void visit(IdOption info, EdmEntityType type);
|
||||
|
||||
void visit(CountOption info);
|
||||
|
||||
void visit(OrderByOption option);
|
||||
|
||||
void visit(SearchOption option);
|
||||
|
||||
void visit(SelectOption option);
|
||||
|
||||
void visit(SkipOption option);
|
||||
|
||||
void visit(SkipTokenOption option);
|
||||
|
||||
void visit(TopOption option);
|
||||
|
||||
void visit(UriResourceCount option);
|
||||
|
||||
void visit(UriResourceRef info);
|
||||
|
||||
void visit(UriResourceRoot info);
|
||||
|
||||
void visit(UriResourceValue info);
|
||||
|
||||
void visit(UriResourceAction info);
|
||||
|
||||
void visit(UriResourceEntitySet info);
|
||||
|
||||
void visit(UriResourceFunction info);
|
||||
|
||||
void visit(UriResourceIt info);
|
||||
|
||||
void visit(UriResourceLambdaAll info);
|
||||
|
||||
void visit(UriResourceLambdaAny info);
|
||||
|
||||
void visit(UriResourceLambdaVariable info);
|
||||
|
||||
void visit(UriResourceNavigation info);
|
||||
|
||||
void visit(UriResourceSingleton info);
|
||||
|
||||
void visit(UriResourceComplexProperty info);
|
||||
|
||||
void visit(UriResourcePrimitiveProperty info);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public enum ReturnRepresentation {
|
||||
REPRESENTATION, MINIMAL
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.ODataException;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.provider.Action;
|
||||
import org.apache.olingo.commons.api.edm.provider.ActionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.AliasInfo;
|
||||
import org.apache.olingo.commons.api.edm.provider.Annotatable;
|
||||
import org.apache.olingo.commons.api.edm.provider.Annotations;
|
||||
import org.apache.olingo.commons.api.edm.provider.ComplexType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityContainerInfo;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EnumType;
|
||||
import org.apache.olingo.commons.api.edm.provider.Function;
|
||||
import org.apache.olingo.commons.api.edm.provider.FunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.Schema;
|
||||
import org.apache.olingo.commons.api.edm.provider.Singleton;
|
||||
import org.apache.olingo.commons.api.edm.provider.Term;
|
||||
import org.apache.olingo.commons.api.edm.provider.TypeDefinition;
|
||||
|
||||
public class SchemaBasedEdmProvider implements EdmProvider {
|
||||
private final List<Schema> edmSchemas = new ArrayList<Schema>();
|
||||
|
||||
protected void addSchema(Schema schema) {
|
||||
this.edmSchemas.add(schema);
|
||||
}
|
||||
|
||||
private Schema getSchema(String ns) {
|
||||
for (Schema s : this.edmSchemas) {
|
||||
if (s.getNamespace().equals(ns)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumType getEnumType(FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
List<EnumType> types = schema.getEnumTypes();
|
||||
if (types != null) {
|
||||
for (EnumType type : types) {
|
||||
if (type.getName().equals(fqn.getName())) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinition getTypeDefinition(FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
List<TypeDefinition> types = schema.getTypeDefinitions();
|
||||
if (types != null) {
|
||||
for (TypeDefinition type : types) {
|
||||
if (type.getName().equals(fqn.getName())) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Function> getFunctions(FullQualifiedName fqn) throws ODataException {
|
||||
ArrayList<Function> foundFuncs = new ArrayList<Function>();
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
List<Function> functions = schema.getFunctions();
|
||||
if (functions != null) {
|
||||
for (Function func : functions) {
|
||||
if (func.getName().equals(fqn.getName())) {
|
||||
foundFuncs.add(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundFuncs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Term getTerm(FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
List<Term> terms = schema.getTerms();
|
||||
if (terms != null) {
|
||||
for (Term term : terms) {
|
||||
if (term.getName().equals(fqn.getName())) {
|
||||
return term;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntitySet getEntitySet(FullQualifiedName fqn, String entitySetName) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
|
||||
if (schema != null) {
|
||||
EntityContainer ec = schema.getEntityContainer();
|
||||
if (ec != null && ec.getEntitySets() != null) {
|
||||
for (EntitySet es : ec.getEntitySets()) {
|
||||
if (es.getName().equals(entitySetName)) {
|
||||
return es;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Singleton getSingleton(FullQualifiedName fqn, String singletonName) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
|
||||
if (schema != null) {
|
||||
EntityContainer ec = schema.getEntityContainer();
|
||||
if (ec != null && ec.getSingletons() != null) {
|
||||
for (Singleton es : ec.getSingletons()) {
|
||||
if (es.getName().equals(singletonName)) {
|
||||
return es;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionImport getActionImport(FullQualifiedName fqn, String actionImportName)
|
||||
throws ODataException {
|
||||
Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
|
||||
if (schema != null) {
|
||||
EntityContainer ec = schema.getEntityContainer();
|
||||
if (ec != null && ec.getActionImports() != null) {
|
||||
for (ActionImport es : ec.getActionImports()) {
|
||||
if (es.getName().equals(actionImportName)) {
|
||||
return es;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionImport getFunctionImport(FullQualifiedName fqn, String functionImportName)
|
||||
throws ODataException {
|
||||
Schema schema = getSchema(fqn.getFullQualifiedNameAsString());
|
||||
if (schema != null) {
|
||||
EntityContainer ec = schema.getEntityContainer();
|
||||
if (ec != null && ec.getFunctionImports() != null) {
|
||||
for (FunctionImport es : ec.getFunctionImports()) {
|
||||
if (es.getName().equals(functionImportName)) {
|
||||
return es;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityContainerInfo getEntityContainerInfo(FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = null;
|
||||
|
||||
if (fqn == null) {
|
||||
for (Schema s : this.edmSchemas) {
|
||||
if (s.getEntityContainer() != null) {
|
||||
schema = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
schema = getSchema(fqn.getFullQualifiedNameAsString());
|
||||
}
|
||||
|
||||
if (schema != null) {
|
||||
EntityContainer ec = schema.getEntityContainer();
|
||||
if (ec != null) {
|
||||
EntityContainerInfo info = new EntityContainerInfo();
|
||||
info.setContainerName(new FullQualifiedName(schema.getNamespace()));
|
||||
if (schema.getEntityContainer().getExtendsContainer() != null) {
|
||||
info.setExtendsContainer(new FullQualifiedName(schema.getEntityContainer().getExtendsContainer()));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AliasInfo> getAliasInfos() throws ODataException {
|
||||
Schema schema = null;
|
||||
for (Schema s : this.edmSchemas) {
|
||||
if (s.getEntityContainer() != null) {
|
||||
schema = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (schema == null) {
|
||||
schema = this.edmSchemas.get(0);
|
||||
}
|
||||
|
||||
AliasInfo ai = new AliasInfo();
|
||||
ai.setAlias(schema.getAlias());
|
||||
ai.setNamespace(schema.getNamespace());
|
||||
return Arrays.asList(ai);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityContainer getEntityContainer() throws ODataException {
|
||||
// note that there can be many schemas, but only one needs to contain the
|
||||
// entity container in a given metadata document.
|
||||
for (Schema s : this.edmSchemas) {
|
||||
if (s.getEntityContainer() != null) {
|
||||
return s.getEntityContainer();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Schema> getSchemas() throws ODataException {
|
||||
return new ArrayList<Schema>(this.edmSchemas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getEntityType(final FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
if (schema.getEntityTypes() != null) {
|
||||
for (EntityType type : schema.getEntityTypes()) {
|
||||
if (type.getName().equals(fqn.getName())) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComplexType getComplexType(final FullQualifiedName fqn) throws ODataException {
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
if (schema.getComplexTypes() != null) {
|
||||
for (ComplexType type : schema.getComplexTypes()) {
|
||||
if (type.getName().equals(fqn.getName())) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getActions(final FullQualifiedName fqn) throws ODataException {
|
||||
ArrayList<Action> actions = new ArrayList<Action>();
|
||||
Schema schema = getSchema(fqn.getNamespace());
|
||||
if (schema != null) {
|
||||
List<Action> types = schema.getActions();
|
||||
if (types != null) {
|
||||
for (Action type : types) {
|
||||
if (type.getName().equals(fqn.getName())) {
|
||||
actions.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotations getAnnotationsGroup(FullQualifiedName targetName) throws ODataException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotatable getAnnoatatable(FullQualifiedName annotatedName) throws ODataException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoBatch;
|
||||
import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
|
||||
import org.apache.olingo.server.api.uri.UriInfoEntityId;
|
||||
import org.apache.olingo.server.api.uri.UriInfoMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriInfoService;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceCount;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceRef;
|
||||
import org.apache.olingo.server.api.uri.UriResourceSingleton;
|
||||
import org.apache.olingo.server.api.uri.UriResourceValue;
|
||||
import org.apache.olingo.server.core.requests.ActionRequest;
|
||||
import org.apache.olingo.server.core.requests.BatchRequest;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.requests.FunctionRequest;
|
||||
import org.apache.olingo.server.core.requests.MediaRequest;
|
||||
import org.apache.olingo.server.core.requests.MetadataRequest;
|
||||
import org.apache.olingo.server.core.requests.ServiceDocumentRequest;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidator;
|
||||
|
||||
public class ServiceDispatcher extends RequestURLHierarchyVisitor {
|
||||
private final OData odata;
|
||||
protected ServiceMetadata metadata;
|
||||
protected ServiceHandler handler;
|
||||
protected CustomContentTypeSupport customContentSupport;
|
||||
private String idOption;
|
||||
protected ServiceRequest request;
|
||||
|
||||
public ServiceDispatcher(OData odata, ServiceMetadata metadata, ServiceHandler handler,
|
||||
CustomContentTypeSupport customContentSupport) {
|
||||
this.odata = odata;
|
||||
this.metadata = metadata;
|
||||
this.handler = handler;
|
||||
this.customContentSupport = customContentSupport;
|
||||
}
|
||||
|
||||
public void execute(ODataRequest odRequest, ODataResponse odResponse)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
UriInfo uriInfo = new Parser().parseUri(odRequest.getRawODataPath(), odRequest.getRawQueryPath(), null,
|
||||
this.metadata.getEdm());
|
||||
|
||||
new UriValidator().validate(uriInfo, odRequest.getMethod());
|
||||
|
||||
visit(uriInfo);
|
||||
|
||||
// this should cover for any unsupported calls until they are implemented
|
||||
if (this.request == null) {
|
||||
this.request = new ServiceRequest(this.odata, this.metadata) {
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentType.APPLICATION_JSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
handler.anyUnsupported(getODataRequest(), response);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// To handle $entity?$id=http://localhost/EntitySet(key) as
|
||||
// http://localhost/EntitySet(key)
|
||||
if (this.idOption != null) {
|
||||
try {
|
||||
this.request = this.request.parseLink(new URI(this.idOption));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ODataHandlerException("Invalid $id value",
|
||||
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED, this.idOption);
|
||||
}
|
||||
}
|
||||
|
||||
this.request.setODataRequest(odRequest);
|
||||
this.request.setUriInfo(uriInfo);
|
||||
this.request.setCustomContentTypeSupport(this.customContentSupport);
|
||||
this.request.execute(this.handler, odResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoMetadata info) {
|
||||
this.request = new MetadataRequest(this.odata, this.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoService info) {
|
||||
this.request = new ServiceDocumentRequest(this.odata, this.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceEntitySet info) {
|
||||
DataRequest dataRequest = new DataRequest(this.odata, this.metadata);
|
||||
dataRequest.setUriResourceEntitySet(info);
|
||||
this.request = dataRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceCount option) {
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
dataRequest.setCountRequest(option != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceComplexProperty info) {
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
dataRequest.setUriResourceProperty(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourcePrimitiveProperty info) {
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
dataRequest.setUriResourceProperty(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceValue info) {
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
if (dataRequest.isPropertyRequest()) {
|
||||
dataRequest.setValueRequest(info != null);
|
||||
} else {
|
||||
MediaRequest mediaRequest = new MediaRequest(this.odata, this.metadata);
|
||||
mediaRequest.setUriResourceEntitySet(dataRequest.getUriResourceEntitySet());
|
||||
this.request = mediaRequest;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceAction info) {
|
||||
ActionRequest actionRequest = new ActionRequest(this.odata, this.metadata);
|
||||
actionRequest.setUriResourceAction(info);
|
||||
this.request = actionRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceFunction info) {
|
||||
FunctionRequest functionRequest = new FunctionRequest(this.odata, this.metadata);
|
||||
functionRequest.setUriResourceFunction(info);
|
||||
this.request = functionRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceNavigation info) {
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
dataRequest.addUriResourceNavigation(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceRef info) {
|
||||
// this is same as data, but return is just entity references.
|
||||
DataRequest dataRequest = (DataRequest) this.request;
|
||||
dataRequest.setReferenceRequest(info != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoBatch info) {
|
||||
this.request = new BatchRequest(this.odata, this.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriResourceSingleton info) {
|
||||
DataRequest dataRequest = new DataRequest(this.odata, this.metadata);
|
||||
dataRequest.setUriResourceSingleton(info);
|
||||
this.request = dataRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoEntityId info) {
|
||||
DataRequest dataRequest = new DataRequest(this.odata, this.metadata);
|
||||
this.request = dataRequest;
|
||||
|
||||
// this can relative or absolute form
|
||||
String id = info.getIdOption().getValue();
|
||||
try {
|
||||
URL url = new URL(id);
|
||||
this.idOption = url.getPath();
|
||||
} catch (MalformedURLException e) {
|
||||
this.idOption = id;
|
||||
}
|
||||
super.visit(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UriInfoCrossjoin info) {
|
||||
DataRequest dataRequest = new DataRequest(this.odata, this.metadata);
|
||||
dataRequest.setCrossJoin(info);
|
||||
this.request = dataRequest;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.processor.Processor;
|
||||
import org.apache.olingo.server.core.requests.ActionRequest;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.requests.FunctionRequest;
|
||||
import org.apache.olingo.server.core.requests.MediaRequest;
|
||||
import org.apache.olingo.server.core.requests.MetadataRequest;
|
||||
import org.apache.olingo.server.core.requests.ServiceDocumentRequest;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.MetadataResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceDocumentResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceResponse;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
|
||||
public interface ServiceHandler extends Processor {
|
||||
|
||||
/**
|
||||
* Read CSDL document of the Service
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void readMetadata(MetadataRequest request, MetadataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Read ServiceDocument of the service
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void readServiceDocument(ServiceDocumentRequest request, ServiceDocumentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Read operation for EntitySets, Entities, Properties, Media etc. Based on the type of request
|
||||
* the response object is different. Even the navigation based queries are handled by this method.
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
<T extends ServiceResponse> void read(DataRequest request, T response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Create new entity in the service based on the entity object provided
|
||||
* @param request
|
||||
* @param entity
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void createEntity(DataRequest request, Entity entity, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Update the entity object.
|
||||
* @param request
|
||||
* @param entity
|
||||
* @param merge - true if merge operation, false it needs to be replaced
|
||||
* @param entityETag - previous entity tag if provided by the user. "*" means allow.
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void updateEntity(DataRequest request, Entity entity, boolean merge, String entityETag,
|
||||
EntityResponse response) throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Delete the Entity
|
||||
* @param request
|
||||
* @param entityETag - entity tag to match, if provided by the user. "*" means allow
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void deleteEntity(DataRequest request, String entityETag, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Update a non-media/stream property.if the value of property NULL, it should be treated as
|
||||
* DeleteProperty 11.4.9.2
|
||||
* @param request
|
||||
* @param property - Updated property.
|
||||
* @param merge - if the property is complex, true here means merge, false is replace
|
||||
* @param entityETag - entity tag to match before update operation, "*" allows all.
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void updateProperty(DataRequest request, Property property, boolean merge, String entityETag,
|
||||
PropertyResponse response) throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Update Stream property, if StreamContent is null, it should treated as delete request
|
||||
* @param request
|
||||
* @param entityETag - entity tag to match before update operation, "*" allows all.
|
||||
* @param streamContent - updated stream content
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void upsertStreamProperty(DataRequest request, String entityETag, InputStream streamContent,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Invocation of a Function. The response object will be based on metadata defined for service
|
||||
* @param request
|
||||
* @param method
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
<T extends ServiceResponse> void invoke(FunctionRequest request, HttpMethod method, T response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Invocation of a Function. The response object will be based on metadata defined for service
|
||||
* @param request
|
||||
* @param eTag
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
<T extends ServiceResponse> void invoke(ActionRequest request, String eTag, T response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Read media stream content of a Entity
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void readMediaStream(MediaRequest request, StreamResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Update of Media Stream Content of a Entity. If the mediaContent is null it should be treated
|
||||
* as delete request.
|
||||
* @param request
|
||||
* @param entityETag - entity etag to match before update operation, "*" allows all.
|
||||
* @param mediaContent - if null, must be treated as delete request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void upsertMediaStream(MediaRequest request, String entityETag, InputStream mediaContent,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Any Unsupported one will be directed here.
|
||||
* @param request
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void anyUnsupported(ODataRequest request, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Add references (relationships) to Entity.
|
||||
* @param request
|
||||
* @param entityETag - entity etag to match before add operation, "*" allows all.
|
||||
* @param idReferences - references to add
|
||||
* @param response - return always should be 204
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void addReference(DataRequest request, String entityETag, List<URI> idReferences, NoContentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Update references (relationships) in an Entity
|
||||
* @param request
|
||||
* @param entityETag
|
||||
* @param referenceId
|
||||
* @param response - always should be 204
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void updateReference(DataRequest request, String entityETag, URI referenceId, NoContentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
/**
|
||||
* Delete references (relationships) in an Entity
|
||||
* @param request
|
||||
* @param deleteId
|
||||
* @param entityETag
|
||||
* @param response - always should be 204
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void deleteReference(DataRequest request, URI deleteId, String entityETag, NoContentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
|
||||
/**
|
||||
* During a batch operation, this method starts the transaction (if any) before any operation is handled
|
||||
* by the service. No nested transactions.
|
||||
* @return must return a unique transaction id that references a atomic operation.
|
||||
*/
|
||||
String startTransaction();
|
||||
|
||||
/**
|
||||
* When a batch operation is complete and all the intermediate service requests are successful, then
|
||||
* commit is called with transaction id returned in the startTransaction method.
|
||||
* @param txnId
|
||||
*/
|
||||
void commit(String txnId);
|
||||
/**
|
||||
* When a batch operation is in-complete due to an error in the middle of changeset, then rollback is
|
||||
* called with transaction id, that returned from startTransaction method.
|
||||
* @param txnId
|
||||
*/
|
||||
void rollback(String txnId);
|
||||
|
||||
/**
|
||||
* This is not complete, more URL parsing changes required. Cross join between two entities.
|
||||
* @param dataRequest
|
||||
* @param entitySetNames
|
||||
* @param response
|
||||
* @throws ODataTranslatedException
|
||||
* @throws ODataApplicationException
|
||||
*/
|
||||
void crossJoin(DataRequest dataRequest, List<String> entitySetNames, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
|
||||
public abstract class ServiceRequest {
|
||||
protected OData odata;
|
||||
protected UriInfo uriInfo;
|
||||
protected ServiceMetadata serviceMetadata;
|
||||
protected CustomContentTypeSupport customContentType;
|
||||
protected ODataRequest request;
|
||||
|
||||
public ServiceRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
this.odata = odata;
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
public OData getOdata() {
|
||||
return odata;
|
||||
}
|
||||
|
||||
public ServiceMetadata getServiceMetaData() {
|
||||
return this.serviceMetadata;
|
||||
}
|
||||
|
||||
public UriInfo getUriInfo() {
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
protected void setUriInfo(UriInfo uriInfo) {
|
||||
this.uriInfo = uriInfo;
|
||||
}
|
||||
|
||||
public boolean allowedMethod() {
|
||||
return isGET();
|
||||
}
|
||||
|
||||
public CustomContentTypeSupport getCustomContentTypeSupport() {
|
||||
return this.customContentType;
|
||||
}
|
||||
|
||||
public void setCustomContentTypeSupport(CustomContentTypeSupport support) {
|
||||
this.customContentType = support;
|
||||
}
|
||||
|
||||
public ODataRequest getODataRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
protected void setODataRequest(ODataRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public ContentType getRequestContentType() {
|
||||
if (this.request.getHeader(HttpHeader.CONTENT_TYPE) != null) {
|
||||
return ContentType.parse(this.request.getHeader(HttpHeader.CONTENT_TYPE));
|
||||
}
|
||||
return ContentType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
|
||||
public abstract void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
|
||||
public abstract ContentType getResponseContentType() throws ContentNegotiatorException;
|
||||
|
||||
public void methodNotAllowed() throws ODataHandlerException {
|
||||
throw new ODataHandlerException("HTTP method " + this.request.getMethod() + " is not allowed.",
|
||||
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, this.request.getMethod()
|
||||
.toString());
|
||||
}
|
||||
|
||||
public void notImplemented() throws ODataHandlerException {
|
||||
throw new ODataHandlerException("not implemented", //$NON-NLS-1$
|
||||
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
protected boolean isGET() {
|
||||
return this.request.getMethod() == HttpMethod.GET;
|
||||
}
|
||||
|
||||
protected boolean isPUT() {
|
||||
return this.request.getMethod() == HttpMethod.PUT;
|
||||
}
|
||||
|
||||
protected boolean isDELETE() {
|
||||
return this.request.getMethod() == HttpMethod.DELETE;
|
||||
}
|
||||
|
||||
protected boolean isPATCH() {
|
||||
return this.request.getMethod() == HttpMethod.PATCH;
|
||||
}
|
||||
|
||||
protected boolean isPOST() {
|
||||
return this.request.getMethod() == HttpMethod.POST;
|
||||
}
|
||||
|
||||
public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl,
|
||||
boolean references) throws ContentNegotiatorException {
|
||||
final ODataFormat format = ODataFormat.fromContentType(getResponseContentType());
|
||||
|
||||
if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
|
||||
return (T) EntitySerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null : contextUrl)
|
||||
.expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
|
||||
.setWriteOnlyReferences(references).build();
|
||||
} else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
|
||||
return (T) EntityCollectionSerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null : contextUrl)
|
||||
.count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
|
||||
.select(uriInfo.getSelectOption()).setWriteOnlyReferences(references).build();
|
||||
} else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
|
||||
return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
|
||||
.expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption()).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ReturnRepresentation getReturnRepresentation() {
|
||||
String prefer = this.request.getHeader(HttpHeader.PREFER);
|
||||
if (prefer == null) {
|
||||
return ReturnRepresentation.REPRESENTATION;
|
||||
}
|
||||
if (prefer.contains("return=minimal")) { //$NON-NLS-1$
|
||||
return ReturnRepresentation.MINIMAL;
|
||||
}
|
||||
return ReturnRepresentation.REPRESENTATION;
|
||||
}
|
||||
|
||||
public String getHeader(String key) {
|
||||
return this.request.getHeader(key);
|
||||
}
|
||||
|
||||
public String getETag() {
|
||||
String etag = getHeader(HttpHeader.IF_MATCH);
|
||||
if (etag == null) {
|
||||
etag = getHeader(HttpHeader.IF_NONE_MATCH);
|
||||
}
|
||||
return ((etag == null) ? "*" : etag); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public ODataSerializer getSerializer() throws ContentNegotiatorException,
|
||||
SerializerException {
|
||||
ODataFormat format = ODataFormat.fromContentType(getResponseContentType());
|
||||
return this.odata.createSerializer(format);
|
||||
}
|
||||
|
||||
public Map<String, String> getPreferences(){
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
List<String> headers = request.getHeaders(HttpHeader.PREFER);
|
||||
if (headers != null) {
|
||||
for (String header:headers) {
|
||||
int idx = header.indexOf('=');
|
||||
if (idx != -1) {
|
||||
String key = header.substring(0, idx);
|
||||
String value = header.substring(idx+1);
|
||||
if (value.startsWith("\"")) {
|
||||
value = value.substring(1);
|
||||
}
|
||||
if (value.endsWith("\"")) {
|
||||
value = value.substring(0, value.length()-1);
|
||||
}
|
||||
map.put(key, value);
|
||||
} else {
|
||||
map.put(header, "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getPreference(String key) {
|
||||
return getPreferences().get(key);
|
||||
}
|
||||
|
||||
public String getQueryParameter(String param) {
|
||||
String queryPath = getODataRequest().getRawQueryPath();
|
||||
if (queryPath != null) {
|
||||
StringTokenizer st = new StringTokenizer(queryPath, ",");
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken();
|
||||
int index = token.indexOf('=');
|
||||
if (index != -1) {
|
||||
String key = token.substring(0, index);
|
||||
String value = token.substring(index+1);
|
||||
if (key.equals(param)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DataRequest parseLink(URI uri) throws UriParserException {
|
||||
String rawPath = uri.getPath();
|
||||
int e = rawPath.indexOf("/", 1);
|
||||
if (-1 == e) {
|
||||
rawPath = uri.getPath();
|
||||
} else {
|
||||
rawPath = rawPath.substring(e);
|
||||
}
|
||||
|
||||
UriInfo uriInfo = new Parser().parseUri(rawPath, uri.getQuery(), null,
|
||||
this.serviceMetadata.getEdm());
|
||||
ServiceDispatcher dispatcher = new ServiceDispatcher(odata, serviceMetadata, null, customContentType);
|
||||
dispatcher.visit(uriInfo);
|
||||
return (DataRequest)dispatcher.request;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
* 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.legacy;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.ComplexProcessor;
|
||||
import org.apache.olingo.server.api.processor.CountComplexCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.CountEntityCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.CountPrimitiveCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.EntityProcessor;
|
||||
import org.apache.olingo.server.api.processor.MediaEntityProcessor;
|
||||
import org.apache.olingo.server.api.processor.MetadataProcessor;
|
||||
import org.apache.olingo.server.api.processor.PrimitiveCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.PrimitiveProcessor;
|
||||
import org.apache.olingo.server.api.processor.PrimitiveValueProcessor;
|
||||
import org.apache.olingo.server.api.processor.Processor;
|
||||
import org.apache.olingo.server.api.processor.ReferenceProcessor;
|
||||
import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
|
||||
import org.apache.olingo.server.core.ODataHandlerException;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.requests.ActionRequest;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.requests.FunctionRequest;
|
||||
import org.apache.olingo.server.core.requests.MediaRequest;
|
||||
import org.apache.olingo.server.core.requests.MetadataRequest;
|
||||
import org.apache.olingo.server.core.requests.ServiceDocumentRequest;
|
||||
import org.apache.olingo.server.core.responses.CountResponse;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.MetadataResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceDocumentResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceResponseVisior;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
|
||||
public class ProcessorServiceHandler implements ServiceHandler {
|
||||
private final List<Processor> processors = new LinkedList<Processor>();
|
||||
private OData odata;
|
||||
private ServiceMetadata serviceMetadata;
|
||||
|
||||
@Override
|
||||
public void init(OData odata, ServiceMetadata serviceMetadata) {
|
||||
this.odata = odata;
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
public void register(Processor processor) {
|
||||
this.processors.add(processor);
|
||||
processor.init(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
private <T extends Processor> T selectProcessor(final Class<T> cls) throws ODataHandlerException {
|
||||
for (final Processor processor : processors) {
|
||||
if (cls.isAssignableFrom(processor.getClass())) {
|
||||
processor.init(odata, serviceMetadata);
|
||||
return cls.cast(processor);
|
||||
}
|
||||
}
|
||||
throw new ODataHandlerException("Processor: " + cls.getSimpleName() + " not registered.",
|
||||
ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, cls.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMetadata(MetadataRequest request, MetadataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(MetadataProcessor.class).readMetadata(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readServiceDocument(ServiceDocumentRequest request, ServiceDocumentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(ServiceDocumentProcessor.class).readServiceDocument(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void read(final DataRequest request, final T response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(CountResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
if (request.getUriResourceProperty() != null) {
|
||||
EdmProperty edmProperty = request.getUriResourceProperty().getProperty();
|
||||
if (edmProperty.isPrimitive()) {
|
||||
selectProcessor(CountPrimitiveCollectionProcessor.class).countPrimitiveCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo());
|
||||
} else {
|
||||
selectProcessor(CountComplexCollectionProcessor.class).countComplexCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo());
|
||||
}
|
||||
} else {
|
||||
selectProcessor(CountEntityCollectionProcessor.class).countEntityCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityProcessor.class).readEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PrimitiveValueResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(PrimitiveValueProcessor.class).readPrimitiveValue(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
EdmProperty edmProperty = request.getUriResourceProperty().getProperty();
|
||||
if (edmProperty.isPrimitive()) {
|
||||
if(edmProperty.isCollection()) {
|
||||
selectProcessor(PrimitiveCollectionProcessor.class).readPrimitiveCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(PrimitiveProcessor.class).readPrimitive(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
} else {
|
||||
if(edmProperty.isCollection()) {
|
||||
selectProcessor(ComplexCollectionProcessor.class).readComplexCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(ComplexProcessor.class).readComplex(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StreamResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EntitySetResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityCollectionProcessor.class).readEntityCollection(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createEntity(DataRequest request, Entity entity, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
if (request.getEntitySet().getEntityType().hasStream()) {
|
||||
selectProcessor(MediaEntityProcessor.class).createMediaEntity(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(),request.getResponseContentType());
|
||||
} else {
|
||||
selectProcessor(EntityProcessor.class).createEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getRequestContentType(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntity(DataRequest request, Entity entity, boolean merge, String entityETag,
|
||||
EntityResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
if (request.getEntitySet().getEntityType().hasStream()) {
|
||||
selectProcessor(MediaEntityProcessor.class).updateMediaEntity(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(),request.getResponseContentType());
|
||||
} else {
|
||||
selectProcessor(EntityProcessor.class).updateEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getRequestContentType(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteEntity(DataRequest request, String entityETag, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(EntityProcessor.class).deleteEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(DataRequest request, Property property, boolean merge,
|
||||
String entityETag, PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
if (property.isPrimitive()) {
|
||||
if (property.isCollection()) {
|
||||
selectProcessor(PrimitiveCollectionProcessor.class).updatePrimitiveCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(), request.getResponseContentType());
|
||||
} else {
|
||||
selectProcessor(PrimitiveProcessor.class).updatePrimitive(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(), request.getResponseContentType());
|
||||
}
|
||||
} else {
|
||||
if (property.isCollection()) {
|
||||
selectProcessor(ComplexCollectionProcessor.class).updateComplexCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(), request.getResponseContentType());
|
||||
} else {
|
||||
selectProcessor(ComplexProcessor.class).updateComplex(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(), request.getResponseContentType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upsertStreamProperty(DataRequest request, String entityETag,
|
||||
InputStream streamContent, NoContentResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
throw new ODataHandlerException("not implemented",
|
||||
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void invoke(final FunctionRequest request, HttpMethod method,
|
||||
final T response) throws ODataTranslatedException, ODataApplicationException {
|
||||
if (method != HttpMethod.GET) {
|
||||
throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
|
||||
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
|
||||
}
|
||||
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityProcessor.class).readEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
if (request.isReturnTypePrimitive()) {
|
||||
if(request.isCollection()) {
|
||||
selectProcessor(PrimitiveCollectionProcessor.class).readPrimitiveCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(PrimitiveProcessor.class).readPrimitive(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
} else {
|
||||
if(request.isCollection()) {
|
||||
selectProcessor(ComplexCollectionProcessor.class).readComplexCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(ComplexProcessor.class).readComplex(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visit(EntitySetResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityCollectionProcessor.class).readEntityCollection(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void invoke(final ActionRequest request, String eTag, final T response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
final HttpMethod method = request.getODataRequest().getMethod();
|
||||
if (method != HttpMethod.POST) {
|
||||
throw new ODataHandlerException("HTTP method " + method + " is not allowed.",
|
||||
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, method.toString());
|
||||
}
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityProcessor.class).readEntity(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
if (request.isReturnTypePrimitive()) {
|
||||
if(request.isCollection()) {
|
||||
selectProcessor(PrimitiveCollectionProcessor.class).readPrimitiveCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(PrimitiveProcessor.class).readPrimitive(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
} else {
|
||||
if(request.isCollection()) {
|
||||
selectProcessor(ComplexCollectionProcessor.class).readComplexCollection(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
|
||||
} else {
|
||||
selectProcessor(ComplexProcessor.class).readComplex(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void visit(EntitySetResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
selectProcessor(EntityCollectionProcessor.class).readEntityCollection(request.getODataRequest(),
|
||||
response.getODataResponse(), request.getUriInfo(), request.getResponseContentType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void readMediaStream(MediaRequest request, StreamResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(MediaEntityProcessor.class).readMediaEntity(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upsertMediaStream(MediaRequest request, String entityETag, InputStream mediaContent,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(MediaEntityProcessor.class).updateMediaEntity(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getRequestContentType(), request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void anyUnsupported(ODataRequest request, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
throw new ODataHandlerException("not implemented",
|
||||
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReference(DataRequest request, String entityETag, List<URI> idReferences,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(ReferenceProcessor.class).createReference(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReference(DataRequest request, String entityETag, URI referenceId,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(ReferenceProcessor.class).updateReference(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo(),
|
||||
request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteReference(DataRequest request, URI deleteId, String entityETag,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
selectProcessor(ReferenceProcessor.class).deleteReference(
|
||||
request.getODataRequest(), response.getODataResponse(), request.getUriInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startTransaction() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(String txnId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(String txnId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void crossJoin(DataRequest dataRequest, List<String> entitySetNames, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
throw new ODataHandlerException("not implemented",
|
||||
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmAction;
|
||||
import org.apache.olingo.commons.api.edm.EdmReturnType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
|
||||
public class ActionRequest extends OperationRequest {
|
||||
private UriResourceAction uriResourceAction;
|
||||
|
||||
public ActionRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
// Actions MAY return data but MUST NOT be further composed with additional
|
||||
// path segments.
|
||||
// On success, the response is 201 Created for actions that create entities,
|
||||
// 200 OK for actions
|
||||
// that return results or 204 No Content for action without a return type.
|
||||
// The client can request
|
||||
// whether any results from the action be returned using the Prefer header.
|
||||
|
||||
if (!hasReturnType()) {
|
||||
handler.invoke(this, getETag(), new NoContentResponse(getServiceMetaData(), response));
|
||||
} else {
|
||||
if (isReturnTypePrimitive()) {
|
||||
handler.invoke(this, getETag(),
|
||||
PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType()));
|
||||
} else if (isReturnTypeComplex()) {
|
||||
handler.invoke(this, getETag(), PropertyResponse.getInstance(this, response,
|
||||
getReturnType().getType(), getContextURL(this.odata), isCollection()));
|
||||
} else {
|
||||
// EdmTypeKind.ENTITY
|
||||
if (isCollection()) {
|
||||
handler.invoke(this, getETag(),
|
||||
EntitySetResponse.getInstance(this, getContextURL(odata), false, response));
|
||||
} else {
|
||||
handler.invoke(this, getETag(),
|
||||
EntityResponse.getInstance(this, getContextURL(odata), false, response));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
// 11.5.4.1 Invoking an Action - only allows POST
|
||||
return (isPOST());
|
||||
}
|
||||
|
||||
public UriResourceAction getUriResourceAction() {
|
||||
return uriResourceAction;
|
||||
}
|
||||
|
||||
public void setUriResourceAction(UriResourceAction uriResourceAction) {
|
||||
this.uriResourceAction = uriResourceAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound() {
|
||||
return this.uriResourceAction.getActionImport() != null;
|
||||
}
|
||||
|
||||
public EdmAction getAction() {
|
||||
return this.uriResourceAction.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
assert (hasReturnType());
|
||||
return getAction().getReturnType().isCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmReturnType getReturnType() {
|
||||
assert (hasReturnType());
|
||||
return getAction().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReturnType() {
|
||||
return getAction().getReturnType() != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.batch.BatchOptions;
|
||||
import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
|
||||
import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ErrorHandler;
|
||||
import org.apache.olingo.server.core.ServiceDispatcher;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
import org.apache.olingo.server.core.batchhandler.referenceRewriting.BatchReferenceRewriter;
|
||||
import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
|
||||
|
||||
public class BatchRequest extends ServiceRequest {
|
||||
private static final String PREFERENCE_CONTINUE_ON_ERROR = "odata.continue-on-error";
|
||||
private final BatchReferenceRewriter rewriter;
|
||||
|
||||
public BatchRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
this.rewriter = new BatchReferenceRewriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
|
||||
validateContentType();
|
||||
boolean continueOnError = isContinueOnError();
|
||||
final String boundary = extractBoundary(getRequestContentType());
|
||||
|
||||
final BatchOptions options = BatchOptions.with().rawBaseUri(request.getRawBaseUri())
|
||||
.rawServiceResolutionUri(this.request.getRawServiceResolutionUri()).build();
|
||||
|
||||
final List<BatchRequestPart> parts = this.odata.createFixedFormatDeserializer()
|
||||
.parseBatchRequest(request.getBody(), boundary, options);
|
||||
|
||||
ODataResponsePart partResponse = null;
|
||||
final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
|
||||
|
||||
for (BatchRequestPart part : parts) {
|
||||
if (part.isChangeSet()) {
|
||||
String txnId = handler.startTransaction();
|
||||
partResponse = processChangeSet(part, handler);
|
||||
if (partResponse.getResponses().get(0).getStatusCode() > 400) {
|
||||
handler.rollback(txnId);
|
||||
}
|
||||
handler.commit(txnId);
|
||||
} else {
|
||||
// single request, a static request
|
||||
ODataRequest partRequest = part.getRequests().get(0);
|
||||
partResponse = process(partRequest, handler);
|
||||
}
|
||||
responseParts.add(partResponse);
|
||||
|
||||
// on error, should we continue?
|
||||
final int statusCode = partResponse.getResponses().get(0).getStatusCode();
|
||||
if ((statusCode >= 400 && statusCode <= 600) && !continueOnError) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// send response
|
||||
final String responseBoundary = "batch_" + UUID.randomUUID().toString();
|
||||
;
|
||||
final InputStream responseContent = odata.createFixedFormatSerializer().batchResponse(
|
||||
responseParts, responseBoundary);
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.MULTIPART_MIXED + ";boundary="
|
||||
+ responseBoundary);
|
||||
response.setContent(responseContent);
|
||||
response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
|
||||
}
|
||||
|
||||
ODataResponsePart process(ODataRequest partRequest, ServiceHandler serviceHandler) {
|
||||
ODataResponse partResponse = executeSingleRequest(partRequest, serviceHandler);
|
||||
addContentID(partRequest, partResponse);
|
||||
return new ODataResponsePart(partResponse, false);
|
||||
}
|
||||
|
||||
ODataResponsePart processChangeSet(BatchRequestPart partRequest, ServiceHandler serviceHandler)
|
||||
throws BatchDeserializerException {
|
||||
List<ODataResponse> changeSetResponses = new ArrayList<ODataResponse>();
|
||||
// change set need to be a in a atomic operation
|
||||
for (ODataRequest changeSetPartRequest : partRequest.getRequests()) {
|
||||
|
||||
this.rewriter.replaceReference(changeSetPartRequest);
|
||||
|
||||
ODataResponse partResponse = executeSingleRequest(changeSetPartRequest, serviceHandler);
|
||||
|
||||
this.rewriter.addMapping(changeSetPartRequest, partResponse);
|
||||
addContentID(changeSetPartRequest, partResponse);
|
||||
|
||||
if (partResponse.getStatusCode() < 400) {
|
||||
changeSetResponses.add(partResponse);
|
||||
} else {
|
||||
// 11.7.4 Responding to a Batch Request
|
||||
return new ODataResponsePart(partResponse, false);
|
||||
}
|
||||
}
|
||||
return new ODataResponsePart(changeSetResponses, true);
|
||||
}
|
||||
|
||||
ODataResponse executeSingleRequest(ODataRequest singleRequest, ServiceHandler handler) {
|
||||
ServiceDispatcher dispatcher = new ServiceDispatcher(this.odata, this.serviceMetadata, handler,
|
||||
this.customContentType);
|
||||
ODataResponse res = new ODataResponse();
|
||||
try {
|
||||
dispatcher.execute(singleRequest, res);
|
||||
} catch (Exception e) {
|
||||
ErrorHandler ehandler = new ErrorHandler(this.odata, this.serviceMetadata,
|
||||
getCustomContentTypeSupport());
|
||||
ehandler.handleException(e, singleRequest, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void addContentID(ODataRequest batchPartRequest, ODataResponse batchPartResponse) {
|
||||
final String contentId = batchPartRequest.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
|
||||
if (contentId != null) {
|
||||
batchPartResponse.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return isPOST();
|
||||
}
|
||||
|
||||
private void validateContentType() throws ODataApplicationException {
|
||||
final String contentType = getRequestContentType().toContentTypeString();
|
||||
|
||||
if (contentType == null
|
||||
|| !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
|
||||
throw new ODataApplicationException("Invalid content type",
|
||||
HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isContinueOnError() {
|
||||
final List<String> preferValues = this.request.getHeaders(HttpHeader.PREFER);
|
||||
|
||||
if (preferValues != null) {
|
||||
for (final String preference : preferValues) {
|
||||
if (PREFERENCE_CONTINUE_ON_ERROR.equals(preference)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String extractBoundary(ContentType contentType) throws BatchDeserializerException {
|
||||
return BatchParserCommon.getBoundary(contentType.toContentTypeString(), 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,769 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.ContextURL.Suffix;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.core.data.PropertyImpl;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmStream;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.RepresentationType;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceSingleton;
|
||||
import org.apache.olingo.server.core.ContentNegotiator;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
import org.apache.olingo.server.core.responses.CountResponse;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
|
||||
public class DataRequest extends ServiceRequest {
|
||||
protected UriResourceEntitySet uriResourceEntitySet;
|
||||
private boolean countRequest;
|
||||
private UriResourceProperty uriResourceProperty;
|
||||
private boolean valueRequest;
|
||||
private final LinkedList<UriResourceNavigation> uriNavigations = new LinkedList<UriResourceNavigation>();
|
||||
private boolean references;
|
||||
|
||||
private RequestType type;
|
||||
private UriResourceSingleton uriResourceSingleton;
|
||||
|
||||
/**
|
||||
* This sub-categorizes the request so that code can be simplified
|
||||
*/
|
||||
interface RequestType {
|
||||
public boolean allowedMethod();
|
||||
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException;
|
||||
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException;
|
||||
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException;
|
||||
}
|
||||
|
||||
public DataRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
public UriResourceEntitySet getUriResourceEntitySet() {
|
||||
return uriResourceEntitySet;
|
||||
}
|
||||
|
||||
public void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
|
||||
this.uriResourceEntitySet = uriResourceEntitySet;
|
||||
this.type = new EntityRequest();
|
||||
}
|
||||
|
||||
public void setCrossJoin(UriInfoCrossjoin info) {
|
||||
this.type = new CrossJoinRequest(info.getEntitySetNames());
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return this.uriResourceSingleton != null;
|
||||
}
|
||||
|
||||
public boolean isCollection() {
|
||||
if (!this.uriNavigations.isEmpty()) {
|
||||
return this.uriNavigations.getLast().isCollection();
|
||||
}
|
||||
return this.uriResourceEntitySet != null && this.uriResourceEntitySet.isCollection();
|
||||
}
|
||||
|
||||
public EdmEntitySet getEntitySet() {
|
||||
return this.uriResourceEntitySet.getEntitySet();
|
||||
}
|
||||
|
||||
public boolean isCountRequest() {
|
||||
return countRequest;
|
||||
}
|
||||
|
||||
public void setCountRequest(boolean countRequest) {
|
||||
this.countRequest = countRequest;
|
||||
this.type = new CountRequest();
|
||||
}
|
||||
|
||||
public boolean isPropertyRequest() {
|
||||
return this.uriResourceProperty != null;
|
||||
}
|
||||
|
||||
public boolean isPropertyComplex() {
|
||||
return (this.uriResourceProperty instanceof UriResourceComplexProperty);
|
||||
}
|
||||
|
||||
public boolean isPropertyStream() {
|
||||
if (isPropertyComplex()) {
|
||||
return false;
|
||||
}
|
||||
EdmProperty property = ((UriResourcePrimitiveProperty)this.uriResourceProperty).getProperty();
|
||||
return (property.getType() instanceof EdmStream);
|
||||
}
|
||||
|
||||
public UriResourceProperty getUriResourceProperty() {
|
||||
return uriResourceProperty;
|
||||
}
|
||||
|
||||
public void setUriResourceProperty(UriResourceProperty uriResourceProperty) {
|
||||
this.uriResourceProperty = uriResourceProperty;
|
||||
this.type = new PropertyRequest();
|
||||
}
|
||||
|
||||
public LinkedList<UriResourceNavigation> getNavigations() {
|
||||
return this.uriNavigations;
|
||||
}
|
||||
|
||||
public void addUriResourceNavigation(UriResourceNavigation uriResourceNavigation) {
|
||||
this.uriNavigations.add(uriResourceNavigation);
|
||||
}
|
||||
|
||||
public UriResourceSingleton getUriResourceSingleton() {
|
||||
return this.uriResourceSingleton;
|
||||
}
|
||||
|
||||
public void setUriResourceSingleton(UriResourceSingleton info) {
|
||||
this.uriResourceSingleton = info;
|
||||
this.type = new SingletonRequest();
|
||||
}
|
||||
|
||||
public List<UriParameter> getKeyPredicates() {
|
||||
if (this.uriResourceEntitySet != null) {
|
||||
return this.uriResourceEntitySet.getKeyPredicates();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isReferenceRequest() {
|
||||
return this.references;
|
||||
}
|
||||
|
||||
public void setReferenceRequest(boolean ref) {
|
||||
this.references = ref;
|
||||
this.type = new ReferenceRequest();
|
||||
}
|
||||
|
||||
public boolean isValueRequest() {
|
||||
return valueRequest;
|
||||
}
|
||||
|
||||
private boolean hasMediaStream() {
|
||||
return this.uriResourceEntitySet != null && this.uriResourceEntitySet.getEntityType().hasStream();
|
||||
}
|
||||
|
||||
private InputStream getMediaStream() {
|
||||
return this.request.getBody();
|
||||
}
|
||||
|
||||
public void setValueRequest(boolean valueRequest) {
|
||||
this.valueRequest = valueRequest;
|
||||
this.type = new ValueRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return this.type.allowedMethod();
|
||||
}
|
||||
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
return type.getContextURL(odata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!this.type.allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
|
||||
this.type.execute(handler, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl, boolean references)
|
||||
throws ContentNegotiatorException {
|
||||
if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
|
||||
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
|
||||
.facetsFrom(getUriResourceProperty().getProperty()).build();
|
||||
}
|
||||
return super.getSerializerOptions(serilizerOptions, contextUrl, references);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return type.getResponseContentType();
|
||||
}
|
||||
|
||||
class EntityRequest implements RequestType {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
// the create/update/delete to navigation property is done through references
|
||||
// see # 11.4.6
|
||||
if (!getNavigations().isEmpty() && !isGET()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
|
||||
: RepresentationType.ENTITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
EntityResponse entityResponse = EntityResponse.getInstance(DataRequest.this,
|
||||
getContextURL(odata), false, response);
|
||||
|
||||
if (isGET()) {
|
||||
if (isCollection()) {
|
||||
handler.read(DataRequest.this,
|
||||
EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), false, response));
|
||||
} else {
|
||||
handler.read(DataRequest.this,entityResponse);
|
||||
}
|
||||
} else if (isPUT() || isPATCH()) {
|
||||
// RFC 2616: he result of a request having both an If-Match header field and either
|
||||
// an If-None-Match or an If-Modified-Since header fields is undefined
|
||||
// by this specification.
|
||||
boolean ifMatch = getHeader(HttpHeader.IF_MATCH) != null;
|
||||
boolean ifNoneMatch = getHeader(HttpHeader.IF_NONE_MATCH).equals("*");
|
||||
if(ifMatch) {
|
||||
handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
|
||||
entityResponse);
|
||||
} else if (ifNoneMatch) {
|
||||
// 11.4.4
|
||||
entityResponse = EntityResponse.getInstance(DataRequest.this,
|
||||
getContextURL(odata), false, response, getReturnRepresentation());
|
||||
handler.createEntity(DataRequest.this, getEntityFromClient(), entityResponse);
|
||||
} else {
|
||||
handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
|
||||
entityResponse);
|
||||
}
|
||||
} else if (isPOST()) {
|
||||
entityResponse = EntityResponse.getInstance(DataRequest.this,
|
||||
getContextURL(odata), false, response, getReturnRepresentation());
|
||||
handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
|
||||
} else if (isDELETE()) {
|
||||
handler.deleteEntity(DataRequest.this, getETag(), entityResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private Entity getEntityFromClient() throws DeserializerException {
|
||||
ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
|
||||
.fromContentType(getRequestContentType()));
|
||||
return deserializer.entity(getODataRequest().getBody(), getEntitySet().getEntityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
// EntitySet based return
|
||||
final UriHelper helper = odata.createUriHelper();
|
||||
ContextURL.Builder builder = buildEntitySetContextURL(helper, getEntitySet(),
|
||||
getKeyPredicates(), getUriInfo(), getNavigations(), isCollection(), false);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
class CountRequest implements RequestType {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return isGET();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentType.TEXT_PLAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
handler.read(DataRequest.this, CountResponse.getInstance(DataRequest.this, response));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is NavigationProperty Reference.
|
||||
*/
|
||||
class ReferenceRequest implements RequestType {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
// references are only allowed on the navigation properties
|
||||
if (getNavigations().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11.4.6.1 - post allowed on only collection valued navigation
|
||||
if (isPOST() && !getNavigations().getLast().isCollection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11.4.6.3 - PUT allowed on single valued navigation
|
||||
if (isPUT() && getNavigations().getLast().isCollection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No defined behavior in spec
|
||||
if (isPATCH()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_REFERENCE
|
||||
: RepresentationType.REFERENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
if (isGET()) {
|
||||
if (isCollection()) {
|
||||
handler.read(DataRequest.this,
|
||||
EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), true, response));
|
||||
} else {
|
||||
handler.read(DataRequest.this,
|
||||
EntityResponse.getInstance(DataRequest.this, getContextURL(odata), true, response));
|
||||
}
|
||||
} else if (isDELETE()) {
|
||||
// if this against the collection, user need to look at $id param for entity ref #11.4.6.2
|
||||
String id = getQueryParameter("$id");
|
||||
if (id == null) {
|
||||
handler.deleteReference(DataRequest.this, null, getETag(), new NoContentResponse(
|
||||
getServiceMetaData(), response));
|
||||
} else {
|
||||
try {
|
||||
handler.deleteReference(DataRequest.this, new URI(id), getETag(), new NoContentResponse(
|
||||
getServiceMetaData(), response));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new DeserializerException("failed to read $id", e, MessageKeys.UNKOWN_CONTENT);
|
||||
}
|
||||
}
|
||||
} else if (isPUT()) {
|
||||
// note this is always against single reference
|
||||
handler.updateReference(DataRequest.this, getETag(), getPayload().get(0), new NoContentResponse(
|
||||
getServiceMetaData(), response));
|
||||
} else if (isPOST()) {
|
||||
// this needs to be against collection of references
|
||||
handler.addReference(DataRequest.this, getETag(), getPayload(), new NoContentResponse(
|
||||
getServiceMetaData(), response));
|
||||
}
|
||||
}
|
||||
|
||||
// http://docs.oasis-open.org/odata/odata-json-format/v4.0/errata02/os
|
||||
// /odata-json-format-v4.0-errata02-os-complete.html#_Toc403940643
|
||||
// The below code reads as property and converts to an URI
|
||||
private List<URI> getPayload() throws DeserializerException {
|
||||
ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
|
||||
.fromContentType(getRequestContentType()));
|
||||
return deserializer.entityReferences(getODataRequest().getBody());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
ContextURL.Builder builder = ContextURL.with().suffix(Suffix.REFERENCE);
|
||||
if (isCollection()) {
|
||||
builder.asCollection();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyRequest implements RequestType {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
// create of properties is not allowed,
|
||||
// only read, update, delete. Note that delete is
|
||||
// same as update with null
|
||||
if (isPOST()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11.4.9.4, collection properties are not supported with merge
|
||||
if (isPATCH() && (isCollection() || isPropertyStream())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
if (isPropertyComplex()) {
|
||||
return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
|
||||
getODataRequest(), getCustomContentTypeSupport(),
|
||||
isCollection() ? RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX);
|
||||
} else if (isPropertyStream()) {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request,
|
||||
getCustomContentTypeSupport(), RepresentationType.BINARY);
|
||||
}
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_PRIMITIVE
|
||||
: RepresentationType.PRIMITIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
EdmProperty edmProperty = getUriResourceProperty().getProperty();
|
||||
|
||||
if (isGET()) {
|
||||
if (isPropertyStream()) {
|
||||
handler.read(DataRequest.this, new StreamResponse(getServiceMetaData(), response));
|
||||
} else {
|
||||
handler.read(DataRequest.this, buildResponse(response, edmProperty));
|
||||
}
|
||||
} else if (isPATCH()) {
|
||||
handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), true,
|
||||
getETag(), buildResponse(response, edmProperty));
|
||||
} else if (isPUT()) {
|
||||
if (isPropertyStream()) {
|
||||
handler.upsertStreamProperty(DataRequest.this, getETag(), request.getBody(),
|
||||
new NoContentResponse(getServiceMetaData(), response));
|
||||
} else {
|
||||
handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false,
|
||||
getETag(), buildResponse(response, edmProperty));
|
||||
}
|
||||
} else if (isDELETE()) {
|
||||
if (isPropertyStream()) {
|
||||
handler.upsertStreamProperty(DataRequest.this, getETag(), request.getBody(),
|
||||
new NoContentResponse(getServiceMetaData(), response));
|
||||
} else {
|
||||
Property property = new PropertyImpl();
|
||||
property.setName(edmProperty.getName());
|
||||
property.setType(edmProperty.getType().getFullQualifiedName()
|
||||
.getFullQualifiedNameAsString());
|
||||
handler.updateProperty(DataRequest.this, property, false, getETag(),
|
||||
buildResponse(response, edmProperty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyResponse buildResponse(ODataResponse response, EdmProperty edmProperty)
|
||||
throws ContentNegotiatorException, SerializerException {
|
||||
PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
|
||||
edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
|
||||
return propertyResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
final UriHelper helper = odata.createUriHelper();
|
||||
EdmProperty edmProperty = getUriResourceProperty().getProperty();
|
||||
|
||||
ContextURL.Builder builder = ContextURL.with().entitySet(getEntitySet());
|
||||
builder = ContextURL.with().entitySet(getEntitySet());
|
||||
builder.keyPath(helper.buildContextURLKeyPredicate(getUriResourceEntitySet()
|
||||
.getKeyPredicates()));
|
||||
String navPath = buildNavPath(helper, getEntitySet().getEntityType(), getNavigations(), true);
|
||||
if (navPath != null && !navPath.isEmpty()) {
|
||||
builder.navOrPropertyPath(navPath+"/"+edmProperty.getName());
|
||||
} else {
|
||||
builder.navOrPropertyPath(edmProperty.getName());
|
||||
}
|
||||
if (isPropertyComplex()) {
|
||||
EdmComplexType type = ((UriResourceComplexProperty) uriResourceProperty).getComplexType();
|
||||
String select = helper.buildContextURLSelectList(type, getUriInfo().getExpandOption(),
|
||||
getUriInfo().getSelectOption());
|
||||
builder.selectList(select);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
class ValueRequest extends PropertyRequest {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
//part2-url-conventions # 4.2
|
||||
if (isPropertyStream() && isGET()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isGET() || isDELETE() || isPUT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
RepresentationType valueRepresentationType = uriResourceProperty.getType() == EdmPrimitiveTypeFactory
|
||||
.getInstance(EdmPrimitiveTypeKind.Binary) ? RepresentationType.BINARY
|
||||
: RepresentationType.VALUE;
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request,
|
||||
getCustomContentTypeSupport(), valueRepresentationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
EdmProperty edmProperty = getUriResourceProperty().getProperty();
|
||||
if (isGET()) {
|
||||
handler.read(DataRequest.this, PrimitiveValueResponse.getInstance(DataRequest.this,
|
||||
response, isCollection(), getUriResourceProperty().getProperty()));
|
||||
} else if (isDELETE()) {
|
||||
Property property = new PropertyImpl();
|
||||
property.setName(edmProperty.getName());
|
||||
property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
|
||||
PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
|
||||
edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
|
||||
handler.updateProperty(DataRequest.this, property, false, getETag(), propertyResponse);
|
||||
} else if (isPUT()) {
|
||||
PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
|
||||
edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
|
||||
handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false,
|
||||
getETag(), propertyResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SingletonRequest implements RequestType {
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return isGET();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
|
||||
getCustomContentTypeSupport(), RepresentationType.ENTITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
final UriHelper helper = odata.createUriHelper();
|
||||
ContextURL.Builder builder = buildEntitySetContextURL(helper,
|
||||
uriResourceSingleton.getSingleton(), null, getUriInfo(), getNavigations(), isCollection(), true);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
handler.read(DataRequest.this,
|
||||
EntityResponse.getInstance(DataRequest.this, getContextURL(odata), false, response));
|
||||
}
|
||||
}
|
||||
|
||||
class CrossJoinRequest implements RequestType {
|
||||
private final List<String> entitySetNames;
|
||||
|
||||
public CrossJoinRequest(List<String> entitySetNames) {
|
||||
this.entitySetNames = entitySetNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return isGET();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
|
||||
getODataRequest(), getCustomContentTypeSupport(), RepresentationType.COLLECTION_COMPLEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
handler.crossJoin(DataRequest.this, this.entitySetNames, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
ContextURL.Builder builder = ContextURL.with().asCollection();
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
private org.apache.olingo.commons.api.data.Property getPropertyValueFromClient(
|
||||
EdmProperty edmProperty) throws DeserializerException {
|
||||
// TODO:this is not right, we should be deserializing the property
|
||||
// (primitive, complex, collection of)
|
||||
// for now it is responsibility of the user
|
||||
ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
|
||||
.fromContentType(getRequestContentType()));
|
||||
return deserializer.property(getODataRequest().getBody(), edmProperty);
|
||||
}
|
||||
|
||||
static ContextURL.Builder buildEntitySetContextURL(UriHelper helper,
|
||||
EdmBindingTarget edmEntitySet, List<UriParameter> keyPredicates, UriInfo uriInfo,
|
||||
LinkedList<UriResourceNavigation> navigations, boolean collectionReturn, boolean singleton)
|
||||
throws SerializerException {
|
||||
|
||||
ContextURL.Builder builder = ContextURL.with().entitySetOrSingletonOrType(edmEntitySet.getName());
|
||||
String select = helper.buildContextURLSelectList(edmEntitySet.getEntityType(),
|
||||
uriInfo.getExpandOption(), uriInfo.getSelectOption());
|
||||
if (!singleton) {
|
||||
builder.suffix(collectionReturn ? null : Suffix.ENTITY);
|
||||
}
|
||||
|
||||
builder.selectList(select);
|
||||
|
||||
final UriInfoResource resource = uriInfo.asUriInfoResource();
|
||||
final List<UriResource> resourceParts = resource.getUriResourceParts();
|
||||
final List<String> path = getPropertyPath(resourceParts);
|
||||
String propertyPath = buildPropertyPath(path);
|
||||
final String navPath = buildNavPath(helper, edmEntitySet.getEntityType(), navigations, collectionReturn);
|
||||
if (navPath != null && !navPath.isEmpty()) {
|
||||
if (keyPredicates != null) {
|
||||
builder.keyPath(helper.buildContextURLKeyPredicate(keyPredicates));
|
||||
}
|
||||
if (propertyPath != null) {
|
||||
propertyPath = navPath+"/"+propertyPath;
|
||||
} else {
|
||||
propertyPath = navPath;
|
||||
}
|
||||
}
|
||||
builder.navOrPropertyPath(propertyPath);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static List<String> getPropertyPath(final List<UriResource> path) {
|
||||
List<String> result = new LinkedList<String>();
|
||||
int index = 1;
|
||||
while (index < path.size() && path.get(index) instanceof UriResourceProperty) {
|
||||
result.add(((UriResourceProperty) path.get(index)).getProperty().getName());
|
||||
index++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String buildPropertyPath(final List<String> path) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (final String segment : path) {
|
||||
result.append(result.length() == 0 ? "" : '/').append(segment); //$NON-NLS-1$
|
||||
}
|
||||
return result.length() == 0?null:result.toString();
|
||||
}
|
||||
|
||||
static String buildNavPath(UriHelper helper, EdmEntityType rootType,
|
||||
LinkedList<UriResourceNavigation> navigations, boolean includeLastPredicates)
|
||||
throws SerializerException {
|
||||
if (navigations.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean containsTarget = false;
|
||||
EdmEntityType type = rootType;
|
||||
for (UriResourceNavigation nav:navigations) {
|
||||
String name = nav.getProperty().getName();
|
||||
EdmNavigationProperty property = type.getNavigationProperty(name);
|
||||
if (property.containsTarget()) {
|
||||
containsTarget = true;
|
||||
}
|
||||
type = nav.getProperty().getType();
|
||||
}
|
||||
|
||||
if (containsTarget) {
|
||||
for (int i = 0; i < navigations.size(); i++) {
|
||||
UriResourceNavigation nav = navigations.get(i);
|
||||
if (i > 0) {
|
||||
sb.append("/");
|
||||
}
|
||||
sb.append(nav.getProperty().getName());
|
||||
|
||||
boolean skipKeys = false;
|
||||
if (navigations.size() == i+1 && !includeLastPredicates ) {
|
||||
skipKeys = true;
|
||||
}
|
||||
|
||||
if (!skipKeys && !nav.getKeyPredicates().isEmpty()) {
|
||||
sb.append("(");
|
||||
sb.append(helper.buildContextURLKeyPredicate(nav.getKeyPredicates()));
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
if (nav.getTypeFilterOnCollection() != null) {
|
||||
sb.append("/")
|
||||
.append(nav.getTypeFilterOnCollection().getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
} else if (nav.getTypeFilterOnEntry() != null) {
|
||||
sb.append("/")
|
||||
.append(nav.getTypeFilterOnEntry().getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
import org.apache.olingo.commons.api.edm.EdmReturnType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
|
||||
public class FunctionRequest extends OperationRequest {
|
||||
private UriResourceFunction uriResourceFunction;
|
||||
|
||||
public FunctionRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
|
||||
// Functions always have return per 11.5.3
|
||||
if (isReturnTypePrimitive()) {
|
||||
// functions can not return a typed property in the context of entity, so
|
||||
// it must be treated
|
||||
// as value based response
|
||||
handler.invoke(this, getODataRequest().getMethod(),
|
||||
PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType()));
|
||||
} else if (isReturnTypeComplex()) {
|
||||
handler.invoke(this, getODataRequest().getMethod(), PropertyResponse.getInstance(this, response,
|
||||
getReturnType().getType(), getContextURL(this.odata), isCollection()));
|
||||
} else {
|
||||
// returnType.getType().getKind() == EdmTypeKind.ENTITY
|
||||
if (isCollection()) {
|
||||
handler.invoke(this, getODataRequest().getMethod(),
|
||||
EntitySetResponse.getInstance(this, getContextURL(odata), false, response));
|
||||
} else {
|
||||
handler.invoke(this, getODataRequest().getMethod(),
|
||||
EntityResponse.getInstance(this, getContextURL(odata), false, response));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
// look for discussion about composable functions in odata-discussion
|
||||
// group with thread "Clarification on "Function" invocations"
|
||||
if (getFunction().isComposable()) {
|
||||
return (isGET() || isPATCH() || isDELETE() || isPOST() || isPUT());
|
||||
}
|
||||
return isGET();
|
||||
}
|
||||
|
||||
public UriResourceFunction getUriResourceFunction() {
|
||||
return uriResourceFunction;
|
||||
}
|
||||
|
||||
public void setUriResourceFunction(UriResourceFunction uriResourceFunction) {
|
||||
this.uriResourceFunction = uriResourceFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound() {
|
||||
return this.uriResourceFunction.getFunctionImport() != null;
|
||||
}
|
||||
|
||||
public EdmFunction getFunction() {
|
||||
return this.uriResourceFunction.getFunction();
|
||||
}
|
||||
|
||||
public List<UriParameter> getParameters() {
|
||||
return this.uriResourceFunction.getParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
return getFunction().getReturnType().isCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmReturnType getReturnType() {
|
||||
return getFunction().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReturnType() {
|
||||
// Part3 {12.1} says must have return type
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
|
||||
public class MediaRequest extends ServiceRequest {
|
||||
private UriResourceEntitySet uriResourceEntitySet;
|
||||
|
||||
public MediaRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
// POST will not be here, because the media is created as part of media
|
||||
// entity creation
|
||||
if (isGET()) {
|
||||
handler.readMediaStream(this, new StreamResponse(getServiceMetaData(), response));
|
||||
} else if (isPUT()) {
|
||||
handler.upsertMediaStream(this, getETag(), getMediaStream(), new NoContentResponse(
|
||||
getServiceMetaData(), response));
|
||||
} else if (isDELETE()) {
|
||||
handler.upsertMediaStream(this, getETag(), null, new NoContentResponse(getServiceMetaData(),
|
||||
response));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
// the request must specify the content type requested.
|
||||
return getRequestContentType();
|
||||
}
|
||||
|
||||
public EdmEntitySet getEntitySet() {
|
||||
return this.uriResourceEntitySet.getEntitySet();
|
||||
}
|
||||
|
||||
public EdmEntityType getEntityType() {
|
||||
return this.uriResourceEntitySet.getEntitySet().getEntityType();
|
||||
}
|
||||
|
||||
public void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
|
||||
this.uriResourceEntitySet = uriResourceEntitySet;
|
||||
}
|
||||
|
||||
public List<UriParameter> getKeyPredicates() {
|
||||
if (this.uriResourceEntitySet != null) {
|
||||
return this.uriResourceEntitySet.getKeyPredicates();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private InputStream getMediaStream() {
|
||||
return this.request.getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowedMethod() {
|
||||
return isGET() || isPUT() || isDELETE();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.RepresentationType;
|
||||
import org.apache.olingo.server.api.uri.UriInfoMetadata;
|
||||
import org.apache.olingo.server.core.ContentNegotiator;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
import org.apache.olingo.server.core.responses.MetadataResponse;
|
||||
|
||||
public class MetadataRequest extends ServiceRequest {
|
||||
|
||||
public MetadataRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(this.uriInfo.getFormatOption(), this.request,
|
||||
this.customContentType, RepresentationType.METADATA);
|
||||
}
|
||||
|
||||
public UriInfoMetadata getUriInfoMetadata() {
|
||||
return uriInfo.asUriInfoMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
|
||||
handler.readMetadata(this, MetadataResponse.getInstance(this, response));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.edm.EdmReturnType;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
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.RepresentationType;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
import org.apache.olingo.server.core.ContentNegotiator;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public abstract class OperationRequest extends ServiceRequest {
|
||||
|
||||
public OperationRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
if (!hasReturnType()) {
|
||||
// this default content type
|
||||
return ContentType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
|
||||
if (isReturnTypePrimitive()) {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_PRIMITIVE
|
||||
: RepresentationType.PRIMITIVE);
|
||||
} else if (isReturnTypeComplex()) {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_COMPLEX
|
||||
: RepresentationType.COMPLEX);
|
||||
} else {
|
||||
return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
|
||||
getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
|
||||
: RepresentationType.ENTITY);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isBound();
|
||||
|
||||
public abstract boolean isCollection();
|
||||
|
||||
public abstract EdmReturnType getReturnType();
|
||||
|
||||
public abstract boolean hasReturnType();
|
||||
|
||||
public ContextURL getContextURL(OData odata) throws SerializerException {
|
||||
if (!hasReturnType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final UriHelper helper = odata.createUriHelper();
|
||||
|
||||
if (isReturnTypePrimitive() || isReturnTypeComplex()) {
|
||||
// Part 1 {10.14, 10.14} since the function return properties does not
|
||||
// represent a Entity property
|
||||
ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
|
||||
if (isCollection()) {
|
||||
builder.asCollection();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/*
|
||||
// EdmTypeKind.ENTITY;
|
||||
if (isBound()) {
|
||||
// Bound means, we know the EnitySet of the return type. Part 1 {10.2,
|
||||
// 10.3}
|
||||
EdmEntitySet entitySet = this.uriResourceFunction.getFunctionImport().getReturnedEntitySet();
|
||||
ContextURL.Builder builder = DataRequest.buildEntitySetContextURL(helper, entitySet,
|
||||
this.uriInfo, isCollection(), false);
|
||||
return builder.build();
|
||||
}
|
||||
*/
|
||||
|
||||
// EdmTypeKind.ENTITY; Not Bound
|
||||
// Here we do not know the EntitySet, then follow directions from
|
||||
// Part-1{10.2. 10.3} to use
|
||||
// {context-url}#{type-name}
|
||||
ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
|
||||
if (isCollection()) {
|
||||
builder.asCollection();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public boolean isReturnTypePrimitive() {
|
||||
return getReturnType().getType().getKind() == EdmTypeKind.PRIMITIVE;
|
||||
}
|
||||
|
||||
public boolean isReturnTypeComplex() {
|
||||
return getReturnType().getType().getKind() == EdmTypeKind.COMPLEX;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.requests;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.RepresentationType;
|
||||
import org.apache.olingo.server.core.ContentNegotiator;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
import org.apache.olingo.server.core.responses.ServiceDocumentResponse;
|
||||
|
||||
public class ServiceDocumentRequest extends ServiceRequest {
|
||||
|
||||
public ServiceDocumentRequest(OData odata, ServiceMetadata serviceMetadata) {
|
||||
super(odata, serviceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentType getResponseContentType() throws ContentNegotiatorException {
|
||||
return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
|
||||
getODataRequest(), getCustomContentTypeSupport(), RepresentationType.SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ServiceHandler handler, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
if (!allowedMethod()) {
|
||||
methodNotAllowed();
|
||||
}
|
||||
handler.readServiceDocument(this,
|
||||
ServiceDocumentResponse.getInstace(this, response, getResponseContentType()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class CountResponse extends ServiceResponse {
|
||||
private final FixedFormatSerializer serializer;
|
||||
|
||||
public static CountResponse getInstance(ServiceRequest request, ODataResponse response) {
|
||||
FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
|
||||
return new CountResponse(request.getServiceMetaData(), serializer, response,
|
||||
request.getPreferences());
|
||||
}
|
||||
|
||||
private CountResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
|
||||
ODataResponse response, Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public void writeCount(int count) throws SerializerException {
|
||||
assert (!isClosed());
|
||||
|
||||
this.response.setContent(this.serializer.count(count));
|
||||
writeOK(HttpContentType.TEXT_PLAIN);
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ReturnRepresentation;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class EntityResponse extends ServiceResponse {
|
||||
private final ReturnRepresentation returnRepresentation;
|
||||
private final ODataSerializer serializer;
|
||||
private final EntitySerializerOptions options;
|
||||
private final ContentType responseContentType;
|
||||
|
||||
private EntityResponse(ServiceMetadata metadata, ODataResponse response,
|
||||
ODataSerializer serializer, EntitySerializerOptions options, ContentType responseContentType,
|
||||
Map<String, String> preferences, ReturnRepresentation returnRepresentation) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
this.options = options;
|
||||
this.responseContentType = responseContentType;
|
||||
this.returnRepresentation = returnRepresentation;
|
||||
}
|
||||
|
||||
public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
|
||||
boolean references, ODataResponse response, ReturnRepresentation returnRepresentation)
|
||||
throws ContentNegotiatorException, SerializerException {
|
||||
EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
|
||||
contextURL, references);
|
||||
return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
|
||||
options, request.getResponseContentType(), request.getPreferences(), returnRepresentation);
|
||||
}
|
||||
|
||||
public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
|
||||
boolean references, ODataResponse response)
|
||||
throws ContentNegotiatorException, SerializerException {
|
||||
EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
|
||||
contextURL, references);
|
||||
return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
|
||||
options, request.getResponseContentType(), request.getPreferences(), null);
|
||||
}
|
||||
|
||||
// write single entity
|
||||
public void writeReadEntity(EdmEntityType entityType, Entity entity) throws SerializerException {
|
||||
|
||||
assert (!isClosed());
|
||||
|
||||
if (entity == null) {
|
||||
writeNotFound(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// write the entity to response
|
||||
this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options));
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
public void writeCreatedEntity(EdmEntityType entityType, Entity entity, String locationHeader)
|
||||
throws SerializerException {
|
||||
// upsert/insert must created a entity, otherwise should have throw an
|
||||
// exception
|
||||
assert (entity != null);
|
||||
|
||||
// Note that if media written just like Stream, but on entity URL
|
||||
|
||||
// 8.2.8.7
|
||||
if (this.returnRepresentation == ReturnRepresentation.MINIMAL) {
|
||||
writeNoContent(false);
|
||||
writeHeader(HttpHeader.LOCATION, locationHeader);
|
||||
writeHeader("Preference-Applied", "return=minimal"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// 8.3.3
|
||||
writeHeader("OData-EntityId", entity.getId().toASCIIString()); //$NON-NLS-1$
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
// return the content of the created entity
|
||||
this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options));
|
||||
writeCreated(false);
|
||||
writeHeader(HttpHeader.LOCATION, locationHeader);
|
||||
writeHeader("Preference-Applied", "return=representation"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
writeHeader(HttpHeader.CONTENT_TYPE, this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
public void writeUpdatedEntity() {
|
||||
// spec says just success response; so either 200 or 204. 200 typically has
|
||||
// payload
|
||||
writeNoContent(true);
|
||||
}
|
||||
|
||||
public void writeDeletedEntityOrReference() {
|
||||
writeNoContent(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public void writeCreated(boolean closeResponse) {
|
||||
this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
|
||||
if (closeResponse) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class EntitySetResponse extends ServiceResponse {
|
||||
private final ODataSerializer serializer;
|
||||
private final EntityCollectionSerializerOptions options;
|
||||
private final ContentType responseContentType;
|
||||
|
||||
private EntitySetResponse(ServiceMetadata metadata, ODataResponse response, ODataSerializer serializer,
|
||||
EntityCollectionSerializerOptions options,
|
||||
ContentType responseContentType, Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
this.options = options;
|
||||
this.responseContentType = responseContentType;
|
||||
}
|
||||
|
||||
public static EntitySetResponse getInstance(ServiceRequest request, ContextURL contextURL,
|
||||
boolean referencesOnly, ODataResponse response) throws ContentNegotiatorException, SerializerException {
|
||||
EntityCollectionSerializerOptions options = request.getSerializerOptions(
|
||||
EntityCollectionSerializerOptions.class, contextURL, referencesOnly);
|
||||
return new EntitySetResponse(request.getServiceMetaData(),response, request.getSerializer(), options,
|
||||
request.getResponseContentType(), request.getPreferences());
|
||||
}
|
||||
|
||||
// write collection of entities
|
||||
// TODO: server paging needs to be implemented.
|
||||
public void writeReadEntitySet(EdmEntityType entityType, EntitySet entitySet)
|
||||
throws SerializerException {
|
||||
|
||||
assert (!isClosed());
|
||||
|
||||
if (entitySet == null) {
|
||||
writeNotFound(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// write the whole collection to response
|
||||
this.response.setContent(this.serializer.entityCollection(metadata, entityType, entitySet, this.options));
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class MetadataResponse extends ServiceResponse {
|
||||
private final ODataSerializer serializer;
|
||||
private final ContentType responseContentType;
|
||||
|
||||
public static MetadataResponse getInstance(ServiceRequest request,
|
||||
ODataResponse response) throws ContentNegotiatorException, SerializerException {
|
||||
return new MetadataResponse(request.getServiceMetaData(), response, request.getSerializer(),
|
||||
request.getResponseContentType(), request.getPreferences());
|
||||
}
|
||||
|
||||
private MetadataResponse(ServiceMetadata metadata, ODataResponse response, ODataSerializer serializer,
|
||||
ContentType responseContentType, Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
this.responseContentType = responseContentType;
|
||||
}
|
||||
|
||||
public void writeMetadata()throws ODataTranslatedException {
|
||||
assert (!isClosed());
|
||||
this.response.setContent(this.serializer.metadataDocument(this.metadata));
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
|
||||
public class NoContentResponse extends ServiceResponse {
|
||||
|
||||
public NoContentResponse(ServiceMetadata metadata, ODataResponse response) {
|
||||
super(metadata, response, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
// 200
|
||||
public void writeOK() {
|
||||
this.response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 201
|
||||
public void writeCreated() {
|
||||
this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 202
|
||||
public void writeAccepted() {
|
||||
this.response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 204
|
||||
public void writeNoContent() {
|
||||
writeNoContent(true);
|
||||
}
|
||||
|
||||
// 304
|
||||
public void writeNotModified() {
|
||||
this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// error response codes
|
||||
|
||||
// 404
|
||||
public void writeNotFound() {
|
||||
writeNotFound(true);
|
||||
}
|
||||
|
||||
// 501
|
||||
public void writeNotImplemented() {
|
||||
this.response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 405
|
||||
public void writeMethodNotAllowed() {
|
||||
this.response.setStatusCode(HttpStatusCode.METHOD_NOT_ALLOWED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 410
|
||||
public void writeGone() {
|
||||
this.response.setStatusCode(HttpStatusCode.GONE.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
// 412
|
||||
public void writePreConditionFailed() {
|
||||
this.response.setStatusCode(HttpStatusCode.PRECONDITION_FAILED.getStatusCode());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmReturnType;
|
||||
import org.apache.olingo.commons.api.http.HttpContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
|
||||
import org.apache.olingo.server.api.serializer.PrimitiveValueSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class PrimitiveValueResponse extends ServiceResponse {
|
||||
private final boolean returnCollection;
|
||||
private EdmProperty type;
|
||||
private EdmReturnType returnType;
|
||||
private final FixedFormatSerializer serializer;
|
||||
|
||||
public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
|
||||
boolean collection, EdmProperty type) {
|
||||
FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
|
||||
return new PrimitiveValueResponse(request.getServiceMetaData(), serializer, response,
|
||||
collection, type, request.getPreferences());
|
||||
}
|
||||
|
||||
public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
|
||||
boolean collection, EdmReturnType type) {
|
||||
FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
|
||||
return new PrimitiveValueResponse(request.getServiceMetaData(), serializer, response,
|
||||
collection, type, request.getPreferences());
|
||||
}
|
||||
|
||||
private PrimitiveValueResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
|
||||
ODataResponse response, boolean collection, EdmProperty type, Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.returnCollection = collection;
|
||||
this.type = type;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
private PrimitiveValueResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
|
||||
ODataResponse response, boolean collection, EdmReturnType type,
|
||||
Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.returnCollection = collection;
|
||||
this.returnType = type;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public void write(Object value) throws SerializerException {
|
||||
if (value == null) {
|
||||
writeNoContent(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.type != null) {
|
||||
PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
|
||||
.facetsFrom(this.type).build();
|
||||
|
||||
this.response.setContent(this.serializer.primitiveValue((EdmPrimitiveType) this.type.getType(),
|
||||
value, options));
|
||||
} else {
|
||||
PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
|
||||
.nullable(this.returnType.isNullable()).maxLength(this.returnType.getMaxLength())
|
||||
.precision(this.returnType.getPrecision()).scale(this.returnType.getScale()).build();
|
||||
this.response.setContent(this.serializer.primitiveValue(
|
||||
(EdmPrimitiveType) this.returnType.getType(), value, options));
|
||||
}
|
||||
|
||||
writeOK(HttpContentType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
public boolean isReturnCollection() {
|
||||
return returnCollection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class PropertyResponse extends ServiceResponse {
|
||||
private PrimitiveSerializerOptions primitiveOptions;
|
||||
private ComplexSerializerOptions complexOptions;
|
||||
private final ContentType responseContentType;
|
||||
private final ODataSerializer serializer;
|
||||
private final boolean collection;
|
||||
|
||||
public static PropertyResponse getInstance(ServiceRequest request, ODataResponse response,
|
||||
EdmType edmType, ContextURL contextURL, boolean collection) throws ContentNegotiatorException,
|
||||
SerializerException {
|
||||
if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
|
||||
PrimitiveSerializerOptions options = request.getSerializerOptions(
|
||||
PrimitiveSerializerOptions.class, contextURL, false);
|
||||
ContentType type = request.getResponseContentType();
|
||||
return new PropertyResponse(request.getServiceMetaData(), request.getSerializer(), response,
|
||||
options, type, collection, request.getPreferences());
|
||||
}
|
||||
ComplexSerializerOptions options = request.getSerializerOptions(ComplexSerializerOptions.class,
|
||||
contextURL, false);
|
||||
ContentType type = request.getResponseContentType();
|
||||
return new PropertyResponse(request.getServiceMetaData(), request.getSerializer(), response,
|
||||
options, type, collection, request.getPreferences());
|
||||
}
|
||||
|
||||
private PropertyResponse(ServiceMetadata metadata, ODataSerializer serializer,
|
||||
ODataResponse response, PrimitiveSerializerOptions options, ContentType contentType,
|
||||
boolean collection, Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
this.primitiveOptions = options;
|
||||
this.responseContentType = contentType;
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
private PropertyResponse(ServiceMetadata metadata, ODataSerializer serializer, ODataResponse response,
|
||||
ComplexSerializerOptions options, ContentType contentType, boolean collection,
|
||||
Map<String, String> preferences) {
|
||||
super(metadata, response, preferences);
|
||||
this.serializer = serializer;
|
||||
this.complexOptions = options;
|
||||
this.responseContentType = contentType;
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public void writeProperty(EdmType edmType, Property property) throws SerializerException {
|
||||
assert (!isClosed());
|
||||
|
||||
if (property == null) {
|
||||
writeNotFound(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.getValue() == null) {
|
||||
writeNoContent(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
|
||||
writePrimitiveProperty((EdmPrimitiveType) edmType, property);
|
||||
} else {
|
||||
writeComplexProperty((EdmComplexType) edmType, property);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeComplexProperty(EdmComplexType type, Property property)
|
||||
throws SerializerException {
|
||||
if (this.collection) {
|
||||
this.response.setContent(this.serializer.complexCollection(this.metadata, type, property,
|
||||
this.complexOptions));
|
||||
} else {
|
||||
this.response.setContent(this.serializer.complex(this.metadata, type, property,
|
||||
this.complexOptions));
|
||||
}
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
private void writePrimitiveProperty(EdmPrimitiveType type, Property property)
|
||||
throws SerializerException {
|
||||
if(this.collection) {
|
||||
this.response.setContent(this.serializer.primitiveCollection(type, property, this.primitiveOptions));
|
||||
} else {
|
||||
this.response.setContent(this.serializer.primitive(type, property, this.primitiveOptions));
|
||||
}
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
public void writePropertyUpdated() {
|
||||
// spec says just success response; so either 200 or 204. 200 typically has
|
||||
// payload
|
||||
writeNoContent(true);
|
||||
}
|
||||
|
||||
public void writePropertyDeleted() {
|
||||
writeNoContent(true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.core.ContentNegotiatorException;
|
||||
import org.apache.olingo.server.core.ServiceRequest;
|
||||
|
||||
public class ServiceDocumentResponse extends ServiceResponse {
|
||||
private final ODataSerializer serializer;
|
||||
private final ContentType responseContentType;
|
||||
|
||||
public static ServiceDocumentResponse getInstace(ServiceRequest request, ODataResponse respose,
|
||||
ContentType responseContentType) throws ContentNegotiatorException, SerializerException {
|
||||
return new ServiceDocumentResponse(request.getServiceMetaData(), respose,
|
||||
request.getSerializer(), responseContentType, request.getPreferences());
|
||||
}
|
||||
|
||||
private ServiceDocumentResponse(ServiceMetadata metadata, ODataResponse respose,
|
||||
ODataSerializer serializer, ContentType responseContentType, Map<String, String> preferences) {
|
||||
super(metadata, respose, preferences);
|
||||
this.serializer = serializer;
|
||||
this.responseContentType = responseContentType;
|
||||
}
|
||||
|
||||
public void writeServiceDocument(String serviceRoot)
|
||||
throws ODataTranslatedException {
|
||||
assert (!isClosed());
|
||||
this.response.setContent(this.serializer.serviceDocument(this.metadata.getEdm(), serviceRoot));
|
||||
writeOK(this.responseContentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
|
||||
public abstract class ServiceResponse {
|
||||
protected ServiceMetadata metadata;
|
||||
protected ODataResponse response;
|
||||
protected Map<String, String> preferences;
|
||||
private boolean closed;
|
||||
private boolean strictApplyPreferences = true;
|
||||
|
||||
public ServiceResponse(ServiceMetadata metadata, ODataResponse response,
|
||||
Map<String, String> preferences) {
|
||||
this.metadata = metadata;
|
||||
this.response = response;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
public ODataResponse getODataResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
protected boolean isClosed() {
|
||||
return this.closed;
|
||||
}
|
||||
|
||||
protected void close() {
|
||||
if (!this.closed) {
|
||||
if (this.strictApplyPreferences) {
|
||||
if (!preferences.isEmpty()) {
|
||||
assert(this.response.getHeaders().get("Preference-Applied") != null);
|
||||
}
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeNoContent(boolean closeResponse) {
|
||||
this.response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||
if (closeResponse) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeNotFound(boolean closeResponse) {
|
||||
response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
|
||||
if (closeResponse) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeServerError(boolean closeResponse) {
|
||||
response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
|
||||
if (closeResponse) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBadRequest(boolean closeResponse) {
|
||||
response.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode());
|
||||
if (closeResponse) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeOK(String contentType) {
|
||||
this.response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
this.response.setHeader(HttpHeader.CONTENT_TYPE, contentType);
|
||||
}
|
||||
|
||||
public void writeHeader(String key, String value) {
|
||||
if ("Preference-Applied".equals(key)) {
|
||||
String previous = this.response.getHeaders().get(key);
|
||||
if (previous != null) {
|
||||
value = previous+";"+value;
|
||||
}
|
||||
this.response.setHeader(key, value);
|
||||
} else {
|
||||
this.response.setHeader(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When true; the "Preference-Applied" header is strictly checked.
|
||||
* @param flag
|
||||
*/
|
||||
public void setStrictlyApplyPreferences(boolean flag) {
|
||||
this.strictApplyPreferences = flag;
|
||||
}
|
||||
|
||||
public abstract void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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.responses;
|
||||
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ServiceResponseVisior {
|
||||
|
||||
public void visit(CountResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(MetadataResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(NoContentResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(PrimitiveValueResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(ServiceDocumentResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(StreamResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
public void visit(EntitySetResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
|
@ -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.core.responses;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
|
||||
public class StreamResponse extends ServiceResponse {
|
||||
|
||||
public StreamResponse(ServiceMetadata metadata, ODataResponse response) {
|
||||
super(metadata, response, Collections.EMPTY_MAP);
|
||||
}
|
||||
|
||||
public void writeStreamResponse(InputStream streamContent, ContentType contentType) {
|
||||
this.response.setContent(streamContent);
|
||||
writeOK(contentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
public void writeBinaryResponse(byte[] streamContent, ContentType contentType) {
|
||||
this.response.setContent(new ByteArrayInputStream(streamContent));
|
||||
writeOK(contentType.toContentTypeString());
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.ODataException;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.provider.Action;
|
||||
import org.apache.olingo.commons.api.edm.provider.ActionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.ComplexType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.EntityType;
|
||||
import org.apache.olingo.commons.api.edm.provider.EnumType;
|
||||
import org.apache.olingo.commons.api.edm.provider.Function;
|
||||
import org.apache.olingo.commons.api.edm.provider.FunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.provider.NavigationPropertyBinding;
|
||||
import org.apache.olingo.commons.api.edm.provider.Parameter;
|
||||
import org.apache.olingo.commons.api.edm.provider.Property;
|
||||
import org.apache.olingo.commons.api.edm.provider.Singleton;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MetadataParserTest {
|
||||
final String NS = "Microsoft.OData.SampleService.Models.TripPin";
|
||||
final FullQualifiedName NSF = new FullQualifiedName(NS);
|
||||
|
||||
EdmProvider provider = null;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MetadataParser parser = new MetadataParser();
|
||||
provider = parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAction() throws ODataException {
|
||||
// test action
|
||||
List<Action> actions = provider.getActions(new FullQualifiedName(NS, "ResetDataSource"));
|
||||
assertNotNull(actions);
|
||||
assertEquals(1, actions.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunction() throws ODataException {
|
||||
// test function
|
||||
List<Function> functions = provider
|
||||
.getFunctions(new FullQualifiedName(NS, "GetFavoriteAirline"));
|
||||
assertNotNull(functions);
|
||||
assertEquals(1, functions.size());
|
||||
assertEquals("GetFavoriteAirline", functions.get(0).getName());
|
||||
assertTrue(functions.get(0).isBound());
|
||||
assertTrue(functions.get(0).isComposable());
|
||||
assertEquals(
|
||||
"person/Trips/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline",
|
||||
functions.get(0).getEntitySetPath());
|
||||
|
||||
List<Parameter> parameters = functions.get(0).getParameters();
|
||||
assertNotNull(parameters);
|
||||
assertEquals(1, parameters.size());
|
||||
assertEquals("person", parameters.get(0).getName());
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Person",parameters.get(0).getType());
|
||||
assertFalse(parameters.get(0).isNullable());
|
||||
|
||||
assertNotNull(functions.get(0).getReturnType());
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Airline",
|
||||
functions.get(0).getReturnType().getType());
|
||||
assertFalse(functions.get(0).getReturnType().isNullable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnumType() throws ODataException {
|
||||
// test enum type
|
||||
EnumType enumType = provider.getEnumType(new FullQualifiedName(NS, "PersonGender"));
|
||||
assertNotNull(enumType);
|
||||
assertEquals("Male", enumType.getMembers().get(0).getName());
|
||||
assertEquals("Female", enumType.getMembers().get(1).getName());
|
||||
assertEquals("Unknown", enumType.getMembers().get(2).getName());
|
||||
assertEquals("0", enumType.getMembers().get(0).getValue());
|
||||
assertEquals("1", enumType.getMembers().get(1).getValue());
|
||||
assertEquals("2", enumType.getMembers().get(2).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityType() throws ODataException {
|
||||
// test Entity Type
|
||||
EntityType et = provider.getEntityType(new FullQualifiedName(NS, "Photo"));
|
||||
assertNotNull(et);
|
||||
assertNotNull(et.getKey());
|
||||
assertEquals("Id", et.getKey().get(0).getName());
|
||||
assertTrue(et.hasStream());
|
||||
assertEquals("Id", et.getProperties().get(0).getName());
|
||||
assertEquals("Edm.Int64", et.getProperties().get(0).getType());
|
||||
assertEquals("Name", et.getProperties().get(1).getName());
|
||||
assertEquals("Edm.String", et.getProperties().get(1).getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexType() throws ODataException {
|
||||
// Test Complex Type
|
||||
ComplexType ct = provider.getComplexType(new FullQualifiedName(NS, "City"));
|
||||
assertNotNull(ct);
|
||||
assertEquals(3, ct.getProperties().size());
|
||||
Property p = ct.getProperties().get(0);
|
||||
assertEquals("CountryRegion", p.getName());
|
||||
assertEquals("Edm.String", p.getType());
|
||||
assertEquals(false, p.isNullable());
|
||||
|
||||
ct = provider.getComplexType(new FullQualifiedName(NS, "Location"));
|
||||
assertNotNull(ct);
|
||||
|
||||
ct = provider.getComplexType(new FullQualifiedName(NS, "EventLocation"));
|
||||
assertNotNull(ct);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntitySet() throws Exception {
|
||||
EntitySet es = provider.getEntitySet(NSF, "People");
|
||||
assertNotNull(es);
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Person",es.getType());
|
||||
|
||||
List<NavigationPropertyBinding> bindings = es.getNavigationPropertyBindings();
|
||||
assertNotNull(bindings);
|
||||
assertEquals(6, bindings.size());
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Flight/From", bindings.get(2)
|
||||
.getPath());
|
||||
assertEquals("Airports", bindings.get(2).getTarget());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionImport() throws Exception {
|
||||
FunctionImport fi = provider.getFunctionImport(NSF, "GetNearestAirport");
|
||||
assertNotNull(fi);
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport", fi.getFunction());
|
||||
assertEquals("Airports", fi.getEntitySet());
|
||||
assertTrue(fi.isIncludeInServiceDocument());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionImport() throws Exception {
|
||||
ActionImport ai = provider.getActionImport(NSF, "ResetDataSource");
|
||||
assertNotNull(ai);
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.ResetDataSource", ai.getAction());
|
||||
assertNull(ai.getEntitySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleton() throws Exception {
|
||||
Singleton single = this.provider.getSingleton(NSF, "Me");
|
||||
assertNotNull(single);
|
||||
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Person",single.getType());
|
||||
|
||||
List<NavigationPropertyBinding> bindings = single.getNavigationPropertyBindings();
|
||||
assertNotNull(bindings);
|
||||
assertEquals(6, bindings.size());
|
||||
assertEquals("Microsoft.OData.SampleService.Models.TripPin.Flight/From", bindings.get(2).getPath());
|
||||
assertEquals("Airports", bindings.get(2).getTarget());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.core.requests.ActionRequest;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.requests.FunctionRequest;
|
||||
import org.apache.olingo.server.core.requests.MediaRequest;
|
||||
import org.apache.olingo.server.core.requests.MetadataRequest;
|
||||
import org.apache.olingo.server.core.responses.CountResponse;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.MetadataResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
import org.apache.olingo.server.example.TripPinServiceTest;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class ServiceDispatcherTest {
|
||||
private Server server;
|
||||
|
||||
public class SampleODataServlet extends HttpServlet {
|
||||
private final ServiceHandler handler; // must be stateless
|
||||
private final EdmProvider provider; // must be stateless
|
||||
|
||||
public SampleODataServlet(ServiceHandler handler, EdmProvider provider) {
|
||||
this.handler = handler;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
OData odata = OData4Impl.newInstance();
|
||||
ServiceMetadata metadata = odata.createServiceMetadata(this.provider, Collections.EMPTY_LIST);
|
||||
|
||||
ODataHttpHandler handler = odata.createHandler(metadata);
|
||||
|
||||
handler.register(this.handler);
|
||||
handler.process(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public int beforeTest(ServiceHandler serviceHandler) throws Exception {
|
||||
MetadataParser parser = new MetadataParser();
|
||||
EdmProvider edmProvider = parser.buildEdmProvider(new FileReader(
|
||||
"src/test/resources/trippin.xml"));
|
||||
|
||||
this.server = new Server();
|
||||
|
||||
ServerConnector connector = new ServerConnector(this.server);
|
||||
this.server.setConnectors(new Connector[] { connector });
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/trippin");
|
||||
context
|
||||
.addServlet(new ServletHolder(new SampleODataServlet(serviceHandler, edmProvider)), "/*");
|
||||
this.server.setHandler(context);
|
||||
this.server.start();
|
||||
|
||||
return connector.getLocalPort();
|
||||
}
|
||||
|
||||
public void afterTest() throws Exception {
|
||||
this.server.stop();
|
||||
}
|
||||
|
||||
interface TestResult {
|
||||
void validate() throws Exception;
|
||||
}
|
||||
|
||||
private void helpGETTest(ServiceHandler handler, String path, TestResult validator)
|
||||
throws Exception {
|
||||
int port = beforeTest(handler);
|
||||
HttpClient http = new HttpClient();
|
||||
http.start();
|
||||
http.GET("http://localhost:" + port + "/" + path);
|
||||
validator.validate();
|
||||
afterTest();
|
||||
}
|
||||
|
||||
private void helpTest(ServiceHandler handler, String path, String method, String payload,
|
||||
TestResult validator) throws Exception {
|
||||
int port = beforeTest(handler);
|
||||
HttpClient http = new HttpClient();
|
||||
http.start();
|
||||
String editUrl = "http://localhost:" + port + "/" + path;
|
||||
http.newRequest(editUrl).method(method)
|
||||
.header("Content-Type", "application/json;odata.metadata=minimal")
|
||||
.content(TripPinServiceTest.content(payload)).send();
|
||||
validator.validate();
|
||||
afterTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadata() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/$metadata", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<MetadataRequest> arg1 = ArgumentCaptor.forClass(MetadataRequest.class);
|
||||
ArgumentCaptor<MetadataResponse> arg2 = ArgumentCaptor.forClass(MetadataResponse.class);
|
||||
Mockito.verify(handler).readMetadata(arg1.capture(), arg2.capture());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntitySet() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<EntityResponse> arg2 = ArgumentCaptor.forClass(EntityResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
// Need toString on ContextURL class
|
||||
// assertEquals("",
|
||||
// request.getContextURL(request.getOdata()).toString());
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntitySetCount() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports/$count", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<CountResponse> arg2 = ArgumentCaptor.forClass(CountResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
// Need toString on ContextURL class
|
||||
// assertEquals("",
|
||||
// request.getContextURL(request.getOdata()).toString());
|
||||
assertEquals("text/plain", request.getResponseContentType().toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntity() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports('0')", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<EntityResponse> arg2 = ArgumentCaptor.forClass(EntityResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals(1, request.getUriResourceEntitySet().getKeyPredicates().size());
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadProperty() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports('0')/IataCode", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<PropertyResponse> arg2 = ArgumentCaptor.forClass(PropertyResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals(true, request.isPropertyRequest());
|
||||
assertEquals(false, request.isPropertyComplex());
|
||||
assertEquals(1, request.getUriResourceEntitySet().getKeyPredicates().size());
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadComplexProperty() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports('0')/Location", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<PropertyResponse> arg2 = ArgumentCaptor.forClass(PropertyResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals(true, request.isPropertyRequest());
|
||||
assertEquals(true, request.isPropertyComplex());
|
||||
assertEquals(1, request.getUriResourceEntitySet().getKeyPredicates().size());
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadProperty$Value() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports('0')/IataCode/$value", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<PrimitiveValueResponse> arg2 = ArgumentCaptor
|
||||
.forClass(PrimitiveValueResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals(true, request.isPropertyRequest());
|
||||
assertEquals(false, request.isPropertyComplex());
|
||||
assertEquals(1, request.getUriResourceEntitySet().getKeyPredicates().size());
|
||||
assertEquals("text/plain", request.getResponseContentType().toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadPropertyRef() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Airports('0')/IataCode/$value", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<PrimitiveValueResponse> arg2 = ArgumentCaptor
|
||||
.forClass(PrimitiveValueResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals(true, request.isPropertyRequest());
|
||||
assertEquals(false, request.isPropertyComplex());
|
||||
assertEquals(1, request.getUriResourceEntitySet().getKeyPredicates().size());
|
||||
assertEquals("text/plain", request.getResponseContentType().toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionImport() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/GetNearestAirport(lat=12.11,lon=34.23)", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<FunctionRequest> arg1 = ArgumentCaptor.forClass(FunctionRequest.class);
|
||||
ArgumentCaptor<PropertyResponse> arg3 = ArgumentCaptor.forClass(PropertyResponse.class);
|
||||
ArgumentCaptor<HttpMethod> arg2 = ArgumentCaptor.forClass(HttpMethod.class);
|
||||
Mockito.verify(handler).invoke(arg1.capture(), arg2.capture(), arg3.capture());
|
||||
|
||||
FunctionRequest request = arg1.getValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionImport() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpTest(handler, "trippin/ResetDataSource", "POST", "", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<ActionRequest> arg1 = ArgumentCaptor.forClass(ActionRequest.class);
|
||||
ArgumentCaptor<NoContentResponse> arg2 = ArgumentCaptor.forClass(NoContentResponse.class);
|
||||
Mockito.verify(handler).invoke(arg1.capture(), Mockito.anyString(), arg2.capture());
|
||||
|
||||
ActionRequest request = arg1.getValue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadMedia() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/Photos(1)/$value", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<MediaRequest> arg1 = ArgumentCaptor.forClass(MediaRequest.class);
|
||||
ArgumentCaptor<StreamResponse> arg2 = ArgumentCaptor.forClass(StreamResponse.class);
|
||||
Mockito.verify(handler).readMediaStream(arg1.capture(), arg2.capture());
|
||||
|
||||
MediaRequest request = arg1.getValue();
|
||||
assertEquals("application/octet-stream", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigation() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/People('russelwhyte')/Friends", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<EntitySetResponse> arg2 = ArgumentCaptor.forClass(EntitySetResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadReference() throws Exception {
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpGETTest(handler, "trippin/People('russelwhyte')/Friends/$ref", new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<EntitySetResponse> arg2 = ArgumentCaptor.forClass(EntitySetResponse.class);
|
||||
Mockito.verify(handler).read(arg1.capture(), arg2.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals("application/json;odata.metadata=minimal", request.getResponseContentType()
|
||||
.toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteReferenceCollection() throws Exception {
|
||||
String payload = "{\n" + "\"@odata.id\": \"/Photos(11)\"\n" + "}";
|
||||
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpTest(handler, "trippin/People('russelwhyte')/Friends/$ref", "POST", payload,
|
||||
new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<String> arg2 = ArgumentCaptor.forClass(String.class);
|
||||
ArgumentCaptor<List> arg3 = ArgumentCaptor.forClass(List.class);
|
||||
ArgumentCaptor<NoContentResponse> arg4 = ArgumentCaptor
|
||||
.forClass(NoContentResponse.class);
|
||||
Mockito.verify(handler).addReference(arg1.capture(), arg2.capture(), arg3.capture(),
|
||||
arg4.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals("application/json;odata.metadata=minimal", request
|
||||
.getResponseContentType().toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteReference() throws Exception {
|
||||
String payload = "{\n" + "\"@odata.id\": \"/Photos(11)\"\n" + "}";
|
||||
|
||||
final ServiceHandler handler = Mockito.mock(ServiceHandler.class);
|
||||
helpTest(handler, "trippin/People('russelwhyte')/Friends('someone')/Photo/$ref", "PUT", payload,
|
||||
new TestResult() {
|
||||
@Override
|
||||
public void validate() throws Exception {
|
||||
ArgumentCaptor<DataRequest> arg1 = ArgumentCaptor.forClass(DataRequest.class);
|
||||
ArgumentCaptor<String> arg2 = ArgumentCaptor.forClass(String.class);
|
||||
ArgumentCaptor<URI> arg3 = ArgumentCaptor.forClass(URI.class);
|
||||
ArgumentCaptor<NoContentResponse> arg4 = ArgumentCaptor
|
||||
.forClass(NoContentResponse.class);
|
||||
Mockito.verify(handler).updateReference(arg1.capture(), arg2.capture(), arg3.capture(),
|
||||
arg4.capture());
|
||||
|
||||
DataRequest request = arg1.getValue();
|
||||
assertEquals("application/json;odata.metadata=minimal", request
|
||||
.getResponseContentType().toContentTypeString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,843 @@
|
|||
/*
|
||||
* 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.example;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
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.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
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.core.data.EntityImpl;
|
||||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.commons.core.data.LinkImpl;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class TripPinDataModel {
|
||||
private final ServiceMetadata metadata;
|
||||
private HashMap<String, EntitySet> entitySetMap;
|
||||
private Map<Integer, Map> tripLinks;
|
||||
private Map<String, Map> peopleLinks;
|
||||
private Map<Integer, Map> flightLinks;
|
||||
|
||||
public TripPinDataModel(ServiceMetadata metadata) throws Exception {
|
||||
this.metadata = metadata;
|
||||
loadData();
|
||||
}
|
||||
|
||||
public void loadData() throws Exception {
|
||||
this.entitySetMap = new HashMap<String, EntitySet>();
|
||||
this.tripLinks = new HashMap<Integer, Map>();
|
||||
this.peopleLinks = new HashMap<String, Map>();
|
||||
this.flightLinks = new HashMap<Integer, Map>();
|
||||
|
||||
EdmEntityContainer ec = metadata.getEdm().getEntityContainer(null);
|
||||
for (EdmEntitySet edmEntitySet : ec.getEntitySets()) {
|
||||
String entitySetName = edmEntitySet.getName();
|
||||
EntitySet set = loadEnities(entitySetName, edmEntitySet.getEntityType());
|
||||
if (set != null) {
|
||||
this.entitySetMap.put(entitySetName, set);
|
||||
}
|
||||
}
|
||||
|
||||
EdmEntityType type = metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName("Microsoft.OData.SampleService.Models.TripPin", "Trip"));
|
||||
this.entitySetMap.put("Trip", loadEnities("Trip", type));
|
||||
|
||||
type = metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName("Microsoft.OData.SampleService.Models.TripPin", "Flight"));
|
||||
this.entitySetMap.put("Flight", loadEnities("Flight", type));
|
||||
|
||||
type = metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName("Microsoft.OData.SampleService.Models.TripPin", "Event"));
|
||||
this.entitySetMap.put("Event", loadEnities("Event", type));
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map tripLinks = mapper.readValue(new FileInputStream(new File(
|
||||
"src/test/resources/trip-links.json")), Map.class);
|
||||
for (Object link : (ArrayList) tripLinks.get("value")) {
|
||||
Map map = (Map) link;
|
||||
this.tripLinks.put((Integer) map.get("TripId"), map);
|
||||
}
|
||||
|
||||
Map peopleLinks = mapper.readValue(new FileInputStream(new File(
|
||||
"src/test/resources/people-links.json")), Map.class);
|
||||
for (Object link : (ArrayList) peopleLinks.get("value")) {
|
||||
Map map = (Map) link;
|
||||
this.peopleLinks.put((String) map.get("UserName"), map);
|
||||
}
|
||||
|
||||
Map flightLinks = mapper.readValue(new FileInputStream(new File(
|
||||
"src/test/resources/flight-links.json")), Map.class);
|
||||
for (Object link : (ArrayList) flightLinks.get("value")) {
|
||||
Map map = (Map) link;
|
||||
this.flightLinks.put((Integer) map.get("PlanItemId"), map);
|
||||
}
|
||||
}
|
||||
|
||||
private EntitySet loadEnities(String entitySetName, EdmEntityType type) {
|
||||
try {
|
||||
ODataJsonDeserializer deserializer = new ODataJsonDeserializer();
|
||||
|
||||
EntitySet set = deserializer.entityCollection(new FileInputStream(new File(
|
||||
"src/test/resources/" + entitySetName.toLowerCase() + ".json")), type);
|
||||
// TODO: the count needs to be part of deserializer
|
||||
set.setCount(set.getEntities().size());
|
||||
for (Entity entity : set.getEntities()) {
|
||||
((EntityImpl) entity).setETag(UUID.randomUUID().toString());
|
||||
((EntityImpl) entity).setId(new URI(TripPinHandler.buildLocation(entity, entitySetName,
|
||||
type)));
|
||||
((EntityImpl) entity).setType(type.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
return set;
|
||||
} catch (FileNotFoundException e) {
|
||||
// keep going
|
||||
e.printStackTrace();
|
||||
} catch (DeserializerException e) {
|
||||
// keep going
|
||||
e.printStackTrace();
|
||||
} catch (URISyntaxException e) {
|
||||
// keep going
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EntitySet getEntitySet(String name) {
|
||||
return getEntitySet(name, -1, -1);
|
||||
}
|
||||
|
||||
public EntitySet getEntitySet(String name, int skip, int pageSize) {
|
||||
EntitySet set = this.entitySetMap.get(name);
|
||||
if (set == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
EntitySetImpl modifiedES = new EntitySetImpl();
|
||||
int i = 0;
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (skip >= 0 && i >= skip && modifiedES.getEntities().size() < pageSize) {
|
||||
modifiedES.getEntities().add(e);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
modifiedES.setCount(i);
|
||||
set.setCount(i);
|
||||
|
||||
if (skip == -1 && pageSize == -1) {
|
||||
return set;
|
||||
}
|
||||
return modifiedES;
|
||||
}
|
||||
|
||||
private List<Entity> getMatch(UriParameter param, List<Entity> es)
|
||||
throws ODataApplicationException {
|
||||
ArrayList<Entity> list = new ArrayList<Entity>();
|
||||
for (Entity entity : es) {
|
||||
|
||||
EdmEntityType entityType = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(entity.getType()));
|
||||
|
||||
EdmProperty property = (EdmProperty) entityType.getProperty(param.getName());
|
||||
EdmType type = property.getType();
|
||||
if (type.getKind() == EdmTypeKind.PRIMITIVE) {
|
||||
Object match = readPrimitiveValue(property, param.getText());
|
||||
Property entityValue = entity.getProperty(param.getName());
|
||||
if (match.equals(entityValue.asPrimitive())) {
|
||||
list.add(entity);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Can not compare complex objects");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static Object readPrimitiveValue(EdmProperty edmProperty, String value)
|
||||
throws ODataApplicationException {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (value.startsWith("'") && value.endsWith("'")) {
|
||||
value = value.substring(1,value.length()-1);
|
||||
}
|
||||
EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmProperty.getType();
|
||||
Class<?> javaClass = getJavaClassForPrimitiveType(edmProperty, edmPrimitiveType);
|
||||
return edmPrimitiveType.valueOfString(value, edmProperty.isNullable(),
|
||||
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
|
||||
edmProperty.isUnicode(), javaClass);
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
throw new ODataApplicationException("Invalid value: " + value + " for property: "
|
||||
+ edmProperty.getName(), 500, Locale.getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
static Class<?> getJavaClassForPrimitiveType(EdmProperty edmProperty, EdmPrimitiveType edmPrimitiveType) {
|
||||
Class<?> javaClass = null;
|
||||
if (edmProperty.getMapping() != null && edmProperty.getMapping().getMappedJavaClass() != null) {
|
||||
javaClass = edmProperty.getMapping().getMappedJavaClass();
|
||||
} else {
|
||||
javaClass = edmPrimitiveType.getDefaultType();
|
||||
}
|
||||
|
||||
edmPrimitiveType.getDefaultType();
|
||||
return javaClass;
|
||||
}
|
||||
|
||||
public Entity getEntity(String name, List<UriParameter> keys) throws ODataApplicationException {
|
||||
EntitySet es = getEntitySet(name);
|
||||
return getEntity(es, keys);
|
||||
}
|
||||
|
||||
public Entity getEntity(EntitySet es, List<UriParameter> keys) throws ODataApplicationException {
|
||||
List<Entity> search = es.getEntities();
|
||||
for (UriParameter param : keys) {
|
||||
search = getMatch(param, search);
|
||||
}
|
||||
if (search.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return search.get(0);
|
||||
}
|
||||
|
||||
private EntitySet getFriends(String userName) {
|
||||
Map<String, Object> map = this.peopleLinks.get(userName);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<String> friends = (ArrayList<String>) map.get("Friends");
|
||||
EntitySet set = getEntitySet("People");
|
||||
|
||||
EntitySetImpl result = new EntitySetImpl();
|
||||
int i = 0;
|
||||
if (friends != null) {
|
||||
for (String friend : friends) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("UserName").getValue().equals(friend)) {
|
||||
result.getEntities().add(e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setCount(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntitySet getTrips(String userName) {
|
||||
Map<String, Object> map = this.peopleLinks.get(userName);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Integer> trips = (ArrayList<Integer>) map.get("Trips");
|
||||
EntitySet set = getEntitySet("Trip");
|
||||
|
||||
EntitySetImpl result = new EntitySetImpl();
|
||||
int i = 0;
|
||||
if (trips != null) {
|
||||
for (int trip : trips) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("TripId").getValue().equals(trip)) {
|
||||
result.getEntities().add(e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setCount(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Entity getPhoto(String userName) {
|
||||
Map<String, Object> map = this.peopleLinks.get(userName);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Integer photoID = (Integer) map.get("Photo");
|
||||
EntitySet set = getEntitySet("Photos");
|
||||
if (photoID != null) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("Id").getValue().equals(photoID.longValue())) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private EntitySet getPlanItems(int tripId, EntitySetImpl result) {
|
||||
getFlights(tripId, result);
|
||||
getEvents(tripId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntitySet getEvents(int tripId, EntitySetImpl result) {
|
||||
Map<Integer, Object> map = this.tripLinks.get(tripId);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Integer> events = (ArrayList<Integer>) map.get("Events");
|
||||
EntitySet set = getEntitySet("Event");
|
||||
int i = result.getEntities().size();
|
||||
if (events != null) {
|
||||
for (int event : events) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("PlanItemId").getValue().equals(event)) {
|
||||
result.getEntities().add(e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setCount(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntitySet getFlights(int tripId, EntitySetImpl result) {
|
||||
Map<Integer, Object> map = this.tripLinks.get(tripId);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Integer> flights = (ArrayList<Integer>) map.get("Flights");
|
||||
EntitySet set = getEntitySet("Flight");
|
||||
int i = result.getEntities().size();
|
||||
if (flights != null) {
|
||||
for (int flight : flights) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("PlanItemId").getValue().equals(flight)) {
|
||||
result.getEntities().add(e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setCount(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntitySet getTripPhotos(int tripId) {
|
||||
Map<Integer, Object> map = this.tripLinks.get(tripId);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Integer> photos = (ArrayList<Integer>) map.get("Photos");
|
||||
|
||||
EntitySet set = getEntitySet("Photos");
|
||||
EntitySetImpl result = new EntitySetImpl();
|
||||
int i = 0;
|
||||
if (photos != null) {
|
||||
for (int photo : photos) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("Id").getValue().equals(photo)) {
|
||||
result.getEntities().add(e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setCount(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Entity getFlightFrom(int flighID) {
|
||||
Map<String, Object> map = this.flightLinks.get(flighID);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String from = (String) map.get("From");
|
||||
EntitySet set = getEntitySet("Airports");
|
||||
|
||||
if (from != null) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("IataCode").getValue().equals(from)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Entity getFlightTo(int flighID) {
|
||||
Map<String, Object> map = this.flightLinks.get(flighID);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String to = (String) map.get("To");
|
||||
EntitySet set = getEntitySet("Airports");
|
||||
|
||||
if (to != null) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("IataCode").getValue().equals(to)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Entity getFlightAirline(int flighID) {
|
||||
Map<String, Object> map = this.flightLinks.get(flighID);
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String airline = (String) map.get("Airline");
|
||||
EntitySet set = getEntitySet("Airlines");
|
||||
|
||||
if (airline != null) {
|
||||
for (Entity e : set.getEntities()) {
|
||||
if (e.getProperty("AirlineCode").getValue().equals(airline)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addNavigationLink(String navigation, Entity parentEntity, Entity childEntity) {
|
||||
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(parentEntity.getType()));
|
||||
String key = type.getKeyPredicateNames().get(0);
|
||||
if (type.getName().equals("Person") && navigation.equals("Friends")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.peopleLinks.put((String) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
|
||||
ArrayList<String> friends = (ArrayList<String>) map.get("Friends");
|
||||
if (friends == null) {
|
||||
friends = new ArrayList<String>();
|
||||
map.put("Friends", friends);
|
||||
}
|
||||
friends.add((String) childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Person") && navigation.equals("Trips")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.peopleLinks.put((String) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
|
||||
ArrayList<Integer> trips = (ArrayList<Integer>) map.get("Trips");
|
||||
if (trips == null) {
|
||||
trips = new ArrayList<Integer>();
|
||||
map.put("Trips", trips);
|
||||
}
|
||||
trips.add((Integer) childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Person") && navigation.equals("Photo")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.peopleLinks.put((String) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
map.put("Photo", childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Trip") && navigation.equals("PlanItems")) {
|
||||
Map map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.tripLinks.put((Integer) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
if (childEntity.getType().equals("Flight")) {
|
||||
ArrayList<Integer> flights = (ArrayList<Integer>) map.get("Flights");
|
||||
if (flights == null) {
|
||||
flights = new ArrayList<Integer>();
|
||||
map.put("Flights", flights);
|
||||
}
|
||||
flights.add((Integer) childEntity.getProperty(key).getValue());
|
||||
} else {
|
||||
ArrayList<Integer> events = (ArrayList<Integer>) map.get("Events");
|
||||
if (events == null) {
|
||||
events = new ArrayList<Integer>();
|
||||
map.put("Events", events);
|
||||
}
|
||||
events.add((Integer) childEntity.getProperty(key).getValue());
|
||||
}
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Trip") && navigation.equals("Photo")) {
|
||||
Map map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.tripLinks.put((Integer) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
ArrayList<Integer> photos = (ArrayList<Integer>) map.get("Photos");
|
||||
if (photos == null) {
|
||||
photos = new ArrayList<Integer>();
|
||||
map.put("Photos", photos);
|
||||
}
|
||||
photos.add((Integer) childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Flight") && navigation.equals("From")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.flightLinks.put((Integer) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
map.put("From", childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Flight") && navigation.equals("To")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.flightLinks.put((Integer) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
map.put("To", childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else if (type.getName().equals("Flight") && navigation.equals("Airline")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map == null) {
|
||||
map = new HashMap();
|
||||
this.flightLinks.put((Integer) parentEntity.getProperty(key).getValue(), map);
|
||||
}
|
||||
map.put("Airline", childEntity.getProperty(key).getValue());
|
||||
setLink(parentEntity, navigation, childEntity);
|
||||
} else {
|
||||
throw new RuntimeException("unknown relation");
|
||||
}
|
||||
}
|
||||
|
||||
protected static void setLink(Entity entity, final String navigationPropertyName,
|
||||
final Entity target) {
|
||||
Link link = new LinkImpl();
|
||||
link.setTitle(navigationPropertyName);
|
||||
link.setInlineEntity(target);
|
||||
entity.getNavigationLinks().add(link);
|
||||
}
|
||||
|
||||
public boolean updateNavigationLink(String navigationProperty, Entity parentEntity,
|
||||
Entity updateEntity) {
|
||||
boolean updated = false;
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(parentEntity.getType()));
|
||||
String key = type.getKeyPredicateNames().get(0);
|
||||
|
||||
EdmEntityType updateType = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(updateEntity.getType()));
|
||||
String updateKey = updateType.getKeyPredicateNames().get(0);
|
||||
|
||||
if (type.getName().equals("Person") && navigationProperty.equals("Photo")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.put("Photo", ((Long) updateEntity.getProperty(updateKey).getValue()).intValue());
|
||||
updated = true;
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("From")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.put("From", updateEntity.getProperty(updateKey).getValue());
|
||||
updated = true;
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("To")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.put("To", updateEntity.getProperty(updateKey).getValue());
|
||||
updated = true;
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("Airline")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.put("Airline", updateEntity.getProperty(updateKey).getValue());
|
||||
updated = true;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("unknown relation");
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
public Entity createEntity(String entitySetName, Entity entity, String location)
|
||||
throws ODataApplicationException {
|
||||
|
||||
EntitySet set = this.entitySetMap.get(entitySetName);
|
||||
EntityImpl copy = new EntityImpl();
|
||||
copy.setType(entity.getType());
|
||||
for (Property p : entity.getProperties()) {
|
||||
copy.addProperty(p);
|
||||
}
|
||||
|
||||
try {
|
||||
copy.setId(new URI(location));
|
||||
copy.setETag(UUID.randomUUID().toString());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ODataApplicationException("Failed to create ID for entity", 500,
|
||||
Locale.getDefault());
|
||||
}
|
||||
|
||||
set.getEntities().add(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
public boolean deleteEntity(String entitySetName, String eTag, String key, Object keyValue) {
|
||||
EntitySet set = getEntitySet(entitySetName);
|
||||
Iterator<Entity> it = set.getEntities().iterator();
|
||||
boolean removed = false;
|
||||
while (it.hasNext()) {
|
||||
Entity entity = it.next();
|
||||
if (entity.getProperty(key).getValue().equals(keyValue) && eTag.equals("*")
|
||||
|| eTag.equals(entity.getETag())) {
|
||||
it.remove();
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public boolean updateProperty(String entitySetName, String eTag, String key, Object keyValue,
|
||||
Property property) {
|
||||
EntitySet set = getEntitySet(entitySetName);
|
||||
Iterator<Entity> it = set.getEntities().iterator();
|
||||
boolean replaced = false;
|
||||
while (it.hasNext()) {
|
||||
Entity entity = it.next();
|
||||
if (entity.getProperty(key).getValue().equals(keyValue) && eTag.equals("*")
|
||||
|| eTag.equals(entity.getETag())) {
|
||||
entity.getProperty(property.getName()).setValue(property.getValueType(),
|
||||
property.getValue());
|
||||
replaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
|
||||
public EntitySet getNavigableEntitySet(Entity parentEntity, UriResourceNavigation navigation) {
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(parentEntity.getType()));
|
||||
|
||||
String key = type.getKeyPredicateNames().get(0);
|
||||
String linkName = navigation.getProperty().getName();
|
||||
|
||||
EntitySet results = null;
|
||||
if (type.getName().equals("Person") && linkName.equals("Friends")) {
|
||||
results = getFriends((String) parentEntity.getProperty(key).getValue());
|
||||
} else if (type.getName().equals("Person") && linkName.equals("Trips")) {
|
||||
results = getTrips((String) parentEntity.getProperty(key).getValue());
|
||||
} else if (type.getName().equals("Trip") && linkName.equals("PlanItems")) {
|
||||
EntitySetImpl planitems = new EntitySetImpl();
|
||||
if (navigation.getTypeFilterOnCollection() == null) {
|
||||
results = getPlanItems((Integer) parentEntity.getProperty(key).getValue(), planitems);
|
||||
} else if (navigation.getTypeFilterOnCollection().getName().equals("Flight")) {
|
||||
results = getFlights((Integer) parentEntity.getProperty(key).getValue(), planitems);
|
||||
} else if (navigation.getTypeFilterOnCollection().getName().equals("Event")) {
|
||||
results = getEvents((Integer) parentEntity.getProperty(key).getValue(), planitems);
|
||||
} else {
|
||||
throw new RuntimeException("unknown relation");
|
||||
}
|
||||
} else if (type.getName().equals("Trip") && linkName.equals("Photos")) {
|
||||
results = getTripPhotos((Integer) parentEntity.getProperty(key).getValue());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public Entity getNavigableEntity(Entity parentEntity, UriResourceNavigation navigation)
|
||||
throws ODataApplicationException {
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(parentEntity.getType()));
|
||||
|
||||
String key = type.getKeyPredicateNames().get(0);
|
||||
String linkName = navigation.getProperty().getName();
|
||||
|
||||
EntitySet results = null;
|
||||
if (navigation.getProperty().isCollection()) {
|
||||
results = getNavigableEntitySet(parentEntity, navigation);
|
||||
return this.getEntity(results, navigation.getKeyPredicates());
|
||||
}
|
||||
if (type.getName().equals("Person") && linkName.equals("Photo")) {
|
||||
return getPhoto((String) parentEntity.getProperty(key).getValue());
|
||||
} else if (type.getName().equals("Flight") && linkName.equals("From")) {
|
||||
return getFlightFrom((Integer) parentEntity.getProperty(key).getValue());
|
||||
} else if (type.getName().equals("Flight") && linkName.equals("To")) {
|
||||
return getFlightTo((Integer) parentEntity.getProperty(key).getValue());
|
||||
} else if (type.getName().equals("Flight") && linkName.equals("Airline")) {
|
||||
return getFlightAirline((Integer) parentEntity.getProperty(key).getValue());
|
||||
} else {
|
||||
throw new RuntimeException("unknown relation");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeNavigationLink(String navigationProperty, Entity parentEntity,
|
||||
Entity deleteEntity) {
|
||||
boolean removed = false;
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(parentEntity.getType()));
|
||||
String key = type.getKeyPredicateNames().get(0);
|
||||
|
||||
if (type.getName().equals("Person") && navigationProperty.equals("Friends")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
ArrayList<String> friends = (ArrayList<String>) map.get("Friends");
|
||||
if (friends != null) {
|
||||
friends.remove(deleteEntity.getProperty(key).getValue());
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
} else if (type.getName().equals("Person") && navigationProperty.equals("Trips")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
ArrayList<Integer> trips = (ArrayList<Integer>) map.get("Trips");
|
||||
if (trips != null) {
|
||||
trips.remove(deleteEntity.getProperty(key).getValue());
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
} else if (type.getName().equals("Person") && navigationProperty.equals("Photo")) {
|
||||
Map map = this.peopleLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.remove("Photo");
|
||||
removed = true;
|
||||
}
|
||||
} else if (type.getName().equals("Trip") && navigationProperty.equals("PlanItems")) {
|
||||
Map map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
if (deleteEntity.getType().equals("Flight")) {
|
||||
ArrayList<Integer> flights = (ArrayList<Integer>) map.get("Flights");
|
||||
if (flights != null) {
|
||||
flights.remove(deleteEntity.getProperty(key).getValue());
|
||||
removed = true;
|
||||
}
|
||||
} else {
|
||||
ArrayList<Integer> events = (ArrayList<Integer>) map.get("Events");
|
||||
if (events != null) {
|
||||
events.remove(deleteEntity.getProperty(key).getValue());
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type.getName().equals("Trip") && navigationProperty.equals("Photo")) {
|
||||
Map map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
ArrayList<Integer> photos = (ArrayList<Integer>) map.get("Photos");
|
||||
if (photos != null) {
|
||||
photos.remove(deleteEntity.getProperty(key).getValue());
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("From")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.remove("From");
|
||||
removed = true;
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("To")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.remove("To");
|
||||
removed = true;
|
||||
}
|
||||
} else if (type.getName().equals("Flight") && navigationProperty.equals("Airline")) {
|
||||
Map map = this.flightLinks.get(parentEntity.getProperty(key).getValue());
|
||||
if (map != null) {
|
||||
map.remove("Airline");
|
||||
removed = true;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("unknown relation");
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
// note these are not tied to entities for simplicity sake
|
||||
public boolean updateMedia(Entity entity, InputStream mediaContent)
|
||||
throws ODataApplicationException {
|
||||
checkForMedia(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
// note these are not tied to entities for simplicity sake
|
||||
public InputStream readMedia(Entity entity) throws ODataApplicationException {
|
||||
checkForMedia(entity);
|
||||
try {
|
||||
return new FileInputStream(new File("src/test/resources/OlingoOrangeTM.png"));
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new ODataApplicationException("image not found", 500, Locale.getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
// note these are not tied to entities for simplicity sake
|
||||
public boolean deleteMedia(Entity entity) throws ODataApplicationException {
|
||||
checkForMedia(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkForMedia(Entity entity) throws ODataApplicationException {
|
||||
EdmEntityType type = this.metadata.getEdm().getEntityType(
|
||||
new FullQualifiedName(entity.getType()));
|
||||
if (!type.hasStream()) {
|
||||
throw new ODataApplicationException("No Media proeprty on the entity", 500,
|
||||
Locale.getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteStream(Entity entity, EdmProperty property) {
|
||||
// should remove stream links
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean updateStream(Entity entity, EdmProperty property, InputStream streamContent) {
|
||||
// should add stream links
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
* 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.example;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmAction;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmSingleton;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ODataTranslatedException;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
import org.apache.olingo.server.core.ServiceHandler;
|
||||
import org.apache.olingo.server.core.requests.ActionRequest;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.requests.FunctionRequest;
|
||||
import org.apache.olingo.server.core.requests.MediaRequest;
|
||||
import org.apache.olingo.server.core.requests.MetadataRequest;
|
||||
import org.apache.olingo.server.core.requests.ServiceDocumentRequest;
|
||||
import org.apache.olingo.server.core.responses.CountResponse;
|
||||
import org.apache.olingo.server.core.responses.EntityResponse;
|
||||
import org.apache.olingo.server.core.responses.EntitySetResponse;
|
||||
import org.apache.olingo.server.core.responses.MetadataResponse;
|
||||
import org.apache.olingo.server.core.responses.NoContentResponse;
|
||||
import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
|
||||
import org.apache.olingo.server.core.responses.PropertyResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceDocumentResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceResponse;
|
||||
import org.apache.olingo.server.core.responses.ServiceResponseVisior;
|
||||
import org.apache.olingo.server.core.responses.StreamResponse;
|
||||
|
||||
public class TripPinHandler implements ServiceHandler {
|
||||
private OData odata;
|
||||
private ServiceMetadata serviceMetadata;
|
||||
private final TripPinDataModel dataModel;
|
||||
|
||||
public TripPinHandler(TripPinDataModel datamodel) {
|
||||
this.dataModel = datamodel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(OData odata, ServiceMetadata serviceMetadata) {
|
||||
this.odata = odata;
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMetadata(MetadataRequest request, MetadataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
response.writeMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readServiceDocument(ServiceDocumentRequest request, ServiceDocumentResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
response.writeServiceDocument(request.getODataRequest().getRawBaseUri());
|
||||
}
|
||||
|
||||
static class EntityDetails {
|
||||
EntitySet entitySet = null;
|
||||
Entity entity = null;
|
||||
EdmEntityType entityType;
|
||||
String navigationProperty;
|
||||
Entity parentEntity = null;
|
||||
}
|
||||
|
||||
private EntityDetails process(final DataRequest request) throws ODataApplicationException {
|
||||
EntitySet entitySet = null;
|
||||
Entity entity = null;
|
||||
EdmEntityType entityType;
|
||||
Entity parentEntity = null;
|
||||
|
||||
if (request.isSingleton()) {
|
||||
EdmSingleton singleton = request.getUriResourceSingleton().getSingleton();
|
||||
entityType = singleton.getEntityType();
|
||||
if (singleton.getName().equals("Me")) {
|
||||
entitySet = this.dataModel.getEntitySet("People");
|
||||
entity = entitySet.getEntities().get(0);
|
||||
}
|
||||
} else {
|
||||
final EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
entityType = edmEntitySet.getEntityType();
|
||||
List<UriParameter> keys = request.getKeyPredicates();
|
||||
|
||||
// TODO: This example so far ignores all system options; but a real
|
||||
// service should not
|
||||
if (keys != null && !keys.isEmpty()) {
|
||||
entity = this.dataModel.getEntity(edmEntitySet.getName(), keys);
|
||||
} else {
|
||||
int skip = 0;
|
||||
if (request.getUriInfo().getSkipTokenOption() != null) {
|
||||
skip = Integer.parseInt(request.getUriInfo().getSkipTokenOption().getValue());
|
||||
}
|
||||
int pageSize = getPageSize(request);
|
||||
entitySet = this.dataModel.getEntitySet(edmEntitySet.getName(), skip, pageSize);
|
||||
if (entitySet.getEntities().size() == pageSize) {
|
||||
try {
|
||||
entitySet.setNext(new URI(request.getODataRequest().getRawRequestUri() + "?$skiptoken="
|
||||
+ (skip + pageSize)));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EntityDetails details = new EntityDetails();
|
||||
|
||||
if (!request.getNavigations().isEmpty() && entity != null) {
|
||||
UriResourceNavigation lastNavigation = request.getNavigations().getLast();
|
||||
for (UriResourceNavigation nav : request.getNavigations()) {
|
||||
entityType = nav.getProperty().getType();
|
||||
if (nav.isCollection()) {
|
||||
entitySet = this.dataModel.getNavigableEntitySet(entity, nav);
|
||||
} else {
|
||||
parentEntity = entity;
|
||||
entity = this.dataModel.getNavigableEntity(parentEntity, nav);
|
||||
}
|
||||
}
|
||||
details.navigationProperty = lastNavigation.getProperty().getName();
|
||||
}
|
||||
|
||||
details.entity = entity;
|
||||
details.entitySet = entitySet;
|
||||
details.entityType = entityType;
|
||||
details.parentEntity = parentEntity;
|
||||
return details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void read(final DataRequest request, final T response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
final EntityDetails details = process(request);
|
||||
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(CountResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
response.writeCount(details.entitySet.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PrimitiveValueResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
EdmProperty edmProperty = request.getUriResourceProperty().getProperty();
|
||||
Property property = details.entity.getProperty(edmProperty.getName());
|
||||
response.write(property.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
EdmProperty edmProperty = request.getUriResourceProperty().getProperty();
|
||||
Property property = details.entity.getProperty(edmProperty.getName());
|
||||
response.writeProperty(edmProperty.getType(), property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StreamResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
// stream property response
|
||||
response.writeStreamResponse(new ByteArrayInputStream("dummy".getBytes()),
|
||||
ContentType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EntitySetResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
if (request.getPreference("odata.maxpagesize") != null) {
|
||||
response.writeHeader("Preference-Applied", request.getPreference("odata.maxpagesize"));
|
||||
}
|
||||
if (details.entity == null && !request.getNavigations().isEmpty()) {
|
||||
response.writeReadEntitySet(details.entityType, new EntitySetImpl());
|
||||
} else {
|
||||
response.writeReadEntitySet(details.entityType, details.entitySet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
if (details.entity == null && !request.getNavigations().isEmpty()) {
|
||||
response.writeNoContent(true);
|
||||
} else {
|
||||
response.writeReadEntity(details.entityType, details.entity);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getPageSize(DataRequest request) {
|
||||
String size = request.getPreference("odata.maxpagesize");
|
||||
if (size == null) {
|
||||
return 8;
|
||||
}
|
||||
return Integer.parseInt(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createEntity(DataRequest request, Entity entity, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
|
||||
String location = buildLocation(entity, edmEntitySet.getName(), edmEntitySet.getEntityType());
|
||||
Entity created = this.dataModel.createEntity(edmEntitySet.getName(), entity, location);
|
||||
|
||||
try {
|
||||
// create references, they come in "@odata.bind" value
|
||||
List<Link> bindings = entity.getNavigationBindings();
|
||||
if (bindings != null & !bindings.isEmpty()) {
|
||||
for (Link link : bindings) {
|
||||
String navigationProperty = link.getTitle();
|
||||
String uri = link.getBindingLink();
|
||||
if (uri != null) {
|
||||
DataRequest bindingRequest = request.parseLink(new URI(uri));
|
||||
|
||||
Entity reference = this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
|
||||
bindingRequest.getKeyPredicates());
|
||||
|
||||
this.dataModel.addNavigationLink(navigationProperty, created, reference);
|
||||
|
||||
} else {
|
||||
for (String binding : link.getBindingLinks()) {
|
||||
DataRequest bindingRequest = request.parseLink(new URI(binding));
|
||||
|
||||
Entity reference = this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
|
||||
bindingRequest.getKeyPredicates());
|
||||
|
||||
this.dataModel.addNavigationLink(navigationProperty, created, reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
|
||||
}
|
||||
|
||||
response.writeCreatedEntity(edmEntitySet.getEntityType(), created, location);
|
||||
}
|
||||
|
||||
static String buildLocation(Entity entity, String name, EdmEntityType type) {
|
||||
String location = "/" + name + "(";
|
||||
int i = 0;
|
||||
boolean usename = type.getKeyPredicateNames().size() > 1;
|
||||
|
||||
for (String key : type.getKeyPredicateNames()) {
|
||||
if (i > 0) {
|
||||
location += ",";
|
||||
}
|
||||
i++;
|
||||
if (usename) {
|
||||
location += (key + "=");
|
||||
}
|
||||
if (entity.getProperty(key).getType().equals("Edm.String")) {
|
||||
location = location + "'" + entity.getProperty(key).getValue().toString() + "'";
|
||||
} else {
|
||||
location = location + entity.getProperty(key).getValue().toString();
|
||||
}
|
||||
}
|
||||
location += ")";
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntity(DataRequest request, Entity entity, boolean merge, String entityETag,
|
||||
EntityResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteEntity(DataRequest request, String eTag, EntityResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
Entity entity = this.dataModel.getEntity(edmEntitySet.getName(), request.getKeyPredicates());
|
||||
if (entity == null) {
|
||||
response.writeNotFound(true);
|
||||
return;
|
||||
}
|
||||
String key = edmEntitySet.getEntityType().getKeyPredicateNames().get(0);
|
||||
boolean removed = this.dataModel.deleteEntity(edmEntitySet.getName(), eTag, key, entity
|
||||
.getProperty(key).getValue());
|
||||
|
||||
if (removed) {
|
||||
response.writeDeletedEntityOrReference();
|
||||
} else {
|
||||
response.writeNotFound(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProperty(DataRequest request, final Property property, boolean merge,
|
||||
String entityETag, PropertyResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
|
||||
EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
Entity entity = this.dataModel.getEntity(edmEntitySet.getName(), request.getKeyPredicates());
|
||||
if (entity == null) {
|
||||
response.writeNotFound(true);
|
||||
return;
|
||||
}
|
||||
|
||||
String key = edmEntitySet.getEntityType().getKeyPredicateNames().get(0);
|
||||
boolean replaced = this.dataModel.updateProperty(edmEntitySet.getName(), entityETag, key,
|
||||
entity.getProperty(key).getValue(), property);
|
||||
|
||||
if (replaced) {
|
||||
if (property.getValue() == null) {
|
||||
response.writePropertyDeleted();
|
||||
} else {
|
||||
response.writePropertyUpdated();
|
||||
}
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void invoke(FunctionRequest request, HttpMethod method,
|
||||
T response) throws ODataTranslatedException, ODataApplicationException {
|
||||
EdmFunction function = request.getFunction();
|
||||
if (function.getName().equals("GetNearestAirport")) {
|
||||
|
||||
final EdmEntityType type = serviceMetadata.getEdm().getEntityContainer(null)
|
||||
.getEntitySet("Airports").getEntityType();
|
||||
|
||||
EntitySet es = this.dataModel.getEntitySet("Airports");
|
||||
int i = new Random().nextInt(es.getEntities().size());
|
||||
final Entity entity = es.getEntities().get(i);
|
||||
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(EntityResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeReadEntity(type, entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ServiceResponse> void invoke(ActionRequest request, String eTag, T response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
EdmAction action = request.getAction();
|
||||
if (action.getName().equals("ResetDataSource")) {
|
||||
try {
|
||||
this.dataModel.loadData();
|
||||
response.accepts(new ServiceResponseVisior() {
|
||||
@Override
|
||||
public void visit(NoContentResponse response) throws ODataTranslatedException,
|
||||
ODataApplicationException {
|
||||
response.writeNoContent();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMediaStream(MediaRequest request, StreamResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
final EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
List<UriParameter> keys = request.getKeyPredicates();
|
||||
Entity entity = this.dataModel.getEntity(edmEntitySet.getName(), keys);
|
||||
|
||||
InputStream contents = this.dataModel.readMedia(entity);
|
||||
response.writeStreamResponse(contents, request.getResponseContentType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upsertMediaStream(MediaRequest request, String entityETag, InputStream mediaContent,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
final EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
List<UriParameter> keys = request.getKeyPredicates();
|
||||
Entity entity = this.dataModel.getEntity(edmEntitySet.getName(), keys);
|
||||
|
||||
if (mediaContent == null) {
|
||||
boolean deleted = this.dataModel.deleteMedia(entity);
|
||||
if (deleted) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeNotFound();
|
||||
}
|
||||
} else {
|
||||
boolean updated = this.dataModel.updateMedia(entity, mediaContent);
|
||||
if (updated) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upsertStreamProperty(DataRequest request, String entityETag, InputStream streamContent,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
final EdmEntitySet edmEntitySet = request.getEntitySet();
|
||||
List<UriParameter> keys = request.getKeyPredicates();
|
||||
Entity entity = this.dataModel.getEntity(edmEntitySet.getName(), keys);
|
||||
|
||||
EdmProperty property = request.getUriResourceProperty().getProperty();
|
||||
|
||||
if (streamContent == null) {
|
||||
boolean deleted = this.dataModel.deleteStream(entity, property);
|
||||
if (deleted) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeNotFound();
|
||||
}
|
||||
} else {
|
||||
boolean updated = this.dataModel.updateStream(entity, property, streamContent);
|
||||
if (updated) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReference(DataRequest request, String entityETag, List<URI> references,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
|
||||
final EntityDetails details = process(request);
|
||||
|
||||
for (URI reference : references) {
|
||||
DataRequest bindingRequest = request.parseLink(reference);
|
||||
Entity linkEntity = this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
|
||||
bindingRequest.getKeyPredicates());
|
||||
this.dataModel.addNavigationLink(details.navigationProperty, details.entity, linkEntity);
|
||||
}
|
||||
response.writeNoContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReference(DataRequest request, String entityETag, URI updateId,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
// this single valued navigation.
|
||||
final EntityDetails details = process(request);
|
||||
DataRequest updateRequest = request.parseLink(updateId);
|
||||
Entity updateEntity = this.dataModel.getEntity(updateRequest.getEntitySet().getName(),
|
||||
updateRequest.getKeyPredicates());
|
||||
boolean updated = false;
|
||||
if (updateEntity != null) {
|
||||
updated = this.dataModel.updateNavigationLink(details.navigationProperty,
|
||||
details.parentEntity, updateEntity);
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteReference(DataRequest request, URI deleteId, String entityETag,
|
||||
NoContentResponse response) throws ODataTranslatedException, ODataApplicationException {
|
||||
boolean removed = false;
|
||||
if (deleteId != null) {
|
||||
final EntityDetails details = process(request);
|
||||
DataRequest deleteRequest = request.parseLink(deleteId);
|
||||
Entity deleteEntity = this.dataModel.getEntity(deleteRequest.getEntitySet().getName(),
|
||||
deleteRequest.getKeyPredicates());
|
||||
if (deleteEntity != null) {
|
||||
removed = this.dataModel.removeNavigationLink(details.navigationProperty, details.entity,
|
||||
deleteEntity);
|
||||
}
|
||||
} else {
|
||||
// this single valued navigation.
|
||||
final EntityDetails details = process(request);
|
||||
removed = this.dataModel.removeNavigationLink(details.navigationProperty,
|
||||
details.parentEntity, details.entity);
|
||||
}
|
||||
if (removed) {
|
||||
response.writeNoContent();
|
||||
} else {
|
||||
response.writeServerError(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void anyUnsupported(ODataRequest request, ODataResponse response)
|
||||
throws ODataTranslatedException, ODataApplicationException {
|
||||
response.setStatusCode(500);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startTransaction() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit(String txnId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(String txnId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void crossJoin(DataRequest dataRequest, List<String> entitySetNames, ODataResponse response) {
|
||||
response.setStatusCode(200);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,756 @@
|
|||
/*
|
||||
* 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.example;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.olingo.commons.core.Encoder;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* Please note that NONE of the system query options are developed in the sample
|
||||
* service like $filter, $orderby etc. So using those options will be ignored
|
||||
* right now. These tests designed to test the framework, all options are responsibilities
|
||||
* of service developer.
|
||||
*/
|
||||
public class TripPinServiceTest {
|
||||
private static Server server = new Server();
|
||||
private static String baseURL;
|
||||
private static HttpClient http = new HttpClient();
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeTest() throws Exception {
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/trippin");
|
||||
context.addServlet(new ServletHolder(new TripPinServlet()), "/*");
|
||||
server.setHandler(context);
|
||||
server.start();
|
||||
int port = connector.getLocalPort();
|
||||
http.start();
|
||||
baseURL = "http://localhost:"+port+"/trippin";
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterTest() throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntitySet() throws Exception {
|
||||
ContentResponse response = http.newRequest(baseURL + "/People")
|
||||
.header("Content-Type", "application/json;odata.metadata=minimal")
|
||||
.method(HttpMethod.GET)
|
||||
.send();
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
|
||||
assertEquals("$metadata#People", node.get("@odata.context").asText());
|
||||
assertEquals(baseURL+"/People?$skiptoken=8", node.get("@odata.nextLink").asText());
|
||||
|
||||
JsonNode person = ((ArrayNode)node.get("value")).get(0);
|
||||
assertEquals("russellwhyte", person.get("UserName").asText());
|
||||
}
|
||||
|
||||
private JsonNode getJSONNode(ContentResponse response) throws IOException,
|
||||
JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode node = objectMapper.readTree(response.getContent());
|
||||
return node;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadEntitySetWithPaging() throws Exception {
|
||||
ContentResponse response = http.newRequest(baseURL + "/People")
|
||||
.header("Prefer", "odata.maxpagesize=10").send();
|
||||
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People", node.get("@odata.context").asText());
|
||||
assertEquals(baseURL+"/People?$skiptoken=10", node.get("@odata.nextLink").asText());
|
||||
|
||||
JsonNode person = ((ArrayNode)node.get("value")).get(0);
|
||||
assertEquals("russellwhyte", person.get("UserName").asText());
|
||||
|
||||
assertNotNull(response.getHeaders().get("Preference-Applied"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadEntityWithKey() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines('AA')");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#Airlines/$entity", node.get("@odata.context").asText());
|
||||
assertEquals("American Airlines", node.get("Name").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadEntityWithNonExistingKey() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines('OO')");
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead$Count() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines/$count");
|
||||
assertEquals(200, response.getStatus());
|
||||
assertEquals("15", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadPrimitiveProperty() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines('AA')/Name");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#Airlines('AA')/Name", node.get("@odata.context").asText());
|
||||
assertEquals("American Airlines", node.get("value").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNonExistentProperty() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines('AA')/Unknown");
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadPrimitiveArrayProperty() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/People('russellwhyte')/Emails");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Emails", node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("Russell@example.com", ((ArrayNode)node.get("value")).get(0).asText());
|
||||
assertEquals("Russell@contoso.com", ((ArrayNode)node.get("value")).get(1).asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadPrimitivePropertyValue() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airlines('AA')/Name/$value");
|
||||
assertEquals(200, response.getStatus());
|
||||
assertEquals("American Airlines", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test @Ignore
|
||||
// TODO: Support geometry types to make this run
|
||||
public void testReadComplexProperty() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Airports('KSFO')/Location");
|
||||
fail("support geometry type");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadComplexArrayProperty() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/People('russellwhyte')/AddressInfo");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/AddressInfo", node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("187 Suffolk Ln.", ((ArrayNode)node.get("value")).get(0).get("Address").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadMedia() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Photos(1)/$value");
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMedia() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Photos(1)/$value";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content("bytecontents"), "image/jpeg")
|
||||
.method(HttpMethod.PUT)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMedia() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Photos(1)/$value";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content("bytecontents"), "image/jpeg")
|
||||
.method(HttpMethod.DELETE)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateStream() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Airlines('AA')/Picture";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content("bytecontents"), "image/jpeg")
|
||||
.method(HttpMethod.POST)
|
||||
.send();
|
||||
// method not allowed
|
||||
assertEquals(405, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateStream2() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Airlines('AA')/Picture";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content("bytecontents"), "image/jpeg")
|
||||
.method(HttpMethod.PUT)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteStream() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Airlines('AA')/Picture";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.DELETE)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadStream() throws Exception {
|
||||
// treating update and create as same for now, as there is details about
|
||||
// how entity payload and media payload can be sent at same time in request's body
|
||||
String editUrl = baseURL + "/Airlines('AA')/Picture";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.GET)
|
||||
.send();
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLambdaAny() throws Exception {
|
||||
// this is just testing to see the labba expresions are going through the
|
||||
// framework, none of the system options are not implemented in example service
|
||||
String query = "Friends/any(d:d/UserName eq 'foo')";
|
||||
ContentResponse response = http.newRequest(baseURL + "/People?$filter="+Encoder.encode(query))
|
||||
.method(HttpMethod.GET)
|
||||
.send();
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleton() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/Me");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#Me", node.get("@odata.context").asText());
|
||||
assertEquals("russellwhyte", node.get("UserName").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectOption() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/People('russellwhyte')?$select=FirstName,LastName");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People(FirstName,LastName)/$entity", node.get("@odata.context").asText());
|
||||
assertEquals("Russell", node.get("FirstName").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionImportWithNoResponse() throws Exception {
|
||||
ContentResponse response = http.POST(baseURL + "/ResetDataSource").send();
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionImport() throws Exception {
|
||||
//TODO: fails because of lack of geometery support
|
||||
ContentResponse response = http.GET(baseURL + "/GetNearestAirport(lat=23.0,lon=34.0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadReferences() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/People('russelwhyte')/$ref");
|
||||
assertEquals(405, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadReferences() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL + "/People('russellwhyte')/Friends/$ref");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#Collection($ref)", node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("/People('scottketchum')", ((ArrayNode)node.get("value")).get(0).get("@odata.id").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCollectionReferences() throws Exception {
|
||||
//GET
|
||||
ContentResponse response = http.GET(baseURL + "/People('kristakemp')/Friends/$ref");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("/People('genevievereeves')", ((ArrayNode)node.get("value")).get(0).get("@odata.id").asText());
|
||||
assertNull(((ArrayNode)node.get("value")).get(1));
|
||||
|
||||
//ADD
|
||||
String payload = "{\n" +
|
||||
" \"@odata.context\": \""+baseURL+"/$metadata#Collection($ref)\",\n" +
|
||||
" \"value\": [\n" +
|
||||
" { \"@odata.id\": \"People('russellwhyte')\" },\n" +
|
||||
" { \"@odata.id\": \"People('scottketchum')\" } \n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
response = http.POST(baseURL + "/People('kristakemp')/Friends/$ref")
|
||||
.content(content(payload), "application/json")
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
//GET
|
||||
response = http.GET(baseURL + "/People('kristakemp')/Friends/$ref");
|
||||
assertEquals(200, response.getStatus());
|
||||
node = getJSONNode(response);
|
||||
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("/People('genevievereeves')", ((ArrayNode)node.get("value")).get(0).get("@odata.id").asText());
|
||||
assertEquals("/People('russellwhyte')", ((ArrayNode)node.get("value")).get(1).get("@odata.id").asText());
|
||||
assertEquals("/People('scottketchum')", ((ArrayNode)node.get("value")).get(2).get("@odata.id").asText());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEntityId() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL+"/$entity?$id="+baseURL + "/People('kristakemp')");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People/$entity", node.get("@odata.context").asText());
|
||||
assertEquals("kristakemp", node.get("UserName").asText());
|
||||
|
||||
// using relative URL
|
||||
response = http.GET(baseURL+"/$entity?$id="+"People('kristakemp')");
|
||||
assertEquals(200, response.getStatus());
|
||||
node = getJSONNode(response);
|
||||
assertEquals("$metadata#People/$entity", node.get("@odata.context").asText());
|
||||
assertEquals("kristakemp", node.get("UserName").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateReadDeleteEntity() throws Exception {
|
||||
String payload = "{\n" +
|
||||
" \"UserName\":\"olingodude\",\n" +
|
||||
" \"FirstName\":\"Olingo\",\n" +
|
||||
" \"LastName\":\"Apache\",\n" +
|
||||
" \"Emails\":[\n" +
|
||||
" \"olingo@apache.org\"\n" +
|
||||
" ],\n" +
|
||||
" \"AddressInfo\":[\n" +
|
||||
" {\n" +
|
||||
" \"Address\":\"100 apache Ln.\",\n" +
|
||||
" \"City\":{\n" +
|
||||
" \"CountryRegion\":\"United States\",\n" +
|
||||
" \"Name\":\"Boise\",\n" +
|
||||
" \"Region\":\"ID\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"Gender\":\"0\",\n" +
|
||||
" \"Concurrency\":635585295719432047\n" +
|
||||
"}";
|
||||
ContentResponse response = http.POST(baseURL + "/People")
|
||||
.content(content(payload), "application/json")
|
||||
.header("Prefer", "return=minimal")
|
||||
.send();
|
||||
// the below woud be 204, if minimal was not supplied
|
||||
assertEquals(204, response.getStatus());
|
||||
assertEquals("/People('olingodude')", response.getHeaders().get("Location"));
|
||||
assertEquals("return=minimal", response.getHeaders().get("Preference-Applied"));
|
||||
|
||||
String location = baseURL+response.getHeaders().get("Location");
|
||||
response = http.GET(location);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
response = http.newRequest(location).method(HttpMethod.DELETE).send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(location);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateEntityWithLinkToRelatedEntities() throws Exception {
|
||||
String payload = "{\n" +
|
||||
" \"UserName\":\"olingo\",\n" +
|
||||
" \"FirstName\":\"Olingo\",\n" +
|
||||
" \"LastName\":\"Apache\",\n" +
|
||||
" \"Emails\":[\n" +
|
||||
" \"olingo@apache.org\"\n" +
|
||||
" ],\n" +
|
||||
" \"AddressInfo\":[\n" +
|
||||
" {\n" +
|
||||
" \"Address\":\"100 apache Ln.\",\n" +
|
||||
" \"City\":{\n" +
|
||||
" \"CountryRegion\":\"United States\",\n" +
|
||||
" \"Name\":\"Boise\",\n" +
|
||||
" \"Region\":\"ID\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"Gender\":\"0\",\n" +
|
||||
" \"Concurrency\":635585295719432047,\n" +
|
||||
"\"Friends@odata.bind\":[\"" +
|
||||
baseURL+"/People('russellwhyte')\",\""+
|
||||
baseURL+"/People('scottketchum')\""+
|
||||
"]"+
|
||||
"}";
|
||||
ContentResponse response = http.POST(baseURL + "/People")
|
||||
.content(content(payload), "application/json")
|
||||
.header("Prefer", "return=minimal")
|
||||
.send();
|
||||
// the below woud be 204, if minimal was not supplied
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(baseURL+"/People('olingo')/Friends");
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People", node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("scottketchum", ((ArrayNode)node.get("value")).get(1).get("UserName").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatePrimitiveProperty() throws Exception {
|
||||
String payload = "{"
|
||||
+ " \"value\":\"Pilar Ackerman\""
|
||||
+ "}";
|
||||
|
||||
String editUrl = baseURL + "/People('russellwhyte')/FirstName";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content(payload), "application/json")
|
||||
.method(HttpMethod.PUT)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/FirstName", node.get("@odata.context").asText());
|
||||
assertEquals("Pilar Ackerman", node.get("value").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatePrimitiveArrayProperty() throws Exception {
|
||||
String payload = "{"
|
||||
+ " \"value\": [\n" +
|
||||
" \"olingo@apache.com\"\n" +
|
||||
" ]"
|
||||
+ "}";
|
||||
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Emails";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.content(content(payload), "application/json")
|
||||
.method(HttpMethod.PUT)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Emails", node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("olingo@apache.com", ((ArrayNode)node.get("value")).get(0).asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteProperty() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/FirstName";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("Russell", node.get("value").asText());
|
||||
|
||||
response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.DELETE)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityCollection() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Friends";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People", node.get("@odata.context").asText());
|
||||
|
||||
JsonNode person = ((ArrayNode)node.get("value")).get(0);
|
||||
assertEquals("scottketchum", person.get("UserName").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityCollection2() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Friends('scottketchum')/Trips";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Friends('scottketchum')/Trips",
|
||||
node.get("@odata.context").asText());
|
||||
assertTrue(node.get("value").isArray());
|
||||
assertEquals("1001", ((ArrayNode)node.get("value")).get(0).get("TripId").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntity() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Trips(1003)";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Trips/$entity",
|
||||
node.get("@odata.context").asText());
|
||||
assertEquals("f94e9116-8bdd-4dac-ab61-08438d0d9a71", node.get("ShareId").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityNotExisting() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Trips(9999)";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntitySetNotExisting() throws Exception {
|
||||
String editUrl = baseURL + "/People('jhondoe')/Trips";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('jhondoe')/Trips",
|
||||
node.get("@odata.context").asText());
|
||||
assertEquals(0, ((ArrayNode)node.get("value")).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadNavigationProperty() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Unknown";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityProperty() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Trips(1003)/PlanItems(5)/ConfirmationCode";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Trips(1003)/PlanItems(5)/ConfirmationCode",
|
||||
node.get("@odata.context").asText());
|
||||
|
||||
assertEquals("JH58494", node.get("value").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityMultipleDerivedTypes() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Trips(1003)/PlanItems";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Trips(1003)/PlanItems",
|
||||
node.get("@odata.context").asText());
|
||||
|
||||
assertEquals("#Microsoft.OData.SampleService.Models.TripPin.Flight",
|
||||
((ArrayNode) node.get("value")).get(0).get("@odata.type").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityCoolectionDerivedFilter() throws Exception {
|
||||
String editUrl = baseURL
|
||||
+ "/People('russellwhyte')/Trips(1003)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Event";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Trips(1003)/PlanItems/"
|
||||
+ "Microsoft.OData.SampleService.Models.TripPin.Event",
|
||||
node.get("@odata.context").asText());
|
||||
|
||||
assertEquals("#Microsoft.OData.SampleService.Models.TripPin.Event",
|
||||
((ArrayNode) node.get("value")).get(0).get("@odata.type").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNavigationPropertyEntityDerivedFilter() throws Exception {
|
||||
String editUrl = baseURL+ "/People('russellwhyte')/Trips(1003)/PlanItems(56)/"
|
||||
+ "Microsoft.OData.SampleService.Models.TripPin.Event";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("$metadata#People('russellwhyte')/Trips(1003)/PlanItems/"
|
||||
+ "Microsoft.OData.SampleService.Models.TripPin.Event/$entity",
|
||||
node.get("@odata.context").asText());
|
||||
|
||||
assertEquals("#Microsoft.OData.SampleService.Models.TripPin.Event", node.get("@odata.type").asText());
|
||||
assertEquals("56", node.get("PlanItemId").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateReference() throws Exception {
|
||||
ContentResponse response = http.GET(baseURL+"/People('ronaldmundy')/Photo/$ref");
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("/Photos(12)", node.get("@odata.id").asText());
|
||||
|
||||
String msg = "{\n" +
|
||||
"\"@odata.id\": \"/Photos(11)\"\n" +
|
||||
"}";
|
||||
String editUrl = baseURL + "/People('ronaldmundy')/Photo/$ref";
|
||||
response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.PUT)
|
||||
.content(content(msg))
|
||||
.header("Content-Type", "application/json;odata.metadata=minimal")
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(baseURL+"/People('ronaldmundy')/Photo/$ref");
|
||||
assertEquals(200, response.getStatus());
|
||||
node = getJSONNode(response);
|
||||
assertEquals("/Photos(11)", node.get("@odata.id").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDelete2ReferenceCollection() throws Exception {
|
||||
// add
|
||||
String msg = "{\n" +
|
||||
"\"@odata.id\": \"/People('russellwhyte')\"\n" +
|
||||
"}";
|
||||
String editUrl = baseURL + "/People('vincentcalabrese')/Friends/$ref";
|
||||
ContentResponse response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.POST)
|
||||
.content(content(msg))
|
||||
.header("Content-Type", "application/json;odata.metadata=minimal")
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
// get
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
JsonNode node = getJSONNode(response);
|
||||
assertEquals("/People('russellwhyte')",
|
||||
((ArrayNode) node.get("value")).get(2).get("@odata.id").asText());
|
||||
|
||||
//delete
|
||||
response = http.newRequest(editUrl+"?$id="+baseURL+"/People('russellwhyte')")
|
||||
.method(HttpMethod.DELETE)
|
||||
.content(content(msg))
|
||||
.header("Content-Type", "application/json;odata.metadata=minimal")
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
// get
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
node = getJSONNode(response);
|
||||
assertNull("/People('russellwhyte')", ((ArrayNode) node.get("value")).get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteReference() throws Exception {
|
||||
String editUrl = baseURL + "/People('russellwhyte')/Photo/$ref";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
response = http.newRequest(editUrl)
|
||||
.method(HttpMethod.DELETE)
|
||||
.send();
|
||||
assertEquals(204, response.getStatus());
|
||||
|
||||
response = http.GET(editUrl);
|
||||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrossJoin() throws Exception {
|
||||
String editUrl = baseURL + "/$crossjoin(People,Airlines)";
|
||||
ContentResponse response = http.GET(editUrl);
|
||||
assertEquals(200, response.getStatus());
|
||||
}
|
||||
|
||||
public static ContentProvider content(final String msg) {
|
||||
return new ContentProvider() {
|
||||
boolean hasNext = true;
|
||||
|
||||
@Override
|
||||
public Iterator<ByteBuffer> iterator() {
|
||||
return new Iterator<ByteBuffer>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
@Override
|
||||
public ByteBuffer next() {
|
||||
hasNext = false;
|
||||
return ByteBuffer.wrap(msg.getBytes());
|
||||
}
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public long getLength() {
|
||||
return msg.length();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.example;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.provider.EdmProvider;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.core.MetadataParser;
|
||||
import org.apache.olingo.server.core.OData4Impl;
|
||||
|
||||
public class TripPinServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 2663595419366214401L;
|
||||
private TripPinDataModel dataModel;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig config) throws ServletException {
|
||||
super.init(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
OData odata = OData4Impl.newInstance();
|
||||
MetadataParser parser = new MetadataParser();
|
||||
EdmProvider edmProvider = null;
|
||||
|
||||
try {
|
||||
edmProvider = parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
|
||||
} catch (XMLStreamException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
ServiceMetadata metadata = odata.createServiceMetadata(edmProvider, Collections.EMPTY_LIST);
|
||||
|
||||
ODataHttpHandler handler = odata.createHandler(metadata);
|
||||
|
||||
if (this.dataModel == null) {
|
||||
try {
|
||||
this.dataModel = new TripPinDataModel(metadata);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to load data for TripPin Service");
|
||||
}
|
||||
}
|
||||
|
||||
handler.register(new TripPinHandler(this.dataModel));
|
||||
handler.process(request, response);
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"AirlineCode":"AA",
|
||||
"Name":"American Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"FM",
|
||||
"Name":"Shanghai Airline"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"MU",
|
||||
"Name":"China Eastern Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"AF",
|
||||
"Name":"Air France"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"AZ",
|
||||
"Name":"Alitalia"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"AC",
|
||||
"Name":"Air Canada"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"OS",
|
||||
"Name":"Austrian Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"TK",
|
||||
"Name":"Turkish Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"JL",
|
||||
"Name":"Japan Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"SQ",
|
||||
"Name":"Singapore Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"KE",
|
||||
"Name":"Korean Air"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"CZ",
|
||||
"Name":"China Southern"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"AK",
|
||||
"Name":"AirAsia"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"HX",
|
||||
"Name":"Hong Kong Airlines"
|
||||
},
|
||||
{
|
||||
"AirlineCode":"EK",
|
||||
"Name":"Emirates"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"IcaoCode":"KSFO",
|
||||
"Name":"San Francisco International Airport",
|
||||
"IataCode":"SFO",
|
||||
"Location":{
|
||||
"Address":"South McDonnell Road, San Francisco, CA 94128",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"San Francisco",
|
||||
"Region":"California"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-122.374722222222,
|
||||
37.6188888888889
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"KLAX",
|
||||
"Name":"Los Angeles International Airport",
|
||||
"IataCode":"LAX",
|
||||
"Location":{
|
||||
"Address":"1 World Way, Los Angeles, CA, 90045",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Los Angeles",
|
||||
"Region":"California"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-118.408055555556,
|
||||
33.9425
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"ZSSS",
|
||||
"Name":"Shanghai Hongqiao International Airport",
|
||||
"IataCode":"SHA",
|
||||
"Location":{
|
||||
"Address":"Hongqiao Road 2550, Changning District",
|
||||
"City":{
|
||||
"CountryRegion":"China",
|
||||
"Name":"Shanghai",
|
||||
"Region":"Shanghai"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
121.336111111111,
|
||||
31.1977777777778
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"ZBAA",
|
||||
"Name":"Beijing Capital International Airport",
|
||||
"IataCode":"PEK",
|
||||
"Location":{
|
||||
"Address":"Airport Road, Chaoyang District, Beijing, 100621",
|
||||
"City":{
|
||||
"CountryRegion":"China",
|
||||
"Name":"Beijing",
|
||||
"Region":"Beijing"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
116.584444444444,
|
||||
40.08
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"KJFK",
|
||||
"Name":"John F. Kennedy International Airport",
|
||||
"IataCode":"JFK",
|
||||
"Location":{
|
||||
"Address":"Jamaica, New York, NY 11430",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"New York City",
|
||||
"Region":"New York"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-73.7788888888889,
|
||||
40.6397222222222
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"LIRA",
|
||||
"Name":"Rome Ciampino Airport",
|
||||
"IataCode":"CIA",
|
||||
"Location":{
|
||||
"Address":"Via Appia Nuova, 1651",
|
||||
"City":{
|
||||
"CountryRegion":"Italy",
|
||||
"Name":"Rome",
|
||||
"Region":""
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
12.5947222222222,
|
||||
41.7991666666667
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"CYYZ",
|
||||
"Name":"Toronto Pearson International Airport",
|
||||
"IataCode":"YYZ",
|
||||
"Location":{
|
||||
"Address":"6301 Silver Dart Dr Mississauga",
|
||||
"City":{
|
||||
"CountryRegion":"Canada",
|
||||
"Name":"Mississauga",
|
||||
"Region":"Ontario"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-79.6305555555555,
|
||||
43.6772222222222
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"YSSY",
|
||||
"Name":"Sydney Airport",
|
||||
"IataCode":"SYD",
|
||||
"Location":{
|
||||
"Address":"Airport Dr Sydney NSW 2020",
|
||||
"City":{
|
||||
"CountryRegion":"Australia",
|
||||
"Name":"Sydney",
|
||||
"Region":""
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
151.177222222222,
|
||||
-33.9461111111111
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"LTBA",
|
||||
"Name":"Istanbul Ataturk Airport",
|
||||
"IataCode":"IST",
|
||||
"Location":{
|
||||
"Address":"Ye\u015filk\u00f6y Mh.34149 \u0130stanbul",
|
||||
"City":{
|
||||
"CountryRegion":"Turkey",
|
||||
"Name":"Istanbul",
|
||||
"Region":""
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
28.8211111111111,
|
||||
40.9766666666667
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"WSSS",
|
||||
"Name":"Singapore Changi Airport",
|
||||
"IataCode":"SIN",
|
||||
"Location":{
|
||||
"Address":"Airport Blvd, Singapore",
|
||||
"City":{
|
||||
"CountryRegion":"Singapore",
|
||||
"Name":"Changi",
|
||||
"Region":""
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
103.987222222222,
|
||||
1.35555555555556
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"OMAA",
|
||||
"Name":"Abu Dhabi International Airport",
|
||||
"IataCode":"AUH",
|
||||
"Location":{
|
||||
"Address":"Sheik Maktoum Bin Rashid Rd Abu Dhabi",
|
||||
"City":{
|
||||
"CountryRegion":"United Arab Emirates",
|
||||
"Name":"Abu Dhabi",
|
||||
"Region":""
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
54.6511111111111,
|
||||
24.4327777777778
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"ZGGG",
|
||||
"Name":"Guangzhou Baiyun International Airport",
|
||||
"IataCode":"CAN",
|
||||
"Location":{
|
||||
"Address":"Jichang Road, Renhezhen, Huadu",
|
||||
"City":{
|
||||
"CountryRegion":"China",
|
||||
"Name":"Guangzhou",
|
||||
"Region":"Guangdong"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
113.265833333333,
|
||||
23.1841666666667
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"KORD",
|
||||
"Name":"O'Hare International Airport",
|
||||
"IataCode":"ORD",
|
||||
"Location":{
|
||||
"Address":"10000 W O'Hare Ave",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Chicago",
|
||||
"Region":"Illinois"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-87.9044444444445,
|
||||
41.9794444444444
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"KATL",
|
||||
"Name":"Hartsfield-Jackson Atlanta International Airport",
|
||||
"IataCode":"ATL",
|
||||
"Location":{
|
||||
"Address":"6000 N Terminal Pkwy",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Atlanta",
|
||||
"Region":"Georgia"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-84.4269444444444,
|
||||
33.6402777777778
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"IcaoCode":"KSEA",
|
||||
"Name":"Seattle-Tacoma International Airport",
|
||||
"IataCode":"SEA",
|
||||
"Location":{
|
||||
"Address":"17801 International Blvd",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"SeaTac",
|
||||
"Region":"Washington"
|
||||
},
|
||||
"Loc":{
|
||||
"type":"Point",
|
||||
"coordinates":[
|
||||
-122.309166666667,
|
||||
47.4488888888889
|
||||
],
|
||||
"crs":{
|
||||
"type":"name",
|
||||
"properties":{
|
||||
"name":"EPSG:4326"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"PlanItemId": 50,
|
||||
"Description": "Client Meeting",
|
||||
"ConfirmationCode": "4372899DD",
|
||||
"StartsAt": "2014-01-02T13:00:00Z",
|
||||
"EndsAt": "2014-01-02T16:00:00Z",
|
||||
"Duration": "PT3H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "Regus Business Center",
|
||||
"City":
|
||||
{
|
||||
"Name": "New York City",
|
||||
"CountryRegion": "United States",
|
||||
"Region": "New York"
|
||||
},
|
||||
"Address": "100 Church Street, 8th Floor, Manhattan, 10007"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 51,
|
||||
"Description": "Visit the Brooklyn Bridge Park",
|
||||
"ConfirmationCode": "4372899AA",
|
||||
"StartsAt": "2014-01-01T15:00:00Z",
|
||||
"EndsAt": "2014-01-01T16:00:00Z",
|
||||
"Duration": "PT1H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "Brooklyn Bridge Park, at Fulton Ferry Landing",
|
||||
"City":
|
||||
{
|
||||
"Name": "New York City",
|
||||
"CountryRegion": "United States",
|
||||
"Region": "New York"
|
||||
},
|
||||
"Address": "Main St Dumbo Brooklyn 11201"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 52,
|
||||
"Description": "Empire State Building",
|
||||
"ConfirmationCode": "4372899BB",
|
||||
"StartsAt": "2014-01-03T10:00:00Z",
|
||||
"EndsAt": "2014-01-03T12:00:00Z",
|
||||
"Duration": "PT2H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "Empire State Building",
|
||||
"City":
|
||||
{
|
||||
"Name": "New York City",
|
||||
"CountryRegion": "United States",
|
||||
"Region": "New York"
|
||||
},
|
||||
"Address": "Empire State Building, 350 5th Ave"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 53,
|
||||
"Description": "Coney Island",
|
||||
"ConfirmationCode": "4372899CC",
|
||||
"StartsAt": "2014-01-03T14:00:00Z",
|
||||
"EndsAt": "2014-01-03T20:00:00Z",
|
||||
"Duration": "PT6H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "",
|
||||
"City":
|
||||
{
|
||||
"Name": "New York City",
|
||||
"CountryRegion": "United States",
|
||||
"Region": "New York"
|
||||
},
|
||||
"Address": "1208 Surf Ave, Brooklyn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 54,
|
||||
"Description": "Shopping at Times Square",
|
||||
"ConfirmationCode": "4372899DD",
|
||||
"StartsAt": "2014-01-04T10:00:00Z",
|
||||
"EndsAt": "2014-01-04T15:00:00Z",
|
||||
"Duration": "PT5H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "",
|
||||
"City":
|
||||
{
|
||||
"Name": "New York City",
|
||||
"CountryRegion": "United States",
|
||||
"Region": "New York"
|
||||
},
|
||||
"Address": "Broadway, 7th Avenue, 42nd and 47th Streets"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 55,
|
||||
"Description": "Dinner",
|
||||
"ConfirmationCode": "4372899EE",
|
||||
"StartsAt": "2014-02-02T18:00:00Z",
|
||||
"EndsAt": "2014-02-02T21:00:00Z",
|
||||
"Duration": "PT3H",
|
||||
"OccursAt":
|
||||
{
|
||||
"Address": "10 Beijing Street, 100000",
|
||||
"City":
|
||||
{
|
||||
"Name": "Beijing",
|
||||
"CountryRegion": "China",
|
||||
"Region": "Beijing"
|
||||
},
|
||||
"BuildingInfo": "Beijing Restaurant"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 56,
|
||||
"Description": "Dinner",
|
||||
"ConfirmationCode": "4372899FF",
|
||||
"StartsAt": "2014-02-02T18:00:00Z",
|
||||
"EndsAt": "2014-02-02T21:00:00Z",
|
||||
"Duration": "PT3H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "Beijing Restaurant",
|
||||
"City":
|
||||
{
|
||||
"Name": "Beijing",
|
||||
"CountryRegion": "China",
|
||||
"Region": "Beijing"
|
||||
},
|
||||
"Address": "10 Beijing Street, 100000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"PlanItemId": 57,
|
||||
"Description": "Dinner",
|
||||
"ConfirmationCode": "4372899GG",
|
||||
"StartsAt": "2014-02-02T18:00:00Z",
|
||||
"EndsAt": "2014-02-02T21:00:00Z",
|
||||
"Duration": "PT3H",
|
||||
"OccursAt":
|
||||
{
|
||||
"BuildingInfo": "Beijing Restaurant",
|
||||
"City":
|
||||
{
|
||||
"Name": "Beijing",
|
||||
"CountryRegion": "China",
|
||||
"Region": "Beijing"
|
||||
},
|
||||
"Address": "10 Beijing Street, 100000"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"PlanItemId": 1,
|
||||
"Airline": "AA",
|
||||
"From": "ORD",
|
||||
"To": "JFK"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 2,
|
||||
"Airline": "AA",
|
||||
"From": "JFK",
|
||||
"To": "ORD"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 3,
|
||||
"Airline": "FM",
|
||||
"From": "SHA",
|
||||
"To": "PEK"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 4,
|
||||
"Airline": "MU",
|
||||
"From": "PEK",
|
||||
"To": "SHA"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 5,
|
||||
"Airline": "FM",
|
||||
"From": "SHA",
|
||||
"To": "PEK"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 6,
|
||||
"Airline": "MU",
|
||||
"From": "PEK",
|
||||
"To": "SHA"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 7,
|
||||
"Airline": "FM",
|
||||
"From": "SHA",
|
||||
"To": "PEK"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 8,
|
||||
"Airline": "MU",
|
||||
"From": "PEK",
|
||||
"To": "SHA"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"PlanItemId": 1,
|
||||
"ConfirmationCode": "JH58493",
|
||||
"FlightNumber": "AA26",
|
||||
"StartsAt": "2014-01-01T06:15:00Z",
|
||||
"EndsAt": "2014-01-01T11:35:00Z"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 2,
|
||||
"ConfirmationCode": "JH38143",
|
||||
"FlightNumber": "AA4035",
|
||||
"StartsAt": "2014-01-04T17:55:00Z",
|
||||
"EndsAt": "2014-01-04T20:45:00Z"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 3,
|
||||
"ConfirmationCode": "JH58494",
|
||||
"FlightNumber": "FM1930",
|
||||
"StartsAt": "2014-02-01T08:00:00Z",
|
||||
"EndsAt": "2014-02-01T09:20:00Z",
|
||||
"SeatNumber": "B11"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 4,
|
||||
"ConfirmationCode": "JH58495",
|
||||
"FlightNumber": "MU1930",
|
||||
"StartsAt": "2014-02-10T15:00:00Z",
|
||||
"EndsAt": "2014-02-10T16:30:00Z",
|
||||
"SeatNumber": "A32"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 5,
|
||||
"ConfirmationCode": "JH58494",
|
||||
"FlightNumber": "FM1930",
|
||||
"StartsAt": "2014-02-01T08:00:00Z",
|
||||
"EndsAt": "2014-02-01T09:20:00Z",
|
||||
"SeatNumber": "B11"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 6,
|
||||
"ConfirmationCode": "JH58495",
|
||||
"FlightNumber": "MU1930",
|
||||
"StartsAt": "2014-02-10T15:00:00Z",
|
||||
"EndsAt": "2014-02-10T16:30:00Z",
|
||||
"SeatNumber": "A32"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 7,
|
||||
"ConfirmationCode": "JH58494",
|
||||
"FlightNumber": "FM1930",
|
||||
"StartsAt": "2014-02-01T08:00:00Z",
|
||||
"EndsAt": "2014-02-01T09:20:00Z",
|
||||
"SeatNumber": "B12"
|
||||
},
|
||||
{
|
||||
"PlanItemId": 8,
|
||||
"ConfirmationCode": "JH58495",
|
||||
"FlightNumber": "MU1930",
|
||||
"StartsAt": "2014-02-10T16:30:00Z",
|
||||
"EndsAt": "2014-02-10T16:30:00Z",
|
||||
"SeatNumber": "A33"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"UserName":"russellwhyte",
|
||||
"Friends": ["scottketchum", "ronaldmundy", "javieralfred", "angelhuffman"],
|
||||
"Trips": [1001, 1003, 1007],
|
||||
"Photo": 1
|
||||
},
|
||||
{
|
||||
"UserName":"scottketchum",
|
||||
"Friends": ["russellwhyte", "ronaldmundy"],
|
||||
"Trips": [1001, 2004],
|
||||
"Photo": 11
|
||||
},
|
||||
{
|
||||
"UserName":"ronaldmundy",
|
||||
"Friends": ["russellwhyte", "scottketchum"],
|
||||
"Trips": [3009],
|
||||
"Photo": 12
|
||||
},
|
||||
{
|
||||
"UserName":"javieralfred",
|
||||
"Friends": ["willieashmore", "vincentcalabrese", "georginabarlow"],
|
||||
"Trips": [4005]
|
||||
},
|
||||
{
|
||||
"UserName":"willieashmore",
|
||||
"Friends": ["javieralfred", "vincentcalabrese"],
|
||||
"Trips": [5007, 5008]
|
||||
},
|
||||
{
|
||||
"UserName":"vincentcalabrese",
|
||||
"Friends": ["javieralfred", "willieashmore"],
|
||||
"Trips": [7010]
|
||||
},
|
||||
{
|
||||
"UserName":"clydeguess",
|
||||
"Friends": ["keithpinckney", "ursulabright"],
|
||||
"Trips": [8011]
|
||||
},
|
||||
{
|
||||
"UserName":"keithpinckney",
|
||||
"Friends": ["clydeguess", "marshallgaray"],
|
||||
"Trips": []
|
||||
},
|
||||
{
|
||||
"UserName":"marshallgaray",
|
||||
"Friends": ["keithpinckney", "elainestewart", "jonirosales"]
|
||||
},
|
||||
{
|
||||
"UserName":"elainestewart",
|
||||
"Friends": ["marshallgaray"]
|
||||
},
|
||||
{
|
||||
"UserName":"salliesampson",
|
||||
"Friends": [""],
|
||||
"Trips": [13012]
|
||||
},
|
||||
{
|
||||
"UserName":"jonirosales",
|
||||
"Friends": ["marshallgaray"],
|
||||
"Trips": [14013]
|
||||
},
|
||||
{
|
||||
"UserName":"georginabarlow",
|
||||
"Friends": ["javieralfred"]
|
||||
},
|
||||
{
|
||||
"UserName":"angelhuffman",
|
||||
"Friends": ["russellwhyte"],
|
||||
"Trips": [16014]
|
||||
},
|
||||
{
|
||||
"UserName":"laurelosborn",
|
||||
"Friends": ["sandyosborn"]
|
||||
},
|
||||
{
|
||||
"UserName":"sandyosborn",
|
||||
"Friends": ["laurelosborn"]
|
||||
},
|
||||
{
|
||||
"UserName":"ursulabright",
|
||||
"Friends": ["keithpinckney"]
|
||||
},
|
||||
{
|
||||
"UserName":"genevievereeves",
|
||||
"Friends": ["kristakemp"]
|
||||
},
|
||||
{
|
||||
"UserName":"kristakemp",
|
||||
"Friends": ["genevievereeves"]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"UserName":"russellwhyte",
|
||||
"FirstName":"Russell",
|
||||
"LastName":"Whyte",
|
||||
"Emails":[
|
||||
"Russell@example.com",
|
||||
"Russell@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
{
|
||||
"Address":"187 Suffolk Ln.",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Boise",
|
||||
"Region":"ID"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"scottketchum",
|
||||
"FirstName":"Scott",
|
||||
"LastName":"Ketchum",
|
||||
"Emails":[
|
||||
"Scott@example.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
{
|
||||
"Address":"2817 Milton Dr.",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Albuquerque",
|
||||
"Region":"NM"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"ronaldmundy",
|
||||
"FirstName":"Ronald",
|
||||
"LastName":"Mundy",
|
||||
"Emails":[
|
||||
"Ronald@example.com",
|
||||
"Ronald@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"javieralfred",
|
||||
"FirstName":"Javier",
|
||||
"LastName":"Alfred",
|
||||
"Emails":[
|
||||
"Javier@example.com",
|
||||
"Javier@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
{
|
||||
"Address":"89 Jefferson Way Suite 2",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Portland",
|
||||
"Region":"WA"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"willieashmore",
|
||||
"FirstName":"Willie",
|
||||
"LastName":"Ashmore",
|
||||
"Emails":[
|
||||
"Willie@example.com",
|
||||
"Willie@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"vincentcalabrese",
|
||||
"FirstName":"Vincent",
|
||||
"LastName":"Calabrese",
|
||||
"Emails":[
|
||||
"Vincent@example.com",
|
||||
"Vincent@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
{
|
||||
"Address":"55 Grizzly Peak Rd.",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Butte",
|
||||
"Region":"MT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"clydeguess",
|
||||
"FirstName":"Clyde",
|
||||
"LastName":"Guess",
|
||||
"Emails":[
|
||||
"Clyde@example.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"keithpinckney",
|
||||
"FirstName":"Keith",
|
||||
"LastName":"Pinckney",
|
||||
"Emails":[
|
||||
"Keith@example.com",
|
||||
"Keith@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"marshallgaray",
|
||||
"FirstName":"Marshall",
|
||||
"LastName":"Garay",
|
||||
"Emails":[
|
||||
"Marshall@example.com",
|
||||
"Marshall@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"ryantheriault",
|
||||
"FirstName":"Ryan",
|
||||
"LastName":"Theriault",
|
||||
"Emails":[
|
||||
"Ryan@example.com",
|
||||
"Ryan@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"0",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"elainestewart",
|
||||
"FirstName":"Elaine",
|
||||
"LastName":"Stewart",
|
||||
"Emails":[
|
||||
"Elaine@example.com",
|
||||
"Elaine@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"salliesampson",
|
||||
"FirstName":"Sallie",
|
||||
"LastName":"Sampson",
|
||||
"Emails":[
|
||||
"Sallie@example.com",
|
||||
"Sallie@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
{
|
||||
"Address":"87 Polk St. Suite 5",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"San Francisco",
|
||||
"Region":"CA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Address":"89 Chiaroscuro Rd.",
|
||||
"City":{
|
||||
"CountryRegion":"United States",
|
||||
"Name":"Portland",
|
||||
"Region":"OR"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"jonirosales",
|
||||
"FirstName":"Joni",
|
||||
"LastName":"Rosales",
|
||||
"Emails":[
|
||||
"Joni@example.com",
|
||||
"Joni@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"georginabarlow",
|
||||
"FirstName":"Georgina",
|
||||
"LastName":"Barlow",
|
||||
"Emails":[
|
||||
"Georgina@example.com",
|
||||
"Georgina@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"angelhuffman",
|
||||
"FirstName":"Angel",
|
||||
"LastName":"Huffman",
|
||||
"Emails":[
|
||||
"Angel@example.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"laurelosborn",
|
||||
"FirstName":"Laurel",
|
||||
"LastName":"Osborn",
|
||||
"Emails":[
|
||||
"Laurel@example.com",
|
||||
"Laurel@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"sandyosborn",
|
||||
"FirstName":"Sandy",
|
||||
"LastName":"Osborn",
|
||||
"Emails":[
|
||||
"Sandy@example.com",
|
||||
"Sandy@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"ursulabright",
|
||||
"FirstName":"Ursula",
|
||||
"LastName":"Bright",
|
||||
"Emails":[
|
||||
"Ursula@example.com",
|
||||
"Ursula@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"genevievereeves",
|
||||
"FirstName":"Genevieve",
|
||||
"LastName":"Reeves",
|
||||
"Emails":[
|
||||
"Genevieve@example.com",
|
||||
"Genevieve@contoso.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
},
|
||||
{
|
||||
"UserName":"kristakemp",
|
||||
"FirstName":"Krista",
|
||||
"LastName":"Kemp",
|
||||
"Emails":[
|
||||
"Krista@example.com"
|
||||
],
|
||||
"AddressInfo":[
|
||||
|
||||
],
|
||||
"Gender":"1",
|
||||
"Concurrency":635585295719432047
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"Id":1,
|
||||
"Name":"My Photo 1"
|
||||
},
|
||||
{
|
||||
"Id":11,
|
||||
"Name":"Trip Photo 11"
|
||||
},
|
||||
{
|
||||
"Id":12,
|
||||
"Name":"Trip Photo 12"
|
||||
},
|
||||
{
|
||||
"Id":13,
|
||||
"Name":"Trip Photo 13"
|
||||
},
|
||||
{
|
||||
"Id":14,
|
||||
"Name":"Trip Photo 14"
|
||||
},
|
||||
{
|
||||
"Id":2,
|
||||
"Name":"My Photo 2"
|
||||
},
|
||||
{
|
||||
"Id":21,
|
||||
"Name":"Trip Photo 21"
|
||||
},
|
||||
{
|
||||
"Id":22,
|
||||
"Name":"Trip Photo 22"
|
||||
},
|
||||
{
|
||||
"Id":23,
|
||||
"Name":"Trip Photo 23"
|
||||
},
|
||||
{
|
||||
"Id":24,
|
||||
"Name":"Trip Photo 24"
|
||||
},
|
||||
{
|
||||
"Id":3,
|
||||
"Name":"My Photo 3"
|
||||
},
|
||||
{
|
||||
"Id":31,
|
||||
"Name":"Trip Photo 31"
|
||||
},
|
||||
{
|
||||
"Id":32,
|
||||
"Name":"Trip Photo 32"
|
||||
},
|
||||
{
|
||||
"Id":33,
|
||||
"Name":"Trip Photo 33"
|
||||
},
|
||||
{
|
||||
"Id":34,
|
||||
"Name":"Trip Photo 34"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"TripId": 1001,
|
||||
"Flights": [1, 2],
|
||||
"Events": [51, 52, 53, 54, 55],
|
||||
"Photos": [21, 22]
|
||||
},
|
||||
{
|
||||
"TripId":2,
|
||||
"Flights": [3, 4],
|
||||
"Events": [55],
|
||||
"Photos": [13, 14]
|
||||
},
|
||||
{
|
||||
"TripId": 1003,
|
||||
"Flights": [5, 6],
|
||||
"Events": [56, 57],
|
||||
"Photos": [23, 24]
|
||||
},
|
||||
{
|
||||
"TripId": 2004,
|
||||
"Flights": [7, 8],
|
||||
"Events": [55, 57],
|
||||
"Photos": [33, 34]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
{
|
||||
"value":[
|
||||
{
|
||||
"TripId": 1001,
|
||||
"ShareId": "9d9b2fa0-efbf-490e-a5e3-bac8f7d47354",
|
||||
"Description": "Trip from San Francisco to New York City. Nice trip with two friends. It is a 4 days' trip. We actually had a client meeting, but we also took one to go sightseeings in New York.",
|
||||
"Name": "Trip in US",
|
||||
"Budget": 3000.0,
|
||||
"StartsAt":"2014-01-01T00:00:00Z",
|
||||
"EndsAt": "2014-01-04T00:00:00Z",
|
||||
"Tags": ["Trip in New York", "business","sightseeing"]
|
||||
},
|
||||
{
|
||||
"TripId":2,
|
||||
"ShareId": "f94e9116-8bdd-4dac-ab61-08438d0d9a71",
|
||||
"Description": "Trip from Shanghai to Beijing",
|
||||
"Name":"Trip in Beijing",
|
||||
"Budget": 3000.0,
|
||||
"Tags": ["Travel", "Beijing"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 3,
|
||||
"ShareId": "9ce142c3-5fd6-4a71-848e-5220ebf1e9f3",
|
||||
"Name": "Honeymoon",
|
||||
"Budget": 800.0,
|
||||
"Description": "Happy honeymoon trip",
|
||||
"Tags": ["Travel", "honeymoon"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 4,
|
||||
"ShareId": "4CCFB043-C79C-44EF-8CFE-CD493CED6654",
|
||||
"Name": "Business trip to OData",
|
||||
"Budget": 324.6,
|
||||
"Description": "Business trip to OData",
|
||||
"Tags": ["business", "odata"],
|
||||
"StartsAt": "2013-01-01T00:00:00Z",
|
||||
"EndsAt": "2013-01-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 5,
|
||||
"ShareId": "4546F419-0070-45F7-BA2C-19E4BC3647E1",
|
||||
"Name": "Travel trip in US",
|
||||
"Budget": 1250.0,
|
||||
"Description": "Travel trip in US",
|
||||
"Tags": ["travel", "overseas"],
|
||||
"StartsAt": "2013-01-19T00:00:00Z",
|
||||
"EndsAt": "2013-01-28T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 6,
|
||||
"ShareId": "26F0E8F6-657A-4561-BF3B-719366EF04FA",
|
||||
"Name": "Study music in Europe",
|
||||
"Budget": 3200.0,
|
||||
"Description": "Study music in Europe",
|
||||
"Tags": ["study", "overseas"],
|
||||
"StartsAt": "2013-03-01T00:00:00Z",
|
||||
"EndsAt": "2013-05-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 7,
|
||||
"ShareId": "2E77BF06-A354-454B-8BCA-5F004C1AFB59",
|
||||
"Name": "Conference talk about OData",
|
||||
"Budget": 2120.55,
|
||||
"Description": "Conference talk about ODatan",
|
||||
"Tags": ["odata", "overseas"],
|
||||
"StartsAt": "2013-07-02T00:00:00Z",
|
||||
"EndsAt": "2013-07-05T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 8,
|
||||
"ShareId": "E6E23FB2-C428-439E-BDAB-9283482F49F0",
|
||||
"Name": "Vocation at hometown",
|
||||
"Budget": 1500.0,
|
||||
"Description": "Vocation at hometown",
|
||||
"Tags": ["voaction"],
|
||||
"StartsAt": "2013-10-01T00:00:00Z",
|
||||
"EndsAt": "2013-10-05T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 9,
|
||||
"ShareId": "FAE31279-35CE-4119-9BDC-53F6E19DD1C5",
|
||||
"Name": "Business trip for tech training",
|
||||
"Budget": 100.0,
|
||||
"Description": "Business trip for tech training",
|
||||
"Tags": ["business"],
|
||||
"StartsAt": "2013-09-01T00:00:00Z",
|
||||
"EndsAt": "2013-09-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 3009,
|
||||
"ShareId": "dd6a09c0-e59b-4745-8612-f4499b676c47",
|
||||
"Name": "Gradutaion trip",
|
||||
"Budget": 6000.0,
|
||||
"Description": "Gradution trip with friends",
|
||||
"Tags": ["Travel"],
|
||||
"StartsAt": "2013-05-01T00:00:00Z",
|
||||
"EndsAt": "2013-05-08T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 2004,
|
||||
"ShareId": "f94e9116-8bdd-4dac-ab61-08438d0d9a71",
|
||||
"Name": "Trip in Beijing",
|
||||
"Budget": 11000.0,
|
||||
"Description": "Trip from Shanghai to Beijing",
|
||||
"Tags": ["Travel", "Beijing"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2013-02-02T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 4005,
|
||||
"ShareId": "f94e9116-8bdd-4dac-ab61-08438d0d9a71",
|
||||
"Name": "Trip in Beijing",
|
||||
"Budget": 800.0,
|
||||
"Description": "Trip from Shanghai to Beijing",
|
||||
"Tags": ["Travel", "Beijing"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 5007,
|
||||
"ShareId": "5ae142c3-5ad6-4a71-768e-5220ebf1e9f3",
|
||||
"Name": "Business Trip",
|
||||
"Budget": 3800.5,
|
||||
"Description": "This is my first business trip",
|
||||
"Tags": ["business", "first"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 5008,
|
||||
"ShareId": "9ce32ac3-5fd6-4a72-848e-2250ebf1e9f3",
|
||||
"Name": "Trip in Europe",
|
||||
"Budget": 2000.0,
|
||||
"Description": "The trip is currently in plan.",
|
||||
"Tags": ["Travel", "plan"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 1003,
|
||||
"Name": "Trip in Beijing",
|
||||
"Budget": 2000.0,
|
||||
"ShareId": "f94e9116-8bdd-4dac-ab61-08438d0d9a71",
|
||||
"Description": "Trip from Shanghai to Beijing",
|
||||
"Tags": ["Travel", "Beijing"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 2004,
|
||||
"ShareId": "f94e9116-8bdd-4dac-ab61-08438d0d9a71",
|
||||
"Name": "Trip in Beijing",
|
||||
"Budget": 11000.0,
|
||||
"Description": "Trip from Shanghai to Beijing",
|
||||
"Tags": ["Travel", "Beijing"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 1007,
|
||||
"ShareId": "9ce142c3-5fd6-4a71-848e-5220ebf1e9f3",
|
||||
"Name": "Honeymoon",
|
||||
"Budget": 2650.0,
|
||||
"Description": "Happy honeymoon trip",
|
||||
"Tags": ["Travel", "honeymoon"],
|
||||
"StartsAt": "2014-02-01T00:00:00Z",
|
||||
"EndsAt": "2014-02-04T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 7010,
|
||||
"ShareId": "dd6a09c0-e59b-4745-8612-f4499b676c47",
|
||||
"Name": "Gradutaion trip",
|
||||
"Budget": 1000.0,
|
||||
"Description": "Gradution trip with friends",
|
||||
"Tags": ["Travel"],
|
||||
"StartsAt": "2013-05-01T00:00:00Z",
|
||||
"EndsAt": "2013-05-08T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 8011,
|
||||
"ShareId": "a88f675d-9199-4392-9656-b08e3b46df8a",
|
||||
"Name": "Study trip",
|
||||
"Budget": 1550.3,
|
||||
"Description": "This is a 2 weeks study trip",
|
||||
"Tags": ["study"],
|
||||
"StartsAt": "2014-01-01T00:00:00Z",
|
||||
"EndsAt": "2013-01-14T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 13012,
|
||||
"ShareId": "a88f675d-9199-4392-9656-b08e3b46df8a",
|
||||
"Name": "Study trip",
|
||||
"Budget": 600.0,
|
||||
"Description": "This is a 2 weeks study trip",
|
||||
"Tags": ["study"],
|
||||
"StartsAt": "2014-01-01T00:00:00Z",
|
||||
"EndsAt": "2013-01-14T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 14013,
|
||||
"ShareId": "a88f675d-9199-4392-9656-b08e3b46df8a",
|
||||
"Name": "Study trip",
|
||||
"Budget": 2000.0,
|
||||
"Description": "This is a 2 weeks study trip",
|
||||
"Tags": ["study"],
|
||||
"StartsAt": "2014-01-01T00:00:00Z",
|
||||
"EndsAt": "2013-01-14T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"TripId": 16014,
|
||||
"ShareId": "cb0b8acb-79cb-4127-8316-772bc4302824",
|
||||
"Name": "DIY Trip",
|
||||
"Budget": 1500.3,
|
||||
"Description": "This is a DIY trip",
|
||||
"Tags": ["Travel", "DIY"],
|
||||
"StartsAt": "2011-02-11T00:00:00Z",
|
||||
"EndsAt": "2011-02-14T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,356 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||
<edmx:DataServices>
|
||||
<Schema Namespace="Microsoft.OData.SampleService.Models.TripPin" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||
<EnumType Name="PersonGender">
|
||||
<Member Name="Male" Value="0" />
|
||||
<Member Name="Female" Value="1" />
|
||||
<Member Name="Unknown" Value="2" />
|
||||
</EnumType>
|
||||
<ComplexType Name="City">
|
||||
<Property Name="CountryRegion" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="Region" Type="Edm.String" Nullable="false" />
|
||||
</ComplexType>
|
||||
<ComplexType Name="Location" OpenType="true">
|
||||
<Property Name="Address" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="City" Type="Microsoft.OData.SampleService.Models.TripPin.City" Nullable="false" />
|
||||
</ComplexType>
|
||||
<ComplexType Name="EventLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||
<Property Name="BuildingInfo" Type="Edm.String" />
|
||||
</ComplexType>
|
||||
<ComplexType Name="AirportLocation" BaseType="Microsoft.OData.SampleService.Models.TripPin.Location" OpenType="true">
|
||||
<Property Name="Loc" Type="Edm.GeographyPoint" Nullable="false" SRID="4326" />
|
||||
</ComplexType>
|
||||
<EntityType Name="Photo" HasStream="true">
|
||||
<Key>
|
||||
<PropertyRef Name="Id" />
|
||||
</Key>
|
||||
<Property Name="Id" Type="Edm.Int64" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="Name" Type="Edm.String" />
|
||||
<Annotation Term="Org.OData.Core.V1.AcceptableMediaTypes">
|
||||
<Collection>
|
||||
<String>image/jpeg</String>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
</EntityType>
|
||||
<EntityType Name="Person" OpenType="true">
|
||||
<Key>
|
||||
<PropertyRef Name="UserName" />
|
||||
</Key>
|
||||
<Property Name="UserName" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="FirstName" Type="Edm.String" Nullable="true" />
|
||||
<Property Name="LastName" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="Emails" Type="Collection(Edm.String)" />
|
||||
<Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)" />
|
||||
<Property Name="Gender" Type="Microsoft.OData.SampleService.Models.TripPin.PersonGender" />
|
||||
<Property Name="Concurrency" Type="Edm.Int64" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Computed" Bool="true" />
|
||||
</Property>
|
||||
<NavigationProperty Name="Friends" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)" />
|
||||
<NavigationProperty Name="Trips" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" ContainsTarget="true" />
|
||||
<NavigationProperty Name="Photo" Type="Microsoft.OData.SampleService.Models.TripPin.Photo" />
|
||||
</EntityType>
|
||||
<EntityType Name="Airline">
|
||||
<Key>
|
||||
<PropertyRef Name="AirlineCode" />
|
||||
</Key>
|
||||
<Property Name="AirlineCode" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="Picture" Type="Edm.Stream" Nullable="true" />
|
||||
</EntityType>
|
||||
<EntityType Name="Airport">
|
||||
<Key>
|
||||
<PropertyRef Name="IcaoCode" />
|
||||
</Key>
|
||||
<Property Name="IcaoCode" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="IataCode" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Immutable" Bool="true" />
|
||||
</Property>
|
||||
<Property Name="Location" Type="Microsoft.OData.SampleService.Models.TripPin.AirportLocation" Nullable="false" />
|
||||
</EntityType>
|
||||
<EntityType Name="PlanItem">
|
||||
<Key>
|
||||
<PropertyRef Name="PlanItemId" />
|
||||
</Key>
|
||||
<Property Name="PlanItemId" Type="Edm.Int32" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="ConfirmationCode" Type="Edm.String" />
|
||||
<Property Name="StartsAt" Type="Edm.DateTimeOffset" />
|
||||
<Property Name="EndsAt" Type="Edm.DateTimeOffset" />
|
||||
<Property Name="Duration" Type="Edm.Duration" />
|
||||
</EntityType>
|
||||
<EntityType Name="PublicTransportation" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem">
|
||||
<Property Name="SeatNumber" Type="Edm.String" />
|
||||
</EntityType>
|
||||
<EntityType Name="Flight" BaseType="Microsoft.OData.SampleService.Models.TripPin.PublicTransportation">
|
||||
<Property Name="FlightNumber" Type="Edm.String" Nullable="false" />
|
||||
<NavigationProperty Name="From" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||
<NavigationProperty Name="To" Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||
<NavigationProperty Name="Airline" Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false" />
|
||||
</EntityType>
|
||||
<EntityType Name="Event" BaseType="Microsoft.OData.SampleService.Models.TripPin.PlanItem" OpenType="true">
|
||||
<Property Name="Description" Type="Edm.String" />
|
||||
<Property Name="OccursAt" Type="Microsoft.OData.SampleService.Models.TripPin.EventLocation" Nullable="false" />
|
||||
</EntityType>
|
||||
<EntityType Name="Trip">
|
||||
<Key>
|
||||
<PropertyRef Name="TripId" />
|
||||
</Key>
|
||||
<Property Name="TripId" Type="Edm.Int32" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="ShareId" Type="Edm.Guid" />
|
||||
<Property Name="Description" Type="Edm.String" />
|
||||
<Property Name="Name" Type="Edm.String" Nullable="false" />
|
||||
<Property Name="Budget" Type="Edm.Single" Nullable="false">
|
||||
<Annotation Term="Org.OData.Measures.V1.ISOCurrency" String="USD" />
|
||||
<Annotation Term="Org.OData.Measures.V1.Scale" Int="2" />
|
||||
</Property>
|
||||
<Property Name="StartsAt" Type="Edm.DateTimeOffset" Nullable="false" />
|
||||
<Property Name="EndsAt" Type="Edm.DateTimeOffset" Nullable="false" />
|
||||
<Property Name="Tags" Type="Collection(Edm.String)" Nullable="false" />
|
||||
<NavigationProperty Name="Photos" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Photo)" />
|
||||
<NavigationProperty Name="PlanItems" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.PlanItem)" ContainsTarget="true" />
|
||||
</EntityType>
|
||||
<Function Name="GetFavoriteAirline" IsBound="true" EntitySetPath="person/Trips/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" IsComposable="true">
|
||||
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false" />
|
||||
</Function>
|
||||
<Function Name="GetInvolvedPeople" IsBound="true" IsComposable="true">
|
||||
<Parameter Name="trip" Type="Microsoft.OData.SampleService.Models.TripPin.Trip" Nullable="false" />
|
||||
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Person)" Nullable="false" />
|
||||
</Function>
|
||||
<Function Name="GetFriendsTrips" IsBound="true" EntitySetPath="person/Friends/Trips" IsComposable="true">
|
||||
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||
<Parameter Name="userName" Type="Edm.String" Nullable="false" />
|
||||
<ReturnType Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Trip)" Nullable="false" />
|
||||
</Function>
|
||||
<Function Name="GetNearestAirport" IsComposable="true">
|
||||
<Parameter Name="lat" Type="Edm.Double" Nullable="false" />
|
||||
<Parameter Name="lon" Type="Edm.Double" Nullable="false" />
|
||||
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airport" Nullable="false" />
|
||||
</Function>
|
||||
<Action Name="ResetDataSource" />
|
||||
<Action Name="ShareTrip" IsBound="true">
|
||||
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
|
||||
<Parameter Name="userName" Type="Edm.String" Nullable="false" />
|
||||
<Parameter Name="tripId" Type="Edm.Int32" Nullable="false" />
|
||||
</Action>
|
||||
<EntityContainer Name="DefaultContainer">
|
||||
<EntitySet Name="Photos" EntityType="Microsoft.OData.SampleService.Models.TripPin.Photo">
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Photos" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Searchable" Bool="true" />
|
||||
<PropertyValue Property="UnsupportedExpressions">
|
||||
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Insertable" Bool="true" />
|
||||
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||
<Collection />
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
</EntitySet>
|
||||
<EntitySet Name="People" EntityType="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||
<NavigationPropertyBinding Path="Friends" Target="People" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports" />
|
||||
<NavigationPropertyBinding Path="Photo" Target="Photos" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos" />
|
||||
<Annotation Term="Org.OData.Core.V1.OptimisticConcurrency">
|
||||
<Collection>
|
||||
<PropertyPath>Concurrency</PropertyPath>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="People" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.NavigationRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Navigability">
|
||||
<EnumMember>Org.OData.Capabilities.V1.NavigationType/None</EnumMember>
|
||||
</PropertyValue>
|
||||
<PropertyValue Property="RestrictedProperties">
|
||||
<Collection>
|
||||
<Record>
|
||||
<PropertyValue Property="NavigationProperty" NavigationPropertyPath="Friends" />
|
||||
<PropertyValue Property="Navigability">
|
||||
<EnumMember>Org.OData.Capabilities.V1.NavigationType/Recursive</EnumMember>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Searchable" Bool="true" />
|
||||
<PropertyValue Property="UnsupportedExpressions">
|
||||
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Insertable" Bool="true" />
|
||||
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||
<Collection>
|
||||
<NavigationPropertyPath>Trips</NavigationPropertyPath>
|
||||
<NavigationPropertyPath>Friends</NavigationPropertyPath>
|
||||
</Collection>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
</EntitySet>
|
||||
<EntitySet Name="Airlines" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airline">
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airlines" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Searchable" Bool="true" />
|
||||
<PropertyValue Property="UnsupportedExpressions">
|
||||
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Insertable" Bool="true" />
|
||||
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||
<Collection />
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
</EntitySet>
|
||||
<EntitySet Name="Airports" EntityType="Microsoft.OData.SampleService.Models.TripPin.Airport">
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Airports" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Searchable" Bool="true" />
|
||||
<PropertyValue Property="UnsupportedExpressions">
|
||||
<EnumMember>Org.OData.Capabilities.V1.SearchExpressions/none</EnumMember>
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.InsertRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Insertable" Bool="false" />
|
||||
<PropertyValue Property="NonInsertableNavigationProperties">
|
||||
<Collection />
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.DeleteRestrictions">
|
||||
<Record>
|
||||
<PropertyValue Property="Deletable" Bool="false" />
|
||||
<PropertyValue Property="NonDeletableNavigationProperties">
|
||||
<Collection />
|
||||
</PropertyValue>
|
||||
</Record>
|
||||
</Annotation>
|
||||
</EntitySet>
|
||||
<Singleton Name="Me" Type="Microsoft.OData.SampleService.Models.TripPin.Person">
|
||||
<NavigationPropertyBinding Path="Friends" Target="People" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" Target="Airlines" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/From" Target="Airports" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Flight/To" Target="Airports" />
|
||||
<NavigationPropertyBinding Path="Photo" Target="Photos" />
|
||||
<NavigationPropertyBinding Path="Microsoft.OData.SampleService.Models.TripPin.Trip/Photos" Target="Photos" />
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Me" />
|
||||
</Singleton>
|
||||
<FunctionImport Name="GetNearestAirport" Function="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport" EntitySet="Airports" IncludeInServiceDocument="true">
|
||||
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Microsoft.OData.SampleService.Models.TripPin.GetNearestAirport" />
|
||||
</FunctionImport>
|
||||
<ActionImport Name="ResetDataSource" Action="Microsoft.OData.SampleService.Models.TripPin.ResetDataSource" />
|
||||
<Annotation Term="Org.OData.Core.V1.Description" String="TripPin service is a sample service for OData V4." />
|
||||
</EntityContainer>
|
||||
<Annotations Target="Microsoft.OData.SampleService.Models.TripPin.DefaultContainer">
|
||||
<Annotation Term="Org.OData.Core.V1.DereferenceableIDs" Bool="true" />
|
||||
<Annotation Term="Org.OData.Core.V1.ConventionalIDs" Bool="true" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.ConformanceLevel">
|
||||
<EnumMember>Org.OData.Capabilities.V1.ConformanceLevelType/Advanced</EnumMember>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.SupportedFormats">
|
||||
<Collection>
|
||||
<String>application/json;odata.metadata=full;IEEE754Compatible=false;odata.streaming=true</String>
|
||||
<String>application/json;odata.metadata=minimal;IEEE754Compatible=false;odata.streaming=true</String>
|
||||
<String>application/json;odata.metadata=none;IEEE754Compatible=false;odata.streaming=true</String>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
<Annotation Term="Org.OData.Capabilities.V1.AsynchronousRequestsSupported" Bool="true" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.BatchContinueOnErrorSupported" Bool="false" />
|
||||
<Annotation Term="Org.OData.Capabilities.V1.FilterFunctions">
|
||||
<Collection>
|
||||
<String>contains</String>
|
||||
<String>endswith</String>
|
||||
<String>startswith</String>
|
||||
<String>length</String>
|
||||
<String>indexof</String>
|
||||
<String>substring</String>
|
||||
<String>tolower</String>
|
||||
<String>toupper</String>
|
||||
<String>trim</String>
|
||||
<String>concat</String>
|
||||
<String>year</String>
|
||||
<String>month</String>
|
||||
<String>day</String>
|
||||
<String>hour</String>
|
||||
<String>minute</String>
|
||||
<String>second</String>
|
||||
<String>round</String>
|
||||
<String>floor</String>
|
||||
<String>ceiling</String>
|
||||
<String>cast</String>
|
||||
<String>isof</String>
|
||||
</Collection>
|
||||
</Annotation>
|
||||
</Annotations>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>
|
|
@ -20,6 +20,8 @@ package org.apache.olingo.server.core.deserializer.json;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -65,6 +67,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
public class ODataJsonDeserializer implements ODataDeserializer {
|
||||
|
@ -267,8 +270,8 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
node.remove(toRemove);
|
||||
}
|
||||
|
||||
private void consumeEntityProperties(final EdmEntityType edmEntityType, final ObjectNode node, final EntityImpl
|
||||
entity) throws DeserializerException {
|
||||
private void consumeEntityProperties(final EdmEntityType edmEntityType, final ObjectNode node,
|
||||
final EntityImpl entity) throws DeserializerException {
|
||||
List<String> propertyNames = edmEntityType.getPropertyNames();
|
||||
for (String propertyName : propertyNames) {
|
||||
JsonNode jsonNode = node.get(propertyName);
|
||||
|
@ -409,7 +412,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
case ENUM:
|
||||
value = readEnumValue(name, type, isNullable, maxLength, precision, scale, isUnicode, mapping,
|
||||
jsonNode);
|
||||
property.setValue(ValueType.PRIMITIVE, value);
|
||||
property.setValue(ValueType.ENUM, value);
|
||||
break;
|
||||
case COMPLEX:
|
||||
value = readComplexNode(name, type, isNullable, jsonNode);
|
||||
|
@ -706,4 +709,81 @@ public class ODataJsonDeserializer implements ODataDeserializer {
|
|||
DeserializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property property(InputStream stream, EdmProperty edmProperty)
|
||||
throws DeserializerException {
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
|
||||
JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
|
||||
final ObjectNode tree = parser.getCodec().readTree(parser);
|
||||
|
||||
Property property = null;
|
||||
JsonNode jsonNode = tree.get(Constants.VALUE);
|
||||
if (jsonNode != null) {
|
||||
property = consumePropertyNode(edmProperty.getName(), edmProperty.getType(),
|
||||
edmProperty.isCollection(),
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
|
||||
edmProperty.isUnicode(), edmProperty.getMapping(),
|
||||
jsonNode);
|
||||
tree.remove(Constants.VALUE);
|
||||
} else {
|
||||
property = consumePropertyNode(edmProperty.getName(), edmProperty.getType(),
|
||||
edmProperty.isCollection(),
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
|
||||
edmProperty.isUnicode(), edmProperty.getMapping(),
|
||||
tree);
|
||||
}
|
||||
return property;
|
||||
} catch (JsonParseException e) {
|
||||
throw new DeserializerException("An JsonParseException occurred", e,
|
||||
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
|
||||
} catch (JsonMappingException e) {
|
||||
throw new DeserializerException("Duplicate property detected", e,
|
||||
DeserializerException.MessageKeys.DUPLICATE_PROPERTY);
|
||||
} catch (IOException e) {
|
||||
throw new DeserializerException("An IOException occurred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
public List<URI> entityReferences(InputStream stream) throws DeserializerException {
|
||||
try {
|
||||
ArrayList<URI> parsedValues = new ArrayList<URI>();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
|
||||
JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
|
||||
final ObjectNode tree = parser.getCodec().readTree(parser);
|
||||
final String key = "@odata.id";
|
||||
JsonNode jsonNode = tree.get(Constants.VALUE);
|
||||
if (jsonNode != null) {
|
||||
if (jsonNode.isArray()) {
|
||||
ArrayNode arrayNode = (ArrayNode)jsonNode;
|
||||
Iterator<JsonNode> it = arrayNode.iterator();
|
||||
while(it.hasNext()) {
|
||||
parsedValues.add(new URI(it.next().get(key).asText()));
|
||||
}
|
||||
} else {
|
||||
parsedValues.add(new URI(jsonNode.asText()));
|
||||
}
|
||||
tree.remove(Constants.VALUE);
|
||||
// if this is value there can be only one property
|
||||
return parsedValues;
|
||||
}
|
||||
parsedValues.add(new URI(tree.get(key).asText()));
|
||||
return parsedValues;
|
||||
} catch (JsonParseException e) {
|
||||
throw new DeserializerException("An JsonParseException occurred", e,
|
||||
DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
|
||||
} catch (JsonMappingException e) {
|
||||
throw new DeserializerException("Duplicate property detected", e,
|
||||
DeserializerException.MessageKeys.DUPLICATE_PROPERTY);
|
||||
} catch (IOException e) {
|
||||
throw new DeserializerException("An IOException occurred", e,
|
||||
DeserializerException.MessageKeys.IO_EXCEPTION);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new DeserializerException("failed to read @odata.id", e,
|
||||
DeserializerException.MessageKeys.UNKOWN_CONTENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -41,6 +41,7 @@ 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.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.server.api.ODataServerError;
|
||||
|
@ -127,7 +128,8 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream entityCollection(final EdmEntityType entityType, final EntitySet entitySet,
|
||||
public InputStream entityCollection(final ServiceMetadata metadata,
|
||||
final EdmEntityType entityType, final EntitySet entitySet,
|
||||
final EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
try {
|
||||
|
@ -145,8 +147,9 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount());
|
||||
}
|
||||
json.writeFieldName(Constants.VALUE);
|
||||
writeEntitySet(entityType, entitySet,
|
||||
options == null ? null : options.getExpand(), options == null ? null : options.getSelect(), json);
|
||||
writeEntitySet(metadata, entityType, entitySet, options == null ? null : options.getExpand(),
|
||||
options == null ? null : options.getSelect(),
|
||||
options == null ? false : options.onlyReferences(), json);
|
||||
if (entitySet.getNext() != null) {
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
}
|
||||
|
@ -159,14 +162,16 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream entity(final EdmEntityType entityType, final Entity entity,
|
||||
final EntitySerializerOptions options) throws SerializerException {
|
||||
public InputStream entity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final EntitySerializerOptions options) throws SerializerException {
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
try {
|
||||
JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
|
||||
writeEntity(entityType, entity, contextURL,
|
||||
options == null ? null : options.getExpand(), options == null ? null : options.getSelect(), json);
|
||||
writeEntity(metadata, entityType, entity, contextURL,
|
||||
options == null ? null : options.getExpand(),
|
||||
options == null ? null : options.getSelect(),
|
||||
options == null ? false: options.onlyReferences(), json);
|
||||
json.close();
|
||||
} catch (final IOException e) {
|
||||
throw new SerializerException("An I/O exception occurred.", e,
|
||||
|
@ -184,18 +189,26 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
return contextURL;
|
||||
}
|
||||
|
||||
protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet,
|
||||
final ExpandOption expand, final SelectOption select, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final EntitySet entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final boolean onlyReference, final JsonGenerator json) throws IOException,
|
||||
SerializerException {
|
||||
json.writeStartArray();
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
writeEntity(entityType, entity, null, expand, select, json);
|
||||
if (onlyReference) {
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString());
|
||||
json.writeEndObject();
|
||||
} else {
|
||||
writeEntity(metadata, entityType, entity, null, expand, select, false, json);
|
||||
}
|
||||
}
|
||||
json.writeEndArray();
|
||||
}
|
||||
|
||||
protected void writeEntity(final EdmEntityType entityType, final Entity entity, final ContextURL contextURL,
|
||||
final ExpandOption expand, final SelectOption select, final JsonGenerator json)
|
||||
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final ContextURL contextURL, final ExpandOption expand,
|
||||
final SelectOption select, boolean onlyReference, final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
if (format != ODataFormat.JSON_NO_METADATA) {
|
||||
|
@ -214,9 +227,63 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
}
|
||||
}
|
||||
writeProperties(entityType, entity.getProperties(), select, json);
|
||||
writeNavigationProperties(entityType, entity, expand, json);
|
||||
json.writeEndObject();
|
||||
if (onlyReference) {
|
||||
json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString());
|
||||
} else {
|
||||
EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
|
||||
if (!resolvedType.equals(entityType)) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#"+entity.getType());
|
||||
}
|
||||
writeProperties(resolvedType, entity.getProperties(), select, json);
|
||||
writeNavigationProperties(metadata, resolvedType, entity, expand, json);
|
||||
json.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
protected EdmEntityType resolveEntityType(ServiceMetadata metadata, EdmEntityType baseType,
|
||||
String derivedTypeName) throws SerializerException {
|
||||
if (baseType.getFullQualifiedName().getFullQualifiedNameAsString().equals(derivedTypeName)) {
|
||||
return baseType;
|
||||
}
|
||||
EdmEntityType derivedType = metadata.getEdm().getEntityType(new FullQualifiedName(derivedTypeName));
|
||||
if (derivedType == null) {
|
||||
throw new SerializerException("EntityType not found",
|
||||
SerializerException.MessageKeys.UNKNOWN_TYPE, derivedTypeName);
|
||||
}
|
||||
EdmEntityType type = derivedType.getBaseType();
|
||||
while (type != null) {
|
||||
if (type.getFullQualifiedName().getFullQualifiedNameAsString()
|
||||
.equals(baseType.getFullQualifiedName().getFullQualifiedNameAsString())) {
|
||||
return derivedType;
|
||||
}
|
||||
type = type.getBaseType();
|
||||
}
|
||||
throw new SerializerException("Wrong base type",
|
||||
SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName, baseType
|
||||
.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
|
||||
protected EdmComplexType resolveComplexType(ServiceMetadata metadata, EdmComplexType baseType,
|
||||
String derivedTypeName) throws SerializerException {
|
||||
if (baseType.getFullQualifiedName().getFullQualifiedNameAsString().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().getFullQualifiedNameAsString()
|
||||
.equals(baseType.getFullQualifiedName().getFullQualifiedNameAsString())) {
|
||||
return derivedType;
|
||||
}
|
||||
type = type.getBaseType();
|
||||
}
|
||||
throw new SerializerException("Wrong base type",
|
||||
SerializerException.MessageKeys.WRONG_BASE_TYPE, derivedTypeName, baseType
|
||||
.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
|
||||
protected void writeProperties(final EdmStructuredType type, final List<Property> properties,
|
||||
|
@ -235,8 +302,9 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
protected void writeNavigationProperties(final EdmStructuredType type, final Linked linked,
|
||||
final ExpandOption expand, final JsonGenerator json) throws SerializerException, IOException {
|
||||
protected void writeNavigationProperties(final ServiceMetadata metadata,
|
||||
final EdmStructuredType type, final Linked linked, final ExpandOption expand,
|
||||
final JsonGenerator json) throws SerializerException, IOException {
|
||||
if (ExpandSelectHelper.hasExpand(expand)) {
|
||||
final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
|
||||
final Set<String> expanded = expandAll ? null :
|
||||
|
@ -251,7 +319,7 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
throw new SerializerException("Expand options $ref and $levels are not supported.",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
writeExpandedNavigationProperty(property, navigationLink,
|
||||
writeExpandedNavigationProperty(metadata, property, navigationLink,
|
||||
innerOptions == null ? null : innerOptions.getExpandOption(),
|
||||
innerOptions == null ? null : innerOptions.getSelectOption(),
|
||||
json);
|
||||
|
@ -260,7 +328,8 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
protected void writeExpandedNavigationProperty(final EdmNavigationProperty property, final Link navigationLink,
|
||||
protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
|
||||
final EdmNavigationProperty property, final Link navigationLink,
|
||||
final ExpandOption innerExpand, final SelectOption innerSelect, JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeFieldName(property.getName());
|
||||
|
@ -269,13 +338,15 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
json.writeStartArray();
|
||||
json.writeEndArray();
|
||||
} else {
|
||||
writeEntitySet(property.getType(), navigationLink.getInlineEntitySet(), innerExpand, innerSelect, json);
|
||||
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
|
||||
innerSelect, false, json);
|
||||
}
|
||||
} else {
|
||||
if (navigationLink == null || navigationLink.getInlineEntity() == null) {
|
||||
json.writeNull();
|
||||
} else {
|
||||
writeEntity(property.getType(), navigationLink.getInlineEntity(), null, innerExpand, innerSelect, json);
|
||||
writeEntity(metadata, property.getType(), navigationLink.getInlineEntity(), null,
|
||||
innerExpand, innerSelect, false, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -316,6 +387,11 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
} else if (property.isComplex()) {
|
||||
writeComplexValue((EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
|
||||
selectedPaths, json);
|
||||
} else if (property.isEnum()) {
|
||||
writePrimitive((EdmPrimitiveType) edmProperty.getType(), property,
|
||||
edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
|
||||
json);
|
||||
} else {
|
||||
throw new SerializerException("Property type not yet supported!",
|
||||
SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
|
||||
|
@ -467,8 +543,8 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream complex(final EdmComplexType type, final Property property,
|
||||
final ComplexSerializerOptions options) throws SerializerException {
|
||||
public InputStream complex(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final ComplexSerializerOptions options) throws SerializerException {
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
try {
|
||||
|
@ -477,11 +553,15 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
if (contextURL != null) {
|
||||
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
|
||||
}
|
||||
EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType());
|
||||
if (!resolvedType.equals(type)) {
|
||||
json.writeStringField(Constants.JSON_TYPE, "#"+property.getType());
|
||||
}
|
||||
final List<Property> values =
|
||||
property.isNull() ? Collections.<Property> emptyList() : property.asComplex().getValue();
|
||||
writeProperties(type, values, options == null ? null : options.getSelect(), json);
|
||||
if (!property.isNull() && property.isComplex()) {
|
||||
writeNavigationProperties(type, property.asComplex(),
|
||||
writeNavigationProperties(metadata, type, property.asComplex(),
|
||||
options == null ? null : options.getExpand(), json);
|
||||
}
|
||||
json.writeEndObject();
|
||||
|
@ -523,8 +603,8 @@ public class ODataJsonSerializer implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream complexCollection(final EdmComplexType type, final Property property,
|
||||
final ComplexSerializerOptions options) throws SerializerException {
|
||||
public InputStream complexCollection(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final ComplexSerializerOptions options) throws SerializerException {
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
CircleStreamBuffer buffer = new CircleStreamBuffer();
|
||||
try {
|
||||
|
|
|
@ -66,7 +66,14 @@ public final class ContextURLBuilder {
|
|||
if (contextURL.getEntitySetOrSingletonOrType() != null) {
|
||||
throw new IllegalArgumentException("ContextURL: $ref with Entity Set");
|
||||
}
|
||||
result.append('#').append(ContextURL.Suffix.REFERENCE.getRepresentation());
|
||||
if(contextURL.isCollection()) {
|
||||
result.append('#');
|
||||
result.append("Collection(")
|
||||
.append(ContextURL.Suffix.REFERENCE.getRepresentation())
|
||||
.append(")");
|
||||
} else {
|
||||
result.append('#').append(ContextURL.Suffix.REFERENCE.getRepresentation());
|
||||
}
|
||||
} else if (contextURL.getSuffix() != null) {
|
||||
if (contextURL.getEntitySetOrSingletonOrType() == null) {
|
||||
throw new IllegalArgumentException("ContextURL: Suffix without preceding Entity Set!");
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -87,14 +87,15 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream entity(final EdmEntityType entityType, final Entity entity,
|
||||
final EntitySerializerOptions options) throws SerializerException {
|
||||
public InputStream entity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final EntitySerializerOptions options) throws SerializerException {
|
||||
throw new SerializerException("Entity serialization not implemented for XML format",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream entityCollection(final EdmEntityType entityType, final EntitySet entitySet,
|
||||
public InputStream entityCollection(final ServiceMetadata metadata,
|
||||
final EdmEntityType entityType, final EntitySet entitySet,
|
||||
final EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
throw new SerializerException("Entityset serialization not implemented for XML format",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
|
@ -114,8 +115,8 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream complex(final EdmComplexType type, final Property property,
|
||||
final ComplexSerializerOptions options) throws SerializerException {
|
||||
public InputStream complex(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final ComplexSerializerOptions options) throws SerializerException {
|
||||
throw new SerializerException("Serialization not implemented for XML format.",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
|
@ -128,8 +129,8 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream complexCollection(final EdmComplexType type, final Property property,
|
||||
final ComplexSerializerOptions options) throws SerializerException {
|
||||
public InputStream complexCollection(final ServiceMetadata metadata, final EdmComplexType type,
|
||||
final Property property, final ComplexSerializerOptions options) throws SerializerException {
|
||||
throw new SerializerException("Serialization not implemented for XML format.",
|
||||
SerializerException.MessageKeys.NOT_IMPLEMENTED);
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -56,12 +56,18 @@ public class UriResourceActionImpl extends UriResourceTypedImpl implements UriRe
|
|||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
return action.getReturnType() !=null && action.getReturnType().isCollection();
|
||||
if (action.getReturnType() != null) {
|
||||
return action.getReturnType().isCollection();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmType getType() {
|
||||
return action.getReturnType() == null ? null : action.getReturnType().getType();
|
||||
if (action.getReturnType() != null) {
|
||||
return action.getReturnType().getType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -60,7 +60,7 @@ public class UriValidator {
|
|||
/* entitySetCount 7 */ { true , false, false, false, false, false, true, false, false, false, false },
|
||||
/* entity 8 */ { false, true , true , false, false, false, false, true , false, false, false },
|
||||
/* mediaStream 9 */ { false, false, false, false, false, false, false, false, false, false, false },
|
||||
/* references 10 */ { true , true , false, false, false, true , true , false, true , true , true },
|
||||
/* references 10 */ { true , true , false, true, false, true , true , false, true , true , true },
|
||||
/* reference 11 */ { false, true , false, false, false, false, false, false, false, false, false },
|
||||
/* propertyComplex 12 */ { false, true , true , false, false, false, false, true , false, false, false },
|
||||
/* propertyComplexCollection 13 */ { true , true , true , false, true , true , false, true , true , true , true },
|
||||
|
@ -78,7 +78,7 @@ public class UriValidator {
|
|||
/* GET 0 */ { true , true , true , true, true , true , true , true , true , true , true },
|
||||
/* POST 0 */ { true , false , true , false, false , true , false , true , false , false , false },
|
||||
/* PUT 0 */ { false , false , false , false, false , false , false , false , false , false , false },
|
||||
/* DELETE 0 */ { false , false , false , false, false , false, false , false, false , false , false },
|
||||
/* DELETE 0 */ { false , false , false , true, false , false, false , false, false , false , false },
|
||||
/* PATCH 0 */ { false , false , false , false, false , false , false , false , false , false , false }
|
||||
};
|
||||
//CHECKSTYLE:ON
|
||||
|
|
|
@ -96,6 +96,8 @@ SerializerException.INCONSISTENT_PROPERTY_TYPE=An inconsistency has been detecte
|
|||
SerializerException.MISSING_PROPERTY=The non-nullable property '%1$s' is missing.
|
||||
SerializerException.WRONG_PROPERTY_VALUE=The value '%2$s' is not valid for property '%1$s'.
|
||||
SerializerException.WRONG_PRIMITIVE_VALUE=The value '%2$s' is not valid for the primitive type '%1$s' and the given facets.
|
||||
SerializerException.UNKNOWN_TYPE=Type '%1s' not found in metadata.
|
||||
SerializerException.WRONG_BASE_TYPE=Type '%1s' is not derived from '%2s'.
|
||||
|
||||
DeserializerException.NOT_IMPLEMENTED=The requested deserialization method has not been implemented yet.
|
||||
DeserializerException.IO_EXCEPTION=An I/O exception occurred.
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -18,8 +18,13 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.deserializer.json;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
|
@ -41,4 +46,33 @@ public class ODataJsonDeserializerBasicTest {
|
|||
assertNotNull(deserializer);
|
||||
deserializer = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadingCollectionProperties() throws Exception {
|
||||
String payload = "{\n" +
|
||||
" \"@odata.context\": \"http://host/service/$metadata#Collection($ref)\",\n" +
|
||||
" \"value\": [\n" +
|
||||
" { \"@odata.id\": \"Orders(10643)\" },\n" +
|
||||
" { \"@odata.id\": \"Orders(10759)\" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
List<URI> values = deserializer.entityReferences(new ByteArrayInputStream(payload.getBytes()));
|
||||
assertEquals(2, values.size());
|
||||
assertEquals("Orders(10643)", values.get(0).toASCIIString());
|
||||
assertEquals("Orders(10759)", values.get(1).toASCIIString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadingProperties() throws Exception {
|
||||
String payload = "{\n" +
|
||||
" \"@odata.context\": \"http://host/service/$metadata#$ref\",\n" +
|
||||
" \"@odata.id\": \"Orders(10643)\"\n" +
|
||||
"}";
|
||||
ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
|
||||
List<URI> values = deserializer.entityReferences(new ByteArrayInputStream(payload
|
||||
.getBytes()));
|
||||
assertEquals(1, values.size());
|
||||
assertEquals("Orders(10643)", values.get(0).toASCIIString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -49,14 +49,17 @@ public class ODataJsonSerializerTest {
|
|||
final ODataJsonSerializer serializer = new ODataJsonSerializer(ODataFormat.APPLICATION_JSON);
|
||||
final ComplexSerializerOptions options = ComplexSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().selectList("ComplexCollection").build()).build();
|
||||
final InputStream in = serializer.complexCollection(ComplexTypeHelper.createType(), complexCollection, options);
|
||||
final InputStream in = serializer.complexCollection(null, ComplexTypeHelper.createType(),
|
||||
complexCollection, options);
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.contains("value")) {
|
||||
assertEquals("{\"@odata.context\":\"$metadata(ComplexCollection)\",\"value\":"
|
||||
+ "[{\"prop1\":\"test1\",\"prop2\":\"test11\"},{\"prop1\":\"test2\",\"prop2\":\"test22\"}]}", line);
|
||||
assertEquals(
|
||||
"{\"@odata.context\":\"$metadata(ComplexCollection)\",\"value\":"
|
||||
+ "[{\"prop1\":\"test1\",\"prop2\":\"test11\"},{\"prop1\":\"test2\",\"prop2\":\"test22\"}]}",
|
||||
line);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -66,8 +66,8 @@ public class TechnicalServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
ODataHttpHandler handler = odata.createHandler(serviceMetadata);
|
||||
handler.register(new TechnicalEntityProcessor(dataProvider));
|
||||
handler.register(new TechnicalPrimitiveComplexProcessor(dataProvider));
|
||||
handler.register(new TechnicalEntityProcessor(dataProvider, serviceMetadata));
|
||||
handler.register(new TechnicalPrimitiveComplexProcessor(dataProvider, serviceMetadata));
|
||||
handler.register(new TechnicalBatchProcessor(dataProvider));
|
||||
handler.process(req, resp);
|
||||
} catch (RuntimeException e) {
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -41,11 +41,14 @@ import org.apache.olingo.commons.core.data.EntityImpl;
|
|||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.commons.core.data.LinkImpl;
|
||||
import org.apache.olingo.commons.core.data.PropertyImpl;
|
||||
import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
|
||||
import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
|
||||
|
||||
|
||||
public class DataCreator {
|
||||
|
||||
private static final UUID GUID = UUID.fromString("01234567-89ab-cdef-0123-456789abcdef");
|
||||
|
||||
private static final String ctPropComp = ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString();
|
||||
private final Map<String, EntitySet> data;
|
||||
|
||||
public DataCreator() {
|
||||
|
@ -96,7 +99,9 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyInt16", i))
|
||||
.addProperty(createPrimitive("PropertyString", "Number:" + i)));
|
||||
}
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETServerSidePaging.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -106,7 +111,9 @@ public class DataCreator {
|
|||
entitySet.getEntities().add(createETKeyNavEntity(1, "I am String Property 1"));
|
||||
entitySet.getEntities().add(createETKeyNavEntity(2, "I am String Property 2"));
|
||||
entitySet.getEntities().add(createETKeyNavEntity(3, "I am String Property 3"));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETKeyNav.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -115,10 +122,12 @@ public class DataCreator {
|
|||
return new EntityImpl()
|
||||
.addProperty(createPrimitive("PropertyInt16", propertyInt16))
|
||||
.addProperty(createPrimitive("PropertyString", propertyString))
|
||||
.addProperty(createComplex("PropertyCompNav",
|
||||
.addProperty(createComplex("PropertyCompNav", ctPropComp,
|
||||
createPrimitive("PropertyInt16", 1)))
|
||||
.addProperty(createKeyNavAllPrimComplexValue("PropertyCompAllPrim"))
|
||||
.addProperty(createComplex("PropertyCompTwoPrim",
|
||||
.addProperty(
|
||||
createComplex("PropertyCompTwoPrim",
|
||||
ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
|
||||
createPrimitive("PropertyInt16", 16),
|
||||
createPrimitive("PropertyString", "Test123")))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyString",
|
||||
|
@ -126,7 +135,9 @@ public class DataCreator {
|
|||
"Employee2@company.example",
|
||||
"Employee3@company.example"))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyInt16", 1000, 2000, 30112))
|
||||
.addProperty(createComplexCollection("CollPropertyComp",
|
||||
.addProperty(
|
||||
createComplexCollection("CollPropertyComp", ComplexTypeProvider.nameCTPrimComp
|
||||
.getFullQualifiedNameAsString(),
|
||||
Arrays.asList(
|
||||
createPrimitive("PropertyInt16", 1),
|
||||
createKeyNavAllPrimComplexValue("PropertyComp")),
|
||||
|
@ -136,9 +147,11 @@ public class DataCreator {
|
|||
Arrays.asList(
|
||||
createPrimitive("PropertyInt16", 3),
|
||||
createKeyNavAllPrimComplexValue("PropertyComp"))))
|
||||
.addProperty(createComplex("PropertyCompCompNav",
|
||||
.addProperty(
|
||||
createComplex("PropertyCompCompNav",
|
||||
ComplexTypeProvider.nameCTCompComp.getFullQualifiedNameAsString(),
|
||||
createPrimitive("PropertyString", "1"),
|
||||
createComplex("PropertyComp", createPrimitive("PropertyInt16", 1))));
|
||||
createComplex("PropertyComp", ctPropComp, createPrimitive("PropertyInt16", 1))));
|
||||
}
|
||||
|
||||
private EntitySet createESTwoKeyNav() {
|
||||
|
@ -148,7 +161,9 @@ public class DataCreator {
|
|||
entitySet.getEntities().add(createESTwoKeyNavEntity(1, "2"));
|
||||
entitySet.getEntities().add(createESTwoKeyNavEntity(2, "1"));
|
||||
entitySet.getEntities().add(createESTwoKeyNavEntity(3, "1"));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETTwoKeyNav.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -157,9 +172,9 @@ public class DataCreator {
|
|||
return new EntityImpl()
|
||||
.addProperty(createPrimitive("PropertyInt16", propertyInt16))
|
||||
.addProperty(createPrimitive("PropertyString", propertyString))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 11),
|
||||
createComplex("PropertyComp",
|
||||
createComplex("PropertyComp", ctPropComp,
|
||||
createPrimitive("PropertyString", "StringValue"),
|
||||
createPrimitive("PropertyBinary", new byte[] { 1, 35, 69, 103, -119, -85, -51, -17 }),
|
||||
createPrimitive("PropertyBoolean", true),
|
||||
|
@ -175,20 +190,26 @@ public class DataCreator {
|
|||
createPrimitive("PropertyInt64", Long.MAX_VALUE),
|
||||
createPrimitive("PropertySByte", Byte.MAX_VALUE),
|
||||
createPrimitive("PropertyTimeOfDay", getTime(21, 5, 59)))))
|
||||
.addProperty(createComplex("PropertyCompNav",
|
||||
.addProperty(
|
||||
createComplex("PropertyCompNav",
|
||||
ComplexTypeProvider.nameCTCompNav.getFullQualifiedNameAsString(),
|
||||
createPrimitive("PropertyInt16", 1),
|
||||
createKeyNavAllPrimComplexValue("PropertyComp")))
|
||||
.addProperty(createComplexCollection("CollPropertyComp"))
|
||||
.addProperty(createComplexCollection("CollPropertyCompNav",
|
||||
.addProperty(createComplexCollection("CollPropertyComp", null))
|
||||
.addProperty(
|
||||
createComplexCollection("CollPropertyCompNav",
|
||||
ComplexTypeProvider.nameCTCompNav.getFullQualifiedNameAsString(),
|
||||
Arrays.asList(createPrimitive("PropertyInt16", 1))))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyString", 1, 2))
|
||||
.addProperty(createComplex("PropertyCompTwoPrim",
|
||||
.addProperty(
|
||||
createComplex("PropertyCompTwoPrim",
|
||||
ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
|
||||
createPrimitive("PropertyInt16", 11),
|
||||
createPrimitive("PropertyString", "11")));
|
||||
}
|
||||
|
||||
private Property createKeyNavAllPrimComplexValue(final String name) {
|
||||
return createComplex(name,
|
||||
return createComplex(name, ComplexTypeProvider.nameCTAllPrim.getFullQualifiedNameAsString(),
|
||||
createPrimitive("PropertyString", "First Resource - positive values"),
|
||||
createPrimitive("PropertyBinary", new byte[] { 1, 35, 69, 103, -119, -85, -51, -17 }),
|
||||
createPrimitive("PropertyBoolean", true),
|
||||
|
@ -213,8 +234,9 @@ public class DataCreator {
|
|||
|
||||
entitySet.getEntities().add(new EntityImpl()
|
||||
.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
createComplexCollection("CollPropertyComp",
|
||||
.addProperty(createComplex("PropertyComp", null,
|
||||
createComplexCollection("CollPropertyComp", ComplexTypeProvider.nameCTTwoPrim
|
||||
.getFullQualifiedNameAsString(),
|
||||
Arrays.asList(
|
||||
createPrimitive("PropertyInt16", 555),
|
||||
createPrimitive("PropertyString", "1 Test Complex in Complex Property")),
|
||||
|
@ -227,8 +249,9 @@ public class DataCreator {
|
|||
|
||||
entitySet.getEntities().add(new EntityImpl()
|
||||
.addProperty(createPrimitive("PropertyInt16", 12345))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
createComplexCollection("CollPropertyComp",
|
||||
.addProperty(createComplex("PropertyComp",null,
|
||||
createComplexCollection("CollPropertyComp", ComplexTypeProvider.nameCTTwoPrim
|
||||
.getFullQualifiedNameAsString(),
|
||||
Arrays.asList(
|
||||
createPrimitive("PropertyInt16", 888),
|
||||
createPrimitive("PropertyString", "11 Test Complex in Complex Property")),
|
||||
|
@ -238,7 +261,9 @@ public class DataCreator {
|
|||
Arrays.asList(
|
||||
createPrimitive("PropertyInt16", 0),
|
||||
createPrimitive("PropertyString", "13 Test Complex in Complex Property"))))));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETCompCollComp.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -260,7 +285,9 @@ public class DataCreator {
|
|||
entitySet.getEntities().add(new EntityImpl()
|
||||
.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
|
||||
.addProperty(createPrimitive("PropertyString", "Test String4")));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETTwoPrim.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -322,7 +349,9 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyDuration", 0))
|
||||
.addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789cccddd")))
|
||||
.addProperty(createPrimitive("PropertyTimeOfDay", getTime(0, 1, 1))));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETAllPrim.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -331,7 +360,7 @@ public class DataCreator {
|
|||
|
||||
Entity entity = new EntityImpl();
|
||||
entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE));
|
||||
entity.addProperty(createComplex("PropertyComp",
|
||||
entity.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyString", "First Resource - first"),
|
||||
createPrimitive("PropertyBinary",
|
||||
new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }),
|
||||
|
@ -353,7 +382,7 @@ public class DataCreator {
|
|||
|
||||
entity = new EntityImpl();
|
||||
entity.addProperty(createPrimitive("PropertyInt16", 7));
|
||||
entity.addProperty(createComplex("PropertyComp",
|
||||
entity.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyString", "Second Resource - second"),
|
||||
createPrimitive("PropertyBinary",
|
||||
new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }),
|
||||
|
@ -375,7 +404,7 @@ public class DataCreator {
|
|||
|
||||
entity = new EntityImpl();
|
||||
entity.addProperty(createPrimitive("PropertyInt16", 0));
|
||||
entity.addProperty(createComplex("PropertyComp",
|
||||
entity.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyString", "Third Resource - third"),
|
||||
createPrimitive("PropertyBinary",
|
||||
new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }),
|
||||
|
@ -394,7 +423,9 @@ public class DataCreator {
|
|||
createPrimitive("PropertySByte", Byte.MAX_VALUE),
|
||||
createPrimitive("PropertyTimeOfDay", getTime(13, 27, 45))));
|
||||
entitySet.getEntities().add(entity);
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETCompAllPrim.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -444,13 +475,15 @@ public class DataCreator {
|
|||
entity.getProperties().addAll(entitySet.getEntities().get(0).getProperties());
|
||||
entity.getProperties().set(0, createPrimitive("PropertyInt16", 3));
|
||||
entitySet.getEntities().add(entity);
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETCollAllPrim.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
private EntitySet createESMixPrimCollComp() {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Property complexCollection = createComplexCollection("CollPropertyComp",
|
||||
final Property complexCollection = createComplexCollection("CollPropertyComp", ctPropComp,
|
||||
Arrays.asList(createPrimitive("PropertyInt16", 123), createPrimitive("PropertyString", "TEST 1")),
|
||||
Arrays.asList(createPrimitive("PropertyInt16", 456), createPrimitive("PropertyString", "TEST 2")),
|
||||
Arrays.asList(createPrimitive("PropertyInt16", 789), createPrimitive("PropertyString", "TEST 3")));
|
||||
|
@ -461,7 +494,7 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyString",
|
||||
"Employee1@company.example", "Employee2@company.example", "Employee3@company.example"))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 111),
|
||||
createPrimitive("PropertyString", "TEST A")))
|
||||
.addProperty(complexCollection));
|
||||
|
@ -470,7 +503,7 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyInt16", 7))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyString",
|
||||
"Employee1@company.example", "Employee2@company.example", "Employee3@company.example"))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 222),
|
||||
createPrimitive("PropertyString", "TEST B")))
|
||||
.addProperty(complexCollection));
|
||||
|
@ -479,11 +512,13 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyInt16", 0))
|
||||
.addProperty(createPrimitiveCollection("CollPropertyString",
|
||||
"Employee1@company.example", "Employee2@company.example", "Employee3@company.example"))
|
||||
.addProperty(createComplex("PropertyComp",
|
||||
.addProperty(createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 333),
|
||||
createPrimitive("PropertyString", "TEST C")))
|
||||
.addProperty(complexCollection));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETMixPrimCollComp.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -519,7 +554,9 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive("PropertyDuration", 6))
|
||||
.addProperty(createPrimitive("PropertyGuid", GUID))
|
||||
.addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 21))));
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETAllKey.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -528,20 +565,22 @@ public class DataCreator {
|
|||
|
||||
Entity entity = new EntityImpl();
|
||||
entity.addProperty(createPrimitive("PropertyInt16", 1));
|
||||
entity.addProperty(createComplex("PropertyComp",
|
||||
createComplex("PropertyComp",
|
||||
entity.addProperty(createComplex("PropertyComp", null,
|
||||
createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 123),
|
||||
createPrimitive("PropertyString", "String 1"))));
|
||||
entitySet.getEntities().add(entity);
|
||||
|
||||
entity = new EntityImpl();
|
||||
entity.addProperty(createPrimitive("PropertyInt16", 2));
|
||||
entity.addProperty(createComplex("PropertyComp",
|
||||
createComplex("PropertyComp",
|
||||
entity.addProperty(createComplex("PropertyComp", null,
|
||||
createComplex("PropertyComp",ctPropComp,
|
||||
createPrimitive("PropertyInt16", 987),
|
||||
createPrimitive("PropertyString", "String 2"))));
|
||||
entitySet.getEntities().add(entity);
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETCompComp.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -571,7 +610,9 @@ public class DataCreator {
|
|||
.addProperty(createPrimitive(DataProvider.MEDIA_PROPERTY_NAME, createImage("black")));
|
||||
entity.setMediaContentType("image/svg+xml");
|
||||
entitySet.getEntities().add(entity);
|
||||
|
||||
for (Entity en:entitySet.getEntities()) {
|
||||
en.setType(EntityTypeProvider.nameETMedia.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -677,22 +718,23 @@ public class DataCreator {
|
|||
return new PropertyImpl(null, name, ValueType.COLLECTION_PRIMITIVE, Arrays.asList(values));
|
||||
}
|
||||
|
||||
protected static Property createComplex(final String name, final Property... properties) {
|
||||
protected static Property createComplex(final String name, String type, final Property... properties) {
|
||||
ComplexValue complexValue = new ComplexValueImpl();
|
||||
for (final Property property : properties) {
|
||||
complexValue.getValue().add(property);
|
||||
}
|
||||
return new PropertyImpl(null, name, ValueType.COMPLEX, complexValue);
|
||||
return new PropertyImpl(type, name, ValueType.COMPLEX, complexValue);
|
||||
}
|
||||
|
||||
protected static Property createComplexCollection(final String name, final List<Property>... propertiesList) {
|
||||
protected static Property createComplexCollection(final String name, String type,
|
||||
final List<Property>... propertiesList) {
|
||||
List<ComplexValue> complexCollection = new ArrayList<ComplexValue>();
|
||||
for (final List<Property> properties : propertiesList) {
|
||||
ComplexValue complexValue = new ComplexValueImpl();
|
||||
complexValue.getValue().addAll(properties);
|
||||
complexCollection.add(complexValue);
|
||||
}
|
||||
return new PropertyImpl(null, name, ValueType.COLLECTION_COMPLEX, complexCollection);
|
||||
return new PropertyImpl(type, name, ValueType.COLLECTION_COMPLEX, complexCollection);
|
||||
}
|
||||
|
||||
private Calendar getDateTime(final int year, final int month, final int day,
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -138,7 +138,7 @@ public class DataProvider {
|
|||
final List<Entity> entities = entitySet.getEntities();
|
||||
final Map<String, Object> newKey = findFreeComposedKey(entities, edmEntitySet.getEntityType());
|
||||
final Entity newEntity = new EntityImpl();
|
||||
|
||||
newEntity.setType(edmEntityType.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
for (final String keyName : edmEntityType.getKeyPredicateNames()) {
|
||||
newEntity.addProperty(DataCreator.createPrimitive(keyName, newKey.get(keyName)));
|
||||
}
|
||||
|
@ -194,7 +194,8 @@ public class DataProvider {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void createProperties(final EdmStructuredType type, List<Property> properties) throws DataProviderException {
|
||||
private void createProperties(final EdmStructuredType type, List<Property> properties)
|
||||
throws DataProviderException {
|
||||
final List<String> keyNames = type instanceof EdmEntityType ?
|
||||
((EdmEntityType) type).getKeyPredicateNames() : Collections.<String> emptyList();
|
||||
for (final String propertyName : type.getPropertyNames()) {
|
||||
|
@ -204,11 +205,11 @@ public class DataProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property createProperty(final EdmProperty edmProperty, final String propertyName)
|
||||
|
||||
private Property createProperty(final EdmProperty edmProperty, final String propertyName)
|
||||
throws DataProviderException {
|
||||
Property newProperty;
|
||||
|
||||
|
||||
if (edmProperty.isPrimitive()) {
|
||||
newProperty = edmProperty.isCollection() ?
|
||||
DataCreator.createPrimitiveCollection(propertyName) :
|
||||
|
@ -216,17 +217,19 @@ public class DataProvider {
|
|||
} else {
|
||||
if (edmProperty.isCollection()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Property newProperty2 = DataCreator.createComplexCollection(propertyName);
|
||||
Property newProperty2 = DataCreator.createComplexCollection(propertyName, edmProperty
|
||||
.getType().getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
newProperty = newProperty2;
|
||||
} else {
|
||||
newProperty = DataCreator.createComplex(propertyName);
|
||||
newProperty = DataCreator.createComplex(propertyName, edmProperty.getType()
|
||||
.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
createProperties((EdmComplexType) edmProperty.getType(), newProperty.asComplex().getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return newProperty;
|
||||
}
|
||||
|
||||
|
||||
public void update(final String rawBaseUri, final EdmEntitySet edmEntitySet, Entity entity,
|
||||
final Entity changedEntity, final boolean patch, final boolean isInsert) throws DataProviderException {
|
||||
|
||||
|
@ -433,7 +436,7 @@ public class DataProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private ComplexValue createComplexValue(final EdmProperty edmProperty, final ComplexValue complexValue,
|
||||
private ComplexValue createComplexValue(final EdmProperty edmProperty, final ComplexValue complexValue,
|
||||
final boolean patch) throws DataProviderException {
|
||||
final ComplexValueImpl result = new ComplexValueImpl();
|
||||
final EdmComplexType edmType = (EdmComplexType) edmProperty.getType();
|
||||
|
@ -445,7 +448,7 @@ public class DataProvider {
|
|||
final Property currentProperty = findProperty(propertyName, givenProperties);
|
||||
final Property newProperty = createProperty(innerEdmProperty, propertyName);
|
||||
result.getValue().add(newProperty);
|
||||
|
||||
|
||||
if (currentProperty != null) {
|
||||
updateProperty(innerEdmProperty, newProperty, currentProperty, patch);
|
||||
} else {
|
||||
|
@ -459,7 +462,7 @@ public class DataProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.apache.olingo.commons.core.data.EntitySetImpl;
|
|||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException;
|
||||
import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
|
||||
|
||||
public class FunctionData {
|
||||
|
||||
|
@ -80,12 +81,12 @@ public class FunctionData {
|
|||
} else if (name.equals("UFCRTCollString")) {
|
||||
return data.get("ESCollAllPrim").getEntities().get(0).getProperty("CollPropertyString");
|
||||
} else if (name.equals("UFCRTCTTwoPrim")) {
|
||||
return DataCreator.createComplex(name,
|
||||
return DataCreator.createComplex(name, ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
|
||||
DataCreator.createPrimitive("PropertyInt16", 16),
|
||||
DataCreator.createPrimitive("PropertyString", "UFCRTCTTwoPrim string value"));
|
||||
} else if (name.equals("UFCRTCTTwoPrimParam")) {
|
||||
try {
|
||||
return DataCreator.createComplex(name,
|
||||
return DataCreator.createComplex(name,ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
|
||||
DataCreator.createPrimitive("PropertyInt16",
|
||||
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16).valueOfString(
|
||||
getParameterText("ParameterInt16", parameters),
|
||||
|
@ -99,7 +100,7 @@ public class FunctionData {
|
|||
throw new DataProviderException("Error in function " + name + ".", e);
|
||||
}
|
||||
} else if (name.equals("UFCRTCollCTTwoPrim")) {
|
||||
return DataCreator.createComplexCollection(name,
|
||||
return DataCreator.createComplexCollection(name,ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
|
||||
Arrays.asList(DataCreator.createPrimitive("PropertyInt16", 16),
|
||||
DataCreator.createPrimitive("PropertyString", "Test123")),
|
||||
Arrays.asList(DataCreator.createPrimitive("PropertyInt16", 17),
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -38,6 +38,7 @@ import org.apache.olingo.commons.core.data.EntitySetImpl;
|
|||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
|
||||
import org.apache.olingo.server.api.processor.ActionEntityCollectionProcessor;
|
||||
|
@ -74,8 +75,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
EntityProcessor, ActionEntityProcessor, MediaEntityProcessor,
|
||||
ActionVoidProcessor {
|
||||
|
||||
public TechnicalEntityProcessor(final DataProvider dataProvider) {
|
||||
private final ServiceMetadata serviceMetadata;
|
||||
|
||||
public TechnicalEntityProcessor(final DataProvider dataProvider, ServiceMetadata serviceMetadata) {
|
||||
super(dataProvider);
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,21 +113,24 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
entitySet,
|
||||
edmEntitySet,
|
||||
request.getRawRequestUri());
|
||||
|
||||
|
||||
// Apply expand system query option
|
||||
final ODataFormat format = ODataFormat.fromContentType(requestedContentType);
|
||||
ODataSerializer serializer = odata.createSerializer(format);
|
||||
final ExpandOption expand = uriInfo.getExpandOption();
|
||||
final SelectOption select = uriInfo.getSelectOption();
|
||||
|
||||
|
||||
// Create a shallow copy of each entity. So the expanded navigation properties can be modified for serialization,
|
||||
// without affecting the data stored in the database.
|
||||
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
|
||||
final EntitySet entitySetSerialization = expandHandler.copyEntitySetShallowRekursive(entitySet);
|
||||
expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand);
|
||||
|
||||
|
||||
// Serialize
|
||||
response.setContent(serializer.entityCollection(edmEntityType, entitySetSerialization,
|
||||
response.setContent(serializer.entityCollection(
|
||||
this.serviceMetadata,
|
||||
edmEntityType,
|
||||
entitySetSerialization,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, edmEntityType, false, expand, select))
|
||||
|
@ -170,17 +177,20 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
edmEntitySet.getEntityType();
|
||||
|
||||
final Entity entity = readEntity(uriInfo);
|
||||
|
||||
|
||||
final ODataFormat format = ODataFormat.fromContentType(requestedContentType);
|
||||
ODataSerializer serializer = odata.createSerializer(format);
|
||||
final ExpandOption expand = uriInfo.getExpandOption();
|
||||
final SelectOption select = uriInfo.getSelectOption();
|
||||
|
||||
|
||||
final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
|
||||
final Entity entitySerialization = expandHandler.copyEntityShallowRekursive(entity);
|
||||
expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand);
|
||||
|
||||
response.setContent(serializer.entity(edmEntitySet.getEntityType(), entitySerialization,
|
||||
|
||||
response.setContent(serializer.entity(
|
||||
this.serviceMetadata,
|
||||
edmEntitySet.getEntityType(),
|
||||
entitySerialization,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, edmEntityType, true, expand, select))
|
||||
|
@ -233,7 +243,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
|
||||
final ODataFormat format = ODataFormat.fromContentType(responseFormat);
|
||||
ODataSerializer serializer = odata.createSerializer(format);
|
||||
response.setContent(serializer.entity(edmEntityType, entity,
|
||||
response.setContent(serializer.entity(this.serviceMetadata, edmEntityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, edmEntityType, true, null, null))
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -44,6 +44,7 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
|||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor;
|
||||
import org.apache.olingo.server.api.processor.ActionComplexProcessor;
|
||||
|
@ -81,8 +82,12 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
|
|||
ComplexProcessor, ActionComplexProcessor,
|
||||
ComplexCollectionProcessor, ActionComplexCollectionProcessor {
|
||||
|
||||
public TechnicalPrimitiveComplexProcessor(final DataProvider dataProvider) {
|
||||
private final ServiceMetadata serviceMetadata;
|
||||
|
||||
public TechnicalPrimitiveComplexProcessor(final DataProvider dataProvider,
|
||||
ServiceMetadata serviceMetadata) {
|
||||
super(dataProvider);
|
||||
this.serviceMetadata = serviceMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,7 +251,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
|
|||
.build()));
|
||||
break;
|
||||
case COMPLEX:
|
||||
response.setContent(serializer.complex((EdmComplexType) type, property,
|
||||
response.setContent(serializer.complex(this.serviceMetadata,(EdmComplexType) type, property,
|
||||
ComplexSerializerOptions.with().contextURL(contextURL)
|
||||
.expand(expand).select(select)
|
||||
.build()));
|
||||
|
@ -262,7 +267,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
|
|||
.build()));
|
||||
break;
|
||||
case COLLECTION_COMPLEX:
|
||||
response.setContent(serializer.complexCollection((EdmComplexType) type, property,
|
||||
response.setContent(serializer.complexCollection(this.serviceMetadata, (EdmComplexType) type, property,
|
||||
ComplexSerializerOptions.with().contextURL(contextURL)
|
||||
.expand(expand).select(select)
|
||||
.build()));
|
||||
|
|
|
@ -22,9 +22,9 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
|
|
@ -41,11 +41,12 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
|||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.core.data.PropertyImpl;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ServiceMetadata;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ODataSerializer;
|
||||
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
|
@ -64,9 +65,9 @@ import org.junit.Test;
|
|||
import org.mockito.Mockito;
|
||||
|
||||
public class ODataJsonSerializerTest {
|
||||
|
||||
private static final Edm edm = OData.newInstance().createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
private static final ServiceMetadata metadata = OData.newInstance().createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList());
|
||||
private static final Edm edm = metadata.getEdm();
|
||||
private static final EdmEntityContainer entityContainer = edm.getEntityContainer(
|
||||
new FullQualifiedName("olingo.odata.test1", "Container"));
|
||||
private final DataProvider data = new DataProvider();
|
||||
|
@ -77,7 +78,7 @@ public class ODataJsonSerializerTest {
|
|||
public void entitySimple() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build());
|
||||
|
@ -109,7 +110,8 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
|
||||
final String resultString = IOUtils.toString(serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(),
|
||||
entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build()));
|
||||
|
@ -130,7 +132,7 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
entity.getProperties().clear();
|
||||
serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build());
|
||||
|
@ -142,7 +144,7 @@ public class ODataJsonSerializerTest {
|
|||
Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
entity.getProperties().get(0).setValue(ValueType.PRIMITIVE, false);
|
||||
try {
|
||||
serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build());
|
||||
|
@ -163,7 +165,7 @@ public class ODataJsonSerializerTest {
|
|||
entitySet.setNext(URI.create("/next"));
|
||||
CountOption countOption = Mockito.mock(CountOption.class);
|
||||
Mockito.when(countOption.getValue()).thenReturn(true);
|
||||
InputStream result = serializer.entityCollection(edmEntitySet.getEntityType(), entitySet,
|
||||
InputStream result = serializer.entityCollection(metadata, edmEntitySet.getEntityType(), entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.count(countOption)
|
||||
|
@ -188,7 +190,7 @@ public class ODataJsonSerializerTest {
|
|||
public void entityCollAllPrim() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().serviceRoot(URI.create("http://host/service/"))
|
||||
.entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
|
@ -224,7 +226,7 @@ public class ODataJsonSerializerTest {
|
|||
public void entityCompAllPrim() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompAllPrim");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build());
|
||||
|
@ -257,7 +259,7 @@ public class ODataJsonSerializerTest {
|
|||
public void entityMixPrimCollComp() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build());
|
||||
|
@ -280,7 +282,7 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
|
||||
Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
|
||||
final String resultString = IOUtils.toString(serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build()));
|
||||
|
@ -295,7 +297,7 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim");
|
||||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
|
||||
.entity(edmEntitySet.getEntityType(), entity, null);
|
||||
.entity(metadata, edmEntitySet.getEntityType(), entity, null);
|
||||
final String resultString = IOUtils.toString(result);
|
||||
final String expectedResult = "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
|
||||
Assert.assertEquals(expectedResult, resultString);
|
||||
|
@ -306,7 +308,7 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESTwoPrim");
|
||||
final EntitySet entitySet = data.readAll(edmEntitySet);
|
||||
InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
|
||||
.entityCollection(edmEntitySet.getEntityType(), entitySet,
|
||||
.entityCollection(metadata, edmEntitySet.getEntityType(), entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build());
|
||||
final String resultString = IOUtils.toString(result);
|
||||
|
@ -323,7 +325,8 @@ public class ODataJsonSerializerTest {
|
|||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
|
||||
Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||
entity.setMediaETag("theMediaETag");
|
||||
final String resultString = IOUtils.toString(serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(),
|
||||
entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.build()));
|
||||
|
@ -337,7 +340,8 @@ public class ODataJsonSerializerTest {
|
|||
public void entitySetMedia() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
|
||||
final EntitySet entitySet = data.readAll(edmEntitySet);
|
||||
final String resultString = IOUtils.toString(serializer.entityCollection(edmEntitySet.getEntityType(), entitySet,
|
||||
final String resultString = IOUtils.toString(serializer.entityCollection(metadata,
|
||||
edmEntitySet.getEntityType(), entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build()).build()));
|
||||
final String expectedResult = "{\"@odata.context\":\"$metadata#ESMedia\",\"value\":["
|
||||
|
@ -358,7 +362,7 @@ public class ODataJsonSerializerTest {
|
|||
final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
|
||||
selectItem1, selectItem2, selectItem2));
|
||||
InputStream result = serializer
|
||||
.entity(entityType, entity,
|
||||
.entity(metadata, entityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, null, select))
|
||||
|
@ -380,7 +384,7 @@ public class ODataJsonSerializerTest {
|
|||
SelectItem selectItem2 = Mockito.mock(SelectItem.class);
|
||||
Mockito.when(selectItem2.isStar()).thenReturn(true);
|
||||
final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(selectItem1, selectItem2));
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.select(select)
|
||||
|
@ -399,7 +403,7 @@ public class ODataJsonSerializerTest {
|
|||
final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
|
||||
ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString")));
|
||||
InputStream result = serializer
|
||||
.entityCollection(entityType, entitySet,
|
||||
.entityCollection(metadata, entityType, entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, null, select))
|
||||
|
@ -424,7 +428,7 @@ public class ODataJsonSerializerTest {
|
|||
ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString"),
|
||||
ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp")));
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.entityCollection(entityType, entitySet,
|
||||
.entityCollection(metadata, entityType, entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, null, select))
|
||||
|
@ -445,7 +449,7 @@ public class ODataJsonSerializerTest {
|
|||
final Entity entity = data.readAll(edmEntitySet).getEntities().get(3);
|
||||
final ExpandOption expand = ExpandSelectMock.mockExpandOption(Arrays.asList(
|
||||
ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
|
||||
InputStream result = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||
.expand(expand)
|
||||
|
@ -484,7 +488,7 @@ public class ODataJsonSerializerTest {
|
|||
Mockito.when(expandItem.getSelectOption()).thenReturn(select);
|
||||
final ExpandOption expand = ExpandSelectMock.mockExpandOption(Arrays.asList(expandItem));
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.entity(entityType, entity,
|
||||
.entity(metadata, entityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, expand, select))
|
||||
|
@ -511,7 +515,7 @@ public class ODataJsonSerializerTest {
|
|||
final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
|
||||
ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertySByte")));
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.entity(entityType, entity,
|
||||
.entity(metadata, entityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, expand, select))
|
||||
|
@ -538,7 +542,7 @@ public class ODataJsonSerializerTest {
|
|||
final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
|
||||
ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyTimeOfDay")));
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.entity(entityType, entity,
|
||||
.entity(metadata, entityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, expand, select))
|
||||
|
@ -569,7 +573,7 @@ public class ODataJsonSerializerTest {
|
|||
Mockito.when(expandItemFirst.getSelectOption()).thenReturn(select);
|
||||
final ExpandOption expand = ExpandSelectMock.mockExpandOption(Arrays.asList(expandItemFirst));
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.entity(entityType, entity,
|
||||
.entity(metadata, entityType, entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet)
|
||||
.selectList(helper.buildContextURLSelectList(entityType, expand, select))
|
||||
|
@ -646,7 +650,7 @@ public class ODataJsonSerializerTest {
|
|||
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty("PropertyComp");
|
||||
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.complex((EdmComplexType) edmProperty.getType(), property,
|
||||
.complex(metadata, (EdmComplexType) edmProperty.getType(), property,
|
||||
ComplexSerializerOptions.with()
|
||||
.contextURL(ContextURL.with()
|
||||
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
|
||||
|
@ -665,7 +669,7 @@ public class ODataJsonSerializerTest {
|
|||
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
|
||||
|
||||
final String resultString = IOUtils.toString(serializer
|
||||
.complexCollection((EdmComplexType) edmProperty.getType(), property,
|
||||
.complexCollection(metadata, (EdmComplexType) edmProperty.getType(), property,
|
||||
ComplexSerializerOptions.with()
|
||||
.contextURL(ContextURL.with()
|
||||
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -1064,13 +1064,16 @@ public class TestUriParserImpl {
|
|||
public void testAlias() throws Exception {
|
||||
testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1)")
|
||||
.goFilter().is("<<PropertyInt16> eq <@p1>>");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLambda() throws Exception {
|
||||
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( l : true )")
|
||||
.goFilter().is("<CollPropertyComp/<ALL;<true>>>");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( x : x/PropertyInt16 eq 2)")
|
||||
.goFilter().is("<CollPropertyComp/<ALL;<<x/PropertyInt16> eq <2>>>>");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( l : true )")
|
||||
.goFilter().is("<CollPropertyComp/<ANY;<true>>>");
|
||||
testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( )")
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.uri.validator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.commons.core.edm.provider.EdmProviderImpl;
|
||||
|
@ -31,9 +34,6 @@ import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
|
|||
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class UriValidatorTest {
|
||||
|
||||
private static final String URI_ALL = "$all";
|
||||
|
@ -77,7 +77,7 @@ public class UriValidatorTest {
|
|||
private static final String QO_SKIPTOKEN = "$skiptoken=123";
|
||||
private static final String QO_TOP = "$top=1";
|
||||
|
||||
private String[][] urisWithValidSystemQueryOptions = {
|
||||
private final String[][] urisWithValidSystemQueryOptions = {
|
||||
{ URI_ALL, QO_FILTER }, { URI_ALL, QO_FORMAT }, { URI_ALL, QO_EXPAND }, { URI_ALL, QO_COUNT },
|
||||
{ URI_ALL, QO_ORDERBY }, /* { URI_ALL, QO_SEARCH }, */{ URI_ALL, QO_SELECT }, { URI_ALL, QO_SKIP },
|
||||
{ URI_ALL, QO_SKIPTOKEN }, { URI_ALL, QO_TOP },
|
||||
|
@ -105,7 +105,7 @@ public class UriValidatorTest {
|
|||
|
||||
{ URI_REFERENCES, QO_FILTER }, { URI_REFERENCES, QO_FORMAT }, { URI_REFERENCES, QO_ORDERBY },
|
||||
/* { URI_REFERENCES, QO_SEARCH }, */{ URI_REFERENCES, QO_SKIP }, { URI_REFERENCES, QO_SKIPTOKEN },
|
||||
{ URI_REFERENCES, QO_TOP },
|
||||
{ URI_REFERENCES, QO_TOP }, { URI_REFERENCES, QO_ID },
|
||||
|
||||
{ URI_REFERENCE, QO_FORMAT },
|
||||
|
||||
|
@ -160,7 +160,7 @@ public class UriValidatorTest {
|
|||
{ ContainerProvider.AIRT_STRING }
|
||||
};
|
||||
|
||||
private String[][] urisWithNonValidSystemQueryOptions = {
|
||||
private final String[][] urisWithNonValidSystemQueryOptions = {
|
||||
{ URI_ALL, QO_ID },
|
||||
|
||||
{ URI_BATCH, QO_FILTER }, { URI_BATCH, QO_FORMAT }, { URI_BATCH, QO_ID }, { URI_BATCH, QO_EXPAND },
|
||||
|
@ -199,7 +199,7 @@ public class UriValidatorTest {
|
|||
/* { URI_MEDIA_STREAM, QO_SEARCH }, */ { URI_MEDIA_STREAM, QO_SELECT }, { URI_MEDIA_STREAM, QO_SKIP },
|
||||
{ URI_MEDIA_STREAM, QO_SKIPTOKEN }, { URI_MEDIA_STREAM, QO_TOP },
|
||||
|
||||
{ URI_REFERENCES, QO_ID }, { URI_REFERENCES, QO_EXPAND }, { URI_REFERENCES, QO_COUNT },
|
||||
{ URI_REFERENCES, QO_EXPAND }, { URI_REFERENCES, QO_COUNT },
|
||||
{ URI_REFERENCES, QO_SELECT },
|
||||
|
||||
{ URI_REFERENCE, QO_FILTER }, { URI_REFERENCE, QO_ID }, { URI_REFERENCE, QO_EXPAND },
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -37,10 +37,11 @@ import org.apache.olingo.commons.core.data.EntityImpl;
|
|||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.commons.core.data.PropertyImpl;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.sample.edmprovider.CarsEdmProvider;
|
||||
|
||||
public class DataProvider {
|
||||
|
||||
private Map<String, EntitySet> data;
|
||||
private final Map<String, EntitySet> data;
|
||||
|
||||
public DataProvider() {
|
||||
data = new HashMap<String, EntitySet>();
|
||||
|
@ -133,6 +134,9 @@ public class DataProvider {
|
|||
.addProperty(createPrimitive("Price", 167189.00))
|
||||
.addProperty(createPrimitive("Currency", "EUR")));
|
||||
|
||||
for (Entity entity:entitySet.getEntities()) {
|
||||
entity.setType(CarsEdmProvider.ET_CAR.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
@ -149,6 +153,9 @@ public class DataProvider {
|
|||
.addProperty(createPrimitive("Name", "Horse Powered Racing"))
|
||||
.addProperty(createAddress("Horse Street 1", "Maranello", "41053", "Italy")));
|
||||
|
||||
for (Entity entity:entitySet.getEntities()) {
|
||||
entity.setType(CarsEdmProvider.ET_MANUFACTURER.getFullQualifiedNameAsString());
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* 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
|
||||
|
@ -74,7 +74,8 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
PrimitiveProcessor, PrimitiveValueProcessor, ComplexProcessor {
|
||||
|
||||
private OData odata;
|
||||
private DataProvider dataProvider;
|
||||
private final DataProvider dataProvider;
|
||||
private ServiceMetadata edm;
|
||||
|
||||
// This constructor is application specific and not mandatory for the Olingo library. We use it here to simulate the
|
||||
// database access
|
||||
|
@ -85,6 +86,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
@Override
|
||||
public void init(OData odata, ServiceMetadata edm) {
|
||||
this.odata = odata;
|
||||
this.edm = edm;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +107,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
// Now the content is serialized using the serializer.
|
||||
final ExpandOption expand = uriInfo.getExpandOption();
|
||||
final SelectOption select = uriInfo.getSelectOption();
|
||||
InputStream serializedContent = serializer.entityCollection(edmEntitySet.getEntityType(), entitySet,
|
||||
InputStream serializedContent = serializer.entityCollection(edm, edmEntitySet.getEntityType(), entitySet,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, false, expand, select, null))
|
||||
|
@ -143,7 +145,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
ODataSerializer serializer = odata.createSerializer(format);
|
||||
final ExpandOption expand = uriInfo.getExpandOption();
|
||||
final SelectOption select = uriInfo.getSelectOption();
|
||||
InputStream serializedContent = serializer.entity(edmEntitySet.getEntityType(), entity,
|
||||
InputStream serializedContent = serializer.entity(edm, edmEntitySet.getEntityType(), entity,
|
||||
EntitySerializerOptions.with()
|
||||
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, true, expand, select, null))
|
||||
|
@ -256,7 +258,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null :
|
||||
getContextUrl(edmEntitySet, true, null, null, edmProperty.getName());
|
||||
InputStream serializerContent = complex ?
|
||||
serializer.complex((EdmComplexType) edmProperty.getType(), property,
|
||||
serializer.complex(edm, (EdmComplexType) edmProperty.getType(), property,
|
||||
ComplexSerializerOptions.with().contextURL(contextURL).build()) :
|
||||
serializer.primitive((EdmPrimitiveType) edmProperty.getType(), property,
|
||||
PrimitiveSerializerOptions.with()
|
||||
|
@ -273,7 +275,7 @@ public class CarsProcessor implements EntityCollectionProcessor, EntityProcessor
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Entity readEntityInternal(final UriInfoResource uriInfo, final EdmEntitySet entitySet)
|
||||
throws DataProvider.DataProviderException {
|
||||
// This method will extract the key values and pass them to the data provider
|
||||
|
|
Loading…
Reference in New Issue