OLINGO-573: New processing framework on server side with single interface with TripPin as example

This commit is contained in:
Ramesh Reddy 2015-03-30 12:40:32 -05:00
parent 3e8c50646e
commit 2b73abcce0
80 changed files with 10821 additions and 229 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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>

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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() {

117
lib/server-core-ext/pom.xml Normal file
View File

@ -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>

View File

@ -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());
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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) {
}
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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()));
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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());
}
});
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
};
}
}

View File

@ -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

View File

@ -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"
}
]
}

View File

@ -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"
}
}
}
}
}
]
}

View File

@ -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"
}
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"]
}
]
}

View File

@ -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
}
]
}

View File

@ -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"
}
]
}

View File

@ -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]
}
]
}

View File

@ -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"
}
]
}

View File

@ -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>

View File

@ -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);
}
}
}

View File

@ -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 {

View File

@ -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!");

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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,

View File

@ -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;
}

View File

@ -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),

View File

@ -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))

View File

@ -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()));

View File

@ -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;

View File

@ -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

View File

@ -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())

View File

@ -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( )")

View File

@ -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 },

View File

@ -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;
}

View File

@ -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