--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.method;
+
+import java.util.concurrent.Semaphore;\r
+import java.util.concurrent.TimeUnit;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.method.MethodInterface.AsyncRequestStatus;\r
+import org.simantics.databoard.method.MethodInterface.AsyncResult;\r
+import org.simantics.databoard.method.MethodInterface.ExecutionError;\r
+import org.simantics.databoard.method.MethodInterface.InvokeListener;\r
+
+public class AsyncResultImpl implements AsyncResult {
+
+ /**
+ * Log4J Error logger.
+ * Security settings are logged with DEBUG level.
+ * Unexpected errors are logged with ERROR level.
+ */
+ static Logger LOGGER = Logger.getLogger("AsyncResultImpl");
+
+ InvokeException invokeException;
+ Object executionError;
+
+ Object response;
+
+ InvokeListener listener;
+
+ // Optional adapters
+ Adapter responseAdapter, errorAdapter;
+
+ Semaphore sleeper = new Semaphore(0);
+
+ public AsyncResultImpl() {
+ }
+
+ @Override
+ public Object getExecutionError() {
+ return executionError;
+ }
+
+ @Override
+ public InvokeException getInvokeException() {
+ return invokeException;
+ }
+
+ public void setInvokeException(final InvokeException error)
+ {
+ this.invokeException = error;
+ final InvokeListener l = listener;
+ sleeper.release(Integer.MAX_VALUE);
+
+ if (l != null) {
+ // TODO use executor instead
+ new Thread() {
+ public void run() {
+ try {
+ l.onException((Exception) error.getCause());
+ } catch (RuntimeException e) {
+ LOGGER.log(Level.SEVERE, "Unexpected runtime exception", e);
+ }
+ };
+ }.start();
+ }
+
+ }
+
+ public void setResponse(Object response) {
+ if (responseAdapter!=null) {
+ try {
+ response = responseAdapter.adapt(response);
+ } catch (AdaptException e) {
+ setInvokeException( new InvokeException("Failed to adapt the respose "+response, e) );
+ return;
+ }
+ }
+
+ this.response = response;
+ final InvokeListener l = listener;
+ sleeper.release(Integer.MAX_VALUE);
+
+ if (l != null) {
+ // TODO use executor instead
+ new Thread() {
+ public void run() {
+ try {
+ l.onCompleted(AsyncResultImpl.this.response);
+ } catch (RuntimeException e) {
+ LOGGER.log(Level.SEVERE, "Unexpected runtime exception", e);
+ }
+ };
+ }.start();
+ }
+ }
+
+ public void setExecutionError(Object executionError) {
+
+ if (errorAdapter!=null) {
+ // Adapt execution error using adapter
+ try {
+ executionError = errorAdapter.adapt(executionError);
+ } catch (AdaptException e) {
+ // Unable to adapt execution error. This is now an invokcation error
+ setInvokeException(new InvokeException("Execution and Invoke failed. Failed to adapt executionError ("+executionError+")", e));
+ return;
+ }
+ }
+
+ this.executionError = executionError;
+ final InvokeListener l = listener;
+ sleeper.release(Integer.MAX_VALUE);
+
+ if (l != null) {
+ // TODO use executor instead
+ new Thread() {
+ public void run() {
+ l.onExecutionError(AsyncResultImpl.this.executionError);
+ // TODO Capture runtimeException, push to log4j
+ };
+ }.start();
+ }
+ }
+
+
+ @Override
+ public Object getResponse() {
+ return response;
+ }
+
+ @Override
+ public AsyncRequestStatus getStatus() {
+ if (invokeException!=null || executionError!=null)
+ return AsyncRequestStatus.Failed;
+ if (response!=null)
+ return AsyncRequestStatus.Succeed;
+ return AsyncRequestStatus.Waiting;
+ }
+
+ @Override
+ public void setListener(InvokeListener listener) {
+ // FIXME event is lost if error/result is set at the same time
+ if (listener!=null) {
+ if (response!=null) listener.onCompleted(response);
+ if (invokeException!=null) listener.onException((Exception)invokeException.getCause());
+ if (executionError!=null) listener.onExecutionError(executionError);
+ }
+ this.listener = listener;
+ }
+
+ @Override
+ public Object waitForResponse() throws InvokeException, ExecutionError, InterruptedException {
+ sleeper.acquire();
+ if (response!=null) return response;
+ if (invokeException!=null) throw invokeException;
+ if (executionError!=null) throw new ExecutionError(executionError);
+ return null;
+ }
+
+ @Override
+ public Object waitForResponse(long timeout, TimeUnit unit)
+ throws InvokeException, ExecutionError, InterruptedException {
+ sleeper.tryAcquire(timeout, unit);
+ if (response!=null) return response;
+ if (invokeException!=null) throw invokeException;
+ if (executionError!=null) throw new ExecutionError(executionError);
+ return null;
+ }
+
+ public void setResponseAdapter(Adapter responseAdapter) {
+ this.responseAdapter = responseAdapter;
+ }
+
+ public void setErrorAdapter(Adapter errorAdapter) {
+ this.errorAdapter = errorAdapter;
+ }
+
+}
+