code: @Override
  	public ActivityData call() throws ActivityException {
  				
  		try {
  			// do the real work asynchronously...
  			logger.trace("activity '{}' at index {} starting", info.getActivity().getId(), index); 
  			return info.getActivity().perform(info.getContext(), info.getData());
  		} catch(Exception e) {
  			logger.error("thread interrupted while executing task '{}' at index {}", info.getActivity().getId(), index);
  			throw new ActivityException("Thread interrupted while executing task '" + info.getActivity().getId() + "' at index " + index, e);
  		} finally {
  			// signal that the task is complete
  			logger.trace("task '{}' at index {} is complete (queue size: {})", info.getActivity().getId(), index, queue.size());
  			queue.offer(index);
  		}
  	}
docs: Actual thread's workhorse method; it implements a "code around" pattern,
  and delegates actual business logic to the {@code Activity}, while retaining
  the logic necessary to signal completion to the caller.
  
  @see java.util.concurrent.Callable#call()