1 package org.codehaus.xfire.aegis.type;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 import ognl.Ognl;
12 import ognl.OgnlException;
13
14 import org.codehaus.xfire.SOAPConstants;
15 import org.codehaus.xfire.XFireRuntimeException;
16 import org.codehaus.xfire.aegis.AegisService;
17 import org.codehaus.xfire.aegis.mapping.TypeRegistry;
18 import org.codehaus.xfire.fault.XFireFault;
19 import org.codehaus.xfire.util.NamespaceHelper;
20 import org.dom4j.Attribute;
21 import org.dom4j.Element;
22 import org.dom4j.Namespace;
23 import org.dom4j.QName;
24
25 /***
26 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse </a>
27 */
28 public class ArrayType
29 extends Type
30 {
31 private String key;
32
33 private String arrayClass;
34
35 private Type childType;
36
37 private String postOgnl;
38
39 /***
40 * Uses an OGNL expression to find an array. It then puts each
41 * array object in as the key (see <code>getKey()</code> for retrieval
42 * when write()'ing in the child type.
43 *
44 * @see org.codehaus.xfire.aegis.type.Type#write(org.dom4j.Element, java.util.Map)
45 */
46 public void write(Element element, Map context) throws XFireFault
47 {
48 try
49 {
50 Object value = null;
51 try
52 {
53 value = Ognl.getValue(getOgnl(), context, (Object) null);
54 }
55 catch ( NullPointerException e )
56 {
57 return;
58 }
59
60 if ( value == null )
61 {
62 return;
63 }
64
65 Element typeEl = element.addElement(getQName());
66
67 if ( value instanceof Object[] )
68 {
69 Object[] children = (Object[]) value;
70
71 for (int i = 0; i < children.length; i++)
72 {
73 context.put( getKey(), children[i] );
74
75 Type type = getChildType();
76 type.write(typeEl, context);
77 }
78 }
79 else if ( value instanceof Collection )
80 {
81 Collection children = (Collection) value;
82 for ( Iterator itr = children.iterator(); itr.hasNext(); )
83 {
84 context.put( getKey(), itr.next());
85
86 Type type = getChildType();
87 type.write(typeEl, context);
88 }
89 }
90
91 context.put( getKey(), null );
92 }
93 catch (OgnlException e)
94 {
95 throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
96 }
97 }
98
99 /***
100 * Semantics are still under development, but here is how it works
101 * currently:
102 * <p>
103 * An ArrayList is built for the elements of the array.
104 * The number of elements in the array are put in as "key.length". The current
105 * index of the array is put in as "key.index". Each child is put in the
106 * array via the OGNL expression (<code>getOgnl()</code>). Finally,
107 * the array is put in the context as "key". (Where key in all of this
108 * refers to the key you specify.)
109 *
110 * @see org.codehaus.xfire.aegis.type.Type#read(org.dom4j.Element, java.util.Map)
111 */
112 public void read( Element element, Map context )
113 throws XFireFault
114 {
115 read( element, 0, context );
116 }
117
118 /***
119 * @see org.codehaus.xfire.aegis.type.Type#read(org.dom4j.Element, int, java.util.Map)
120 */
121 public void read(Element root, int occurrence, Map context) throws XFireFault
122 {
123 List elements = root.elements( getQName() );
124 if ( elements.size() <= occurrence )
125 return;
126
127 Element element = (Element) elements.get(occurrence);
128
129 int size = element.elements().size();
130
131 List array = new ArrayList(size);
132 context.put( getKey() + ".length", new Integer(size) );
133
134 for ( int i = 0; i < size; i++ )
135 {
136 context.put( getKey() + ".index", new Integer(i) );
137
138 getChildType().read(element, i, context);
139
140 try
141 {
142 Object value = Ognl.getValue(getOgnl(), context, (Object) null);
143 array.add(value);
144 }
145 catch (OgnlException e)
146 {
147 throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
148 }
149
150 i++;
151 }
152
153 if ( array.size() > 0 )
154 {
155 context.put( getKey(), array );
156
157 if ( getPostOgnl() != null )
158 {
159 try
160 {
161 Ognl.getValue( getPostOgnl(), context, array );
162 }
163 catch (OgnlException e)
164 {
165 throw new XFireFault( "Couldn't process message.", e, XFireFault.SENDER );
166 }
167 }
168 }
169 }
170
171 public boolean isComplex()
172 {
173 return true;
174 }
175
176 public Set getDependencies()
177 {
178 Set deps = new HashSet();
179
180 deps.add( getChildType() );
181
182 return deps;
183 }
184
185 public Type getChildType()
186 {
187 return childType;
188 }
189
190 public void setChildType(Type childType)
191 {
192 this.childType = childType;
193 }
194
195 public String getKey()
196 {
197 return key;
198 }
199
200 public void setKey(String key)
201 {
202 this.key = key;
203 }
204
205 public String getPostOgnl()
206 {
207 return postOgnl;
208 }
209
210 public void setPostOgnl(String postOgnl)
211 {
212 this.postOgnl = postOgnl;
213 }
214
215 /***
216 * @see org.codehaus.xfire.aegis.type.Type#writeSchema(org.dom4j.Element)
217 */
218 public void writeSchema(Element root)
219 {
220 Namespace xsdNs = root.getNamespaceForURI(SOAPConstants.XSD);
221 Namespace arrayNs = root.getNamespaceForURI( getSchemaType().getNamespaceURI() );
222
223 org.dom4j.QName elementQ = new org.dom4j.QName( "element", xsdNs );
224 Element concreteEl = root.addElement( elementQ );
225 concreteEl.addAttribute("name", getName());
226
227
228 org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
229
230 Element complex = concreteEl.addElement(complexQ);
231
232
233 org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs);
234 Element seq = complex.addElement(seqQ);
235
236
237 Type type = getChildType();
238
239 Element element = seq.addElement(elementQ);
240 Namespace typeNS = root.getNamespaceForURI( type.getSchemaType().getNamespaceURI() );
241
242 if ( type.isComplex() )
243 {
244 element.addAttribute("ref", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
245 }
246 else
247 {
248 element.addAttribute("name", type.getName());
249 element.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
250 element.addAttribute("nillable", "true");
251 }
252
253
254 element.addAttribute("minOccurs", "0");
255 element.addAttribute("maxOccurs", "unbounded");
256 }
257
258 /***
259 * @see org.codehaus.xfire.aegis.type.Type#configure(org.dom4j.Element)
260 */
261 public void configure(Element configuration,
262 AegisService service,
263 TypeRegistry reg)
264 {
265 setName(configuration.attributeValue("name"));
266 setOgnl(configuration.attributeValue("ognl"));
267 setPostOgnl(configuration.attributeValue("postOgnl"));
268 setKey(configuration.attributeValue("key"));
269 setDocumentation(configuration.getTextTrim());
270
271 setQName(QName.get(getName(), service.getDefaultNamespace()));
272
273 Attribute xsdAt = configuration.attribute("schemaType");
274 if (xsdAt != null)
275 {
276 setSchemaType(null);
277 }
278 else
279 {
280 Namespace ns = NamespaceHelper.getNamespace(configuration, service
281 .getDefaultNamespace());
282 setSchemaType(new QName(getName(), ns));
283 }
284
285 if ( configuration.elements().size() > 1 )
286 {
287 throw new XFireRuntimeException("Only one array child type allowed.");
288 }
289
290 Element childTypeEl = (Element) configuration.elements().get(0);
291 QName typeQ = QName.get(childTypeEl.getName(), service.getSoapVersion());
292
293 Type type = reg.createType(typeQ);
294 type.configure(childTypeEl, service, reg);
295
296 setChildType(type);
297 }
298
299 }