KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > forms > util > ContainerWidgetAsMap


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.forms.util;
17
18 import java.util.AbstractMap JavaDoc;
19 import java.util.AbstractSet JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import org.apache.cocoon.forms.formmodel.AbstractContainerWidget;
27 import org.apache.cocoon.forms.formmodel.ContainerWidget;
28 import org.apache.cocoon.forms.formmodel.Repeater;
29 import org.apache.cocoon.forms.formmodel.Widget;
30 import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
31
32 /**
33  * A <code>Map</code> view of a container widget, keys being children names and values either
34  * maps (for container children), objects (for terminal children) or lists (for repeaters).
35  * <p>
36  * The returned map is non-modifiable, except using the <code>put()</code> method, which much
37  * refer to an existing child widget, and <code>putAll(Map)</code> that will silently ignore keys
38  * that don't refer to existing child widgets.
39  * <p>
40  * Also, this map accepts getting and setting values for keys that correspond to value-less widgets
41  * such as {@link org.apache.cocoon.forms.formmodel.Action}. The result in that case is always
42  * <code>null</code>. This is to allow global retrieving or filling of the map values.
43  *
44  * @since 2.1.8
45  * @version $Id: ContainerWidgetAsMap.java 327865 2005-10-23 22:03:06Z sylvain $
46  */

47 public class ContainerWidgetAsMap extends AbstractMap JavaDoc {
48     private AbstractContainerWidget container;
49     private boolean lowerCase;
50
51     /**
52      * Wraps a container widget in a <code>Map</code>.
53      * <p>
54      * The <code>keysToLowerCase</code> argument specifies if input keys given in <code>get()</code>,
55      * <code>put()</code> and <code>putAll()</code> should be converted to lower case before searching for
56      * the corresponding widget. This feature allows to directly feed widgets with <code>Map</code>s coming
57      * from JDBC resultset rows where keys are uppercase (see <a HREF="http://jdbi.codehaus.org">JDBI</a>).
58      *
59      * @param container the container to wrap
60      * @param keysToLowerCase should we convert keys to lower case?
61      */

62     public ContainerWidgetAsMap(AbstractContainerWidget container, boolean keysToLowerCase) {
63         this.container = container;
64         this.lowerCase = keysToLowerCase;
65     }
66
67     /**
68      * Same as <code>ContainerWidgetAsMap(container, false)</code>
69      */

70     public ContainerWidgetAsMap(AbstractContainerWidget container) {
71         this(container, false);
72     }
73
74     /**
75      * Get the container widget that is wrapped by this <code>Map</code>.
76      *
77      * @return the wrapped {@link ContainerWidget}
78      */

79     public ContainerWidget getWidget() {
80         return this.container;
81     }
82     
83     /**
84      * Get a widget relative to the container wrapped by this <code>Map</code>
85      *
86      * @param path a widget lookup path
87      * @return the widget pointed to by <code>path</code> or <code>null</code> if it doesn't exist.
88      * @see Widget#lookupWidget(String)
89      */

90     public Widget getWidget(String JavaDoc path) {
91         return this.container.lookupWidget(path);
92     }
93
94     /**
95      * Put a value in a child widget. The value must be compatible with the datatype
96      * expected by the child widget. In the case of repeaters and containers, this
97      * datatype is <code>Collection</code> and <code>Map</code> respectively, which
98      * will be used to fill the rows and child widgets.
99      * <p>
100      * Note also that the contract of <code>put</code> requires the previous value
101      * to be returned. In the case of repeaters and containers, the value is a live
102      * wrapper around the actual widget, meaning that it's not different from the
103      * current value.
104      */

105     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
106         String JavaDoc name = (String JavaDoc)key;
107         if (lowerCase) name = name.toLowerCase();
108         
109         Widget w = container.getChild(name);
110         if (w != null) {
111             return setValue(w, value);
112         } else {
113             throw new UnsupportedOperationException JavaDoc(container + " has no child named '" + key + "'");
114         }
115     }
116
117     public void putAll(Map JavaDoc map) {
118         Iterator JavaDoc iter = map.entrySet().iterator();
119         while(iter.hasNext()) {
120             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
121             String JavaDoc name = (String JavaDoc)entry.getKey();
122             if (lowerCase) name = name.toLowerCase();
123             Widget w = container.getChild(name);
124             if (w != null) {
125                 setValue(w, entry.getValue());
126             }
127         }
128     }
129
130     public Object JavaDoc get(Object JavaDoc key) {
131         String JavaDoc name = (String JavaDoc)key;
132         if (lowerCase) name = name.toLowerCase();
133         Widget w = container.getChild(name);
134         return w == null ? null : asValueOrMap(w);
135     }
136
137     public Set JavaDoc entrySet() {
138         return new ContainerEntrySet();
139     }
140
141     private Object JavaDoc asValueOrMap(Widget w) {
142         if (w instanceof Repeater) {
143             return new RepeaterAsList((Repeater)w, lowerCase);
144         } else if (w instanceof AbstractContainerWidget) {
145             return new ContainerWidgetAsMap((AbstractContainerWidget)w, lowerCase);
146         } else {
147             try {
148                 return w.getValue();
149             } catch (UnsupportedOperationException JavaDoc uoe) {
150                 // This widget doesn't hold a value
151
return null;
152             }
153         }
154     }
155
156     /**
157      * Set a widget's value and returns the previous value as required by put().
158      */

159     private Object JavaDoc setValue(Widget w, Object JavaDoc value) {
160         if (w instanceof Repeater) {
161             // Must be a collection
162
if (!(value instanceof Collection JavaDoc)) {
163                 throw new IllegalArgumentException JavaDoc("A repeater cannot be filled with " + value);
164             }
165             List JavaDoc result = new RepeaterAsList((Repeater)w, lowerCase);
166             result.addAll((Collection JavaDoc)value);
167             return result;
168
169         } else if (w instanceof AbstractContainerWidget) {
170             // Must be a map
171
if (!(value instanceof Map JavaDoc)) {
172                 throw new IllegalArgumentException JavaDoc("A container cannot be filled with " + value);
173             }
174             Map JavaDoc result = new ContainerWidgetAsMap((AbstractContainerWidget)w);
175             result.putAll((Map JavaDoc)value);
176             return result;
177         } else {
178             try {
179                 Object JavaDoc result = w.getValue();
180                 w.setValue(value);
181                 return result;
182             } catch (UnsupportedOperationException JavaDoc uoe) {
183                 // This widget doesn't hold a value
184
return null;
185             }
186         }
187     }
188
189     private class ContainerEntrySet extends AbstractSet JavaDoc {
190         public Iterator JavaDoc iterator() {
191             return new ContainerEntryIterator();
192         }
193
194         public int size() {
195             return container.getSize();
196         }
197     }
198
199     private class ContainerEntryIterator extends AbstractIteratorDecorator {
200         public ContainerEntryIterator() {
201             super(container.getChildren());
202         }
203
204         public Object JavaDoc next() {
205             return new ContainerEntry((Widget)super.next());
206         }
207     }
208
209     private class ContainerEntry implements Map.Entry JavaDoc {
210         Widget widget;
211         public ContainerEntry(Widget w) {
212             widget = w;
213         }
214         public Object JavaDoc getKey() {
215             return widget.getName();
216         }
217         public Object JavaDoc getValue() {
218             return asValueOrMap(widget);
219         }
220         public Object JavaDoc setValue(Object JavaDoc value) {
221             Object JavaDoc result = asValueOrMap(widget);
222             ContainerWidgetAsMap.this.setValue(widget, value);
223             return result;
224         }
225     }
226 }
Popular Tags