You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2015/07/08 10:15:06 UTC

[12/12] olingo-odata4 git commit: [OLINGO-708] Merge branch 'master' into OLINGO-708_AsyncSupportTec

[OLINGO-708] Merge branch 'master' into OLINGO-708_AsyncSupportTec


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

Branch: refs/heads/OLINGO-708_AsyncSupportTec
Commit: 1476b034b5501121fc097de7b79090c6755326a3
Parents: 2080f23 3a103d5
Author: mibo <mi...@apache.org>
Authored: Wed Jul 8 10:03:43 2015 +0200
Committer: mibo <mi...@apache.org>
Committed: Wed Jul 8 10:14:15 2015 +0200

----------------------------------------------------------------------
 ext/karaf/karaf-fit/pom.xml                     |   2 +-
 .../osgi/itests/OlingoOSGiTestSupport.java      |   2 +-
 .../fit/tecsvc/client/ActionImportITCase.java   |  70 +-
 .../fit/tecsvc/client/AsyncSupportITCase.java   | 156 +++-
 .../BasicHttpExceptionHandlingITCase.java       |   4 +-
 .../olingo/fit/tecsvc/client/BasicITCase.java   |  21 +-
 .../fit/tecsvc/client/BatchClientITCase.java    |  96 +-
 .../tecsvc/client/EdmEnabledClientITCase.java   |  63 --
 .../tecsvc/client/EntityReferencesITCase.java   |  43 +
 .../fit/tecsvc/client/ExpandSelectITCase.java   |  12 +
 .../fit/tecsvc/client/FunctionImportITCase.java |  76 ++
 .../tecsvc/client/PrimitiveComplexITCase.java   |   3 +-
 .../tecsvc/client/SystemQueryOptionITCase.java  |   4 +-
 .../fit/tecsvc/http/BasicBatchITCase.java       |  15 +-
 .../olingo/fit/tecsvc/http/BasicHttpITCase.java |  89 +-
 .../fit/tecsvc/http/EntityReferenceITCase.java  |  54 +-
 .../olingo/fit/tecsvc/http/PingITCase.java      |  12 +-
 .../olingo/fit/v4/AuthBatchTestITCase.java      |   4 +-
 .../apache/olingo/fit/v4/BatchTestITCase.java   |  20 +-
 .../olingo/fit/v4/ConformanceTestITCase.java    |  15 +-
 .../olingo/fit/v4/EntityRetrieveTestITCase.java |   3 +-
 .../olingo/fit/v4/MediaEntityTestITCase.java    |   4 +-
 .../api/communication/header/HeaderName.java    | 194 ----
 .../api/communication/header/ODataHeaders.java  |  21 -
 .../communication/header/ODataPreferences.java  |  28 +-
 .../api/communication/request/ODataRequest.java |  33 +-
 .../communication/response/ODataResponse.java   |   9 -
 .../api/domain/ClientEntitySetIterator.java     |  14 +-
 .../client/api/domain/ClientPrimitiveValue.java |   2 +
 .../olingo/client/core/ODataClientImpl.java     |  18 +-
 .../communication/header/ODataHeadersImpl.java  |  17 -
 .../request/AbstractODataRequest.java           |  54 +-
 .../request/AsyncBatchRequestWrapperImpl.java   |   8 +-
 .../request/AsyncRequestWrapperImpl.java        |  29 +-
 .../request/batch/ODataBatchRequestImpl.java    |   3 +-
 .../request/batch/ODataBatchUtilities.java      |  10 +-
 .../request/batch/ODataChangesetImpl.java       |   4 +-
 .../invoke/AbstractODataInvokeRequest.java      |   7 +-
 .../retrieve/EdmMetadataRequestImpl.java        |   6 -
 .../response/AbstractODataResponse.java         |  60 +-
 .../batch/ODataBatchResponseManager.java        |  12 +-
 .../core/domain/ClientPrimitiveValueImpl.java   |   5 +
 .../ClientODataDeserializerImpl.java            |  11 +-
 .../apache/olingo/client/core/AbstractTest.java |   5 +-
 .../olingo/client/core/v4/EntityTest.java       |   3 +-
 .../olingo/commons/api/format/AcceptType.java   |  26 +-
 .../olingo/commons/api/format/ContentType.java  |  85 +-
 .../olingo/commons/api/format/TypeUtil.java     |  36 +-
 .../olingo/commons/api/http/HttpHeader.java     |  20 +-
 .../commons/api/format/ContentTypeTest.java     |   1 -
 .../olingo/server/core/uri/antlr/UriLexer.g4    |  16 +-
 .../olingo/server/core/uri/antlr/UriParser.g4   |   2 +-
 .../json/ODataJsonDeserializer.java             |   3 +-
 .../serializer/json/ODataJsonSerializer.java    |   5 +-
 .../core/uri/parser/UriParseTreeVisitor.java    |   3 +-
 .../tecsvc/async/TechnicalAsyncService.java     |  13 +-
 .../olingo/server/tecsvc/data/ActionData.java   |  59 +-
 .../olingo/server/tecsvc/data/DataCreator.java  | 903 +++++++++++--------
 .../olingo/server/tecsvc/data/DataProvider.java |  22 +-
 .../olingo/server/tecsvc/data/FunctionData.java |  82 +-
 .../processor/TechnicalActionProcessor.java     |   9 +-
 .../processor/TechnicalEntityProcessor.java     |  39 +-
 .../tecsvc/processor/TechnicalProcessor.java    |   9 +-
 .../tecsvc/provider/ContainerProvider.java      |  12 +-
 .../tecsvc/provider/FunctionProvider.java       |  20 +-
 .../server/tecsvc/provider/SchemaProvider.java  |   4 +-
 .../server/tecsvc/data/DataProviderTest.java    |   6 +-
 .../olingo/server/core/ODataHandlerTest.java    |   4 +-
 ...ataJsonDeserializerActionParametersTest.java |  18 +-
 .../json/ODataJsonSerializerTest.java           |  13 +-
 .../core/uri/antlr/TestFullResourcePath.java    |  26 +-
 .../olingo/server/core/uri/antlr/TestLexer.java |  35 +-
 .../core/uri/antlr/TestUriParserImpl.java       |   6 +-
 pom.xml                                         |  10 +-
 samples/client/pom.xml                          |   2 +-
 75 files changed, 1507 insertions(+), 1303 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1476b034/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
----------------------------------------------------------------------
diff --cc fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
index db7dc5c,0000000..fb0cfd1
mode 100644,000000..100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
@@@ -1,97 -1,0 +1,245 @@@
 +/*
 + * 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.assertFalse;
 +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.net.URI;
++import java.util.List;
 +import java.util.concurrent.TimeUnit;
 +
++import junit.framework.Assert;
 +import org.apache.olingo.client.api.ODataClient;
 +import org.apache.olingo.client.api.communication.request.ODataRequest;
++import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
 +import org.apache.olingo.client.api.communication.response.AsyncResponseWrapper;
++import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
 +import org.apache.olingo.client.api.communication.response.ODataResponse;
 +import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
 +import org.apache.olingo.client.api.domain.ClientEntity;
++import org.apache.olingo.client.api.domain.ClientEntitySet;
++import org.apache.olingo.client.api.domain.ClientObjectFactory;
++import org.apache.olingo.client.api.domain.ClientProperty;
++import org.apache.olingo.client.api.domain.ClientValue;
 +import org.apache.olingo.client.core.ODataClientFactory;
 +import org.apache.olingo.commons.api.data.Entity;
 +import org.apache.olingo.commons.api.data.ResWrap;
++import org.apache.olingo.commons.api.edm.FullQualifiedName;
 +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.fit.AbstractBaseTestITCase;
 +import org.apache.olingo.fit.tecsvc.TecSvcConst;
 +import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
 +import org.junit.Test;
 +
 +public final class AsyncSupportITCase extends AbstractBaseTestITCase {
 +  private static final String ES_ALL_PRIM = "ESAllPrim";
 +  private static final String SERVICE_URI = TecSvcConst.BASE_URI;
++  public static final int SLEEP_TIMEOUT_IN_MS = 100;
 +
 +  @Test
-   public void testSimple() throws Exception {
++  public void testReadEntity() throws Exception {
 +    ODataClient client = getClient();
 +    URI uri = client.newURIBuilder(SERVICE_URI)
 +        .appendEntitySetSegment(ES_ALL_PRIM)
 +        .appendKeySegment(32767).build();
 +
 +    //
 +    final ODataRetrieveResponse<ClientEntity> response = getClient().getRetrieveRequestFactory()
 +        .getEntityRequest(uri).execute();
 +    assertEquals(32767, response.getBody().getProperty("PropertyInt16").getPrimitiveValue().toValue());
 +    assertEquals(200, response.getStatusCode());
 +
 +    // first async request
++
 +    ODataRequest re1 = getClient().getRetrieveRequestFactory()
 +            .getEntityRequest(uri)
-             .addCustomHeader("Prefer", "respond-async, " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++            .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
 +    AsyncResponseWrapper<ODataResponse> first = client.getAsyncRequestFactory().getAsyncRequestWrapper(re1).execute();
 +
 +    assertTrue(first.isPreferenceApplied());
 +
 +    // second async request
 +    ODataRequest re2 = getClient().getRetrieveRequestFactory()
 +            .getEntityRequest(uri)
-             .addCustomHeader("Prefer", "respond-async, " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++            .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
 +    AsyncResponseWrapper<ODataResponse> second = client.getAsyncRequestFactory().getAsyncRequestWrapper(re2).execute();
 +    assertTrue(second.isPreferenceApplied());
 +
 +    // get result of first async request
 +    assertFalse(first.isDone());
 +
-     TimeUnit.SECONDS.sleep(2);
++    waitTillDone(first, 2);
 +    assertTrue(first.isDone());
 +
 +    assertNotNull(first.getODataResponse());
 +    ODataResponse firstResponse = first.getODataResponse();
 +    assertEquals(200, firstResponse.getStatusCode());
 +    ResWrap<Entity> entity = getClient().getDeserializer(ContentType.APPLICATION_JSON)
 +        .toEntity(firstResponse.getRawResponse());
 +    assertEquals(32767, entity.getPayload().getProperty("PropertyInt16").asPrimitive());
 +    assertEquals("First Resource - positive values", entity.getPayload().getProperty("PropertyString").asPrimitive());
 +  }
 +
++  @Test
++  public void testReadEntitySet() throws Exception {
++    ODataClient client = getClient();
++    URI uri = client.newURIBuilder(SERVICE_URI)
++        .appendEntitySetSegment(ES_ALL_PRIM)
++        .build();
++
++    //
++    final ODataRetrieveResponse<ClientEntitySet> response = getClient().getRetrieveRequestFactory()
++        .getEntitySetRequest(uri).execute();
++    assertEquals(200, response.getStatusCode());
++    ClientEntitySet responseBody = response.getBody();
++    assertEquals(3, responseBody.getEntities().size());
++    checkEntityAvailableWith(responseBody, "PropertyInt16", 32767);
++
++    // first async request
++    ODataRequest re1 = getClient().getRetrieveRequestFactory()
++        .getEntitySetRequest(uri)
++        .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++    AsyncResponseWrapper<ODataResponse> first = client.getAsyncRequestFactory().getAsyncRequestWrapper(re1).execute();
++
++    assertTrue(first.isPreferenceApplied());
++
++    // second async request
++    ODataRequest re2 = getClient().getRetrieveRequestFactory()
++        .getEntitySetRequest(uri)
++        .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++    AsyncResponseWrapper<ODataResponse> second = client.getAsyncRequestFactory().getAsyncRequestWrapper(re2).execute();
++    assertTrue(second.isPreferenceApplied());
++
++    // get result of first async request
++    assertFalse(first.isDone());
++
++    waitTillDone(first, 2);
++    assertTrue(first.isDone());
++
++    assertNotNull(first.getODataResponse());
++    ODataResponse firstResponse = first.getODataResponse();
++    assertEquals(200, firstResponse.getStatusCode());
++    ResWrap<Entity> entity = getClient().getDeserializer(ContentType.APPLICATION_JSON)
++        .toEntity(firstResponse.getRawResponse());
++    assertEquals(32767, entity.getPayload().getProperty("PropertyInt16").asPrimitive());
++    assertEquals("First Resource - positive values", entity.getPayload().getProperty("PropertyString").asPrimitive());
++  }
++
++  private void checkEntityAvailableWith(ClientEntitySet entitySet, String property, Object value) {
++    List<ClientEntity> entities = entitySet.getEntities();
++    for (ClientEntity entity : entities) {
++      ClientProperty ep = entity.getProperty("PropertyInt16");
++      if(ep != null) {
++        assertEquals(value, ep.getPrimitiveValue().toValue());
++        return;
++      }
++    }
++    fail("Entity with property '" + property +
++        "' and value '" + value + "' not found in entitySet '" + entitySet + "'");
++  }
++
++  private static final String NAV_PROPERTY_ET_TWO_PRIM_ONE = "NavPropertyETTwoPrimOne";
++
++  @Test
++  public void testCreateEntity() throws Exception {
++    ODataClient client = getClient();
++    URI uri = client.newURIBuilder(SERVICE_URI)
++        .appendEntitySetSegment(ES_ALL_PRIM).build();
++
++    //
++    final ClientObjectFactory factory = client.getObjectFactory();
++    ClientEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETAllPrim"));
++    newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt64",
++        factory.newPrimitiveValueBuilder().buildInt32(42)));
++    newEntity.addLink(factory.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_PRIM_ONE,
++        client.newURIBuilder(SERVICE_URI)
++            .appendEntitySetSegment("ESTwoPrim")
++            .appendKeySegment(32766)
++            .build()));
++
++    final ODataEntityCreateRequest<ClientEntity> createRequest =
++        client.getCUDRequestFactory().getEntityCreateRequest(uri, newEntity);
++    assertNotNull(createRequest);
++    final ODataEntityCreateResponse<ClientEntity> createResponse = createRequest.execute();
++
++    assertEquals(HttpStatusCode.CREATED.getStatusCode(), createResponse.getStatusCode());
++    assertEquals(SERVICE_URI + "/ESAllPrim(1)", createResponse.getHeader(HttpHeader.LOCATION).iterator().next());
++    final ClientEntity createdEntity = createResponse.getBody();
++    assertNotNull(createdEntity);
++    final ClientProperty property1 = createdEntity.getProperty("PropertyInt64");
++    assertNotNull(property1);
++    assertEquals(42, property1.getPrimitiveValue().toValue());
++    final ClientProperty property2 = createdEntity.getProperty("PropertyDecimal");
++    assertNotNull(property2);
++    assertNull(property2.getPrimitiveValue());    //
++
++
++//    // first async request
++//    ODataRequest re1 = getClient().getRetrieveRequestFactory()
++//        .getEntityRequest(uri)
++//        .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++//    AsyncResponseWrapper<ODataResponse> first = client.getAsyncRequestFactory().getAsyncRequestWrapper(re1).execute();
++//
++//    assertTrue(first.isPreferenceApplied());
++//
++//    // second async request
++//    ODataRequest re2 = getClient().getRetrieveRequestFactory()
++//        .getEntityRequest(uri)
++//        .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
++//    AsyncResponseWrapper<ODataResponse> second = client.getAsyncRequestFactory().getAsyncRequestWrapper(re2).execute();
++//    assertTrue(second.isPreferenceApplied());
++//
++//    // get result of first async request
++//    assertFalse(first.isDone());
++//
++//    waitTillDone(first, 2);
++//    assertTrue(first.isDone());
++//
++//    assertNotNull(first.getODataResponse());
++//    ODataResponse firstResponse = first.getODataResponse();
++//    assertEquals(200, firstResponse.getStatusCode());
++//    ResWrap<Entity> entity = getClient().getDeserializer(ContentType.APPLICATION_JSON)
++//        .toEntity(firstResponse.getRawResponse());
++//    assertEquals(32767, entity.getPayload().getProperty("PropertyInt16").asPrimitive());
++//    assertEquals("First Resource - positive values", entity.getPayload().getProperty("PropertyString").asPrimitive());
++  }
++
++
++  private void waitTillDone(AsyncResponseWrapper async, int maxWaitInSeconds) throws InterruptedException {
++    int waitCounter = maxWaitInSeconds * 1000;
++    while(!async.isDone() && waitCounter > 0) {
++      TimeUnit.MILLISECONDS.sleep(SLEEP_TIMEOUT_IN_MS);
++      waitCounter -= SLEEP_TIMEOUT_IN_MS;
++    }
++  }
++
 +  @Override
 +  protected ODataClient getClient() {
 +    ODataClient odata = ODataClientFactory.getClient();
 +    odata.getConfiguration().setDefaultPubFormat(ContentType.JSON);
 +    return odata;
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1476b034/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/async/TechnicalAsyncService.java
----------------------------------------------------------------------
diff --cc lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/async/TechnicalAsyncService.java
index 2b752f0,0000000..6a1cede
mode 100644,000000..100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/async/TechnicalAsyncService.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/async/TechnicalAsyncService.java
@@@ -1,250 -1,0 +1,259 @@@
 +/*
 + * 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.async;
 +
 +import java.io.Closeable;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.Map;
 +import java.util.concurrent.ExecutorService;
 +import java.util.concurrent.Executors;
 +import java.util.concurrent.TimeUnit;
 +import java.util.concurrent.atomic.AtomicInteger;
 +import java.util.regex.Matcher;
 +import java.util.regex.Pattern;
 +
 +import org.apache.olingo.commons.api.ODataRuntimeException;
 +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.ODataLibraryException;
 +import org.apache.olingo.server.api.ODataRequest;
 +import org.apache.olingo.server.api.ODataResponse;
 +import org.apache.olingo.server.api.processor.Processor;
 +import org.apache.olingo.server.api.serializer.SerializerException;
 +
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
 +public class TechnicalAsyncService {
 +
 +  public static final String TEC_ASYNC_SLEEP = "tec.sleep";
 +
 +  private static final Map<String, AsyncRunner> LOCATION_2_ASYNC_RUNNER =
 +      Collections.synchronizedMap(new HashMap<String, AsyncRunner>());
 +  private static final ExecutorService ASYNC_REQUEST_EXECUTOR = Executors.newFixedThreadPool(10);
 +  private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
 +  public static final String STATUS_MONITOR_TOKEN = "status";
 +
 +
- 
- 
 +  public <T extends Processor> AsyncProcessor<T> register(T processor, Class<T> processorInterface) {
 +    return new AsyncProcessor<T>(processor, processorInterface, this);
 +  }
 +
++  public static void updateHeader(ODataResponse response, HttpStatusCode status, String location) {
++    response.setStatusCode(status.getStatusCode());
++    response.setHeader(HttpHeader.LOCATION, location);
++    response.setHeader(HttpHeader.PREFERENCE_APPLIED, "respond-async");
++
++  }
++
++  public static void acceptedResponse(ODataResponse response, String location) {
++    updateHeader(response, HttpStatusCode.ACCEPTED, location);
++  }
++
 +
 +  private static final class AsyncProcessorHolder {
 +    private static final TechnicalAsyncService INSTANCE = new TechnicalAsyncService();
 +  }
 +
 +  public static TechnicalAsyncService getInstance() {
 +    return AsyncProcessorHolder.INSTANCE;
 +  }
 +
 +  public void shutdownThreadPool() {
 +    ASYNC_REQUEST_EXECUTOR.shutdown();
 +  }
 +
 +  public boolean isStatusMonitorResource(HttpServletRequest request) {
 +    return request.getRequestURL() != null && request.getRequestURL().toString().contains(STATUS_MONITOR_TOKEN);
 +  }
 +
 +  String processAsynchronous(AsyncProcessor dispatchedProcessor)
 +      throws ODataApplicationException, ODataLibraryException {
 +    // use executor thread pool
 +    String location = createNewAsyncLocation(dispatchedProcessor.getRequest());
 +    dispatchedProcessor.setLocation(location);
 +    AsyncRunner run = new AsyncRunner(dispatchedProcessor);
 +    LOCATION_2_ASYNC_RUNNER.put(location, run);
 +    ASYNC_REQUEST_EXECUTOR.execute(run);
 +    //
 +    return location;
 +  }
 +
 +  public void handle(HttpServletRequest request, HttpServletResponse response) throws SerializerException, IOException {
 +    String location = getAsyncLocation(request);
 +    AsyncRunner runner = LOCATION_2_ASYNC_RUNNER.get(location);
 +
 +    if(runner == null) {
 +      response.setStatus(HttpStatusCode.NOT_FOUND.getStatusCode());
 +    } else {
 +      if(runner.isFinished()) {
 +        ODataResponse wrapResult = runner.getDispatched().getProcessResponse();
 +        wrapToAsyncHttpResponse(wrapResult, response);
 +        LOCATION_2_ASYNC_RUNNER.remove(location);
 +      } else {
 +        response.setStatus(HttpStatusCode.ACCEPTED.getStatusCode());
 +        response.setHeader(HttpHeader.LOCATION, location);
 +        String content = "In progress for async location = " + location;
 +        writeToResponse(response, content);
 +      }
 +    }
 +  }
 +
 +  private static void writeToResponse(HttpServletResponse response, InputStream input) throws IOException {
 +    copy(input, response.getOutputStream());
 +  }
 +
 +  private void writeToResponse(HttpServletResponse response, String content) {
 +    writeToResponse(response, content.getBytes());
 +  }
 +
 +  private static void writeToResponse(HttpServletResponse response, byte[] content) {
 +    OutputStream output = null;
 +    try {
 +      output = response.getOutputStream();
 +      output.write(content);
 +    } catch (IOException e) {
 +      throw new ODataRuntimeException(e);
 +    } finally {
 +      closeStream(output);
 +    }
 +  }
 +
 +  static void wrapToAsyncHttpResponse(final ODataResponse odResponse, final HttpServletResponse response)
 +      throws SerializerException, IOException {
 +    OData odata = OData.newInstance();
 +    InputStream odResponseStream = odata.createFixedFormatSerializer().asyncResponse(odResponse);
 +
 +    response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_HTTP.toContentTypeString());
 +    response.setHeader(HttpHeader.CONTENT_ENCODING, "binary");
 +    response.setStatus(HttpStatusCode.OK.getStatusCode());
 +
 +    writeToResponse(response, odResponseStream);
 +  }
 +
 +  static void writeHttpResponse(final ODataResponse odResponse, final HttpServletResponse response) throws IOException {
 +    response.setStatus(odResponse.getStatusCode());
 +
 +    for (Map.Entry<String, String> entry : odResponse.getHeaders().entrySet()) {
 +      response.setHeader(entry.getKey(), entry.getValue());
 +    }
 +
 +    copy(odResponse.getContent(), response.getOutputStream());
 +  }
 +
 +  static void copy(final InputStream input, final OutputStream output) {
 +    if(output == null || input == null) {
 +      return;
 +    }
 +
 +    try {
 +      byte[] buffer = new byte[1024];
 +      int n;
 +      while (-1 != (n = input.read(buffer))) {
 +        output.write(buffer, 0, n);
 +      }
 +    } catch (IOException e) {
 +      throw new ODataRuntimeException(e);
 +    } finally {
 +      closeStream(output);
 +      closeStream(input);
 +    }
 +  }
 +
 +
 +  private static void closeStream(final Closeable closeable) {
 +    if (closeable != null) {
 +      try {
 +        closeable.close();
 +      } catch (IOException e) {
 +        throw new RuntimeException(e);
 +      }
 +    }
 +  }
 +
 +
 +  private String createNewAsyncLocation(ODataRequest request) {
 +    int pos = request.getRawBaseUri().lastIndexOf("/") + 1;
 +    return request.getRawBaseUri().substring(0, pos) + STATUS_MONITOR_TOKEN + "/" + ID_GENERATOR.incrementAndGet();
 +  }
 +
 +  private String getAsyncLocation(HttpServletRequest request) {
 +    return request.getRequestURL().toString();
 +  }
 +
 +  private static class AsyncRunner implements Runnable {
 +    private final AsyncProcessor dispatched;
 +    private int defaultSleepTimeInSeconds = 0;
 +    private Exception exception;
 +    boolean finished = false;
 +
 +    public AsyncRunner(AsyncProcessor wrap) {
 +      this(wrap, 0);
 +    }
 +
 +    public AsyncRunner(AsyncProcessor wrap, int defaultSleepTimeInSeconds) {
 +      this.dispatched = wrap;
 +      if(defaultSleepTimeInSeconds > 0) {
 +        this.defaultSleepTimeInSeconds = defaultSleepTimeInSeconds;
 +      }
 +    }
 +
 +    @Override
 +    public void run() {
 +      try {
 +        int sleep = getSleepTime(dispatched);
 +        TimeUnit.SECONDS.sleep(sleep);
 +        dispatched.process();
 +      } catch (Exception e) {
 +        exception = e;
 +      }
 +      finished = true;
 +    }
 +
 +    private int getSleepTime(AsyncProcessor wrap) {
 +      String preferHeader = wrap.getPreferHeader();
 +      Matcher matcher = Pattern.compile("(" + TEC_ASYNC_SLEEP +
 +              "=)(\\d*)").matcher(preferHeader);
 +      if (matcher.find()) {
 +        String waitTimeAsString = matcher.group(2);
 +        return Integer.parseInt(waitTimeAsString);
 +      }
 +      return defaultSleepTimeInSeconds;
 +    }
 +
 +    public Exception getException() {
 +      return exception;
 +    }
 +
 +    public boolean isFinished() {
 +      return finished;
 +    }
 +
 +    public AsyncProcessor getDispatched() {
 +      return dispatched;
 +    }
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1476b034/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --cc lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 60d7538,2045704..fc37b40
--- 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
@@@ -357,8 -339,9 +360,9 @@@ public class TechnicalEntityProcessor e
  
      final Entity entity = readEntity(uriInfo, true);
      final UriResourceNavigation navigationProperty = getLastNavigation(uriInfo);
+     ensureNavigationPropertyNotNull(navigationProperty);
      dataProvider.createReference(entity, navigationProperty.getProperty(), references.getEntityReferences().get(0),
 -        request.getRawBaseUri());
 +            request.getRawBaseUri());
  
      response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
    }
@@@ -398,23 -382,6 +403,20 @@@
    private void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
        final ContentType requestedFormat, final boolean isReference)
        throws ODataApplicationException, ODataLibraryException {
 +    //
 +    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
 +      TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
 +      TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
 +      processor.init(odata, serviceMetadata);
 +      AsyncProcessor<EntityProcessor> asyncProcessor = asyncService.register(processor, EntityProcessor.class);
 +      asyncProcessor.prepareFor().readEntity(request, response, uriInfo, requestedFormat);
 +      String location = asyncProcessor.processAsync();
-       //
-       response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
-       response.setHeader(HttpHeader.LOCATION, location);
-       response.setHeader(HttpHeader.PREFERENCE_APPLIED, "respond-async");
++      TechnicalAsyncService.acceptedResponse(response, location);
 +      //
 +      return;
 +    }
 +    //
 +
      final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
      final EdmEntityType edmEntityType = edmEntitySet == null ?
          (EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()
@@@ -453,6 -420,6 +455,21 @@@
    private void readEntityCollection(final ODataRequest request, final ODataResponse response,
        final UriInfo uriInfo, final ContentType requestedContentType, final boolean isReference)
        throws ODataApplicationException, ODataLibraryException {
++    //
++    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
++      TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
++      TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
++      processor.init(odata, serviceMetadata);
++      AsyncProcessor<EntityCollectionProcessor> asyncProcessor =
++          asyncService.register(processor, EntityCollectionProcessor.class);
++      asyncProcessor.prepareFor().readEntityCollection(request, response, uriInfo, requestedContentType);
++      String location = asyncProcessor.processAsync();
++      TechnicalAsyncService.acceptedResponse(response, location);
++      //
++      return;
++    }
++    //
++
      final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
      final EdmEntityType edmEntityType = edmEntitySet == null ?
          (EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()