@SuppressWarnings("unchecked") protected void onInvocation(final HandlerContext ctx, final Invocation invocation) { final RemoteReference toReference = invocation.getToReference(); final LocalObjects.LocalObjectEntry<Object> entry = objects.findLocalObjectByReference(toReference); if (entry != null) { final Task<Object> result = InternalUtils.safeInvoke( () -> entry.run(target -> performInvocation(ctx, invocation, entry, target))); // this has to be done here because of exceptions that can occur before performInvocation is // even called. if (invocation.getCompletion() != null) { InternalUtils.linkFuturesOnError(result, invocation.getCompletion()); } } else { if (toReference instanceof Actor) { // on activate will handle the completion; InternalUtils.safeInvoke( () -> executionSerializer.offerJob( toReference, () -> onActivate(ctx, invocation), maxQueueSize)); } else { // missing actor observer invocation.setHops(invocation.getHops() + 1); if (invocation.getCompletion() != null) { invocation.getCompletion().completeExceptionally(new ObserverNotFound()); } } } }
@SuppressWarnings("unchecked") protected Task<Object> performInvocation( HandlerContext ctx, final Invocation invocation, final LocalObjects.LocalObjectEntry entry, final LocalObjects.LocalObjectEntry target) { if (logger.isDebugEnabled()) { logger.debug("Invoking {} ", invocation); } try { if (target == null || target.isDeactivated()) { // if the entry is deactivated, forward the message back to the net. ctx.write(invocation); return Task.fromValue(null); } if (target.getObject() == null) { if (target instanceof ObserverEntry) { return Task.fromException(new ObserverNotFound()); } ctx.write(invocation); return Task.fromValue(null); } final ObjectInvoker invoker = DefaultDescriptorFactory.get().getInvoker(target.getObject().getClass()); final ActorTaskContext context = ActorTaskContext.current(); if (invocation.getHeaders() != null && invocation.getHeaders().size() > 0 && runtime.getStickyHeaders() != null) { for (Map.Entry e : invocation.getHeaders().entrySet()) { if (runtime.getStickyHeaders().contains(e.getKey())) { context.setProperty(String.valueOf(e.getKey()), e.getValue()); } } } // todo: it would be nice to separate this last part into another handler (InvocationHandler) // to be able intercept the invocation right before it actually happens, good for logging and // metrics if (context != null) { context.setRuntime(runtime); } else { runtime.bind(); } final Task result = invoker.safeInvoke(target.getObject(), invocation.getMethodId(), invocation.getParams()); if (invocation.getCompletion() != null) { InternalUtils.linkFutures(result, invocation.getCompletion()); } return result; } catch (Throwable exception) { if (logger.isDebugEnabled()) { logger.debug("Unknown application error. ", exception); } if (invocation.getCompletion() != null) { invocation.getCompletion().completeExceptionally(exception); } return Task.fromException(exception); } }
private Task<Void> onActivate(HandlerContext ctx, final Invocation invocation) { // this must run serialized by the remote reference key. LocalObjects.LocalObjectEntry<Object> entry = objects.findLocalObjectByReference(invocation.getToReference()); if (entry == null) { objects.registerLocalObject(invocation.getToReference(), null); entry = objects.findLocalObjectByReference(invocation.getToReference()); } // queues the invocation final LocalObjects.LocalObjectEntry<Object> theEntry = entry; final Task result = entry.run(target -> performInvocation(ctx, invocation, theEntry, target)); if (invocation.getCompletion() != null) { InternalUtils.linkFuturesOnError(result, invocation.getCompletion()); } // yielding since we blocked the entry before running on activate (serialized execution) return Task.done(); }