/******************************************************************************* * Copyright (c) 2010 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.method; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.adapter.Adapter; import org.simantics.databoard.method.MethodInterface.AsyncRequestStatus; import org.simantics.databoard.method.MethodInterface.AsyncResult; import org.simantics.databoard.method.MethodInterface.ExecutionError; import org.simantics.databoard.method.MethodInterface.InvokeListener; 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; } }