You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/04/27 14:39:04 UTC

olingo-odata4 git commit: [OLINGO-604] Implement Action imports in TechSvc part 2

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 0d015cb7b -> ae97061e3


[OLINGO-604] Implement Action imports in TechSvc part 2


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ae97061e
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ae97061e
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ae97061e

Branch: refs/heads/master
Commit: ae97061e3cb12a4683ae40b34012ffe2e6c93d16
Parents: 0d015cb
Author: Christian Amend <ch...@apache.org>
Authored: Mon Apr 27 14:23:02 2015 +0200
Committer: Christian Amend <ch...@apache.org>
Committed: Mon Apr 27 14:33:53 2015 +0200

----------------------------------------------------------------------
 .../fit/tecsvc/client/ActionImportITCase.java   | 296 +++++++++++++++++++
 .../olingo/client/api/uri/SegmentType.java      |   2 +
 .../olingo/client/api/uri/URIBuilder.java       |   8 +
 .../olingo/client/core/uri/URIBuilderImpl.java  |  11 +-
 .../client/core/uri/v4/URIBuilderTest.java      |   4 +-
 .../apache/olingo/commons/api/data/Entity.java  |   1 +
 .../olingo/server/tecsvc/data/ActionData.java   | 122 +++++---
 .../olingo/server/tecsvc/data/DataCreator.java  |  14 +-
 .../olingo/server/tecsvc/data/DataProvider.java |  20 ++
 .../server/tecsvc/data/EntityActionResult.java  |  43 +++
 .../processor/TechnicalEntityProcessor.java     | 117 ++++++--
 .../TechnicalPrimitiveComplexProcessor.java     |  76 +++--
 .../tecsvc/processor/TechnicalProcessor.java    |  15 +
 13 files changed, 619 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java
new file mode 100644
index 0000000..49502bd
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java
@@ -0,0 +1,296 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.net.URI;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.ODataClientErrorException;
+import org.apache.olingo.client.api.communication.response.ODataInvokeResponse;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.commons.api.domain.ODataCollectionValue;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
+import org.apache.olingo.commons.api.domain.ODataEntity;
+import org.apache.olingo.commons.api.domain.ODataEntitySet;
+import org.apache.olingo.commons.api.domain.ODataProperty;
+import org.apache.olingo.commons.api.domain.ODataValue;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.fit.AbstractBaseTestITCase;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.junit.Test;
+
+public class ActionImportITCase extends AbstractBaseTestITCase {
+
+  @Test
+  public void primitveAction() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTString").build();
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class).execute();
+    assertEquals(200, response.getStatusCode());
+    assertEquals("UARTString string value", response.getBody().getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void primitveActionInvalidParameters() throws Exception {
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("Invalid", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt32(1));
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTString").build();
+    try {
+      getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+          .execute();
+      fail("Expected an ODataClientErrorException");
+    } catch (ODataClientErrorException e) {
+      assertEquals(400, e.getStatusLine().getStatusCode());
+    }
+  }
+
+  @Test
+  public void primitveCollectionAction() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollStringTwoParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 3));
+    parameters.put("ParameterDuration", getClient().getObjectFactory().newPrimitiveValueBuilder().setType(
+        EdmPrimitiveTypeKind.Duration).setValue(new BigDecimal(1)).build());
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataCollectionValue<ODataValue> valueArray = response.getBody().getCollectionValue();
+    assertEquals(3, valueArray.size());
+    Iterator<ODataValue> iterator = valueArray.iterator();
+    assertEquals("PT1S", iterator.next().asPrimitive().toValue());
+    assertEquals("PT2S", iterator.next().asPrimitive().toValue());
+    assertEquals("PT3S", iterator.next().asPrimitive().toValue());
+  }
+
+  @Test
+  public void complexAction() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCTTwoPrimParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 3));
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataComplexValue complexValue = response.getBody().getComplexValue();
+    ODataProperty propInt16 = complexValue.get("PropertyInt16");
+    assertNotNull(propInt16);
+    assertEquals(3, propInt16.getPrimitiveValue().toValue());
+    ODataProperty propString = complexValue.get("PropertyString");
+    assertNotNull(propString);
+    assertEquals("UARTCTTwoPrimParam string value", propString.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void complexCollectionActionNoContent() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollCTTwoPrimParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 0));
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataCollectionValue<ODataValue> complexValueCollection = response.getBody().getCollectionValue();
+    assertEquals(0, complexValueCollection.size());
+  }
+
+  @Test
+  public void complexCollectionActionSubContent() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollCTTwoPrimParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 1));
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataCollectionValue<ODataValue> complexValueCollection = response.getBody().getCollectionValue();
+    assertEquals(1, complexValueCollection.size());
+    Iterator<ODataValue> iterator = complexValueCollection.iterator();
+
+    ODataComplexValue next = iterator.next().asComplex();
+    assertEquals(16, next.get("PropertyInt16").getPrimitiveValue().toValue());
+    assertEquals("Test123", next.get("PropertyString").getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void complexCollectionActionAllContent() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollCTTwoPrimParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters.put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 3));
+    ODataInvokeResponse<ODataProperty> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataProperty.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataCollectionValue<ODataValue> complexValueCollection = response.getBody().getCollectionValue();
+    assertEquals(3, complexValueCollection.size());
+    Iterator<ODataValue> iterator = complexValueCollection.iterator();
+
+    ODataComplexValue next = iterator.next().asComplex();
+    assertEquals(16, next.get("PropertyInt16").getPrimitiveValue().toValue());
+    assertEquals("Test123", next.get("PropertyString").getPrimitiveValue().toValue());
+
+    next = iterator.next().asComplex();
+    assertEquals(17, next.get("PropertyInt16").getPrimitiveValue().toValue());
+    assertEquals("Test456", next.get("PropertyString").getPrimitiveValue().toValue());
+
+    next = iterator.next().asComplex();
+    assertEquals(18, next.get("PropertyInt16").getPrimitiveValue().toValue());
+    assertEquals("Test678", next.get("PropertyString").getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void entityActionETTwoKeyTwoPrim() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTETTwoKeyTwoPrimParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) -365));
+    ODataInvokeResponse<ODataEntity> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntity.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataEntity entity = response.getBody();
+    ODataProperty propInt16 = entity.getProperty("PropertyInt16");
+    assertNotNull(propInt16);
+    assertEquals(-365, propInt16.getPrimitiveValue().toValue());
+    ODataProperty propString = entity.getProperty("PropertyString");
+    assertNotNull(propString);
+    assertEquals("Test String2", propString.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void entityCollectionActionETKeyNav() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollETKeyNavParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 3));
+    ODataInvokeResponse<ODataEntitySet> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntitySet.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataEntitySet entitySet = response.getBody();
+    assertEquals(3, entitySet.getEntities().size());
+    Integer key = 1;
+    for (ODataEntity entity : entitySet.getEntities()) {
+      assertEquals(key, entity.getProperty("PropertyInt16").getPrimitiveValue().toValue());
+      key++;
+    }
+  }
+
+  @Test
+  public void entityCollectionActionETKeyNavEmptyCollection() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollETKeyNavParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 0));
+    ODataInvokeResponse<ODataEntitySet> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntitySet.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataEntitySet entitySet = response.getBody();
+    assertEquals(0, entitySet.getEntities().size());
+  }
+
+  @Test
+  public void entityCollectionActionETKeyNavNegativeParam() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollETKeyNavParam").build();
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterInt16", getClient().getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) -10));
+    ODataInvokeResponse<ODataEntitySet> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntitySet.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataEntitySet entitySet = response.getBody();
+    assertEquals(0, entitySet.getEntities().size());
+  }
+
+  @Test
+  public void entityCollectionActionETAllPrim() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTCollESAllPrimParam").build();
+    Calendar time = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+    time.clear();
+    time.set(Calendar.HOUR_OF_DAY, 3);
+    time.set(Calendar.MINUTE, 0);
+    time.set(Calendar.SECOND, 0);
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterTimeOfDay", getClient().getObjectFactory().newPrimitiveValueBuilder().setType(
+            EdmPrimitiveTypeKind.TimeOfDay).setValue(time).build());
+    ODataInvokeResponse<ODataEntitySet> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntitySet.class, parameters)
+            .execute();
+    assertEquals(200, response.getStatusCode());
+    ODataEntitySet entitySet = response.getBody();
+    assertEquals(3, entitySet.getEntities().size());
+    Integer key = 1;
+    for (ODataEntity entity : entitySet.getEntities()) {
+      assertEquals(key, entity.getProperty("PropertyInt16").getPrimitiveValue().toValue());
+      key++;
+    }
+  }
+
+  @Test
+  public void entityActionETAllPrim() throws Exception {
+    URI actionURI =
+        getClient().newURIBuilder(TecSvcConst.BASE_URI).appendActionCallSegment("AIRTESAllPrimParam").build();
+    Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+    dateTime.clear();
+    dateTime.set(1012, 2, 0, 0, 0, 0);
+    Map<String, ODataValue> parameters = new HashMap<String, ODataValue>();
+    parameters
+        .put("ParameterDate", getClient().getObjectFactory().newPrimitiveValueBuilder().setType(
+            EdmPrimitiveTypeKind.Date).setValue(dateTime).build());
+    ODataInvokeResponse<ODataEntity> response =
+        getClient().getInvokeRequestFactory().getActionInvokeRequest(actionURI, ODataEntity.class, parameters)
+            .execute();
+    // Check 201
+    assertEquals(201, response.getStatusCode());
+  }
+
+  @Override
+  protected ODataClient getClient() {
+    ODataClient odata = ODataClientFactory.getClient();
+    odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON_NO_METADATA);
+    return odata;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/SegmentType.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/SegmentType.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/SegmentType.java
index 5da7f09..f3f2a50 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/SegmentType.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/SegmentType.java
@@ -37,6 +37,8 @@ public enum SegmentType {
   COUNT("$count"),
   BOUND_OPERATION,
   UNBOUND_OPERATION,
+  BOUND_ACTION,
+  UNBOUND_ACTION,
   METADATA("$metadata"),
   BATCH("$batch"),
   LINKS("$links"),

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/URIBuilder.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/URIBuilder.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/URIBuilder.java
index af6beb7..1c8f89d 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/URIBuilder.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/URIBuilder.java
@@ -355,4 +355,12 @@ public interface URIBuilder {
    * @see org.apache.olingo.client.api.uri.QueryOption#SELECT
    */
   URIBuilder expandWithSelect(String expandItem, String... selectItems);
+
+  /**
+   * Appends action segment to the URI.
+   *
+   * @param action Action name
+   * @return current URIBuilder instance
+   */
+  URIBuilder appendActionCallSegment(String action);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIBuilderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIBuilderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIBuilderImpl.java
index 452596c..82f090e 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIBuilderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIBuilderImpl.java
@@ -180,6 +180,13 @@ public class URIBuilderImpl implements URIBuilder {
   }
 
   @Override
+  public URIBuilder appendActionCallSegment(final String action) {
+    segments.add(new Segment(
+        segments.size() == 1 ? SegmentType.UNBOUND_ACTION : SegmentType.BOUND_ACTION, action));
+    return this;
+  }
+  
+  @Override
   public URIBuilder appendOperationCallSegment(final String operation) {
     segments.add(new Segment(
         segments.size() == 1 ? SegmentType.UNBOUND_OPERATION : SegmentType.BOUND_OPERATION, operation));
@@ -266,7 +273,9 @@ public class URIBuilderImpl implements URIBuilder {
         case BOUND_OPERATION:
           segmentsBuilder.append(getBoundOperationSeparator());
           break;
-
+        case BOUND_ACTION:
+          segmentsBuilder.append(getBoundOperationSeparator());
+          break;
         default:
           if (segmentsBuilder.length() > 0 && segmentsBuilder.charAt(segmentsBuilder.length() - 1) != '/') {
             segmentsBuilder.append('/');

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/client-core/src/test/java/org/apache/olingo/client/core/uri/v4/URIBuilderTest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/uri/v4/URIBuilderTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/uri/v4/URIBuilderTest.java
index f55e37f..14fa566 100644
--- a/lib/client-core/src/test/java/org/apache/olingo/client/core/uri/v4/URIBuilderTest.java
+++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/uri/v4/URIBuilderTest.java
@@ -100,10 +100,10 @@ public class URIBuilderTest extends AbstractTest {
     final URIBuilder uriBuilder = getClient().newURIBuilder(SERVICE_ROOT).
         appendEntitySetSegment("Categories").appendKeySegment(1).
         appendNavigationSegment("Products").appendNavigationSegment("Model").
-        appendOperationCallSegment("AllOrders");
+        appendActionCallSegment("AllOrders");
 
     assertEquals(new org.apache.http.client.utils.URIBuilder(
-        SERVICE_ROOT + "/Categories(1)/Products/Model.AllOrders()").build(), uriBuilder.build());
+        SERVICE_ROOT + "/Categories(1)/Products/Model.AllOrders").build(), uriBuilder.build());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Entity.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Entity.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Entity.java
index acd3022..167c5c3 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Entity.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Entity.java
@@ -158,6 +158,7 @@ public class Entity extends Linked {
     for (Property property : properties) {
       if (name.equals(property.getName())) {
         result = property;
+        break;
       }
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
index d2a8525..17561a8 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
@@ -24,6 +24,7 @@ import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.commons.api.data.ComplexValue;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityCollection;
 import org.apache.olingo.commons.api.data.Parameter;
@@ -49,11 +50,17 @@ public class ActionData {
   protected static Property primitiveCollectionAction(String name, Map<String, Parameter> parameters)
       throws DataProviderException {
     if ("UARTCollStringTwoParam".equals(name)) {
-      List<Object> collectionValues = new ArrayList<Object>();
-      int loopCount = (Integer) parameters.get("ParameterInt16").asPrimitive();
+      Parameter paramInt16 = parameters.get("ParameterInt16");
+      Parameter paramDuration = parameters.get("ParameterDuration");
+      if (paramInt16 == null || paramDuration == null) {
+        throw new DataProviderException("Missing parameters for action: UARTCollStringTwoParam",
+            HttpStatusCode.BAD_REQUEST);
+      }
+      short loopCount = (Short) paramInt16.asPrimitive();
+      BigDecimal duration = (BigDecimal) paramDuration.asPrimitive();
       EdmPrimitiveType primDuration = OData.newInstance().createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration);
-      BigDecimal duration = (BigDecimal) parameters.get("ParameterDuration").asPrimitive();
       BigDecimal addValue = new BigDecimal(1);
+      List<Object> collectionValues = new ArrayList<Object>();
       for (int i = 0; i < loopCount; i++) {
         try {
           String value = primDuration.valueToString(duration, false, null, null, null, null);
@@ -63,78 +70,92 @@ public class ActionData {
         }
         duration = duration.add(addValue);
       }
-      return DataCreator.createPrimitiveCollection(null, collectionValues);
+      return new Property(null, name, ValueType.COLLECTION_PRIMITIVE, collectionValues);
     }
     throw new DataProviderException("Action " + name + " is not yet implemented.");
   }
 
   protected static Property complexAction(String name, Map<String, Parameter> parameters) throws DataProviderException {
     if ("UARTCTTwoPrimParam".equals(name)) {
-      Integer number = (Integer) parameters.get("ParameterInt16").asPrimitive();
-      if (number == null) {
-        number = new Integer(32767);
+      Parameter paramInt16 = parameters.get("ParameterInt16");
+      Short number;
+      if (paramInt16 == null) {
+        number = new Short((short) 32767);
+      } else {
+        number = (Short) paramInt16.asPrimitive();
       }
-      Property complexProp = createCTTwoPrimComplexProperty(number, "UARTCTTwoPrimParam string value");
 
-      return complexProp;
+      return createCTTwoPrimComplexProperty(number, "UARTCTTwoPrimParam string value");
     }
     throw new DataProviderException("Action " + name + " is not yet implemented.");
   }
 
-  private static Property createCTTwoPrimComplexProperty(Integer number, String text) {
-    List<Property> props = new ArrayList<Property>();
+  private static Property createCTTwoPrimComplexProperty(Short number, String text) {
+    ComplexValue compValue = new ComplexValue();
     Property propInt = new Property();
     propInt.setName("PropertyInt16");
     propInt.setValue(ValueType.PRIMITIVE, number);
-    props.add(propInt);
+    compValue.getValue().add(propInt);
     Property propString = new Property();
     propString.setName("PropertyString");
     propString.setValue(ValueType.PRIMITIVE, text);
-    props.add(propString);
+    compValue.getValue().add(propString);
 
     Property complexProp = new Property();
-    complexProp.setValue(ValueType.COMPLEX, props);
+    complexProp.setValue(ValueType.COMPLEX, compValue);
     return complexProp;
   }
 
   protected static Property complexCollectionAction(String name, Map<String, Parameter> parameters)
       throws DataProviderException {
     if ("UARTCollCTTwoPrimParam".equals(name)) {
-      ArrayList<Property> complexCollection = new ArrayList<Property>();
-      complexCollection.add(createCTTwoPrimComplexProperty(16, "Test123"));
-      complexCollection.add(createCTTwoPrimComplexProperty(17, "Test456"));
-      complexCollection.add(createCTTwoPrimComplexProperty(18, "Test678"));
-
-      Integer number = (Integer) parameters.get("ParameterInt16").asPrimitive();
-      if (number != null && number >= 0 && number < complexCollection.size()) {
-        complexCollection.subList(number, complexCollection.size() - 1).clear();
-      }
+      List<ComplexValue> complexCollection = new ArrayList<ComplexValue>();
+      complexCollection.add(createCTTwoPrimComplexProperty((short) 16, "Test123").asComplex());
+      complexCollection.add(createCTTwoPrimComplexProperty((short) 17, "Test456").asComplex());
+      complexCollection.add(createCTTwoPrimComplexProperty((short) 18, "Test678").asComplex());
+
+      Parameter paramInt16 = parameters.get("ParameterInt16");
+      if (paramInt16 != null) {
+        Short number = (Short) paramInt16.asPrimitive();
+        if (number < 0) {
+          complexCollection.clear();
+        } else if (number >= 0 && number < complexCollection.size()) {
+          complexCollection = complexCollection.subList(0, number);
 
-      Property complexCollProperty = new Property();
-      complexCollProperty.setValue(ValueType.COLLECTION_COMPLEX, complexCollection);
-      return complexCollProperty;
+        }
+        Property complexCollProperty = new Property();
+        complexCollProperty.setValue(ValueType.COLLECTION_COMPLEX, complexCollection);
+        return complexCollProperty;
+      }
     }
     throw new DataProviderException("Action " + name + " is not yet implemented.");
   }
 
-  protected static Entity entityAction(String name, Map<String, Parameter> parameters) throws DataProviderException {
+  protected static EntityActionResult entityAction(String name, Map<String, Parameter> parameters)
+      throws DataProviderException {
     if ("UARTETTwoKeyTwoPrimParam".equals(name)) {
-      Integer number = (Integer) parameters.get("ParameterInt16").asPrimitive();
-      if (number == null) {
-        number = 0;
+      Parameter parameter = parameters.get("ParameterInt16");
+      Short number;
+      if (parameter != null) {
+        number = (Short) parameter.asPrimitive();
+      } else {
+        number = (short) 0;
       }
+
       EntityCollection entityCollection = new DataCreator().getData().get("ESTwoKeyTwoPrim");
       for (Entity entity : entityCollection.getEntities()) {
-        if (number.equals(entity.getProperty("PropertyInt16").asPrimitive())) {
-          return entity;
+        Object asPrimitive = entity.getProperty("PropertyInt16").asPrimitive();
+        if (number.equals(asPrimitive)) {
+          return new EntityActionResult().setEntity(entity);
         }
       }
       // Entity Not found
       throw new DataProviderException("Entity not found with key: " + number, HttpStatusCode.NOT_FOUND);
     } else if ("UARTETAllPrimParam".equals(name)) {
-      Calendar date = (Calendar) parameters.get("ParameterDate").asPrimitive();
+      Parameter paramDate = parameters.get("ParameterDate");
       EntityCollection entityCollection = new DataCreator().getData().get("ESAllPrim");
-      if (date != null) {
+      if (paramDate != null) {
+        Calendar date = (Calendar) paramDate.asPrimitive();
         boolean freeKey;
         Short key = 0;
         do {
@@ -147,10 +168,10 @@ public class ActionData {
           }
           key++;
         } while (!freeKey);
-        // TODO: Set create response code
-        return createAllPrimEntity(key, "UARTETAllPrimParam string value", date);
+        return new EntityActionResult().setEntity(createAllPrimEntity(key, "UARTETAllPrimParam string value", date))
+            .setCreated(true);
       } else {
-        return entityCollection.getEntities().get(0);
+        return new EntityActionResult().setEntity(entityCollection.getEntities().get(0));
       }
     }
     throw new DataProviderException("Action " + name + " is not yet implemented.");
@@ -178,26 +199,31 @@ public class ActionData {
   protected static EntityCollection entityCollectionAction(String name, Map<String, Parameter> parameters)
       throws DataProviderException {
     if ("UARTCollETKeyNavParam".equals(name)) {
-      Short number = (Short) parameters.get("ParameterInt16").asPrimitive();
+      Parameter paramInt16 = parameters.get("ParameterInt16");
+      Short number;
+      if (paramInt16 == null) {
+        number = (short) 0;
+      } else {
+        number = (Short) paramInt16.asPrimitive();
+      }
       EntityCollection collection = new EntityCollection();
-      if (number != null && number > 0) {
-        for (int i = 1; i <= number; i++) {
-          collection.getEntities().add(createETKeyNavEntity(number));
+      if (number > 0) {
+        for (short i = 1; i <= number; i++) {
+          collection.getEntities().add(createETKeyNavEntity(i));
         }
-      } else {
-        return collection;
       }
+      return collection;
     } else if ("UARTCollETAllPrimParam".equals(name)) {
-      Calendar timeOfDay = (Calendar) parameters.get("ParameterTimeOfDay").asPrimitive();
+      Parameter paramTimeOfDay = parameters.get("ParameterTimeOfDay");
       EntityCollection collection = new EntityCollection();
-      if (timeOfDay != null) {
+      if (paramTimeOfDay != null) {
+        Calendar timeOfDay = (Calendar) paramTimeOfDay.asPrimitive();
         int count = timeOfDay.get(Calendar.HOUR_OF_DAY);
         for (short i = 1; i <= count; i++) {
           collection.getEntities().add(createAllPrimEntity(i, "UARTCollETAllPrimParam int16 value: " + i, null));
         }
-      } else {
-        return collection;
-      }  
+      }
+      return collection;
     }
     throw new DataProviderException("Action " + name + " is not yet implemented.");
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
index 37b7752..dcb3bfd 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
@@ -85,13 +85,13 @@ public class DataCreator {
 
   private EntityCollection createESTwoKeyTwoPrim() {
     EntityCollection entitySet = new EntityCollection();
-    entitySet.getEntities().add(createETTwoKeyTwoPrimEntity(32767, "Test String1"));
-    entitySet.getEntities().add(createETKeyNavEntity(-365, "Test String2"));
-    entitySet.getEntities().add(createETKeyNavEntity(-32766, "Test String3"));
+    entitySet.getEntities().add(createETTwoKeyTwoPrimEntity((short) 32767, "Test String1"));
+    entitySet.getEntities().add(createETTwoKeyTwoPrimEntity((short) -365, "Test String2"));
+    entitySet.getEntities().add(createETTwoKeyTwoPrimEntity((short) -32766, "Test String3"));
     return entitySet;
   }
 
-  private Entity createETTwoKeyTwoPrimEntity(int propertyInt16, String propertyString) {
+  private Entity createETTwoKeyTwoPrimEntity(short propertyInt16, String propertyString) {
     return new Entity().addProperty(createPrimitive("PropertyInt16", propertyInt16))
         .addProperty(createPrimitive("PropertyString", propertyString));
   }
@@ -266,7 +266,7 @@ public class DataCreator {
         .addProperty(createPrimitive("PropertyGuid", UUID.fromString("76543201-23ab-cdef-0123-456789dddfff")))
         .addProperty(createPrimitive("PropertyTimeOfDay", getTime(23, 49, 14))));
 
-    entitySet.getEntities().add(new Entity().addProperty(createPrimitive("PropertyInt16", 0))
+    entitySet.getEntities().add(new Entity().addProperty(createPrimitive("PropertyInt16", (short) 0))
         .addProperty(createPrimitive("PropertyString", "")).addProperty(createPrimitive("PropertyBoolean", false))
         .addProperty(createPrimitive("PropertyByte", 0)).addProperty(createPrimitive("PropertySByte", 0))
         .addProperty(createPrimitive("PropertyInt32", 0)).addProperty(createPrimitive("PropertyInt64", 0))
@@ -600,7 +600,7 @@ public class DataCreator {
     return new Property(null, name, ValueType.COLLECTION_COMPLEX, complexCollection);
   }
 
-  private static Calendar getDateTime(final int year, final int month, final int day,
+  protected static Calendar getDateTime(final int year, final int month, final int day,
       final int hour, final int minute, final int second) {
     Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
     dateTime.clear();
@@ -608,7 +608,7 @@ public class DataCreator {
     return dateTime;
   }
 
-  private static Calendar getTime(final int hour, final int minute, final int second) {
+  protected static Calendar getTime(final int hour, final int minute, final int second) {
     Calendar time = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
     time.clear();
     time.set(Calendar.HOUR_OF_DAY, hour);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
index 878efce..676b6ce 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
@@ -495,11 +495,31 @@ public class DataProvider {
     return ActionData.primitiveAction(name, actionParameters);
   }
 
+  public Property processActionComplex(String name, Map<String, Parameter> actionParameters)
+      throws DataProviderException {
+    return ActionData.complexAction(name, actionParameters);
+  }
+
+  public Property processActionComplexCollection(String name, Map<String, Parameter> actionParameters)
+      throws DataProviderException {
+    return ActionData.complexCollectionAction(name, actionParameters);
+  }
+
   public Property processActionPrimitiveCollection(String name, Map<String, Parameter> actionParameters)
       throws DataProviderException {
     return ActionData.primitiveCollectionAction(name, actionParameters);
   }
 
+  public EntityActionResult processActionEntity(String name, Map<String, Parameter> actionParameters)
+      throws DataProviderException {
+    return ActionData.entityAction(name, actionParameters);
+  }
+
+  public EntityCollection processActionEntityCollection(String name, Map<String, Parameter> actionParameters)
+      throws DataProviderException {
+    return ActionData.entityCollectionAction(name, actionParameters);
+  }
+
   public void setEdm(final Edm edm) {
     this.edm = edm;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/EntityActionResult.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/EntityActionResult.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/EntityActionResult.java
new file mode 100644
index 0000000..8611cf7
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/EntityActionResult.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.data;
+
+import org.apache.olingo.commons.api.data.Entity;
+
+public class EntityActionResult {
+  private Entity entity;
+  private boolean created = false;
+  
+  public Entity getEntity() {
+    return entity;
+  }
+  public EntityActionResult setEntity(Entity entity) {
+    this.entity = entity;
+    return this;
+  }
+  public boolean isCreated() {
+    return created;
+  }
+  public EntityActionResult setCreated(boolean created) {
+    this.created = created;
+    return this;
+  }
+  
+  
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 6d7d928..024628c 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -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
@@ -52,6 +52,7 @@ 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.serializer.SerializerResult;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
@@ -59,6 +60,7 @@ import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
+import org.apache.olingo.server.tecsvc.data.EntityActionResult;
 import org.apache.olingo.server.tecsvc.data.RequestValidator;
 import org.apache.olingo.server.tecsvc.processor.queryoptions.ExpandSystemQueryOptionHandler;
 import org.apache.olingo.server.tecsvc.processor.queryoptions.options.CountHandler;
@@ -117,14 +119,14 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
       ODataSerializer serializer = odata.createSerializer(format);
       final ExpandOption expand = uriInfo.getExpandOption();
       final SelectOption select = uriInfo.getSelectOption();
-      
+
       // Transform the entity graph to a tree. The construction is controlled by the expand tree.
-      // Apply all expand system query options to the tree.So the expanded navigation properties can be modified 
+      // Apply all expand system query options to the tree.So the expanded navigation properties can be modified
       // for serialization,without affecting the data stored in the database.
       final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler();
-      final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet, 
-                                                                                           edmEntitySet, 
-                                                                                           expand);
+      final EntityCollection entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet,
+          edmEntitySet,
+          expand);
       expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand);
 
       // Serialize
@@ -147,8 +149,32 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
   public void processActionEntityCollection(final ODataRequest request, final ODataResponse response,
       final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
       throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Process entity collection is not supported yet.",
-        HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    EdmAction action = checkBoundAndExtractAction(uriInfo);
+    DeserializerResult deserializerResult =
+        odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
+            .actionParameters(request.getBody(), action);
+
+    EntityCollection collection =
+        dataProvider.processActionEntityCollection(action.getName(), deserializerResult.getActionParameters());
+
+    if (collection == null) {
+      // Collection Propertys must never be null
+      throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+    } else if (collection.getEntities().contains(null) && !action.getReturnType().isNullable()) {
+      // Not nullable return type but array contains a null value
+      throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+    }
+    EdmEntityType type = (EdmEntityType) action.getReturnType().getType();
+    ContextURL contextURL = ContextURL.with().type(type).asCollection().build();
+    EntityCollectionSerializerOptions options = EntityCollectionSerializerOptions.with().contextURL(contextURL).build();
+
+    SerializerResult result =
+        odata.createSerializer(ODataFormat.fromContentType(responseFormat))
+            .entityCollection(serviceMetadata, type, collection, options);
+
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setContent(result.getContent());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
   }
 
   @Override
@@ -230,7 +256,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
     final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
     final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
-    
+
     final Entity entity;
     ExpandOption expand = null;
     if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly
@@ -238,14 +264,14 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
       dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()),
           requestFormat.toContentTypeString());
     } else {
-      final DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
-                                                         .entity(request.getBody(), edmEntityType);
-      new RequestValidator(dataProvider, 
-                           odata.createUriHelper(), 
-                           serviceMetadata.getEdm(), 
-                           request.getRawBaseUri()
-                           ).validate(edmEntitySet, deserializerResult.getEntity());
-      
+      final DeserializerResult deserializerResult =
+          odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
+              .entity(request.getBody(), edmEntityType);
+      new RequestValidator(dataProvider,
+          odata.createUriHelper(),
+          serviceMetadata.getEdm(),
+          request.getRawBaseUri()).validate(edmEntitySet, deserializerResult.getEntity());
+
       entity = dataProvider.create(edmEntitySet);
       dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, true);
       expand = deserializerResult.getExpandTree();
@@ -271,11 +297,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
       throws ODataApplicationException, DeserializerException, SerializerException {
     final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
     Entity entity;
-    
+
     try {
       entity = readEntity(uriInfo);
-    } catch(ODataApplicationException e) {
-      if(e.getStatusCode() == HttpStatusCode.NOT_FOUND.getStatusCode()) {
+    } catch (ODataApplicationException e) {
+      if (e.getStatusCode() == HttpStatusCode.NOT_FOUND.getStatusCode()) {
         // Perform upsert
         createEntity(request, response, uriInfo, requestFormat, responseFormat);
         return;
@@ -286,15 +312,14 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     checkRequestFormat(requestFormat);
     final ODataDeserializer deserializer = odata.createDeserializer(ODataFormat.fromContentType(requestFormat));
     final Entity changedEntity = deserializer.entity(request.getBody(), edmEntitySet.getEntityType()).getEntity();
-    
-    new RequestValidator(dataProvider, 
-                         true,        // Update
-                         request.getMethod() == HttpMethod.PATCH,
-                         odata.createUriHelper(), 
-                         serviceMetadata.getEdm(), 
-                         request.getRawBaseUri()
-                         ).validate(edmEntitySet, changedEntity);
-    
+
+    new RequestValidator(dataProvider,
+        true, // Update
+        request.getMethod() == HttpMethod.PATCH,
+        odata.createUriHelper(),
+        serviceMetadata.getEdm(),
+        request.getRawBaseUri()).validate(edmEntitySet, changedEntity);
+
     dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity,
         request.getMethod() == HttpMethod.PATCH, false);
     response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
@@ -325,8 +350,36 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
   public void processActionEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType requestFormat, final ContentType responseFormat)
       throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Any action returning an entity is not supported yet.",
-        HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    EdmAction action = checkBoundAndExtractAction(uriInfo);
+    DeserializerResult deserializerResult =
+        odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
+            .actionParameters(request.getBody(), action);
+
+    EntityActionResult entityResult =
+        dataProvider.processActionEntity(action.getName(), deserializerResult.getActionParameters());
+    EdmEntityType type = (EdmEntityType) action.getReturnType().getType();
+    if (entityResult == null || entityResult.getEntity() == null) {
+      if (action.getReturnType().isNullable()) {
+        response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+      } else {
+        // Not nullable return type so we have to give back a 500
+        throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+      }
+    } else {
+      ContextURL contextURL = ContextURL.with().type(type).build();
+      EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextURL).build();
+
+      SerializerResult result = odata.createSerializer(ODataFormat.fromContentType(responseFormat))
+          .entity(serviceMetadata, type, entityResult.getEntity(), options);
+
+      if(entityResult.isCreated()){
+        response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+      }else{
+        response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      }
+      response.setContent(result.getContent());
+      response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
index d811670..d847b32 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java
@@ -68,7 +68,6 @@ import org.apache.olingo.server.api.uri.UriHelper;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
@@ -121,7 +120,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
 
     Property property = dataProvider.processActionPrimitive(action.getName(), deserializerResult.getActionParameters());
     EdmPrimitiveType type = (EdmPrimitiveType) action.getReturnType().getType();
-    if (property.isNull()) {
+    if (property == null || property.isNull()) {
       if (action.getReturnType().isNullable()) {
         response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
       } else {
@@ -141,18 +140,6 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
     }
   }
 
-  private EdmAction checkBoundAndExtractAction(final UriInfo uriInfo) throws ODataApplicationException {
-    final UriInfoResource resource = uriInfo.asUriInfoResource();
-    List<UriResource> uriResourceParts = resource.getUriResourceParts();
-    if (uriResourceParts.size() > 1) {
-      throw new ODataApplicationException("Bound acctions not supported yet.",
-          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
-    UriResourceAction uriResourceAction = (UriResourceAction) uriResourceParts.get(0);
-    EdmAction action = uriResourceAction.getAction();
-    return action;
-  }
-
   @Override
   public void readPrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, SerializerException {
@@ -177,8 +164,32 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
   public void processActionPrimitiveCollection(final ODataRequest request, final ODataResponse response,
       final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
       throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Not supported yet.",
-        HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    EdmAction action = checkBoundAndExtractAction(uriInfo);
+    DeserializerResult deserializerResult =
+        odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
+            .actionParameters(request.getBody(), action);
+
+    Property property =
+        dataProvider.processActionPrimitiveCollection(action.getName(), deserializerResult.getActionParameters());
+
+    if (property == null || property.isNull()) {
+      // Collection Propertys must never be null
+      throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+    } else if (property.asCollection().contains(null) && !action.getReturnType().isNullable()) {
+      // Not nullable return type but array contains a null value
+      throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+    }
+    EdmPrimitiveType type = (EdmPrimitiveType) action.getReturnType().getType();
+    ContextURL contextURL = ContextURL.with().type(type).asCollection().build();
+    PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextURL).build();
+
+    SerializerResult result =
+        odata.createSerializer(ODataFormat.fromContentType(responseFormat))
+            .primitiveCollection(type, property, options);
+
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setContent(result.getContent());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
   }
 
   @Override
@@ -199,8 +210,32 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
   public void processActionComplex(ODataRequest request, ODataResponse response, UriInfo uriInfo,
       ContentType requestFormat, ContentType responseFormat)
       throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Not supported yet.",
-        HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    EdmAction action = checkBoundAndExtractAction(uriInfo);
+    DeserializerResult deserializerResult =
+        odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
+            .actionParameters(request.getBody(), action);
+
+    Property property = dataProvider.processActionComplex(action.getName(), deserializerResult.getActionParameters());
+    EdmComplexType type = (EdmComplexType) action.getReturnType().getType();
+    if (property == null || property.isNull()) {
+      if (action.getReturnType().isNullable()) {
+        response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+      } else {
+        // Not nullable return type so we have to give back a 500
+        throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
+      }
+    } else {
+      ContextURL contextURL = ContextURL.with().type(type).build();
+      ComplexSerializerOptions options = ComplexSerializerOptions.with().contextURL(contextURL).build();
+
+      SerializerResult result =
+          odata.createSerializer(ODataFormat.fromContentType(responseFormat)).complex(serviceMetadata, type, property,
+              options);
+
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setContent(result.getContent());
+      response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+    }
   }
 
   @Override
@@ -232,9 +267,10 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
         odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
             .actionParameters(request.getBody(), action);
 
-    Property property = dataProvider.processActionPrimitive(action.getName(), deserializerResult.getActionParameters());
+    Property property =
+        dataProvider.processActionComplexCollection(action.getName(), deserializerResult.getActionParameters());
 
-    if (property.isNull()) {
+    if (property == null || property.isNull()) {
       // Collection Propertys must never be null
       throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT);
     } else if (property.asCollection().contains(null) && !action.getReturnType().isNullable()) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae97061e/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index d826b19..f2a1f23 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -24,6 +24,7 @@ import java.util.Locale;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityCollection;
 import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.edm.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmBindingTarget;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
@@ -34,9 +35,11 @@ import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.uri.UriInfo;
 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.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
@@ -212,4 +215,16 @@ public abstract class TechnicalProcessor implements Processor {
           HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
     }
   }
+  
+  protected EdmAction checkBoundAndExtractAction(final UriInfo uriInfo) throws ODataApplicationException {
+    final UriInfoResource resource = uriInfo.asUriInfoResource();
+    List<UriResource> uriResourceParts = resource.getUriResourceParts();
+    if (uriResourceParts.size() > 1) {
+      throw new ODataApplicationException("Bound acctions not supported yet.",
+          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    }
+    UriResourceAction uriResourceAction = (UriResourceAction) uriResourceParts.get(0);
+    EdmAction action = uriResourceAction.getAction();
+    return action;
+  }
 }