View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.concurrent;
20  
21  import org.apache.shiro.SecurityUtils;
22  import org.apache.shiro.subject.Subject;
23  
24  import java.util.concurrent.Executor;
25  
26  /**
27   * {@code Executor} implementation that will automatically first associate any argument
28   * {@link Runnable} instances with the currently available {@link Subject} and then
29   * dispatch the Subject-enabled runnable to an underlying delegate {@link Executor}
30   * instance.
31   * <p/>
32   * This is a simplification for applications that want to execute code as the currently
33   * executing {@code Subject} on another thread, but don't want or need to call the
34   * {@link Subject#associateWith(Runnable)} method and dispatch to a Thread manually.  This
35   * simplifies code and reduces Shiro dependencies across application source code.
36   * <p/>
37   * Consider this code that could be repeated in many places across an application:
38   * <pre>
39   * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
40   * {@link Subject Subject} subject = {@link SecurityUtils SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()};
41   * {@link Runnable Runnable} work = subject.{@link Subject#associateWith(Runnable) associateWith(applicationWork)};
42   * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
43   * </pre>
44   * Instead, if the {@code Executor} instance used in application code is an instance of this class (which delegates
45   * to the target Executor that you want), all places in code like the above reduce to this:
46   * <pre>
47   * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
48   * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
49   * </pre>
50   * Notice there is no use of the Shiro API in the 2nd code block, encouraging the principle of loose coupling across
51   * your codebase.
52   *
53   * @see SubjectAwareExecutorService
54   * @since 1.0
55   */
56  public class SubjectAwareExecutor implements Executor {
57  
58      /**
59       * The target Executor instance that will actually execute the subject-associated Runnable instances.
60       */
61      private Executor targetExecutor;
62  
63      public SubjectAwareExecutor() {
64      }
65  
66      public SubjectAwareExecutor(Executor targetExecutor) {
67          if (targetExecutor == null) {
68              throw new NullPointerException("target Executor instance cannot be null.");
69          }
70          this.targetExecutor = targetExecutor;
71      }
72  
73      /**
74       * Returns the target Executor instance that will actually execute the subject-associated Runnable instances.
75       *
76       * @return target Executor instance that will actually execute the subject-associated Runnable instances.
77       */
78      public Executor getTargetExecutor() {
79          return targetExecutor;
80      }
81  
82      /**
83       * Sets target Executor instance that will actually execute the subject-associated Runnable instances.
84       *
85       * @param targetExecutor the target Executor instance that will actually execute the subject-associated Runnable
86       *                       instances.
87       */
88      public void setTargetExecutor(Executor targetExecutor) {
89          this.targetExecutor = targetExecutor;
90      }
91  
92      /**
93       * Returns the currently Subject instance that should be associated with Runnable or Callable instances before
94       * being dispatched to the target {@code Executor} instance.  This implementation merely defaults to returning
95       * {@code SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()}.
96       *
97       * @return the currently Subject instance that should be associated with Runnable or Callable instances before
98       *         being dispatched to the target {@code Executor} instance.
99       */
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 }