View Javadoc
1   package org.codehaus.plexus.context;
2   
3   /*
4    * Copyright 2001-2006 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.util.Collections;
20  import java.util.Map;
21  import java.util.Map.Entry;
22  import java.util.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.ConcurrentMap;
24  import java.util.concurrent.atomic.AtomicBoolean;
25  
26  /**
27   * Default implementation of Context.
28   *
29   * This implementation is a static hierarchial store. It has the normal <code>get()</code>
30   * and <code>put</code> methods. The <code>hide</code> method will hide a property. When
31   * a property has been hidden the containerContext will not search in the parent containerContext for the value.
32   *
33   * @author <a href="mailto:dev@avalon.codehaus.org">Avalon Development Team</a>
34   * @version $Id$
35   */
36  public class DefaultContext
37      implements Context
38  {
39      /**
40       * Context data.
41       */
42      private final ConcurrentMap<Object, Object> contextData = new ConcurrentHashMap<Object, Object>();
43  
44      /**
45       * Is the containerContext read only.
46       */
47      private final AtomicBoolean readOnly = new AtomicBoolean(false);
48  
49      /**
50       * Create an empty Context.
51       */
52      public DefaultContext()
53      {
54      }
55  
56      /**
57       * Create a Context with specified data.  The specified data is copied into the context so any subsequent updates
58       * to supplied map are not reflected in this context.  Additionally, changes to this context are not reflected in
59       * the specified map.
60       *
61       * @param contextData the containerContext data
62       */
63      public DefaultContext( Map<Object, Object> contextData )
64      {
65          if ( contextData == null )
66          {
67              throw new NullPointerException( "contextData is null" );
68          }
69  
70          // check for nulls in key and value
71          for ( Entry<Object, Object> entry : contextData.entrySet() )
72          {
73              Object key = entry.getKey();
74              Object value = entry.getValue();
75              if ( key == null )
76              {
77                  throw new IllegalArgumentException( "Key is null" );
78              }
79              if ( value != null )
80              {
81                  this.contextData.put( key, value );
82              }
83          }
84      }
85  
86      public boolean contains( Object key )
87      {
88          Object data = contextData.get( key );
89  
90          return data != null;
91      }
92  
93      public Object get( Object key )
94          throws ContextException
95      {
96          Object data = contextData.get( key );
97  
98          if ( data == null )
99          {
100             // There is no data for the key
101             throw new ContextException( "Unable to resolve context key: " + key );
102         }
103         return data;
104     }
105 
106     public void put( Object key, Object value )
107         throws IllegalStateException
108     {
109         checkWriteable();
110 
111         // check for a null key
112         if (key == null)
113         {
114             throw new IllegalArgumentException("Key is null");
115         }
116 
117         if ( value == null )
118         {
119             contextData.remove( key );
120         }
121         else
122         {
123             contextData.put( key, value );
124         }
125     }
126 
127     public void hide( Object key )
128         throws IllegalStateException
129     {
130         checkWriteable();
131         
132         contextData.remove( key );
133     }
134 
135     /**
136      * Utility method to retrieve containerContext data
137      *
138      * @return the containerContext data
139      */
140     public Map<Object,Object> getContextData()
141     {
142         return Collections.unmodifiableMap( contextData );
143 
144     }
145 
146     /**
147      * Make the containerContext read-only.
148      * Any attempt to write to the containerContext via put()
149      * will result in an IllegalStateException.
150      */
151     public void makeReadOnly()
152     {
153         readOnly.set( true );
154     }
155 
156     /**
157      * Utility method to check if containerContext is writeable and if not throw exception.
158      *
159      * @throws java.lang.IllegalStateException if containerContext is read only
160      */
161     protected void checkWriteable()
162         throws IllegalStateException
163     {
164         if ( readOnly.get() )
165         {
166             throw new IllegalStateException( "Context is read only and can not be modified" );
167         }
168     }
169     
170     public String toString()
171     {
172         return contextData.toString();
173     }
174 }