Package org.jboss.seam.cron.spi.asynchronous

Source Code of org.jboss.seam.cron.spi.asynchronous.AsynchronousInterceptor

/**
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.seam.cron.spi.asynchronous;

import java.util.concurrent.Future;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.jboss.seam.cron.api.asynchronous.Asynchronous;
import org.jboss.seam.cron.api.queue.Queue;
import org.jboss.seam.cron.impl.scheduling.exception.InternalException;
import org.jboss.seam.cron.spi.SeamCronExtension;
import org.jboss.solder.logging.Logger;

/**
* <p>
* Interceptor for asynchronous methods. Service providers for asynchronous
* method invocation should enable this interceptor in the beans.xml which ships
* with their implementation jar.
* </p><p>
* Method may be directly marked as #{@link Asynchronous} or may exist on a type
* marked as #{@link Asynchronous}.
* </p>
*
* @author Peter Royle
*/
@Asynchronous
@Interceptor
public class AsynchronousInterceptor {

    // We need to track where the method is being invoked from so that we can
    // handle it properly.
    protected static final String INVOKED_IN_THREAD = "INVOKED_IN_THREAD";
    public ThreadLocal<Boolean> invokedFromInterceptorInThread = new ThreadLocal<Boolean>();
    Logger log = Logger.getLogger(AsynchronousInterceptor.class);
    @Inject
    BeanManager beanMan;
    @Inject
    Instance<Invoker> iceCopies;
    @Inject SeamCronExtension cronExtension;

    public AsynchronousInterceptor() {
    }

    @AroundInvoke
    private Object executeAsynchronously(final InvocationContext ctx) throws Exception {

        if (invokedFromInterceptorInThread.get() == null) {

            if (ctx.getContextData().get(INVOKED_IN_THREAD) == null) {

                // Step 1. When the method is invoked originally, the interceptor
                // which wraps it will land here, because the InvocationContext
                // hasn't been fiddled with in the background thread.

                Object result = null;

                if (log.isTraceEnabled()) {
                    log.trace("Intercepting method invocation of " + ctx.getMethod().getName() + " to make it @Asynchronous");
                }

                Queue queue = ctx.getMethod().getAnnotation(Queue.class);
                String queueId = queue == null ? null : queue.value();

                final Invoker ice = iceCopies.get();
                ice.setInvocationContext(ctx);
                final CronAsynchronousProvider asyncStrategy = cronExtension.getAsynchronousProvider();

                if (Future.class.isAssignableFrom(ctx.getMethod().getReturnType())) {
                    // swap the "dummy" Future for a truly asynchronous future to return to the caller immediately
                    ice.setPopResultsFromFuture(true);
                    result = asyncStrategy.executeAndReturnFuture(queueId, ice);
                } else {
                    asyncStrategy.executeWithoutReturn(queueId, ice);
                    result = null;
                }

                // this will either be a Future, or null
                return result;

            } else {

                // Step 2. The new thread (created in Step 1 above) will assign
                // INVOKED_IN_THREAD to TRUE in the InvocationContext and then
                // invoke ctx.proceed(). The interceptor which wraps that invocation
                // will land here.

                if (Boolean.TRUE.equals(ctx.getContextData().get(INVOKED_IN_THREAD))) {
                    if (log.isTraceEnabled()) {
                        log.trace("Executing original method in new thread for " + ctx.getMethod().getName());
                    }
                    invokedFromInterceptorInThread.set(Boolean.TRUE);
                    return ctx.proceed();
                } else {
                    throw new InternalException("The framework got into an illegal state while atempting to keep track of Interceptors around asynchronous method invocations. This is certainly a bug. Please file it in the SEAMCRON Jira with full stack trace");
                }
            }
        } else {

            // The interceptor around the backgrounded method invocation
            // will set the invokedFromInterceptorInThread ThreadLocal to true
            // (see Step 2 above) and then invoke ctx.proceed(); The interceptor
            // around that invocation will land here. This simply forwards
            // execution to the originating method in this new thread, which will
            // not cause any further interceptors to be triggered.

            if (log.isTraceEnabled()) {
                log.trace("Bypassing interceptor in new thread for " + ctx.getMethod().getName());
            }
            return ctx.proceed();
        }

    }
}
TOP

Related Classes of org.jboss.seam.cron.spi.asynchronous.AsynchronousInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.