Search in sources :

Example 1 with AwaitContext

use of com.disney.groovity.tags.Await.AwaitContext in project groovity by disney.

the class Async method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, final Closure body) throws Exception {
    final Integer timeoutSeconds = resolve(attributes, TIMEOUT, Integer.class);
    final ScriptHelper scriptHelper = getScriptHelper(body);
    final Binding binding = scriptHelper.getBinding();
    final Map variables = binding.getVariables();
    final AwaitContext asyncContext = AwaitContext.get(variables);
    DeadlockFreeExecutor createdThreadPool = null;
    // make a copy of current binding for async
    final Map asyncVariables = asyncCopy(variables);
    if (asyncContext == null || !asyncVariables.containsKey(Async.EXECUTOR_BINDING)) {
        Integer numThreads = resolve(attributes, POOL, Integer.class);
        if (numThreads != null) {
            createdThreadPool = new DeadlockFreeExecutor(interruptFactory, numThreads);
            asyncVariables.put(EXECUTOR_BINDING, createdThreadPool);
        }
    }
    final DeadlockFreeExecutor asyncPool = createdThreadPool != null ? createdThreadPool : ((asyncContext != null) ? getExecutor(asyncVariables) : sharedThreadPool);
    final boolean shutdownPool = createdThreadPool != null;
    final CharArrayWriter out = new CharArrayWriter();
    asyncVariables.put(OUT, out);
    if (asyncContext != null) {
        // signal a boundary for sequencing async output
        asyncContext.signalAsync(variables, out);
    }
    final Execution parentStack = asyncContext != null ? asyncContext.getWaitingExecution() : null;
    String scriptPath = scriptHelper.getClassLoader().getScriptName();
    final long timeoutTime = timeoutSeconds == null ? -1 : System.currentTimeMillis() + (timeoutSeconds * 1000);
    final Callable<Object> bodyRunner = new Callable<Object>() {

        @Override
        public Object call() throws Exception {
            Binding asyncBinding = new Binding(asyncVariables);
            Binding oldThreadBinding = ScriptHelper.THREAD_BINDING.get();
            ScriptHelper.THREAD_BINDING.set(asyncBinding);
            final Execution restoreStack = parentStack != null ? GroovityStatistics.registerStack(parentStack) : null;
            try {
                Closure asyncBody;
                if (body.getThisObject() instanceof Class) {
                    // if the parent script is not available it is a special case (static) and we may share the context
                    asyncBody = body;
                    asyncBody.setDelegate(asyncBinding);
                    asyncBody.setResolveStrategy(Closure.DELEGATE_FIRST);
                } else {
                    Script asyncInstance = scriptHelper.load(scriptPath);
                    asyncBody = body.rehydrate(asyncInstance, asyncInstance, asyncInstance);
                }
                if (timeoutTime > 0) {
                    // use an interrupt to enforce the timeout
                    long startTime = System.currentTimeMillis();
                    if (startTime > timeoutTime) {
                        throw new InterruptedException();
                    }
                    final ScheduledFuture<?> interrupt = interruptFactory.scheduleInterrupt(timeoutTime - startTime);
                    try {
                        return asyncBody.call();
                    } finally {
                        interrupt.cancel(true);
                    }
                }
                return asyncBody.call();
            } catch (Throwable e) {
                if (asyncContext == null) {
                    // with no known waiters this exception could get lost, let's log it
                    log.log(Level.SEVERE, "Error in async", e);
                }
                throw e;
            } finally {
                if (oldThreadBinding == null) {
                    ScriptHelper.THREAD_BINDING.remove();
                } else {
                    ScriptHelper.THREAD_BINDING.set(oldThreadBinding);
                }
                if (parentStack != null) {
                    GroovityStatistics.registerStack(restoreStack);
                }
                if (shutdownPool) {
                    sharedThreadPool.submit(new Runnable() {

                        @Override
                        public void run() {
                            asyncPool.shutdown();
                            try {
                                if (!asyncPool.awaitTermination(60, TimeUnit.SECONDS)) {
                                    asyncPool.shutdownNow();
                                    asyncPool.awaitTermination(60, TimeUnit.SECONDS);
                                }
                            } catch (InterruptedException e) {
                                asyncPool.shutdownNow();
                            }
                        }
                    });
                }
            }
        }
    };
    Future<Object> future = asyncPool.submit(bodyRunner);
    if (asyncContext != null) {
        asyncContext.add(future);
    }
    String var = resolve(attributes, VAR, String.class);
    if (var != null && var.length() > 0) {
        variables.put(var, future);
    }
    return future;
}
Also used : Binding(groovy.lang.Binding) Script(groovy.lang.Script) Closure(groovy.lang.Closure) CharArrayWriter(java.io.CharArrayWriter) Callable(java.util.concurrent.Callable) Execution(com.disney.groovity.stats.GroovityStatistics.Execution) ScriptHelper(com.disney.groovity.util.ScriptHelper) HashMap(java.util.HashMap) Map(java.util.Map) AwaitContext(com.disney.groovity.tags.Await.AwaitContext) DeadlockFreeExecutor(com.disney.groovity.util.DeadlockFreeExecutor)

Example 2 with AwaitContext

use of com.disney.groovity.tags.Await.AwaitContext in project groovity by disney.

the class Accept method tag.

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, Closure body) throws Exception {
    // channel may be null, which will create an anonymous channel that can only be offered to via reference
    Object channel = resolve(attributes, "channel");
    Policy policy = Policy.block;
    String policyStr = resolve(attributes, "policy", String.class);
    if (policyStr != null) {
        policy = Policy.valueOf(policyStr);
    }
    int qSize = -1;
    Object qDef = resolve(attributes, "q");
    if (qDef != null) {
        if (qDef instanceof Number) {
            qSize = ((Number) qDef).intValue();
        } else {
            qSize = Integer.valueOf(qDef.toString());
        }
    }
    Closure completed = resolve(attributes, "completed", Closure.class);
    final ScriptHelper scriptHelper = getScriptHelper(body);
    final Binding binding = scriptHelper.getBinding();
    final Map variables = binding.getVariables();
    final Map asyncVariables = Async.asyncCopy(variables);
    final AwaitContext asyncContext = AwaitContext.get(variables);
    final CharArrayWriter out = new CharArrayWriter();
    asyncVariables.put(OUT, out);
    if (asyncContext != null) {
        // signal a boundary for sequencing async output
        asyncContext.signalAsync(variables, out);
    }
    Binding asyncBinding = new Binding(asyncVariables);
    Object owner;
    if (body.getThisObject() instanceof Class) {
        // if the parent script is not available it is a special case (static) and we may share the context
        owner = body.getOwner();
    } else {
        // in normal contexts create a safe copy of the script
        Binding oldThreadBinding = ScriptHelper.THREAD_BINDING.get();
        ScriptHelper.THREAD_BINDING.set(asyncBinding);
        try {
            owner = scriptHelper.load(scriptHelper.getClassLoader().getScriptName());
        } finally {
            if (oldThreadBinding == null) {
                ScriptHelper.THREAD_BINDING.remove();
            } else {
                ScriptHelper.THREAD_BINDING.set(oldThreadBinding);
            }
        }
    }
    AsyncChannel asyncChan = AsyncChannel.open(sharedThreadPool, channel, qSize, policy, body, completed, owner, asyncBinding);
    String var = resolve(attributes, "var", String.class);
    if (var != null && var.length() > 0) {
        bind(body, var, asyncChan);
    }
    if (asyncContext != null) {
        asyncContext.add(asyncChan.getFuture());
    }
    return asyncChan;
}
Also used : Policy(com.disney.groovity.util.AsyncChannel.Policy) Binding(groovy.lang.Binding) Closure(groovy.lang.Closure) AsyncChannel(com.disney.groovity.util.AsyncChannel) CharArrayWriter(java.io.CharArrayWriter) ScriptHelper(com.disney.groovity.util.ScriptHelper) Map(java.util.Map) AwaitContext(com.disney.groovity.tags.Await.AwaitContext)

Aggregations

AwaitContext (com.disney.groovity.tags.Await.AwaitContext)2 ScriptHelper (com.disney.groovity.util.ScriptHelper)2 Binding (groovy.lang.Binding)2 Closure (groovy.lang.Closure)2 CharArrayWriter (java.io.CharArrayWriter)2 Map (java.util.Map)2 Execution (com.disney.groovity.stats.GroovityStatistics.Execution)1 AsyncChannel (com.disney.groovity.util.AsyncChannel)1 Policy (com.disney.groovity.util.AsyncChannel.Policy)1 DeadlockFreeExecutor (com.disney.groovity.util.DeadlockFreeExecutor)1 Script (groovy.lang.Script)1 HashMap (java.util.HashMap)1 Callable (java.util.concurrent.Callable)1