View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
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  package org.springframework.extensions.webscripts;
20  
21  import java.util.Collection;
22  import java.util.Iterator;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.mozilla.javascript.Scriptable;
27  import org.mozilla.javascript.Wrapper;
28  
29  /**
30   * Implementation of a Scriptable Map. This is the best choice where you want values to be
31   * persisted directly to an underlying map supplied on construction. The class automatically
32   * wraps/unwraps JS objects as they enter/leave the underlying map via the Scriptable interface
33   * methods - objects are untouched if accessed via the usual Map interface methods.
34   * 
35   * Access should be by string key only - not integer index - unless you are sure the wrapped
36   * map will maintain insertion order of the elements.
37   * 
38   * @author Kevin Roast
39   */
40  public class ScriptableWrappedMap implements ScriptableMap, Wrapper
41  {
42      private Map map;
43      private Scriptable parentScope;
44      private Scriptable prototype;
45      
46      
47      /**
48       * Construction
49       * 
50       * @param scope
51       * @param map
52       * 
53       * @return  scriptable wrapped map
54       */
55      public static ScriptableWrappedMap wrap(Scriptable scope, Map<Object, Object> map)
56      {
57          return new ScriptableWrappedMap(scope, map);
58      }
59  
60      /**
61       * Construct
62       * 
63       * @param map
64       */
65      public ScriptableWrappedMap(Map map)
66      {
67          this.map = map;
68      }
69      
70      /**
71       * Construct
72       * 
73       * @param scope
74       * @param map
75       */
76      public ScriptableWrappedMap(Scriptable scope, Map map)
77      {
78          this.parentScope = scope;
79          this.map = map;
80      }
81      
82      /* (non-Javadoc)
83       * @see org.mozilla.javascript.Wrapper#unwrap()
84       */
85      public Object unwrap()
86      {
87          return map;
88      }
89  
90      /* (non-Javadoc)
91       * @see org.mozilla.javascript.Scriptable#getClassName()
92       */
93      public String getClassName()
94      {
95          return "ScriptableWrappedMap";
96      }
97      
98      /* (non-Javadoc)
99       * @see org.mozilla.javascript.Scriptable#get(java.lang.String, org.mozilla.javascript.Scriptable)
100      */
101     public Object get(String name, Scriptable start)
102     {
103         // get the property from the underlying QName map
104         if ("length".equals(name))
105         {
106             return map.size();
107         }
108         else
109         {
110             return ScriptValueConverter.wrapValue(this.parentScope != null ? this.parentScope : start, map.get(name));
111         }
112     }
113 
114     /* (non-Javadoc)
115      * @see org.mozilla.javascript.Scriptable#get(int, org.mozilla.javascript.Scriptable)
116      */
117     public Object get(int index, Scriptable start)
118     {
119         Object value =  null;
120         int i=0;
121         Iterator itrValues = map.values().iterator();
122         while (i++ <= index && itrValues.hasNext())
123         {
124             value = itrValues.next();
125         }
126         return ScriptValueConverter.wrapValue(this.parentScope != null ? this.parentScope : start, value);
127     }
128 
129     /* (non-Javadoc)
130      * @see org.mozilla.javascript.Scriptable#has(java.lang.String, org.mozilla.javascript.Scriptable)
131      */
132     public boolean has(String name, Scriptable start)
133     {
134         // locate the property in the underlying map
135         return map.containsKey(name);
136     }
137 
138     /* (non-Javadoc)
139      * @see org.mozilla.javascript.Scriptable#has(int, org.mozilla.javascript.Scriptable)
140      */
141     public boolean has(int index, Scriptable start)
142     {
143         return (index >= 0 && map.values().size() > index);
144     }
145 
146     /* (non-Javadoc)
147      * @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object)
148      */
149     @SuppressWarnings("unchecked")
150     public void put(String name, Scriptable start, Object value)
151     {
152         map.put(name, ScriptValueConverter.unwrapValue(value));
153     }
154 
155     /* (non-Javadoc)
156      * @see org.mozilla.javascript.Scriptable#put(int, org.mozilla.javascript.Scriptable, java.lang.Object)
157      */
158     public void put(int index, Scriptable start, Object value)
159     {
160         // TODO: implement?
161     }
162 
163     /* (non-Javadoc)
164      * @see org.mozilla.javascript.Scriptable#delete(java.lang.String)
165      */
166     public void delete(String name)
167     {
168         map.remove(name);
169     }
170 
171     /* (non-Javadoc)
172      * @see org.mozilla.javascript.Scriptable#delete(int)
173      */
174     public void delete(int index)
175     {
176         int i=0;
177         Iterator itrKeys = map.keySet().iterator();
178         while (i <= index && itrKeys.hasNext())
179         {
180             Object key = itrKeys.next();
181             if (i == index)
182             {
183                 map.remove(key);
184                 break;
185             }
186         }
187     }
188 
189     /* (non-Javadoc)
190      * @see org.mozilla.javascript.Scriptable#getPrototype()
191      */
192     public Scriptable getPrototype()
193     {
194         return this.prototype;
195     }
196 
197     /* (non-Javadoc)
198      * @see org.mozilla.javascript.Scriptable#setPrototype(org.mozilla.javascript.Scriptable)
199      */
200     public void setPrototype(Scriptable prototype)
201     {
202         this.prototype = prototype;
203     }
204 
205     /* (non-Javadoc)
206      * @see org.mozilla.javascript.Scriptable#getParentScope()
207      */
208     public Scriptable getParentScope()
209     {
210         return this.parentScope;
211     }
212 
213     /* (non-Javadoc)
214      * @see org.mozilla.javascript.Scriptable#setParentScope(org.mozilla.javascript.Scriptable)
215      */
216     public void setParentScope(Scriptable parent)
217     {
218         this.parentScope = parent;
219     }
220 
221     /* (non-Javadoc)
222      * @see org.mozilla.javascript.Scriptable#getIds()
223      */
224     public Object[] getIds()
225     {
226         return map.keySet().toArray();
227     }
228 
229     /* (non-Javadoc)
230      * @see org.mozilla.javascript.Scriptable#getDefaultValue(java.lang.Class)
231      */
232     public Object getDefaultValue(Class hint)
233     {
234         return null;
235     }
236 
237     /* (non-Javadoc)
238      * @see org.mozilla.javascript.Scriptable#hasInstance(org.mozilla.javascript.Scriptable)
239      */
240     public boolean hasInstance(Scriptable value)
241     {
242         if (!(value instanceof Wrapper))
243             return false;
244         Object instance = ((Wrapper)value).unwrap();
245         return Map.class.isInstance(instance);
246     }
247     
248     /* (non-Javadoc)
249      * @see java.util.Map#clear()
250      */
251     public void clear()
252     {
253         this.map.clear();
254     }
255 
256     /* (non-Javadoc)
257      * @see java.util.Map#containsKey(java.lang.Object)
258      */
259     public boolean containsKey(Object key)
260     {
261         return this.map.containsKey(key);
262     }
263 
264     /* (non-Javadoc)
265      * @see java.util.Map#containsValue(java.lang.Object)
266      */
267     public boolean containsValue(Object value)
268     {
269         return this.map.containsValue(value);
270     }
271 
272     /* (non-Javadoc)
273      * @see java.util.Map#entrySet()
274      */
275     public Set entrySet()
276     {
277         return this.map.entrySet();
278     }
279 
280     /* (non-Javadoc)
281      * @see java.util.Map#get(java.lang.Object)
282      */
283     public Object get(Object key)
284     {
285         return this.map.get(key);
286     }
287 
288     /* (non-Javadoc)
289      * @see java.util.Map#isEmpty()
290      */
291     public boolean isEmpty()
292     {
293         return (this.map.size() == 0);
294     }
295 
296     /* (non-Javadoc)
297      * @see java.util.Map#keySet()
298      */
299     public Set keySet()
300     {
301         return this.map.keySet();
302     }
303 
304     /* (non-Javadoc)
305      * @see java.util.Map#put(java.lang.Object, java.lang.Object)
306      */
307     public Object put(Object key, Object value)
308     {
309         return this.map.put(key, value);
310     }
311 
312     /* (non-Javadoc)
313      * @see java.util.Map#putAll(java.util.Map)
314      */
315     public void putAll(Map t)
316     {
317         this.putAll(t);
318     }
319 
320     /* (non-Javadoc)
321      * @see java.util.Map#remove(java.lang.Object)
322      */
323     public Object remove(Object key)
324     {
325         return this.map.remove(key);
326     }
327 
328     /* (non-Javadoc)
329      * @see java.util.Map#size()
330      */
331     public int size()
332     {
333         return this.map.size();
334     }
335 
336     /* (non-Javadoc)
337      * @see java.util.Map#values()
338      */
339     public Collection values()
340     {
341         return this.map.values();
342     }
343 }