1 package org.codehaus.xfire.aegis.type.basic;
2
3 import java.lang.reflect.Array;
4 import java.util.ArrayList;
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Set;
8
9 import javax.xml.namespace.QName;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.codehaus.xfire.MessageContext;
14 import org.codehaus.xfire.XFireRuntimeException;
15 import org.codehaus.xfire.aegis.MessageReader;
16 import org.codehaus.xfire.aegis.MessageWriter;
17 import org.codehaus.xfire.aegis.type.Type;
18 import org.codehaus.xfire.fault.XFireFault;
19 import org.codehaus.xfire.soap.SoapConstants;
20 import org.codehaus.xfire.util.NamespaceHelper;
21 import org.codehaus.yom.Attribute;
22 import org.codehaus.yom.Element;
23
24 /***
25 * An ArrayType.
26 *
27 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
28 */
29 public class ArrayType
30 extends Type
31 {
32 private QName componentName;
33 private static final Log logger = LogFactory.getLog(ArrayType.class);
34
35 public ArrayType()
36 {
37 setNillable(true);
38 }
39
40 public Object readObject(MessageReader reader, MessageContext context)
41 throws XFireFault
42 {
43 try
44 {
45 Type compType = getComponentType();
46
47 List values = new ArrayList();
48
49 while ( reader.hasMoreElementReaders() )
50 {
51 values.add( compType.readObject(reader.getNextElementReader(), context) );
52 }
53
54 return makeArray(getComponentType().getTypeClass(), values);
55 }
56 catch (IllegalArgumentException e)
57 {
58 throw new XFireRuntimeException("Illegal argument.", e);
59 }
60 }
61
62 protected Object makeArray(Class arrayType, List values)
63 {
64 if (Integer.TYPE.equals(arrayType))
65 {
66 Object[] objects = values.toArray();
67 Object array = Array.newInstance(Integer.TYPE, objects.length);
68 for (int i = 0, n = objects.length; i < n; i++)
69 {
70 Array.set(array, i, objects[i]);
71 }
72 return array;
73 }
74 else if (Long.TYPE.equals(arrayType))
75 {
76 Object[] objects = values.toArray();
77 Object array = Array.newInstance(Long.TYPE, objects.length);
78 for (int i = 0, n = objects.length; i < n; i++)
79 {
80 Array.set(array, i, objects[i]);
81 }
82 return array;
83 }
84 else if (Short.TYPE.equals(arrayType))
85 {
86 Object[] objects = values.toArray();
87 Object array = Array.newInstance(Short.TYPE, objects.length);
88 for (int i = 0, n = objects.length; i < n; i++)
89 {
90 Array.set(array, i, objects[i]);
91 }
92 return array;
93 }
94 else if (Double.TYPE.equals(arrayType))
95 {
96 Object[] objects = values.toArray();
97 Object array = Array.newInstance(Double.TYPE, objects.length);
98 for (int i = 0, n = objects.length; i < n; i++)
99 {
100 Array.set(array, i, objects[i]);
101 }
102 return array;
103 }
104 else if (Float.TYPE.equals(arrayType))
105 {
106 Object[] objects = values.toArray();
107 Object array = Array.newInstance(Float.TYPE, objects.length);
108 for (int i = 0, n = objects.length; i < n; i++)
109 {
110 Array.set(array, i, objects[i]);
111 }
112 return array;
113 }
114 else if (Byte.TYPE.equals(arrayType))
115 {
116 Object[] objects = values.toArray();
117 Object array = Array.newInstance(Byte.TYPE, objects.length);
118 for (int i = 0, n = objects.length; i < n; i++)
119 {
120 Array.set(array, i, objects[i]);
121 }
122 return array;
123 }
124 else if (Boolean.TYPE.equals(arrayType))
125 {
126 Object[] objects = values.toArray();
127 Object array = Array.newInstance(Boolean.TYPE, objects.length);
128 for (int i = 0, n = objects.length; i < n; i++)
129 {
130 Array.set(array, i, objects[i]);
131 }
132 return array;
133 }
134
135 return values.toArray( (Object[]) Array.newInstance( getComponentType().getTypeClass(),
136 values.size()) );
137 }
138
139 public void writeObject(Object values, MessageWriter writer, MessageContext context)
140 throws XFireFault
141 {
142 if (values == null)
143 return;
144
145 Type type = getComponentType();
146
147 String ns = null;
148 if (type.isAbstract())
149 ns = getSchemaType().getNamespaceURI();
150 else
151 ns = type.getSchemaType().getNamespaceURI();
152
153 String name = type.getSchemaType().getLocalPart();
154
155 if ( type == null )
156 throw new XFireRuntimeException( "Couldn't find type for " + type.getTypeClass() + "." );
157
158 Class arrayType = type.getTypeClass();
159
160 if (Object.class.isAssignableFrom(arrayType))
161 {
162 Object[] objects = (Object[]) values;
163 for (int i = 0, n = objects.length; i < n; i++)
164 {
165 writeValue(objects[i], writer, context, type, name, ns);
166 }
167 }
168 else if (Integer.TYPE.equals(arrayType))
169 {
170 int[] objects = (int[]) values;
171 for (int i = 0, n = objects.length; i < n; i++)
172 {
173 writeValue(new Integer(objects[i]), writer, context, type, name, ns);
174 }
175 }
176 else if (Long.TYPE.equals(arrayType))
177 {
178 long[] objects = (long[]) values;
179 for (int i = 0, n = objects.length; i < n; i++)
180 {
181 writeValue(new Long(objects[i]), writer, context, type, name, ns);
182 }
183 }
184 else if (Short.TYPE.equals(arrayType))
185 {
186 short[] objects = (short[]) values;
187 for (int i = 0, n = objects.length; i < n; i++)
188 {
189 writeValue(new Short(objects[i]), writer, context, type, name, ns);
190 }
191 }
192 else if (Double.TYPE.equals(arrayType))
193 {
194 double[] objects = (double[]) values;
195 for (int i = 0, n = objects.length; i < n; i++)
196 {
197 writeValue(new Double(objects[i]), writer, context, type, name, ns);
198 }
199 }
200 else if (Float.TYPE.equals(arrayType))
201 {
202 float[] objects = (float[]) values;
203 for (int i = 0, n = objects.length; i < n; i++)
204 {
205 writeValue(new Float(objects[i]), writer, context, type, name, ns);
206 }
207 }
208 else if (Byte.TYPE.equals(arrayType))
209 {
210 byte[] objects = (byte[]) values;
211 for (int i = 0, n = objects.length; i < n; i++)
212 {
213 writeValue(new Byte(objects[i]), writer, context, type, name, ns);
214 }
215 }
216 else if (Boolean.TYPE.equals(arrayType))
217 {
218 boolean[] objects = (boolean[]) values;
219 for (int i = 0, n = objects.length; i < n; i++)
220 {
221 writeValue(new Boolean(objects[i]), writer, context, type, name, ns);
222 }
223 }
224 }
225
226 protected void writeValue(Object value,
227 MessageWriter writer,
228 MessageContext context,
229 Type type,
230 String name,
231 String ns)
232 throws XFireFault
233 {
234 MessageWriter cwriter = writer.getElementWriter(name, ns);
235
236 type.writeObject( value, cwriter, context );
237
238 cwriter.close();
239 }
240
241 public void writeSchema(Element root)
242 {
243 try
244 {
245 Element complex = new Element(SoapConstants.XSD_PREFIX + ":complexType",
246 SoapConstants.XSD);
247 complex.addAttribute(new Attribute("name", getSchemaType().getLocalPart()));
248 root.appendChild(complex);
249
250 Element seq = new Element(SoapConstants.XSD_PREFIX + ":sequence",
251 SoapConstants.XSD);
252 complex.appendChild(seq);
253
254 Element element = new Element(SoapConstants.XSD_PREFIX + ":element",
255 SoapConstants.XSD);
256 seq.appendChild(element);
257
258 Type componentType = getComponentType();
259 String prefix = NamespaceHelper.getUniquePrefix((Element) root.getParent(),
260 componentType.getSchemaType().getNamespaceURI());
261
262 String typeName = prefix + ":"
263 + componentType.getSchemaType().getLocalPart();
264
265 element.addAttribute(new Attribute("name", componentType.getSchemaType().getLocalPart()));
266 element.addAttribute(new Attribute("type", typeName));
267
268 if (componentType.isNillable())
269 {
270 element.addAttribute(new Attribute("nillable", "true"));
271 }
272
273 element.addAttribute(new Attribute("minOccurs", "0"));
274 element.addAttribute(new Attribute("maxOccurs", "unbounded"));
275
276 }
277 catch (IllegalArgumentException e)
278 {
279 throw new XFireRuntimeException("Illegal argument.", e);
280 }
281 }
282
283 /***
284 * We need to write a complex type schema for Beans, so return true.
285 *
286 * @see org.codehaus.xfire.aegis.type.Type#isComplex()
287 */
288 public boolean isComplex()
289 {
290 return true;
291 }
292
293 public QName getComponentName()
294 {
295 return componentName;
296 }
297
298 public void setComponentName(QName componentName)
299 {
300 this.componentName = componentName;
301 }
302
303 /***
304 * @see org.codehaus.xfire.aegis.type.Type#getDependencies()
305 */
306 public Set getDependencies()
307 {
308 Set deps = new HashSet();
309
310 deps.add( getComponentType() );
311
312 return deps;
313 }
314
315 /***
316 * Get the <code>Type</code> of the elements in the array.
317 *
318 * @return
319 */
320 public Type getComponentType()
321 {
322 Class compType = getTypeClass().getComponentType();
323
324 Type type;
325
326 if (componentName == null)
327 {
328 type = getTypeMapping().getType(compType);
329 }
330 else
331 {
332 type = getTypeMapping().getType(componentName);
333
334
335 if (type == null)
336 {
337 logger.debug("Couldn't find array component type "
338 + componentName + ". Creating one instead.");
339 }
340 }
341
342 if (type == null)
343 {
344 type = getTypeMapping().getTypeCreator().createType(compType);
345 getTypeMapping().register(type);
346 }
347
348 return type;
349 }
350 }