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