KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > encoding > ser > ArraySerializer


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.encoding.ser;
57
58 import org.jboss.axis.AxisEngine;
59 import org.jboss.axis.Constants;
60 import org.jboss.axis.MessageContext;
61 import org.jboss.axis.encoding.SerializationContext;
62 import org.jboss.axis.encoding.Serializer;
63 import org.jboss.axis.schema.SchemaVersion;
64 import org.jboss.axis.soap.SOAPConstants;
65 import org.jboss.axis.utils.JavaUtils;
66 import org.jboss.axis.utils.Messages;
67 import org.jboss.axis.wsdl.fromJava.Types;
68 import org.jboss.logging.Logger;
69 import org.w3c.dom.Element JavaDoc;
70 import org.xml.sax.Attributes JavaDoc;
71 import org.xml.sax.helpers.AttributesImpl JavaDoc;
72
73 import javax.xml.namespace.QName JavaDoc;
74 import java.io.IOException JavaDoc;
75 import java.lang.reflect.Array JavaDoc;
76 import java.util.Collection JavaDoc;
77 import java.util.HashMap JavaDoc;
78 import java.util.Iterator JavaDoc;
79
80 /**
81  * An ArraySerializer handles serializing of arrays.
82  * <p/>
83  * Some code borrowed from ApacheSOAP - thanks to Matt Duftler!
84  *
85  * @author Glen Daniels (gdaniels@macromedia.com)
86  * <p/>
87  * Multi-reference stuff:
88  * @author Rich Scheuerle (scheu@us.ibm.com)
89  */

90 public class ArraySerializer implements Serializer
91 {
92    private static Logger log = Logger.getLogger(ArraySerializer.class.getName());
93
94    // Maps the a componentType Class to its type QName
95
// Usefull when you want to override the default
96
private HashMap JavaDoc componentTypeMap = new HashMap JavaDoc();
97
98    /**
99     * Serialize an element that is an array.
100     *
101     * @param name is the element name
102     * @param attributes are the attributes...serialize is free to add more.
103     * @param value is the value
104     * @param context is the SerializationContext
105     */

106    public void serialize(QName JavaDoc name, Attributes JavaDoc attributes,
107                          Object JavaDoc value, SerializationContext context)
108            throws IOException JavaDoc
109    {
110       if (value == null)
111          throw new IOException JavaDoc(Messages.getMessage("cantDoNullArray00"));
112
113       MessageContext msgContext = context.getMessageContext();
114       SchemaVersion schema = SchemaVersion.SCHEMA_2001;
115       SOAPConstants soap = SOAPConstants.SOAP11_CONSTANTS;
116       if (msgContext != null)
117       {
118          schema = msgContext.getSchemaVersion();
119          soap = msgContext.getSOAPConstants();
120       }
121
122       Class JavaDoc cls = value.getClass();
123       Collection JavaDoc list = null;
124
125       if (!cls.isArray())
126       {
127          if (!(value instanceof Collection JavaDoc))
128          {
129             throw new IOException JavaDoc(Messages.getMessage("cantSerialize00", cls.getName()));
130          }
131          list = (Collection JavaDoc)value;
132       }
133
134       // Get the componentType of the array/list
135
Class JavaDoc componentType;
136       if (list == null)
137       {
138          componentType = cls.getComponentType();
139       }
140       else
141       {
142          componentType = Object JavaDoc.class;
143       }
144
145       // Explicitly registered component type qnames have priority
146
// In most cases we won't have them unless a subclass sets it explicitly
147
// TDI 17-Jun-2004
148
QName JavaDoc componentQName = (QName JavaDoc)componentTypeMap.get(componentType);
149
150       String JavaDoc dims = "";
151
152       // Check to see if componentType is also an array.
153
// If so, set the componentType to the most nested non-array
154
// componentType. Increase the dims string by "[]"
155
// each time through the loop.
156
// Note from Rich Scheuerle:
157
// This won't handle Lists of Lists or
158
// arrays of Lists....only arrays of arrays.
159

160       // Only do this, if the type was not explicitly registered
161
if (componentQName == null)
162       {
163          while (componentType.isArray())
164          {
165             componentType = componentType.getComponentType();
166             if (soap == SOAPConstants.SOAP12_CONSTANTS)
167                dims += "* ";
168             else
169                dims += "[]";
170          }
171       }
172
173       // Get the QName of the componentType.
174
if (componentQName == null)
175       {
176          componentQName = context.getQNameForClass(componentType);
177       }
178
179       // If not found, look at the super classes
180
if (componentQName == null)
181       {
182          Class JavaDoc searchCls = componentType;
183          while (searchCls != null && componentQName == null)
184          {
185             searchCls = searchCls.getSuperclass();
186             componentQName = context.getQNameForClass(searchCls);
187          }
188          if (componentQName != null)
189          {
190             componentType = searchCls;
191          }
192       }
193
194       if (componentQName == null)
195       {
196          throw new IOException JavaDoc(Messages.getMessage("noType00", componentType.getName()));
197       }
198
199       String JavaDoc prefix = context.getPrefixForURI(componentQName.getNamespaceURI());
200       String JavaDoc compType = prefix + ":" + componentQName.getLocalPart();
201       int len = (list == null) ? Array.getLength(value) : list.size();
202
203       String JavaDoc arrayType;
204       if (soap == SOAPConstants.SOAP12_CONSTANTS)
205          arrayType = dims + len;
206       else
207          arrayType = dims + "[" + len + "]";
208
209       // Discover whether array can be serialized directly as a two-dimensional
210
// array (i.e. arrayType=int[2,3]) versus an array of arrays.
211
// Benefits:
212
// - Less text passed on the wire.
213
// - Easier to read wire format
214
// - Tests the deserialization of multi-dimensional arrays.
215
// Drawbacks:
216
// - Is not safe! It is possible that the arrays are multiply
217
// referenced. Transforming into a 2-dim array will cause the
218
// multi-referenced information to be lost. Plus there is no
219
// way to determine whether the arrays are multi-referenced.
220
// - .NET currently (Dec 2002) does not support 2D SOAP-encoded arrays
221
//
222
// OLD Comment as to why this was ENABLED:
223
// It is necessary for
224
// interoperability (echo2DStringArray). It is 'safe' for now
225
// because Axis treats arrays as non multi-ref (see the note
226
// in SerializationContextImpl.isPrimitive(...) )
227
// More complicated processing is necessary for 3-dim arrays, etc.
228
//
229
// Axis 1.1 - December 2002
230
// Turned this OFF because Microsoft .NET can not deserialize
231
// multi-dimensional SOAP-encoded arrays, and this interopability
232
// is pretty high visibility. Make it a global configuration parameter:
233
// <parameter name="enable2DArrayEncoding" value="true"/> (tomj)
234
//
235

236       // Check the message context to see if we should turn 2D processing ON
237
// Default is OFF
238
boolean enable2Dim = false;
239
240       // Vidyanand : added this check
241
if (msgContext != null)
242       {
243          enable2Dim =
244                  JavaUtils.isTrueExplicitly(msgContext.getAxisEngine().getOption(AxisEngine.PROP_TWOD_ARRAY_ENCODING));
245       }
246
247       int dim2Len = -1;
248       if (enable2Dim && !dims.equals(""))
249       {
250          if (cls.isArray() && len > 0)
251          {
252             boolean okay = true;
253             // Make sure all of the component arrays are the same size
254
for (int i = 0; i < len && okay; i++)
255             {
256
257                Object JavaDoc elementValue = Array.get(value, i);
258                if (elementValue == null)
259                   okay = false;
260                else if (dim2Len < 0)
261                {
262                   dim2Len = Array.getLength(elementValue);
263                   if (dim2Len <= 0)
264                   {
265                      okay = false;
266                   }
267                }
268                else if (dim2Len != Array.getLength(elementValue))
269                {
270                   okay = false;
271                }
272             }
273             // Update the arrayType to use mult-dim array encoding
274
if (okay)
275             {
276                dims = dims.substring(0, dims.length() - 2);
277                if (soap == SOAPConstants.SOAP12_CONSTANTS)
278                   arrayType = dims + len + " " + dim2Len;
279                else
280                   arrayType = dims + "[" + len + "," + dim2Len + "]";
281             }
282             else
283             {
284                dim2Len = -1;
285             }
286          }
287       }
288
289       // Need to distinguish if this is array processing for an
290
// actual schema array or for a maxOccurs usage.
291
// For the maxOccurs case, the currentXMLType of the context is
292
// the same as the componentQName.
293
boolean maxOccursUsage = (msgContext != null && !msgContext.isEncoded()) &&
294               componentQName.equals(context.getCurrentXMLType());
295
296       if (!maxOccursUsage)
297       {
298          AttributesImpl JavaDoc attrs;
299          if (attributes == null)
300          {
301             attrs = new AttributesImpl JavaDoc();
302          }
303          else if (attributes instanceof AttributesImpl JavaDoc)
304          {
305             attrs = (AttributesImpl JavaDoc)attributes;
306          }
307          else
308          {
309             attrs = new AttributesImpl JavaDoc(attributes);
310          }
311
312
313          if (attrs.getIndex(soap.getEncodingURI(), soap.getAttrItemType()) == -1)
314          {
315             String JavaDoc encprefix =
316                     context.getPrefixForURI(soap.getEncodingURI());
317
318             if (soap != SOAPConstants.SOAP12_CONSTANTS)
319             {
320                compType = compType + arrayType;
321
322                attrs.addAttribute(soap.getEncodingURI(),
323                        soap.getAttrItemType(),
324                        encprefix + ":arrayType",
325                        "CDATA",
326                        compType);
327
328             }
329             else
330             {
331                attrs.addAttribute(soap.getEncodingURI(),
332                        soap.getAttrItemType(),
333                        encprefix + ":itemType",
334                        "CDATA",
335                        compType);
336
337                attrs.addAttribute(soap.getEncodingURI(),
338                        "arraySize",
339                        encprefix + ":arraySize",
340                        "CDATA",
341                        arrayType);
342             }
343          }
344
345          // Force type to be SOAP_ARRAY for all array serialization.
346
//
347
// There are two choices here:
348
// Force the type to type=SOAP_ARRAY
349
// Pros: More interop test successes.
350
// Cons: Since we have specific type information it
351
// is more correct to use it. Plus the specific
352
// type information may be important on the
353
// server side to disambiguate overloaded operations.
354
// Use the specific type information:
355
// Pros: The specific type information is more correct
356
// and may be useful for operation overloading.
357
// Cons: More interop test failures (as of 2/6/2002).
358
//
359
int typeI = attrs.getIndex(schema.getXsiURI(),
360                  "type");
361          if (typeI != -1)
362          {
363             String JavaDoc qname =
364                     context.getPrefixForURI(schema.getXsiURI(),
365                             "xsi") + ":type";
366             QName JavaDoc soapArray;
367             if (soap == SOAPConstants.SOAP12_CONSTANTS)
368             {
369                soapArray = Constants.SOAP_ARRAY12;
370             }
371             else
372             {
373                soapArray = Constants.SOAP_ARRAY;
374             }
375
376             attrs.setAttribute(typeI,
377                     schema.getXsiURI(),
378                     "type",
379                     qname,
380                     "CDATA",
381                     context.qName2String(soapArray));
382          }
383          attributes = attrs;
384       }
385
386       // For the maxOccurs case, each item is named with the QName
387
// we got in the arguments. For normal array case, we write an element with
388
// that QName, and then serialize each item as <item>
389
QName JavaDoc elementName = name;
390       Attributes JavaDoc serializeAttr = attributes;
391       if (!maxOccursUsage)
392       {
393          serializeAttr = null; // since we are putting them here
394
context.startElement(name, attributes);
395          elementName = Constants.QNAME_LITERAL_ITEM;
396       }
397
398       if (dim2Len < 0)
399       {
400          // Normal case, serialize each array element
401
if (list == null)
402          {
403             for (int index = 0; index < len; index++)
404             {
405                Object JavaDoc aValue = Array.get(value, index);
406
407                // Serialize the element.
408
context.serialize(elementName, serializeAttr, aValue,
409                        componentQName, // prefered type QName
410
true, // Send null values
411
Boolean.FALSE); // Don't send xsi:type if it matches preferred QName
412
}
413          }
414          else
415          {
416             for (Iterator JavaDoc iterator = list.iterator(); iterator.hasNext();)
417             {
418                Object JavaDoc aValue = iterator.next();
419
420                // Serialize the element.
421
context.serialize(elementName, serializeAttr, aValue,
422                        componentQName, // prefered type QName
423
true, // Send null values
424
Boolean.FALSE); // Don't send xsi:type if it matches preferred QName
425

426             }
427          }
428       }
429       else
430       {
431          // Serialize as a 2 dimensional array
432
for (int index = 0; index < len; index++)
433          {
434             for (int index2 = 0; index2 < dim2Len; index2++)
435             {
436                Object JavaDoc aValue = Array.get(Array.get(value, index), index2);
437                context.serialize(elementName, null, aValue);
438             }
439          }
440       }
441
442       if (!maxOccursUsage)
443          context.endElement();
444    }
445
446    public String JavaDoc getMechanismType()
447    {
448       return Constants.AXIS_SAX;
449    }
450
451    public void addComponentTypeMapping(Class JavaDoc pomponentType, QName JavaDoc typeName)
452    {
453       componentTypeMap.put(pomponentType, typeName);
454    }
455
456    /**
457     * Return XML schema for the specified type, suitable for insertion into
458     * the &lt;types&gt; element of a WSDL document, or underneath an
459     * &lt;element&gt; or &lt;attribute&gt; declaration.
460     *
461     * @param javaType the Java Class we're writing out schema for
462     * @param types the Java2WSDL Types object which holds the context
463     * for the WSDL being generated.
464     * @return a type element containing a schema simpleType/complexType
465     * @see org.jboss.axis.wsdl.fromJava.Types
466     */

467    public Element JavaDoc writeSchema(Class JavaDoc javaType, Types types) throws Exception JavaDoc
468    {
469       // If an array the component type should be processed first
470
String JavaDoc componentTypeName = null;
471       Class JavaDoc componentType = null;
472       if (javaType.isArray())
473       {
474          String JavaDoc dimString = "[]";
475          componentType = javaType.getComponentType();
476          if (componentType.isArray())
477          {
478             while (componentType.isArray())
479             {
480                dimString += "[]";
481                componentType = componentType.getComponentType();
482             }
483          }
484          else
485          {
486             types.writeType(componentType, null);
487          }
488          componentTypeName =
489                  types.getQNameString(types.getTypeQName(componentType)) +
490                  dimString;
491       }
492
493       // Use Types helper method to actually create the complexType
494
return types.createArrayElement(componentTypeName);
495    }
496 }
497
Popular Tags