Repository: olingo-odata2 Updated Branches: refs/heads/ProtocolBufferPrototype [created] 62bc99e37
Prototype: Protocol Buffer Support Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/62bc99e3 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/62bc99e3 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/62bc99e3 Branch: refs/heads/ProtocolBufferPrototype Commit: 62bc99e37a209c35f58fb91c7a2bd58f7f8b9bf6 Parents: f86e307 Author: Tamara Boehm <[email protected]> Authored: Tue Jun 24 13:20:51 2014 +0200 Committer: Tamara Boehm <[email protected]> Committed: Tue Jun 24 13:20:51 2014 +0200 ---------------------------------------------------------------------- odata2-lib/odata-ref/pom.xml | 100 +++++++++----- .../odata2/ref/processor/ListsProcessor.java | 131 +++++++++++++++++++ 2 files changed, 200 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/62bc99e3/odata2-lib/odata-ref/pom.xml ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-ref/pom.xml b/odata2-lib/odata-ref/pom.xml index 84a49d5..434966f 100644 --- a/odata2-lib/odata-ref/pom.xml +++ b/odata2-lib/odata-ref/pom.xml @@ -1,22 +1,14 @@ <?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. ---> +<!-- 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> @@ -69,6 +61,47 @@ </instructions> </configuration> </plugin> + <plugin> + <groupId>de.softwareforge.mojo</groupId> + <artifactId>maven-protoc-plugin</artifactId> + <version>0.2-HPS-2</version> + <executions> + <execution> + <id>generate-sources</id> + <goals> + <goal>compile</goal> + </goals> + <phase>generate-sources</phase> + <configuration> + <protoSourceRoot>${basedir}/src/main/resources/</protoSourceRoot> + <includes> + <param>**/*.proto</param> + </includes> + </configuration> + </execution> + </executions> + <configuration> + <protocExecutable>/usr/local/bin/protoc</protocExecutable> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>add-source</id> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${project.build.directory}/generated-sources/java/</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> </plugins> </build> @@ -84,7 +117,7 @@ <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> - + <dependency> <groupId>org.apache.olingo</groupId> <artifactId>olingo-odata2-core</artifactId> @@ -97,18 +130,23 @@ <version>${project.version}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-all</artifactId> - <version>${mockito.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>${junit.version}</version> - <scope>test</scope> - </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>${mockito.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <version>2.5.0</version> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/62bc99e3/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java index 7e22a3d..e6781f3 100644 --- a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java +++ b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java @@ -18,9 +18,13 @@ ******************************************************************************/ package org.apache.olingo.odata2.ref.processor; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -76,9 +80,11 @@ import org.apache.olingo.odata2.api.exception.ODataHttpException; import org.apache.olingo.odata2.api.exception.ODataNotFoundException; import org.apache.olingo.odata2.api.exception.ODataNotImplementedException; import org.apache.olingo.odata2.api.processor.ODataContext; +import org.apache.olingo.odata2.api.processor.ODataProcessor; import org.apache.olingo.odata2.api.processor.ODataRequest; import org.apache.olingo.odata2.api.processor.ODataResponse; import org.apache.olingo.odata2.api.processor.ODataSingleProcessor; +import org.apache.olingo.odata2.api.processor.part.EntitySetProcessor; import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode; import org.apache.olingo.odata2.api.uri.KeyPredicate; import org.apache.olingo.odata2.api.uri.NavigationSegment; @@ -111,8 +117,15 @@ import org.apache.olingo.odata2.api.uri.info.GetMediaResourceUriInfo; import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo; import org.apache.olingo.odata2.api.uri.info.PostUriInfo; import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo; +import org.apache.olingo.odata2.core.ep.util.CircleStreamBuffer; +import org.apache.olingo.odata2.ref.model.AddressBookProtos; import org.apache.olingo.odata2.ref.processor.ScenarioDataSource.BinaryData; +import com.google.protobuf.Descriptors; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.Message; + /** * Implementation of the centralized parts of OData processing, * allowing to use the simplified DataSource for the @@ -121,10 +134,24 @@ import org.apache.olingo.odata2.ref.processor.ScenarioDataSource.BinaryData; */ public class ListsProcessor extends ODataSingleProcessor { + private static final String CUSTOM_CONTENT_TYPE = "application/x-protobuf"; // TODO: Paging size should be configurable. private static final int SERVER_PAGING_SIZE = 100; private final BeanPropertyAccess valueAccess; private final ScenarioDataSource dataSource; + private static Map<String, String> mapping; + static { + mapping = new HashMap<String, String>(); + mapping.put("org.apache.olingo.odata2.ref.model.Room", "org.apache.olingo.odata2.ref.model.AddressBookProtos$Room"); + mapping.put("org.apache.olingo.odata2.ref.model.Employee", + "org.apache.olingo.odata2.ref.model.AddressBookProtos$Employee"); + mapping.put("org.apache.olingo.odata2.ref.model.Manager", + "org.apache.olingo.odata2.ref.model.AddressBookProtos$Employee"); + mapping.put("org.apache.olingo.odata2.ref.model.Location", + "org.apache.olingo.odata2.ref.model.AddressBookProtos$Employee$Location"); + mapping.put("org.apache.olingo.odata2.ref.model.City", + "org.apache.olingo.odata2.ref.model.AddressBookProtos$Employee$City"); + } public ListsProcessor(final ScenarioDataSource dataSource) { this(dataSource, new BeanPropertyAccess()); @@ -136,6 +163,21 @@ public class ListsProcessor extends ODataSingleProcessor { } @Override + public List<String> getCustomContentTypes(final Class<? extends ODataProcessor> processorFeature) + throws ODataException { + if (processorFeature == EntitySetProcessor.class) { + List<String> customContentTypes = new ArrayList<String>(); + // otherwise fit fails if no media type has been entered + customContentTypes.add(HttpContentType.APPLICATION_ATOM_XML_FEED_UTF8); + customContentTypes.add(CUSTOM_CONTENT_TYPE); + return customContentTypes; + } else { + return Collections.emptyList(); + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override public ODataResponse readEntitySet(final GetEntitySetUriInfo uriInfo, final String contentType) throws ODataException { ArrayList<Object> data = new ArrayList<Object>(); @@ -191,6 +233,47 @@ public class ListsProcessor extends ODataSingleProcessor { final EdmEntityType entityType = entitySet.getEntityType(); List<Map<String, Object>> values = new ArrayList<Map<String, Object>>(); + + if (CUSTOM_CONTENT_TYPE.equals(contentType)) { + Descriptors.Descriptor addressBookDescriptor = AddressBookProtos.AddressBook.getDescriptor(); + AddressBookProtos.AddressBook.Builder addressBook = AddressBookProtos.AddressBook.newBuilder(); + CircleStreamBuffer buffer = new CircleStreamBuffer(); + try { + for (final Object entryData : data) { + String className = mapping.get(entryData.getClass().getName()); + + Class<Message> object = (Class<Message>) Class.forName(className); + Descriptors.Descriptor descriptor = ( Descriptors.Descriptor) object.getMethod("getDescriptor").invoke(object); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) object.getMethod("newBuilder").invoke(object); + Message message = getStructuralTypeValueMapProtobuf(entryData, descriptor, + builder, entityType); + + FieldDescriptor fd = addressBookDescriptor.findFieldByName(descriptor.getName().toLowerCase()); + if (fd != null) { + addressBook.addRepeatedField(fd, message); + } + } + OutputStream output = buffer.getOutputStream(); + + + addressBook.build().writeTo(output); + } catch (IOException e) { + throw new ODataException(e); + } catch (IllegalArgumentException e) { + throw new ODataException(e); + } catch (SecurityException e) { + throw new ODataException(e); + } catch (IllegalAccessException e) { + throw new ODataException(e); + } catch (InvocationTargetException e) { + throw new ODataException(e); + } catch (NoSuchMethodException e) { + throw new ODataException(e); + } catch (ClassNotFoundException e) { + throw new ODataException(e); + } + return ODataResponse.entity(buffer.getInputStream()).build(); + } for (final Object entryData : data) { values.add(getStructuralTypeValueMap(entryData, entityType)); } @@ -1522,7 +1605,55 @@ public class ListsProcessor extends ODataSingleProcessor { } } } + private Message getStructuralTypeValueMapProtobuf(final Object data, final Descriptors.Descriptor descriptor, + final GeneratedMessage.Builder message, + final EdmStructuralType type) throws ODataException { + // String cname = data.getClass().getName(); + Map<String, Object> valueMap = new HashMap<String, Object>(); + + for (final String propertyName : type.getPropertyNames()) { + final EdmProperty property = (EdmProperty) type.getProperty(propertyName); + final Object value = valueAccess.getPropertyValue(data, property); + Descriptors.FieldDescriptor fieldDescriptor = descriptor.findFieldByName(propertyName.toLowerCase()); + if(value!=null){ + if (property.isSimple()) { + if(value instanceof Calendar){ + message.setField(fieldDescriptor, ((Calendar)value).getTimeInMillis()); + } else{ + message.setField(fieldDescriptor, value); + } + + } else { + String className = mapping.get(value.getClass().getName()); + + Class<Message> object; + try { + object = (Class<Message>) Class.forName(className); + Descriptors.Descriptor descr = ( Descriptors.Descriptor) object.getMethod("getDescriptor").invoke(object); + GeneratedMessage.Builder builder = (GeneratedMessage.Builder) object.getMethod("newBuilder").invoke(object); + message.setField(fieldDescriptor, getStructuralTypeValueMapProtobuf(value,descr, + builder, (EdmStructuralType) property.getType())); + } catch (ClassNotFoundException e) { + throw new ODataException(e); + } catch (IllegalArgumentException e) { + throw new ODataException(e); + } catch (SecurityException e) { + throw new ODataException(e); + } catch (IllegalAccessException e) { + throw new ODataException(e); + } catch (InvocationTargetException e) { + throw new ODataException(e); + } catch (NoSuchMethodException e) { + throw new ODataException(e); + } + + } + } + } + return message.build(); + } + private <T> Map<String, Object> getSimpleTypeValueMap(final T data, final List<EdmProperty> propertyPath) throws ODataException { final EdmProperty property = propertyPath.get(propertyPath.size() - 1);
