[OLINGO-708] Second proposal
This commit is contained in:
parent
2a841552f4
commit
3a736368e3
|
@ -20,6 +20,7 @@ package org.apache.olingo.server.api;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -97,6 +98,15 @@ public class ODataRequest {
|
||||||
return values == null ? null : values.get(0);
|
return values == null ? null : values.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all headers.
|
||||||
|
* @return an unmodifiable Map of header names/values
|
||||||
|
*/
|
||||||
|
public Map<String, List<String>> getAllHeaders() {
|
||||||
|
return Collections.unmodifiableMap(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the body of the request.
|
* Gets the body of the request.
|
||||||
* @return the request payload as {@link InputStream} or null
|
* @return the request payload as {@link InputStream} or null
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.olingo.server.api.ODataHttpHandler;
|
||||||
import org.apache.olingo.server.api.ServiceMetadata;
|
import org.apache.olingo.server.api.ServiceMetadata;
|
||||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||||
import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
|
import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
|
||||||
|
import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
|
||||||
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
||||||
import org.apache.olingo.server.tecsvc.processor.TechnicalActionProcessor;
|
import org.apache.olingo.server.tecsvc.processor.TechnicalActionProcessor;
|
||||||
import org.apache.olingo.server.tecsvc.processor.TechnicalBatchProcessor;
|
import org.apache.olingo.server.tecsvc.processor.TechnicalBatchProcessor;
|
||||||
|
@ -63,6 +64,12 @@ public class TechnicalServlet extends HttpServlet {
|
||||||
protected void service(final HttpServletRequest request, final HttpServletResponse response)
|
protected void service(final HttpServletRequest request, final HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
try {
|
try {
|
||||||
|
if(TechnicalAsyncService.getInstance().isStatusMonitorResource(request)) {
|
||||||
|
TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
|
||||||
|
asyncService.handle(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OData odata = OData.newInstance();
|
OData odata = OData.newInstance();
|
||||||
EdmxReference reference = new EdmxReference(URI.create("../v4.0/cs02/vocabularies/Org.OData.Core.V1.xml"));
|
EdmxReference reference = new EdmxReference(URI.create("../v4.0/cs02/vocabularies/Org.OData.Core.V1.xml"));
|
||||||
reference.addInclude(new EdmxReferenceInclude("Org.OData.Core.V1", "Core"));
|
reference.addInclude(new EdmxReferenceInclude("Org.OData.Core.V1", "Core"));
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class TechnicalServletContextListener implements ServletContextListener {
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent servletContextEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent servletContextEvent) {
|
||||||
|
TechnicalAsyncService.getInstance().shutdownThreadPool();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,400 @@
|
||||||
|
/*
|
||||||
|
* 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.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
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.http.HttpHeader;
|
||||||
|
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||||
|
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 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 = "async";
|
||||||
|
|
||||||
|
private static class MyInvocationHandler implements InvocationHandler {
|
||||||
|
private final Object wrappedInstance;
|
||||||
|
private Method invokeMethod;
|
||||||
|
private Object[] invokeParameters;
|
||||||
|
|
||||||
|
public MyInvocationHandler(Object wrappedInstance) {
|
||||||
|
this.wrappedInstance = wrappedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
|
||||||
|
if(Processor.class.isAssignableFrom(method.getDeclaringClass())) {
|
||||||
|
invokeMethod = method;
|
||||||
|
invokeParameters = objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ODataResponse processResponse;
|
||||||
|
|
||||||
|
public Object process() throws InvocationTargetException, IllegalAccessException {
|
||||||
|
processResponse = new ODataResponse();
|
||||||
|
replaceInvokeParameter(processResponse);
|
||||||
|
return invokeMethod.invoke(wrappedInstance, invokeParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getInvokeParameters() {
|
||||||
|
return invokeParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <P> void replaceInvokeParameter(P replacement) {
|
||||||
|
if(replacement == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> copy = new ArrayList<Object>();
|
||||||
|
for (Object parameter : invokeParameters) {
|
||||||
|
if (replacement.getClass() == parameter.getClass()) {
|
||||||
|
copy.add(replacement);
|
||||||
|
} else {
|
||||||
|
copy.add(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invokeParameters = copy.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <P> P getParameter(Class<P> parameterClass) {
|
||||||
|
for (Object parameter : invokeParameters) {
|
||||||
|
if (parameter != null && parameterClass == parameter.getClass()) {
|
||||||
|
return parameterClass.cast(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ODataResponse getProcessResponse() {
|
||||||
|
return processResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AsyncProcessor<T extends Processor> {
|
||||||
|
private final MyInvocationHandler handler;
|
||||||
|
private final TechnicalAsyncService service;
|
||||||
|
private final Object proxyInstance;
|
||||||
|
private final T proxyProcessor;
|
||||||
|
private String location;
|
||||||
|
private String preferHeader;
|
||||||
|
|
||||||
|
public AsyncProcessor(T processor, Class<T> processorInterface, TechnicalAsyncService service) {
|
||||||
|
Class<? extends Processor> aClass = processor.getClass();
|
||||||
|
Class[] interfaces = aClass.getInterfaces();
|
||||||
|
handler = new MyInvocationHandler(processor);
|
||||||
|
proxyInstance = Proxy.newProxyInstance(aClass.getClassLoader(), interfaces, handler);
|
||||||
|
proxyProcessor = processorInterface.cast(proxyInstance);
|
||||||
|
this.service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T prepareFor() {
|
||||||
|
return proxyProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ODataRequest getRequest() {
|
||||||
|
return getParameter(ODataRequest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ODataResponse getResponse() {
|
||||||
|
return getParameter(ODataResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ODataResponse getProcessResponse() {
|
||||||
|
return handler.getProcessResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private <P> P getParameter(Class<P> parameterClass) {
|
||||||
|
for (Object parameter : handler.getInvokeParameters()) {
|
||||||
|
if (parameter != null && parameterClass == parameter.getClass()) {
|
||||||
|
return parameterClass.cast(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String processAsync() throws ODataApplicationException, ODataLibraryException {
|
||||||
|
preferHeader = getRequest().getHeader(HttpHeader.PREFER);
|
||||||
|
ODataRequest request = copyRequest(getRequest());
|
||||||
|
handler.replaceInvokeParameter(request);
|
||||||
|
handler.replaceInvokeParameter(new ODataResponse());
|
||||||
|
return service.processAsynchronous(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object process() throws InvocationTargetException, IllegalAccessException {
|
||||||
|
return handler.process();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ODataRequest copyRequest(ODataRequest request) {
|
||||||
|
ODataRequest req = new ODataRequest();
|
||||||
|
req.setBody(request.getBody());
|
||||||
|
req.setMethod(request.getMethod());
|
||||||
|
req.setRawBaseUri(request.getRawBaseUri());
|
||||||
|
req.setRawODataPath(request.getRawODataPath());
|
||||||
|
req.setRawQueryPath(request.getRawQueryPath());
|
||||||
|
req.setRawRequestUri(request.getRawRequestUri());
|
||||||
|
req.setRawServiceResolutionUri(request.getRawServiceResolutionUri());
|
||||||
|
|
||||||
|
for (Map.Entry<String, List<String>> header : request.getAllHeaders().entrySet()) {
|
||||||
|
if(HttpHeader.PREFER.toLowerCase().equals(
|
||||||
|
header.getKey().toLowerCase())) {
|
||||||
|
preferHeader = header.getValue().get(0);
|
||||||
|
} else {
|
||||||
|
req.addHeader(header.getKey(), header.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPreferHeader() {
|
||||||
|
return preferHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocation(String loc) {
|
||||||
|
this.location = loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public <T extends Processor> AsyncProcessor<T> register(T processor, Class<T> processorInterface) {
|
||||||
|
return new AsyncProcessor<T>(processor, processorInterface, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.getRequestURI() != null && request.getRequestURI().contains(STATUS_MONITOR_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 status(ODataRequest request, ODataResponse response)
|
||||||
|
throws ODataApplicationException, ODataLibraryException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel(ODataRequest request, ODataResponse response)
|
||||||
|
throws ODataApplicationException, ODataLibraryException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
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();
|
||||||
|
convertToHttp(response, wrapResult);
|
||||||
|
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 void writeToResponse(HttpServletResponse response, String content) {
|
||||||
|
OutputStream output = null;
|
||||||
|
try {
|
||||||
|
output = response.getOutputStream();
|
||||||
|
output.write(content.getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ODataRuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
closeStream(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convertToHttp(final HttpServletResponse response, final ODataResponse odResponse) {
|
||||||
|
response.setStatus(odResponse.getStatusCode());
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> entry : odResponse.getHeaders().entrySet()) {
|
||||||
|
response.setHeader(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream input = odResponse.getContent();
|
||||||
|
if (input != null) {
|
||||||
|
OutputStream output = null;
|
||||||
|
try {
|
||||||
|
output = response.getOutputStream();
|
||||||
|
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) {
|
||||||
|
return request.getRawBaseUri() + "/" + STATUS_MONITOR_TOKEN + request.getRawODataPath() +
|
||||||
|
"?" + STATUS_MONITOR_TOKEN + "=" + ID_GENERATOR.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAsyncLocation(HttpServletRequest request) {
|
||||||
|
return "http://localhost:8080" + request.getRequestURI() + "?" + request.getQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAsyncQueryPart(ODataRequest request) {
|
||||||
|
String rawQueryPath = request.getRawQueryPath();
|
||||||
|
if(rawQueryPath != null) {
|
||||||
|
Matcher m = Pattern.compile("(" + STATUS_MONITOR_TOKEN + "=\\d*)").matcher(rawQueryPath);
|
||||||
|
if(m.find()) {
|
||||||
|
return m.group();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getRequest().getHeader(HttpHeader.PREFER);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,6 +60,7 @@ import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||||
import org.apache.olingo.server.api.uri.queryoption.IdOption;
|
import org.apache.olingo.server.api.uri.queryoption.IdOption;
|
||||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||||
|
import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
|
||||||
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
||||||
import org.apache.olingo.server.tecsvc.data.RequestValidator;
|
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.ExpandSystemQueryOptionHandler;
|
||||||
|
@ -143,6 +144,25 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||||
}
|
}
|
||||||
checkRequestFormat(requestFormat);
|
checkRequestFormat(requestFormat);
|
||||||
|
|
||||||
|
//
|
||||||
|
if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
|
||||||
|
TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
|
||||||
|
TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
|
||||||
|
processor.init(odata, serviceMetadata);
|
||||||
|
TechnicalAsyncService.AsyncProcessor<EntityProcessor> asyncProcessor =
|
||||||
|
asyncService.register(processor, EntityProcessor.class);
|
||||||
|
asyncProcessor.prepareFor().createEntity(request, response, uriInfo, requestFormat, responseFormat);
|
||||||
|
String location = asyncProcessor.processAsync();
|
||||||
|
//
|
||||||
|
response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
|
||||||
|
response.setHeader(HttpHeader.LOCATION, location);
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
|
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
|
||||||
final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
|
final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
|
||||||
final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||||
|
@ -167,7 +187,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||||
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
|
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
|
||||||
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
|
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
|
||||||
response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
|
response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
|
||||||
.getContent());
|
.getContent());
|
||||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||||
response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
|
response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
|
||||||
} else {
|
} else {
|
||||||
|
@ -217,13 +237,13 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||||
request.getRawBaseUri()).validate(edmEntitySet, changedEntity);
|
request.getRawBaseUri()).validate(edmEntitySet, changedEntity);
|
||||||
|
|
||||||
dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity,
|
dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity,
|
||||||
request.getMethod() == HttpMethod.PATCH, false);
|
request.getMethod() == HttpMethod.PATCH, false);
|
||||||
|
|
||||||
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
|
final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
|
||||||
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
|
if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
|
||||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||||
response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
|
response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
|
||||||
.getContent());
|
.getContent());
|
||||||
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
|
||||||
} else {
|
} else {
|
||||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||||
|
@ -337,7 +357,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||||
final Entity entity = readEntity(uriInfo, true);
|
final Entity entity = readEntity(uriInfo, true);
|
||||||
final UriResourceNavigation navigationProperty = getLastNavigation(uriInfo);
|
final UriResourceNavigation navigationProperty = getLastNavigation(uriInfo);
|
||||||
dataProvider.createReference(entity, navigationProperty.getProperty(), references.getEntityReferences().get(0),
|
dataProvider.createReference(entity, navigationProperty.getProperty(), references.getEntityReferences().get(0),
|
||||||
request.getRawBaseUri());
|
request.getRawBaseUri());
|
||||||
|
|
||||||
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
|
||||||
}
|
}
|
||||||
|
@ -377,6 +397,23 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||||
private void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
|
private void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
|
||||||
final ContentType requestedFormat, final boolean isReference)
|
final ContentType requestedFormat, final boolean isReference)
|
||||||
throws ODataApplicationException, ODataLibraryException {
|
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);
|
||||||
|
TechnicalAsyncService.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);
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
|
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
|
||||||
final EdmEntityType edmEntityType = edmEntitySet == null ?
|
final EdmEntityType edmEntityType = edmEntitySet == null ?
|
||||||
(EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()
|
(EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()
|
||||||
|
|
|
@ -39,4 +39,7 @@
|
||||||
<url-pattern>/odata.svc/*</url-pattern>
|
<url-pattern>/odata.svc/*</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<listener>
|
||||||
|
<listener-class>org.apache.olingo.server.tecsvc.TechnicalServletContextListener</listener-class>
|
||||||
|
</listener>
|
||||||
</web-app>
|
</web-app>
|
||||||
|
|
Loading…
Reference in New Issue