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.env.DefaultEnvironment;
20 
21 import hunt.shiro.env.NamedObjectEnvironment;
22 
23 import hunt.shiro.Exceptions;
24 import hunt.shiro.mgt.SecurityManager;
25 import hunt.shiro.util.Common;
26 import hunt.shiro.util.LifecycleUtils;
27 
28 import hunt.collection;
29 import hunt.Exceptions;
30 
31 import std.array;
32 
33 /**
34  * Simple/default {@code Environment} implementation that stores Shiro objects as key-value pairs in a
35  * {@link java.util.Map Map} instance.  The key is the object name, the value is the object itself.
36  *
37  */
38 class DefaultEnvironment : NamedObjectEnvironment, Destroyable {
39 
40     /**
41      * The default name under which the application's {@code SecurityManager} instance may be acquired, equal to
42      * {@code securityManager}.
43      */
44     enum string DEFAULT_SECURITY_MANAGER_KEY = "securityManager";
45 
46     protected Map!(string, Object) objects;
47     private string securityManagerName;
48 
49     /**
50      * Creates a new instance with a thread-safe {@link ConcurrentHashMap} backing map.
51      */
52     this() {
53         this(new HashMap!(string, Object)());
54     }
55 
56     /**
57      * Creates a new instance with the specified backing map.
58      *
59      * @param seed backing map to use to maintain Shiro objects.
60      */
61     this(Map!(string, Object) seed) {
62         this.securityManagerName = DEFAULT_SECURITY_MANAGER_KEY;
63         if (seed is null) {
64             throw new IllegalArgumentException("Backing map cannot be null.");
65         }
66         this.objects = seed;
67     }
68 
69     /**
70      * Returns the application's {@code SecurityManager} instance accessible in the backing map using the
71      * {@link #getSecurityManagerName() securityManagerName} property as the lookup key.
72      * <p/>
73      * This implementation guarantees that a non-null instance is always returned, as this is expected for
74      * Environment API end-users.  If subclasses have the need to perform the map lookup without this guarantee
75      * (for example, during initialization when the instance may not have been added to the map yet), the
76      * {@link #lookupSecurityManager()} method is provided as an alternative.
77      *
78      * @return the application's {@code SecurityManager} instance accessible in the backing map using the
79      *         {@link #getSecurityManagerName() securityManagerName} property as the lookup key.
80      */
81      SecurityManager getSecurityManager(){
82         SecurityManager securityManager = lookupSecurityManager();
83         if (securityManager  is null) {
84             throw new IllegalStateException("No SecurityManager found in Environment.  This is an invalid " ~
85                     "environment state.");
86         }
87         return securityManager;
88     }
89 
90      void setSecurityManager(SecurityManager securityManager) {
91         if (securityManager  is null) {
92             throw new IllegalArgumentException("Null SecurityManager instances are not allowed.");
93         }
94         string name = getSecurityManagerName();
95         setObject(name, cast(Object)securityManager);
96     }
97 
98     /**
99      * Looks up the {@code SecurityManager} instance in the backing map without performing any non-null guarantees.
100      *
101      * @return the {@code SecurityManager} in the backing map, or {@code null} if it has not yet been populated.
102      */
103     protected SecurityManager lookupSecurityManager() {
104         string name = getSecurityManagerName();
105         return cast(SecurityManager)getObject(name);
106     }
107 
108     /**
109      * Returns the name of the {@link SecurityManager} instance in the backing map.  Used as a key to lookup the
110      * instance.  Unless set otherwise, the default is {@code securityManager}.
111      *
112      * @return the name of the {@link SecurityManager} instance in the backing map.  Used as a key to lookup the
113      *         instance.
114      */
115      string getSecurityManagerName() {
116         return securityManagerName;
117     }
118 
119     /**
120      * Sets the name of the {@link SecurityManager} instance in the backing map.  Used as a key to lookup the
121      * instance.  Unless set otherwise, the default is {@code securityManager}.
122      *
123      * @param securityManagerName the name of the {@link SecurityManager} instance in the backing map.  Used as a key
124      *                            to lookup the instance. 
125      */
126      void setSecurityManagerName(string securityManagerName) {
127         this.securityManagerName = securityManagerName;
128     }
129 
130     /**
131      * Returns the live (modifiable) internal objects collection.
132      *
133      * @return the live (modifiable) internal objects collection.
134      */
135      Map!(string,Object) getObjects() {
136         return this.objects;
137     }
138 
139     //@SuppressWarnings({"unchecked"})
140     Object getObject(string name) { // , TypeInfo requiredType
141         if (name.empty()) {
142             throw new NullPointerException("name parameter cannot be null.");
143         }
144         // if (requiredType is null) {
145         //     throw new NullPointerException("requiredType parameter cannot be null.");
146         // }
147         Object o = this.objects.get(name);
148         if (o is null) {
149             return null;
150         }
151 
152         // if (requiredType != typeid(o)) {
153         //     string msg = "Object named '" ~ name ~ "' is not of required type [" ~ requiredType.toString() ~ "].";
154         //     throw new RequiredTypeException(msg);
155         // }
156         return o;
157     }
158 
159      void setObject(string name, Object instance) {
160         if (name  is null) {
161             throw new NullPointerException("name parameter cannot be null.");
162         }
163         if (instance  is null) {
164             this.objects.remove(name);
165         } else {
166             this.objects.put(name, instance);
167         }
168     }
169 
170     void destroy(){
171         LifecycleUtils.destroy(this.objects.values());
172     }
173 }