001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.concurrent;
020
021import org.apache.shiro.SecurityUtils;
022import org.apache.shiro.subject.Subject;
023
024import java.util.concurrent.Executor;
025
026/**
027 * {@code Executor} implementation that will automatically first associate any argument
028 * {@link Runnable} instances with the currently available {@link Subject} and then
029 * dispatch the Subject-enabled runnable to an underlying delegate {@link Executor}
030 * instance.
031 * <p/>
032 * This is a simplification for applications that want to execute code as the currently
033 * executing {@code Subject} on another thread, but don't want or need to call the
034 * {@link Subject#associateWith(Runnable)} method and dispatch to a Thread manually.  This
035 * simplifies code and reduces Shiro dependencies across application source code.
036 * <p/>
037 * Consider this code that could be repeated in many places across an application:
038 * <pre>
039 * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
040 * {@link Subject Subject} subject = {@link SecurityUtils SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()};
041 * {@link Runnable Runnable} work = subject.{@link Subject#associateWith(Runnable) associateWith(applicationWork)};
042 * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
043 * </pre>
044 * Instead, if the {@code Executor} instance used in application code is an instance of this class (which delegates
045 * to the target Executor that you want), all places in code like the above reduce to this:
046 * <pre>
047 * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
048 * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
049 * </pre>
050 * Notice there is no use of the Shiro API in the 2nd code block, encouraging the principle of loose coupling across
051 * your codebase.
052 *
053 * @see SubjectAwareExecutorService
054 * @since 1.0
055 */
056public class SubjectAwareExecutor implements Executor {
057
058    /**
059     * The target Executor instance that will actually execute the subject-associated Runnable instances.
060     */
061    private Executor targetExecutor;
062
063    public SubjectAwareExecutor() {
064    }
065
066    public SubjectAwareExecutor(Executor targetExecutor) {
067        if (targetExecutor == null) {
068            throw new NullPointerException("target Executor instance cannot be null.");
069        }
070        this.targetExecutor = targetExecutor;
071    }
072
073    /**
074     * Returns the target Executor instance that will actually execute the subject-associated Runnable instances.
075     *
076     * @return target Executor instance that will actually execute the subject-associated Runnable instances.
077     */
078    public Executor getTargetExecutor() {
079        return targetExecutor;
080    }
081
082    /**
083     * Sets target Executor instance that will actually execute the subject-associated Runnable instances.
084     *
085     * @param targetExecutor the target Executor instance that will actually execute the subject-associated Runnable
086     *                       instances.
087     */
088    public void setTargetExecutor(Executor targetExecutor) {
089        this.targetExecutor = targetExecutor;
090    }
091
092    /**
093     * Returns the currently Subject instance that should be associated with Runnable or Callable instances before
094     * being dispatched to the target {@code Executor} instance.  This implementation merely defaults to returning
095     * {@code SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()}.
096     *
097     * @return the currently Subject instance that should be associated with Runnable or Callable instances before
098     *         being dispatched to the target {@code Executor} instance.
099     */
100    protected Subject getSubject() {
101        return SecurityUtils.getSubject();
102    }
103
104    /**
105     * Utility method for subclasses to associate the argument {@code Runnable} with the currently executing subject
106     * and then return the associated Runnable.  The default implementation merely defaults to
107     * <pre>
108     * Subject subject = {@link #getSubject() getSubject()};
109     * return subject.{@link Subject#associateWith(Runnable) associateWith(r)};
110     * </pre>
111     *
112     * @param r the argument runnable to be associated with the current subject
113     * @return the associated runnable instance reflecting the current subject
114     */
115    protected Runnable associateWithSubject(Runnable r) {
116        Subject subject = getSubject();
117        return subject.associateWith(r);
118    }
119
120    /**
121     * Executes the specified runnable by first associating it with the currently executing {@code Subject} and then
122     * dispatches the associated Runnable to the underlying target {@link Executor} instance.
123     *
124     * @param command the runnable to associate with the currently executing subject and then to execute via the target
125     *                {@code Executor} instance.
126     */
127    public void execute(Runnable command) {
128        Runnable associated = associateWithSubject(command);
129        getTargetExecutor().execute(associated);
130    }
131}