KickJava   Java API By Example, From Geeks To Geeks.

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


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.Constants;
59 import org.jboss.axis.MessageContext;
60 import org.jboss.axis.encoding.DeserializationContext;
61 import org.jboss.axis.encoding.Deserializer;
62 import org.jboss.axis.encoding.DeserializerImpl;
63 import org.jboss.axis.encoding.DeserializerTarget;
64 import org.jboss.axis.message.SOAPHandler;
65 import org.jboss.axis.soap.SOAPConstants;
66 import org.jboss.axis.utils.ClassUtils;
67 import org.jboss.axis.utils.JavaUtils;
68 import org.jboss.axis.utils.Messages;
69 import org.jboss.axis.wsdl.symbolTable.SchemaUtils;
70 import org.jboss.logging.Logger;
71 import org.xml.sax.Attributes JavaDoc;
72 import org.xml.sax.SAXException JavaDoc;
73
74 import javax.xml.namespace.QName JavaDoc;
75 import java.util.ArrayList JavaDoc;
76 import java.util.HashMap JavaDoc;
77 import java.util.StringTokenizer JavaDoc;
78
79
80 /**
81  * An ArrayDeserializer handles deserializing SOAP
82  * arrays.
83  * <p/>
84  * Some code borrowed from ApacheSOAP - thanks to Matt Duftler!
85  *
86  * @author Glen Daniels (gdaniels@macromedia.com)
87  * <p/>
88  * Multi-reference stuff:
89  * @author Rich Scheuerle (scheu@us.ibm.com)
90  */

91 public class ArrayDeserializer extends DeserializerImpl
92 {
93    private static Logger log = Logger.getLogger(ArrayDeserializer.class.getName());
94
95    public QName JavaDoc arrayType = null;
96    public int curIndex = 0;
97    QName JavaDoc defaultItemType;
98    int length;
99    Class JavaDoc arrayClass = null;
100    ArrayList JavaDoc mDimLength = null; // If set, array of multi-dim lengths
101
ArrayList JavaDoc mDimFactor = null; // If set, array of factors for multi-dim []
102
SOAPConstants soapConstants = SOAPConstants.SOAP11_CONSTANTS;
103
104    /**
105     * This method is invoked after startElement when the element requires
106     * deserialization (i.e. the element is not an href & the value is not nil)
107     * DeserializerImpl provides default behavior, which simply
108     * involves obtaining a correct Deserializer and plugging its handler.
109     *
110     * @param namespace is the namespace of the element
111     * @param localName is the name of the element
112     * @param prefix is the prefix of the element
113     * @param attributes are the attrs on the element...used to get the type
114     * @param context is the DeserializationContext
115     */

116    public void onStartElement(String JavaDoc namespace, String JavaDoc localName,
117                               String JavaDoc prefix, Attributes JavaDoc attributes,
118                               DeserializationContext context)
119            throws SAXException JavaDoc
120    {
121       // Deserializing the xml array requires processing the
122
// xsi:type= attribute, the soapenc:arrayType attribute,
123
// and the xsi:type attributes of the individual elements.
124
//
125
// The xsi:type=<qName> attribute is used to determine the java
126
// type of the array to instantiate. Axis expects it
127
// to be set to the generic "soapenc:Array" or to
128
// a specific qName. If the generic "soapenc:Array"
129
// specification is used, Axis determines the array
130
// type by examining the soapenc:arrayType attribute.
131
//
132
// The soapenc:arrayType=<qname><dims> is used to determine
133
// i) the number of dimensions,
134
// ii) the length of each dimension,
135
// iii) the default xsi:type of each of the elements.
136
//
137
// If the arrayType attribute is missing, Axis assumes
138
// a single dimension array with length equal to the number
139
// of nested elements. In such cases, the default xsi:type of
140
// the elements is determined using the array xsi:type.
141
//
142
// The xsi:type attributes of the individual elements of the
143
// array are used to determine the java type of the element.
144
// If the xsi:type attribute is missing for an element, the
145
// default xsi:type value is used.
146

147       if (log.isDebugEnabled())
148       {
149          log.debug("Enter: ArrayDeserializer::startElement()");
150       }
151
152       MessageContext msgContext = context.getMessageContext();
153       if (msgContext != null)
154       {
155          soapConstants = msgContext.getSOAPConstants();
156       }
157
158       // Get the qname for the array type=, set it to null if
159
// the generic type is used.
160
QName JavaDoc typeQName = context.getTypeFromAttributes(namespace,
161               localName,
162               attributes);
163       if (typeQName == null)
164       {
165          typeQName = getDefaultType();
166       }
167
168       if (typeQName != null &&
169               Constants.equals(Constants.SOAP_ARRAY, typeQName))
170       {
171          typeQName = null;
172       }
173
174       // Now get the arrayType value
175
QName JavaDoc arrayTypeValue = context.getQNameFromString(Constants.getValue(attributes,
176               Constants.URIS_SOAP_ENC,
177               soapConstants.getAttrItemType()));
178
179       // The first part of the arrayType expression is
180
// the default item type qname.
181
// The second part is the dimension information
182
String JavaDoc dimString = null;
183       QName JavaDoc innerQName = null;
184       String JavaDoc innerDimString = "";
185       if (arrayTypeValue != null)
186       {
187          if (soapConstants != SOAPConstants.SOAP12_CONSTANTS)
188          {
189             String JavaDoc arrayTypeValueNamespaceURI =
190                     arrayTypeValue.getNamespaceURI();
191             String JavaDoc arrayTypeValueLocalPart =
192                     arrayTypeValue.getLocalPart();
193
194             int leftBracketIndex =
195                     arrayTypeValueLocalPart.lastIndexOf('[');
196             int rightBracketIndex =
197                     arrayTypeValueLocalPart.lastIndexOf(']');
198             if (leftBracketIndex == -1
199                     || rightBracketIndex == -1
200                     || rightBracketIndex < leftBracketIndex)
201             {
202                throw new IllegalArgumentException JavaDoc(Messages.getMessage("badArrayType00",
203                        "" + arrayTypeValue));
204             }
205
206             dimString =
207                     arrayTypeValueLocalPart.substring(leftBracketIndex + 1,
208                             rightBracketIndex);
209             arrayTypeValueLocalPart =
210                     arrayTypeValueLocalPart.substring(0, leftBracketIndex);
211
212             // If multi-dim array set to soapenc:Array
213
if (arrayTypeValueLocalPart.endsWith("]"))
214             {
215                defaultItemType = Constants.SOAP_ARRAY;
216                innerQName = new QName JavaDoc(arrayTypeValueNamespaceURI,
217                        arrayTypeValueLocalPart.substring(0,
218                                arrayTypeValueLocalPart.indexOf("[")));
219                innerDimString = arrayTypeValueLocalPart.substring(arrayTypeValueLocalPart.indexOf("["));
220             }
221             else
222             {
223                defaultItemType = new QName JavaDoc(arrayTypeValueNamespaceURI,
224                        arrayTypeValueLocalPart);
225             }
226
227          }
228          else
229          {
230             String JavaDoc arraySizeValue = attributes.getValue(soapConstants.getEncodingURI(), Constants.ATTR_ARRAY_SIZE);
231             int leftStarIndex = arraySizeValue.lastIndexOf('*');
232
233             // Skip to num if any
234
if (leftStarIndex != -1)
235             {
236                // "*" => ""
237
if (leftStarIndex == 0 && arraySizeValue.length() == 1)
238                {
239                   // "* *" => ""
240
}
241                else if (leftStarIndex == (arraySizeValue.length() - 1))
242                {
243                   throw new IllegalArgumentException JavaDoc(Messages.getMessage("badArraySize00",
244                           "" + arraySizeValue));
245                   // "* N" => "N"
246
}
247                else
248                {
249                   dimString = arraySizeValue.substring(leftStarIndex + 2);
250                   innerQName = arrayTypeValue;
251                   innerDimString = arraySizeValue.substring(0, leftStarIndex + 1);
252                }
253             }
254             else
255             {
256                dimString = arraySizeValue;
257             }
258
259             if (innerDimString == null || innerDimString.length() == 0)
260             {
261                defaultItemType = arrayTypeValue;
262             }
263             else
264             {
265                defaultItemType = Constants.SOAP_ARRAY12;
266             }
267          }
268       }
269
270       // If no type QName and no defaultItemType qname, use xsd:anyType
271
if (defaultItemType == null && typeQName == null)
272       {
273          defaultItemType = Constants.XSD_ANYTYPE;
274       }
275
276       // Determine the class type for the array.
277
arrayClass = null;
278       if (typeQName != null)
279       {
280          arrayClass = context.getTypeMapping().
281                  getClassForQName(typeQName);
282       }
283       else
284       {
285          // type= information is not sufficient.
286
// Get an array of the default item type.
287
Class JavaDoc arrayItemClass = null;
288          QName JavaDoc compQName = defaultItemType;
289
290          // Nested array, use the innermost qname
291
String JavaDoc dims = "[]";
292          if (innerQName != null)
293          {
294             compQName = innerQName;
295
296             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
297             {
298                int offset = 0;
299                while ((offset = innerDimString.indexOf('*', offset)) != -1)
300                {
301                   dims += "[]";
302                   offset++;
303                }
304             }
305             else
306             {
307                dims += innerDimString;
308             }
309          }
310
311          arrayItemClass = context.getTypeMapping().
312                  getClassForQName(compQName);
313          if (arrayItemClass != null)
314          {
315             try
316             {
317                String JavaDoc textClassName = JavaUtils.getTextClassName(arrayItemClass.getName()) + dims;
318                String JavaDoc loadableClassName = JavaUtils.getLoadableClassName(textClassName);
319                arrayClass = ClassUtils.forName(loadableClassName);
320             }
321             catch (Exception JavaDoc e)
322             {
323                throw new SAXException JavaDoc(Messages.getMessage("noComponent00",
324                        "" + defaultItemType));
325             }
326          }
327       }
328
329       if (arrayClass == null)
330       {
331          throw new SAXException JavaDoc(Messages.getMessage("noComponent00", "" + defaultItemType));
332       }
333
334       if (dimString == null || dimString.length() == 0)
335       {
336          // Size determined using length of the members
337
value = new ArrayListExtension(arrayClass);
338       }
339       else
340       {
341          try
342          {
343             StringTokenizer JavaDoc tokenizer;
344             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
345             {
346                tokenizer = new StringTokenizer JavaDoc(dimString);
347             }
348             else
349             {
350                tokenizer = new StringTokenizer JavaDoc(dimString, "[],");
351             }
352
353             length = Integer.parseInt(tokenizer.nextToken());
354             if (tokenizer.hasMoreTokens())
355             {
356                // If the array is passed as a multi-dimensional array
357
// (i.e. int[2][3]) then store all of the
358
// mult-dim lengths.
359
// The valueReady method uses this array to set the
360
// proper mult-dim element.
361
mDimLength = new ArrayList JavaDoc();
362                mDimLength.add(new Integer JavaDoc(length));
363
364                while (tokenizer.hasMoreTokens())
365                {
366                   mDimLength.add(new Integer JavaDoc(Integer.parseInt(tokenizer.nextToken())));
367                }
368             }
369
370             // Create an ArrayListExtension class to store the ArrayList
371
// plus converted objects.
372
ArrayList JavaDoc list = new ArrayListExtension(arrayClass, length);
373             // ArrayList lacks a setSize(), so...
374
for (int i = 0; i < length; i++)
375             {
376                list.add(null);
377             }
378             value = list;
379
380          }
381          catch (NumberFormatException JavaDoc e)
382          {
383             throw new IllegalArgumentException JavaDoc(Messages.getMessage("badInteger00", dimString));
384          }
385       }
386
387       // If soapenc:offset specified, set the current index accordingly
388
String JavaDoc offset = Constants.getValue(attributes,
389               Constants.URIS_SOAP_ENC,
390               Constants.ATTR_OFFSET);
391       if (offset != null)
392       {
393          if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
394          {
395             throw new SAXException JavaDoc(Messages.getMessage("noSparseArray"));
396          }
397
398          int leftBracketIndex = offset.lastIndexOf('[');
399          int rightBracketIndex = offset.lastIndexOf(']');
400
401          if (leftBracketIndex == -1
402                  || rightBracketIndex == -1
403                  || rightBracketIndex < leftBracketIndex)
404          {
405             throw new SAXException JavaDoc(Messages.getMessage("badOffset00", offset));
406          }
407
408          curIndex =
409                  convertToIndex(offset.substring(leftBracketIndex + 1,
410                          rightBracketIndex),
411                          "badOffset00");
412       }
413
414       if (log.isDebugEnabled())
415       {
416          log.debug("Exit: ArrayDeserializer::startElement()");
417       }
418    }
419
420
421    /**
422     * onStartChild is called on each child element.
423     *
424     * @param namespace is the namespace of the child element
425     * @param localName is the local name of the child element
426     * @param prefix is the prefix used on the name of the child element
427     * @param attributes are the attributes of the child element
428     * @param context is the deserialization context.
429     * @return is a Deserializer to use to deserialize a child (must be
430     * a derived class of SOAPHandler) or null if no deserialization should
431     * be performed.
432     */

433    public SOAPHandler onStartChild(String JavaDoc namespace,
434                                    String JavaDoc localName,
435                                    String JavaDoc prefix,
436                                    Attributes JavaDoc attributes,
437                                    DeserializationContext context)
438            throws SAXException JavaDoc
439    {
440       if (log.isDebugEnabled())
441       {
442          log.debug("Enter: ArrayDeserializer.onStartChild()");
443       }
444
445       // If the position attribute is set,
446
// use it to update the current index
447
if (attributes != null)
448       {
449          String JavaDoc pos =
450                  Constants.getValue(attributes,
451                          Constants.URIS_SOAP_ENC,
452                          Constants.ATTR_POSITION);
453          if (pos != null)
454          {
455             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS)
456             {
457                throw new SAXException JavaDoc(Messages.getMessage("noSparseArray"));
458             }
459
460             int leftBracketIndex = pos.lastIndexOf('[');
461             int rightBracketIndex = pos.lastIndexOf(']');
462
463             if (leftBracketIndex == -1
464                     || rightBracketIndex == -1
465                     || rightBracketIndex < leftBracketIndex)
466             {
467                throw new SAXException JavaDoc(Messages.getMessage("badPosition00", pos));
468             }
469
470             curIndex =
471                     convertToIndex(pos.substring(leftBracketIndex + 1,
472                             rightBracketIndex),
473                             "badPosition00");
474          }
475
476          // If the xsi:nil attribute, set the value to null
477
// and return since there is nothing to deserialize.
478
if (context.isNil(attributes))
479          {
480             setChildValue(null, new Integer JavaDoc(curIndex++));
481             return null;
482          }
483       }
484
485       // Use the xsi:type setting on the attribute if it exists.
486
QName JavaDoc itemType = context.getTypeFromAttributes(namespace,
487               localName,
488               attributes);
489
490       // Get the deserializer for the type.
491
Deserializer dSer = null;
492       if (itemType != null && (context.getCurElement().getHref() == null))
493       {
494          dSer = context.getDeserializerForType(itemType);
495       }
496
497       if (dSer == null)
498       {
499          // No deserializer can be found directly. Need to look harder
500
QName JavaDoc defaultType = defaultItemType;
501          Class JavaDoc javaType = null;
502          if (arrayClass != null &&
503                  arrayClass.isArray() &&
504                  defaultType == null)
505          {
506             javaType = arrayClass.getComponentType();
507             defaultType = context.getTypeMapping().getTypeQName(javaType);
508          }
509
510          // We don't have a deserializer, the safest thing to do
511
// is to set up using the DeserializerImpl below.
512
// The DeserializerImpl will take care of href/id and
513
// install the appropriate serializer, etc. The problem
514
// is that takes a lot of time and will occur
515
// all the time if no xsi:types are sent. Most of the
516
// time an item is a simple schema type (i.e. String)
517
// so the following shortcut is used to get a Deserializer
518
// for these cases.
519
if (itemType == null && dSer == null)
520          {
521             if (defaultType != null && SchemaUtils.isSimpleSchemaType(defaultType))
522             {
523                dSer = context.getDeserializer(javaType, defaultType);
524             }
525          }
526
527          // If no deserializer is
528
// found, the deserializer is set to DeserializerImpl().
529
// It is possible that the element has an href, thus we
530
// won't know the type until the definitition is encountered.
531
if (dSer == null)
532          {
533             dSer = new DeserializerImpl();
534             // Determine a default type for the deserializer
535
if (itemType == null)
536             {
537                dSer.setDefaultType(defaultType);
538             }
539          }
540       }
541
542
543       // Register the callback value target, and
544
// keep track of this index so we know when it has been set.
545
dSer.registerValueTarget(new DeserializerTarget(this, new Integer JavaDoc(curIndex)));
546
547       // The framework handles knowing when the value is complete, as
548
// long as we tell it about each child we're waiting on...
549
addChildDeserializer(dSer);
550
551       curIndex++;
552
553       if (log.isDebugEnabled())
554       {
555          log.debug("Exit: ArrayDeserializer.onStartChild()");
556       }
557
558       return (SOAPHandler)dSer;
559    }
560
561    public void characters(char[] chars, int i, int i1) throws SAXException JavaDoc
562    {
563       for (int idx = i; i < i1; i++)
564       {
565          if (!Character.isWhitespace(chars[idx]))
566             throw new SAXException JavaDoc(Messages.getMessage("charsInArray"));
567       }
568    }
569
570    /**
571     * set is called during deserialization to assign
572     * the Object value to the array position indicated by hint.
573     * The hint is always a single Integer. If the array being
574     * deserialized is a multi-dimensional array, the hint is
575     * converted into a series of indices to set the correct
576     * nested position.
577     * The array deserializer always deserializes into
578     * an ArrayList, which is converted and copied into the
579     * actual array after completion (by valueComplete).
580     * It is important to wait until all indices have been
581     * processed before invoking valueComplete.
582     *
583     * @param value value of the array element
584     * @param hint index of the array element (Integer)
585     */

586    public void setChildValue(Object JavaDoc value, Object JavaDoc hint) throws SAXException JavaDoc
587    {
588       if (log.isDebugEnabled())
589       {
590          log.debug("Enter: ArrayDeserializer::setValue(" + value + ", " + hint + ")");
591       }
592       ArrayList JavaDoc list = (ArrayList JavaDoc)this.value;
593       int offset = ((Integer JavaDoc)hint).intValue();
594
595       if (this.mDimLength == null)
596       {
597          // Normal Case: Set the element in the list
598
// grow the list if necessary to accomodate the new member
599
while (list.size() <= offset)
600          {
601             list.add(null);
602          }
603
604          list.set(offset, value);
605       }
606       else
607       {
608          // Multi-Dim Array case: Need to find the nested ArrayList
609
// and set the proper element.
610

611          // Convert the offset into a series of indices
612
ArrayList JavaDoc mDimIndex = toMultiIndex(offset);
613
614          // Get/Create the nested ArrayList
615
for (int i = 0; i < mDimLength.size(); i++)
616          {
617             int length = ((Integer JavaDoc)mDimLength.get(i)).intValue();
618             int index = ((Integer JavaDoc)mDimIndex.get(i)).intValue();
619             while (list.size() < length)
620             {
621                list.add(null);
622             }
623             // If not the last dimension, get the nested ArrayList
624
// Else set the value
625
if (i < mDimLength.size() - 1)
626             {
627                if (list.get(index) == null)
628                {
629                   list.set(index, new ArrayList JavaDoc());
630                }
631                list = (ArrayList JavaDoc)list.get(index);
632             }
633             else
634             {
635                list.set(index, value);
636             }
637          }
638       }
639    }
640
641    /**
642     * When valueComplete() is invoked on the array,
643     * first convert the array value into the expected array.
644     * Then call super.valueComplete() to inform referents
645     * that the array value is ready.
646     */

647    public void valueComplete() throws SAXException JavaDoc
648    {
649       if (componentsReady())
650       {
651          try
652          {
653             if (arrayClass != null)
654             {
655                value = JavaUtils.convert(value, arrayClass);
656             }
657          }
658          catch (RuntimeException JavaDoc e)
659          {
660             // We must ignore exceptions from convert for Arrays with null - why?
661
}
662       }
663
664       super.valueComplete();
665    }
666
667    /**
668     * Converts the given string to an index.
669     * Assumes the string consists of a brackets surrounding comma
670     * separated digits. For example "[2]" or [2,3]".
671     * The routine returns a single index.
672     * For example "[2]" returns 2.
673     * For example "[2,3]" depends on the size of the multiple dimensions.
674     * if the dimensions are "[3,5]" then 13 is returned (2*5) + 3.
675     *
676     * @param text representing index text
677     * @param exceptKey exception message key
678     * @return index
679     */

680    private int convertToIndex(String JavaDoc text, String JavaDoc exceptKey)
681            throws SAXException JavaDoc
682    {
683       StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(text, "[],");
684       int index = 0;
685       try
686       {
687          if (mDimLength == null)
688          {
689             // Normal Case: Single dimension
690
index = Integer.parseInt(tokenizer.nextToken());
691             if (tokenizer.hasMoreTokens())
692             {
693                throw new SAXException JavaDoc(Messages.getMessage(exceptKey, text));
694             }
695          }
696          else
697          {
698             // Multiple Dimensions:
699
int dim = -1;
700             ArrayList JavaDoc work = new ArrayList JavaDoc();
701             while (tokenizer.hasMoreTokens())
702             {
703                // Problem if the number of dimensions specified exceeds
704
// the number of dimensions of arrayType
705
dim++;
706                if (dim >= mDimLength.size())
707                {
708                   throw new SAXException JavaDoc(Messages.getMessage(exceptKey, text));
709                }
710                // Get the next token and convert to integer
711
int workIndex = Integer.parseInt(tokenizer.nextToken());
712
713                // Problem if the index is out of range.
714
if (workIndex < 0 ||
715                        workIndex >=
716                        ((Integer JavaDoc)mDimLength.get(dim)).intValue())
717                {
718                   throw new SAXException JavaDoc(Messages.getMessage(exceptKey, text));
719                }
720                work.add(new Integer JavaDoc(workIndex));
721             }
722             index = toSingleIndex(work); // Convert to single index
723
}
724       }
725       catch (SAXException JavaDoc e)
726       {
727          throw e;
728       }
729       catch (Exception JavaDoc e)
730       {
731          throw new SAXException JavaDoc(Messages.getMessage(exceptKey, text));
732       }
733       return index;
734    }
735
736    /**
737     * Converts single index to list of multiple indices.
738     *
739     * @param single index
740     * @return list of multiple indices or null if not multiple indices.
741     */

742    private ArrayList JavaDoc toMultiIndex(int single)
743    {
744       if (mDimLength == null)
745          return null;
746
747       // Calculate the index factors if not already known
748
if (mDimFactor == null)
749       {
750          mDimFactor = new ArrayList JavaDoc();
751          for (int i = 0; i < mDimLength.size(); i++)
752          {
753             int factor = 1;
754             for (int j = i + 1; j < mDimLength.size(); j++)
755             {
756                factor *= ((Integer JavaDoc)mDimLength.get(j)).intValue();
757             }
758             mDimFactor.add(new Integer JavaDoc(factor));
759          }
760       }
761
762       ArrayList JavaDoc rc = new ArrayList JavaDoc();
763       for (int i = 0; i < mDimLength.size(); i++)
764       {
765          int factor = ((Integer JavaDoc)mDimFactor.get(i)).intValue();
766          rc.add(new Integer JavaDoc(single / factor));
767          single = single % factor;
768       }
769       return rc;
770    }
771
772    /**
773     * Converts multiple index to single index.
774     *
775     * @param indexArray list of multiple indices
776     * @return single index
777     */

778    private int toSingleIndex(ArrayList JavaDoc indexArray)
779    {
780       if (mDimLength == null || indexArray == null)
781          return -1;
782
783       // Calculate the index factors if not already known
784
if (mDimFactor == null)
785       {
786          mDimFactor = new ArrayList JavaDoc();
787          for (int i = 0; i < mDimLength.size(); i++)
788          {
789             int factor = 1;
790             for (int j = i + 1; j < mDimLength.size(); j++)
791             {
792                factor *= ((Integer JavaDoc)mDimLength.get(j)).intValue();
793             }
794             mDimFactor.add(new Integer JavaDoc(factor));
795          }
796       }
797
798       int single = 0;
799       for (int i = 0; i < indexArray.size(); i++)
800       {
801          single += ((Integer JavaDoc)mDimFactor.get(i)).intValue() *
802                  ((Integer JavaDoc)indexArray.get(i)).intValue();
803       }
804       return single;
805    }
806
807    /**
808     * During processing, the Array Deserializer stores the array in
809     * an ArrayListExtension class. This class contains all of the
810     * normal function of an ArrayList, plus it keeps a list of the
811     * converted array values. This class is essential to support
812     * arrays that are multi-referenced.
813     */

814    public class ArrayListExtension extends ArrayList JavaDoc
815            implements JavaUtils.ConvertCache
816    {
817       private HashMap JavaDoc table = null;
818       private Class JavaDoc arrayClass = null; // The array class.
819

820       /**
821        * Constructors
822        */

823       ArrayListExtension(Class JavaDoc arrayClass)
824       {
825          super();
826          this.arrayClass = arrayClass;
827          // Don't use the array class as a hint
828
// if it can't be instantiated
829
if (arrayClass == null ||
830                  arrayClass.isInterface() ||
831                  java.lang.reflect.Modifier.isAbstract(arrayClass.getModifiers()))
832          {
833             arrayClass = null;
834          }
835       }
836
837       ArrayListExtension(Class JavaDoc arrayClass, int length)
838       {
839          super(length);
840          this.arrayClass = arrayClass;
841          // Don't use the array class as a hint
842
// if it can't be instantiated
843
if (arrayClass == null ||
844                  arrayClass.isInterface() ||
845                  java.lang.reflect.Modifier.isAbstract(arrayClass.getModifiers()))
846          {
847             arrayClass = null;
848          }
849       }
850
851       /**
852        * Store converted value
853        */

854       public void setConvertedValue(Class JavaDoc cls, Object JavaDoc value)
855       {
856          if (table == null)
857             table = new HashMap JavaDoc();
858          table.put(cls, value);
859       }
860
861       /**
862        * Get previously converted value
863        */

864       public Object JavaDoc getConvertedValue(Class JavaDoc cls)
865       {
866          if (table == null)
867             return null;
868          return table.get(cls);
869       }
870
871       /**
872        * Get the destination array class described by the xml
873        */

874       public Class JavaDoc getDestClass()
875       {
876          return arrayClass;
877       }
878    }
879
880 }
881
Popular Tags