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 module hunt.shiro.concurrent.SubjectAwareExecutor;
20 
21 import hunt.shiro.SecurityUtils;
22 import hunt.shiro.subject.Subject;
23 
24 import hunt.Exceptions;
25 import hunt.util.Common;
26 import hunt.util.Runnable;
27 
28 
29 /**
30  * {@code Executor} implementation that will automatically first associate any argument
31  * {@link Runnable} instances with the currently available {@link Subject} and then
32  * dispatch the Subject-enabled runnable to an underlying delegate {@link Executor}
33  * instance.
34  * <p/>
35  * This is a simplification for applications that want to execute code as the currently
36  * executing {@code Subject} on another thread, but don't want or need to call the
37  * {@link Subject#associateWith(Runnable)} method and dispatch to a Thread manually.  This
38  * simplifies code and reduces Shiro dependencies across application source code.
39  * <p/>
40  * Consider this code that could be repeated in many places across an application:
41  * <pre>
42  * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
43  * {@link Subject Subject} subject = {@link SecurityUtils SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()};
44  * {@link Runnable Runnable} work = subject.{@link Subject#associateWith(Runnable) associateWith(applicationWork)};
45  * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
46  * </pre>
47  * Instead, if the {@code Executor} instance used in application code is an instance of this class (which delegates
48  * to the target Executor that you want), all places in code like the above reduce to this:
49  * <pre>
50  * {@link Runnable Runnable} applicationWork = //instantiate or acquire Runnable from somewhere
51  * {@link Executor anExecutor}.{@link Executor#execute(Runnable) execute(work)};
52  * </pre>
53  * Notice there is no use of the Shiro API in the 2nd code block, encouraging the principle of loose coupling across
54  * your codebase.
55  *
56  * @see SubjectAwareExecutorService
57  */
58 class SubjectAwareExecutor : Executor {
59 
60     /**
61      * The target Executor instance that will actually execute the subject-associated Runnable instances.
62      */
63     private Executor targetExecutor;
64 
65     this() {
66     }
67 
68     this(Executor targetExecutor) {
69         if (targetExecutor  is null) {
70             throw new NullPointerException("target Executor instance cannot be null.");
71         }
72         this.targetExecutor = targetExecutor;
73     }
74 
75     /**
76      * Returns the target Executor instance that will actually execute the subject-associated Runnable instances.
77      *
78      * @return target Executor instance that will actually execute the subject-associated Runnable instances.
79      */
80     Executor getTargetExecutor() {
81         return targetExecutor;
82     }
83 
84     /**
85      * Sets target Executor instance that will actually execute the subject-associated Runnable instances.
86      *
87      * @param targetExecutor the target Executor instance that will actually execute the subject-associated Runnable
88      *                       instances.
89      */
90      void setTargetExecutor(Executor targetExecutor) {
91         this.targetExecutor = targetExecutor;
92     }
93 
94     /**
95      * Returns the currently Subject instance that should be associated with Runnable or Callable instances before
96      * being dispatched to the target {@code Executor} instance.  This implementation merely defaults to returning
97      * {@code SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()}.
98      *
99      * @return the currently Subject instance that should be associated with Runnable or Callable instances before
100      *         being dispatched to the target {@code Executor} instance.
101      */
102     // protected Subject getSubject() {
103     //     return SecurityUtils.getSubject();
104     // }
105 
106     /**
107      * Utility method for subclasses to associate the argument {@code Runnable} with the currently executing subject
108      * and then return the associated Runnable.  The default implementation merely defaults to
109      * <pre>
110      * Subject subject = {@link #getSubject() getSubject()};
111      * return subject.{@link Subject#associateWith(Runnable) associateWith(r)};
112      * </pre>
113      *
114      * @param r the argument runnable to be associated with the current subject
115      * @return the associated runnable instance reflecting the current subject
116      */
117     // protected Runnable associateWithSubject(Runnable r) {
118     //     Subject subject = getSubject();
119     //     return subject.associateWith(r);
120     // }
121 
122     /**
123      * Executes the specified runnable by first associating it with the currently executing {@code Subject} and then
124      * dispatches the associated Runnable to the underlying target {@link Executor} instance.
125      *
126      * @param command the runnable to associate with the currently executing subject and then to execute via the target
127      *                {@code Executor} instance.
128      */
129      void execute(Runnable command) {
130         import hunt.logging.Logger;
131         warning("dddddddddddddddddddddd");
132         // Runnable associated = associateWithSubject(command);
133         // getTargetExecutor().execute(associated);
134     }
135 }