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 }