KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2001-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
17 package org.apache.axis.encoding.ser;
18
19 import org.apache.axis.Constants;
20 import org.apache.axis.components.logger.LogFactory;
21 import org.apache.axis.encoding.DeserializationContext;
22 import org.apache.axis.encoding.Deserializer;
23 import org.apache.axis.encoding.DeserializerImpl;
24 import org.apache.axis.encoding.DeserializerTarget;
25 import org.apache.axis.message.SOAPHandler;
26 import org.apache.axis.utils.ClassUtils;
27 import org.apache.axis.utils.JavaUtils;
28 import org.apache.axis.utils.Messages;
29 import org.apache.axis.wsdl.symbolTable.SchemaUtils;
30 import org.apache.commons.logging.Log;
31 import org.apache.axis.soap.SOAPConstants;
32
33 import org.xml.sax.Attributes JavaDoc;
34 import org.xml.sax.SAXException JavaDoc;
35
36 import javax.xml.namespace.QName JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.StringTokenizer JavaDoc;
40
41
42 /**
43  * An ArrayDeserializer handles deserializing SOAP
44  * arrays.
45  *
46  * Some code borrowed from ApacheSOAP - thanks to Matt Duftler!
47  *
48  * @author Glen Daniels (gdaniels@apache.org)
49  *
50  * Multi-reference stuff:
51  * @author Rich Scheuerle (scheu@us.ibm.com)
52  */

53 public class ArrayDeserializer extends DeserializerImpl
54 {
55     protected static Log log =
56         LogFactory.getLog(ArrayDeserializer.class.getName());
57
58     public QName JavaDoc arrayType = null;
59     public int curIndex = 0;
60     QName JavaDoc defaultItemType;
61     int length;
62     Class JavaDoc arrayClass = null;
63     ArrayList JavaDoc mDimLength = null; // If set, array of multi-dim lengths
64
ArrayList JavaDoc mDimFactor = null; // If set, array of factors for multi-dim []
65
SOAPConstants soapConstants = SOAPConstants.SOAP11_CONSTANTS;
66
67     /**
68      * This method is invoked after startElement when the element requires
69      * deserialization (i.e. the element is not an href & the value is not nil)
70      * DeserializerImpl provides default behavior, which simply
71      * involves obtaining a correct Deserializer and plugging its handler.
72      * @param namespace is the namespace of the element
73      * @param localName is the name of the element
74      * @param prefix is the prefix of the element
75      * @param attributes are the attrs on the element...used to get the type
76      * @param context is the DeserializationContext
77      */

78     public void onStartElement(String JavaDoc namespace, String JavaDoc localName,
79                              String JavaDoc prefix, Attributes JavaDoc attributes,
80                              DeserializationContext context)
81         throws SAXException JavaDoc
82     {
83         // Deserializing the xml array requires processing the
84
// xsi:type= attribute, the soapenc:arrayType attribute,
85
// and the xsi:type attributes of the individual elements.
86
//
87
// The xsi:type=<qName> attribute is used to determine the java
88
// type of the array to instantiate. Axis expects it
89
// to be set to the generic "soapenc:Array" or to
90
// a specific qName. If the generic "soapenc:Array"
91
// specification is used, Axis determines the array
92
// type by examining the soapenc:arrayType attribute.
93
//
94
// The soapenc:arrayType=<qname><dims> is used to determine
95
// i) the number of dimensions,
96
// ii) the length of each dimension,
97
// iii) the default xsi:type of each of the elements.
98
//
99
// If the arrayType attribute is missing, Axis assumes
100
// a single dimension array with length equal to the number
101
// of nested elements. In such cases, the default xsi:type of
102
// the elements is determined using the array xsi:type.
103
//
104
// The xsi:type attributes of the individual elements of the
105
// array are used to determine the java type of the element.
106
// If the xsi:type attribute is missing for an element, the
107
// default xsi:type value is used.
108

109         if (log.isDebugEnabled()) {
110             log.debug("Enter: ArrayDeserializer::startElement()");
111         }
112
113         soapConstants = context.getSOAPConstants();
114
115         // Get the qname for the array type=, set it to null if
116
// the generic type is used.
117
QName JavaDoc typeQName = context.getTypeFromAttributes(namespace,
118                                                         localName,
119                                                         attributes);
120         if (typeQName == null) {
121             typeQName = getDefaultType();
122         }
123
124         if (typeQName != null &&
125             Constants.equals(Constants.SOAP_ARRAY, typeQName)) {
126             typeQName = null;
127         }
128
129         // Now get the arrayType value
130
QName JavaDoc arrayTypeValue = context.getQNameFromString(
131                       Constants.getValue(attributes,
132                                          Constants.URIS_SOAP_ENC,
133                                          soapConstants.getAttrItemType()));
134
135         // The first part of the arrayType expression is
136
// the default item type qname.
137
// The second part is the dimension information
138
String JavaDoc dimString = null;
139         QName JavaDoc innerQName = null;
140         String JavaDoc innerDimString = "";
141         if (arrayTypeValue != null) {
142             if (soapConstants != SOAPConstants.SOAP12_CONSTANTS) {
143                 // Doing SOAP 1.1
144
// Array dimension noted like this : [][x]
145
String JavaDoc arrayTypeValueNamespaceURI =
146                     arrayTypeValue.getNamespaceURI();
147                 String JavaDoc arrayTypeValueLocalPart =
148                     arrayTypeValue.getLocalPart();
149
150                 int leftBracketIndex =
151                     arrayTypeValueLocalPart.lastIndexOf('[');
152                 int rightBracketIndex =
153                     arrayTypeValueLocalPart.lastIndexOf(']');
154                 if (leftBracketIndex == -1
155                     || rightBracketIndex == -1
156                     || rightBracketIndex < leftBracketIndex) {
157                         throw new IllegalArgumentException JavaDoc(
158                           Messages.getMessage("badArrayType00",
159                                                "" + arrayTypeValue));
160                 }
161
162                 dimString =
163                     arrayTypeValueLocalPart.substring(leftBracketIndex + 1,
164                                                       rightBracketIndex);
165                 arrayTypeValueLocalPart =
166                     arrayTypeValueLocalPart.substring(0, leftBracketIndex);
167
168                 // If multi-dim array set to soapenc:Array
169
if (arrayTypeValueLocalPart.endsWith("]")) {
170                     defaultItemType = Constants.SOAP_ARRAY;
171                     int bracket = arrayTypeValueLocalPart.indexOf("[");
172                     innerQName = new QName JavaDoc(arrayTypeValueNamespaceURI,
173                                            arrayTypeValueLocalPart.substring(0, bracket));
174                     innerDimString = arrayTypeValueLocalPart.substring(bracket);
175                 } else {
176                     defaultItemType = new QName JavaDoc(arrayTypeValueNamespaceURI,
177                                                 arrayTypeValueLocalPart);
178                 }
179
180             } else {
181                 String JavaDoc arraySizeValue = attributes.getValue(soapConstants.getEncodingURI(), Constants.ATTR_ARRAY_SIZE);
182                 int leftStarIndex = arraySizeValue.lastIndexOf('*');
183
184                 // Skip to num if any
185
if (leftStarIndex != -1) {
186                     // "*" => ""
187
if (leftStarIndex == 0 && arraySizeValue.length() == 1) {
188                         // "* *" => ""
189
} else if (leftStarIndex == (arraySizeValue.length() - 1)) {
190                         throw new IllegalArgumentException JavaDoc(
191                           Messages.getMessage("badArraySize00",
192                                                "" + arraySizeValue));
193                         // "* N" => "N"
194
} else {
195                         dimString = arraySizeValue.substring(leftStarIndex + 2);
196                         innerQName = arrayTypeValue;
197                         innerDimString = arraySizeValue.substring(0, leftStarIndex + 1);
198                     }
199                 } else {
200                     dimString = arraySizeValue;
201                 }
202
203                 if (innerDimString == null || innerDimString.length() == 0) {
204                     defaultItemType = arrayTypeValue;
205                 } else {
206                     defaultItemType = Constants.SOAP_ARRAY12;
207                 }
208             }
209         }
210
211         // If no type QName and no defaultItemType qname, use xsd:anyType
212
if (defaultItemType == null && typeQName == null) {
213             Class JavaDoc destClass = context.getDestinationClass();
214             if (destClass != null && destClass.isArray()) {
215                 // This will get set OK down below...
216
} else {
217                 defaultItemType = Constants.XSD_ANYTYPE;
218             }
219         }
220         
221         // Determine the class type for the array.
222
arrayClass = null;
223         if (typeQName != null) {
224             arrayClass = context.getTypeMapping().
225                 getClassForQName(typeQName);
226         }
227         
228         if (typeQName == null || arrayClass == null) {
229             // type= information is not sufficient.
230
// Get an array of the default item type.
231
Class JavaDoc arrayItemClass = null;
232             QName JavaDoc compQName = defaultItemType;
233
234             // Nested array, use the innermost qname
235
String JavaDoc dims = "[]";
236             if (innerQName != null) {
237                 compQName = innerQName;
238
239                 if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
240                     // With SOAP 1.2 Array, we append [] for each * found
241
int offset = 0;
242                     while ((offset = innerDimString.indexOf('*', offset)) != -1) {
243                         dims += "[]";
244                         offset ++;
245                     }
246                 } else {
247                     // With SOAP 1.1 Array, we can append directly the complete innerDimString
248
dims += innerDimString;
249                 }
250             }
251
252             // item Class
253
arrayItemClass = context.getTypeMapping().getClassForQName(compQName);
254             if (arrayItemClass != null) {
255                 try {
256                     // Append the dimension found to the classname computed from the itemClass
257
// to form the array classname
258
//
259
String JavaDoc loadableArrayClassName = JavaUtils.getLoadableClassName(
260                             JavaUtils.getTextClassName(arrayItemClass.getName()) + dims);
261                     arrayClass = ClassUtils.forName(loadableArrayClassName,
262                                                     true,
263                                                     arrayItemClass.getClassLoader());
264                 } catch (Exception JavaDoc e) {
265                     throw new SAXException JavaDoc(
266                             Messages.getMessage("noComponent00",
267                                                 "" + defaultItemType));
268                 }
269             }
270         }
271         if (arrayClass == null) {
272             arrayClass = context.getDestinationClass();
273         }
274
275         if (arrayClass == null) {
276             throw new SAXException JavaDoc(
277                Messages.getMessage("noComponent00", "" + defaultItemType));
278         }
279
280         if (dimString == null || dimString.length() == 0) {
281             // Size determined using length of the members
282
value = new ArrayListExtension(arrayClass);
283         } else {
284             try
285             {
286                 StringTokenizer JavaDoc tokenizer;
287                 if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
288                     tokenizer = new StringTokenizer JavaDoc(dimString);
289                 } else {
290                     tokenizer = new StringTokenizer JavaDoc(dimString, "[],");
291                 }
292
293                 length = Integer.parseInt(tokenizer.nextToken());
294                 if (tokenizer.hasMoreTokens()) {
295                         // If the array is passed as a multi-dimensional array
296
// (i.e. int[2][3]) then store all of the
297
// mult-dim lengths.
298
// The valueReady method uses this array to set the
299
// proper mult-dim element.
300
mDimLength = new ArrayList JavaDoc();
301                         mDimLength.add(new Integer JavaDoc(length));
302                         
303                         while(tokenizer.hasMoreTokens()) {
304                             mDimLength.add(
305                                 new Integer JavaDoc(
306                                     Integer.parseInt(tokenizer.nextToken())));
307                         }
308                     }
309
310                 // Create an ArrayListExtension class to store the ArrayList
311
// plus converted objects.
312
ArrayList JavaDoc list = new ArrayListExtension(arrayClass, length);
313
314                 // This is expensive as our array may not grown this big.
315
// Prevents problems when XML claims a huge size
316
// that it doesn't actually fill.
317
//for (int i = 0; i < length; i++) {
318
// list.add(null);
319
//}
320
value = list;
321
322             }
323             catch (NumberFormatException JavaDoc e)
324             {
325                 throw new IllegalArgumentException JavaDoc(
326                         Messages.getMessage("badInteger00", dimString));
327             }
328         }
329
330         // If soapenc:offset specified, set the current index accordingly
331
String JavaDoc offset = Constants.getValue(attributes,
332                                          Constants.URIS_SOAP_ENC,
333                                          Constants.ATTR_OFFSET);
334         if (offset != null) {
335             if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
336                 throw new SAXException JavaDoc(Messages.getMessage("noSparseArray"));
337             }
338
339             int leftBracketIndex = offset.lastIndexOf('[');
340             int rightBracketIndex = offset.lastIndexOf(']');
341
342             if (leftBracketIndex == -1
343                 || rightBracketIndex == -1
344                 || rightBracketIndex < leftBracketIndex)
345             {
346                 throw new SAXException JavaDoc(
347                         Messages.getMessage("badOffset00", offset));
348             }
349
350             curIndex =
351                 convertToIndex(offset.substring(leftBracketIndex + 1,
352                                                 rightBracketIndex),
353                                "badOffset00");
354         }
355
356         if (log.isDebugEnabled()) {
357             log.debug("Exit: ArrayDeserializer::startElement()");
358         }
359     }
360
361
362     /**
363      * onStartChild is called on each child element.
364      * @param namespace is the namespace of the child element
365      * @param localName is the local name of the child element
366      * @param prefix is the prefix used on the name of the child element
367      * @param attributes are the attributes of the child element
368      * @param context is the deserialization context.
369      * @return is a Deserializer to use to deserialize a child (must be
370      * a derived class of SOAPHandler) or null if no deserialization should
371      * be performed.
372      */

373     public SOAPHandler onStartChild(String JavaDoc namespace,
374                                     String JavaDoc localName,
375                                     String JavaDoc prefix,
376                                     Attributes JavaDoc attributes,
377                                     DeserializationContext context)
378         throws SAXException JavaDoc
379     {
380         if (log.isDebugEnabled()) {
381             log.debug("Enter: ArrayDeserializer.onStartChild()");
382         }
383
384         // If the position attribute is set,
385
// use it to update the current index
386
if (attributes != null) {
387             String JavaDoc pos =
388                 Constants.getValue(attributes,
389                                    Constants.URIS_SOAP_ENC,
390                                    Constants.ATTR_POSITION);
391             if (pos != null) {
392                 if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
393                     throw new SAXException JavaDoc(Messages.getMessage("noSparseArray"));
394                 }
395
396                 int leftBracketIndex = pos.lastIndexOf('[');
397                 int rightBracketIndex = pos.lastIndexOf(']');
398
399                 if (leftBracketIndex == -1
400                     || rightBracketIndex == -1
401                     || rightBracketIndex < leftBracketIndex)
402                 {
403                     throw new SAXException JavaDoc(
404                             Messages.getMessage("badPosition00", pos));
405                 }
406                 
407                 curIndex =
408                     convertToIndex(pos.substring(leftBracketIndex + 1,
409                                                  rightBracketIndex),
410                                    "badPosition00");
411             }
412
413             // If the xsi:nil attribute, set the value to null
414
// and return since there is nothing to deserialize.
415
if (context.isNil(attributes)) {
416                 setChildValue(null, new Integer JavaDoc(curIndex++));
417                 return null;
418             }
419         }
420
421         // Use the xsi:type setting on the attribute if it exists.
422
QName JavaDoc itemType = context.getTypeFromAttributes(namespace,
423                                                        localName,
424                                                        attributes);
425
426         // Get the deserializer for the type.
427
Deserializer dSer = null;
428         if (itemType != null && (context.getCurElement().getHref() == null)) {
429             dSer = context.getDeserializerForType(itemType);
430         }
431
432         if (dSer == null) {
433             // No deserializer can be found directly. Need to look harder
434
QName JavaDoc defaultType = defaultItemType;
435             Class JavaDoc javaType = null;
436             if (arrayClass != null &&
437                 arrayClass.isArray() &&
438                 defaultType == null) {
439                 javaType = arrayClass.getComponentType();
440                 defaultType = context.getTypeMapping().getTypeQName(javaType);
441             }
442
443             // We don't have a deserializer, the safest thing to do
444
// is to set up using the DeserializerImpl below.
445
// The DeserializerImpl will take care of href/id and
446
// install the appropriate serializer, etc. The problem
447
// is that takes a lot of time and will occur
448
// all the time if no xsi:types are sent. Most of the
449
// time an item is a simple schema type (i.e. String)
450
// so the following shortcut is used to get a Deserializer
451
// for these cases.
452
if (itemType == null && dSer == null) {
453                 if (defaultType != null && SchemaUtils.isSimpleSchemaType(defaultType)) {
454                     dSer = context.getDeserializer(javaType, defaultType);
455                 }
456             }
457             
458             // If no deserializer is
459
// found, the deserializer is set to DeserializerImpl().
460
// It is possible that the element has an href, thus we
461
// won't know the type until the definitition is encountered.
462
if (dSer == null) {
463                 dSer = new DeserializerImpl();
464                 // Determine a default type for the deserializer
465
if (itemType == null) {
466                     dSer.setDefaultType(defaultType);
467                 }
468             }
469         }
470
471
472         // Register the callback value target, and
473
// keep track of this index so we know when it has been set.
474
dSer.registerValueTarget(
475             new DeserializerTarget(this, new Integer JavaDoc(curIndex)));
476         
477         // The framework handles knowing when the value is complete, as
478
// long as we tell it about each child we're waiting on...
479
addChildDeserializer(dSer);
480
481         curIndex++;
482
483         // In case of multi-array, we need to specify the destination class
484
// of the children elements of this element array deserializer.
485
context.setDestinationClass(arrayClass.getComponentType());
486         
487         if (log.isDebugEnabled()) {
488             log.debug("Exit: ArrayDeserializer.onStartChild()");
489         }
490         
491         return (SOAPHandler)dSer;
492     }
493
494     public void onEndChild(String JavaDoc namespace, String JavaDoc localName, DeserializationContext context) throws SAXException JavaDoc {
495         // reverse onStartChild operation.
496
context.setDestinationClass(arrayClass);
497     }
498
499     public void characters(char[] chars, int i, int i1) throws SAXException JavaDoc {
500         for (int idx = i; i < i1; i++) {
501             if (!Character.isWhitespace(chars[idx]))
502                 throw new SAXException JavaDoc(Messages.getMessage("charsInArray"));
503         }
504     }
505
506     /**
507      * set is called during deserialization to assign
508      * the Object value to the array position indicated by hint.
509      * The hint is always a single Integer. If the array being
510      * deserialized is a multi-dimensional array, the hint is
511      * converted into a series of indices to set the correct
512      * nested position.
513      * The array deserializer always deserializes into
514      * an ArrayList, which is converted and copied into the
515      * actual array after completion (by valueComplete).
516      * It is important to wait until all indices have been
517      * processed before invoking valueComplete.
518      * @param value value of the array element
519      * @param hint index of the array element (Integer)
520      **/

521     public void setChildValue(Object JavaDoc value, Object JavaDoc hint) throws SAXException JavaDoc
522     {
523         if (log.isDebugEnabled()) {
524             log.debug("Enter: ArrayDeserializer::setValue(" + value + ", " + hint + ")");
525         }
526         ArrayList JavaDoc list = (ArrayList JavaDoc)this.value;
527         int offset = ((Integer JavaDoc)hint).intValue();
528
529         if (this.mDimLength == null) {
530             // Normal Case: Set the element in the list
531
// grow the list if necessary to accomodate the new member
532
while (list.size() <= offset) {
533                 list.add(null);
534             }
535
536             list.set(offset, value);
537         } else {
538             // Multi-Dim Array case: Need to find the nested ArrayList
539
// and set the proper element.
540

541             // Convert the offset into a series of indices
542
ArrayList JavaDoc mDimIndex = toMultiIndex(offset);
543
544             // Get/Create the nested ArrayList
545
for(int i=0; i < mDimLength.size(); i++) {
546                 int length = ((Integer JavaDoc)mDimLength.get(i)).intValue();
547                 int index = ((Integer JavaDoc)mDimIndex.get(i)).intValue();
548                 while (list.size() < length) {
549                     list.add(null);
550                 }
551                 // If not the last dimension, get the nested ArrayList
552
// Else set the value
553
if (i < mDimLength.size()-1) {
554                     if (list.get(index) == null) {
555                         list.set(index, new ArrayList JavaDoc());
556                     }
557                     list = (ArrayList JavaDoc) list.get(index);
558                 } else {
559                     list.set(index, value);
560                 }
561             }
562         }
563     }
564
565     /**
566      * When valueComplete() is invoked on the array,
567      * first convert the array value into the expected array.
568      * Then call super.valueComplete() to inform referents
569      * that the array value is ready.
570      **/

571     public void valueComplete() throws SAXException JavaDoc
572     {
573         if (componentsReady()) {
574            try {
575                 if (arrayClass != null) {
576                     value = JavaUtils.convert(value, arrayClass);
577                 }
578            } catch (RuntimeException JavaDoc e) {
579                // We must ignore exceptions from convert for Arrays with null - why?
580
}
581         }
582         
583         super.valueComplete();
584     }
585
586     /**
587      * Converts the given string to an index.
588      * Assumes the string consists of a brackets surrounding comma
589      * separated digits. For example "[2]" or [2,3]".
590      * The routine returns a single index.
591      * For example "[2]" returns 2.
592      * For example "[2,3]" depends on the size of the multiple dimensions.
593      * if the dimensions are "[3,5]" then 13 is returned (2*5) + 3.
594      * @param text representing index text
595      * @param exceptKey exception message key
596      * @return index
597      */

598     private int convertToIndex(String JavaDoc text, String JavaDoc exceptKey)
599         throws SAXException JavaDoc {
600         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(text, "[],");
601         int index = 0;
602         try {
603             if (mDimLength == null) {
604                 // Normal Case: Single dimension
605
index = Integer.parseInt(tokenizer.nextToken());
606                 if (tokenizer.hasMoreTokens()) {
607                     throw new SAXException JavaDoc(
608                         Messages.getMessage(exceptKey, text));
609                 }
610             }
611             else {
612                 // Multiple Dimensions:
613
int dim = -1;
614                 ArrayList JavaDoc work = new ArrayList JavaDoc();
615                 while(tokenizer.hasMoreTokens()) {
616                     // Problem if the number of dimensions specified exceeds
617
// the number of dimensions of arrayType
618
dim++;
619                     if (dim >= mDimLength.size()) {
620                         throw new SAXException JavaDoc(
621                             Messages.getMessage(exceptKey, text));
622                     }
623                     // Get the next token and convert to integer
624
int workIndex = Integer.parseInt(tokenizer.nextToken());
625
626                     // Problem if the index is out of range.
627
if (workIndex < 0 ||
628                         workIndex >=
629                             ((Integer JavaDoc)mDimLength.get(dim)).intValue()) {
630                         throw new SAXException JavaDoc(
631                             Messages.getMessage(exceptKey, text));
632                     }
633                     work.add(new Integer JavaDoc(workIndex));
634                 }
635                 index = toSingleIndex(work); // Convert to single index
636
}
637         } catch (SAXException JavaDoc e) {
638             throw e;
639         } catch (Exception JavaDoc e) {
640             throw new SAXException JavaDoc(Messages.getMessage(exceptKey, text));
641         }
642         return index;
643     }
644
645     /**
646      * Converts single index to list of multiple indices.
647      * @param single index
648      * @return list of multiple indices or null if not multiple indices.
649      */

650     private ArrayList JavaDoc toMultiIndex(int single) {
651         if (mDimLength == null)
652             return null;
653
654         // Calculate the index factors if not already known
655
if (mDimFactor == null) {
656             mDimFactor = new ArrayList JavaDoc();
657             for (int i=0; i < mDimLength.size(); i++) {
658                 int factor = 1;
659                 for (int j=i+1; j<mDimLength.size(); j++) {
660                     factor *= ((Integer JavaDoc)mDimLength.get(j)).intValue();
661                 }
662                 mDimFactor.add(new Integer JavaDoc(factor));
663             }
664         }
665
666         ArrayList JavaDoc rc = new ArrayList JavaDoc();
667         for (int i=0; i < mDimLength.size(); i++) {
668             int factor = ((Integer JavaDoc)mDimFactor.get(i)).intValue();
669             rc.add(new Integer JavaDoc(single / factor));
670             single = single % factor;
671         }
672         return rc;
673     }
674
675     /**
676      * Converts multiple index to single index.
677      * @param indexArray list of multiple indices
678      * @return single index
679      */

680     private int toSingleIndex(ArrayList JavaDoc indexArray) {
681         if (mDimLength == null || indexArray == null)
682             return -1;
683
684         // Calculate the index factors if not already known
685
if (mDimFactor == null) {
686             mDimFactor = new ArrayList JavaDoc();
687             for (int i=0; i < mDimLength.size(); i++) {
688                 int factor = 1;
689                 for (int j=i+1; j<mDimLength.size(); j++) {
690                     factor *= ((Integer JavaDoc)mDimLength.get(j)).intValue();
691                 }
692                 mDimFactor.add(new Integer JavaDoc(factor));
693             }
694         }
695
696         int single = 0;
697         for (int i=0; i < indexArray.size(); i++) {
698             single += ((Integer JavaDoc)mDimFactor.get(i)).intValue()*
699                 ((Integer JavaDoc)indexArray.get(i)).intValue();
700         }
701         return single;
702     }
703
704     /**
705      * During processing, the Array Deserializer stores the array in
706      * an ArrayListExtension class. This class contains all of the
707      * normal function of an ArrayList, plus it keeps a list of the
708      * converted array values. This class is essential to support
709      * arrays that are multi-referenced.
710      **/

711     public class ArrayListExtension extends ArrayList JavaDoc
712         implements JavaUtils.ConvertCache {
713         private HashMap JavaDoc table = null;
714         private Class JavaDoc arrayClass = null; // The array class.
715
/**
716          * Constructors
717          */

718         ArrayListExtension(Class JavaDoc arrayClass) {
719             super();
720             this.arrayClass = arrayClass;
721             // Don't use the array class as a hint
722
// if it can't be instantiated
723
if (arrayClass == null ||
724                 arrayClass.isInterface() ||
725                 java.lang.reflect.Modifier.isAbstract(
726                     arrayClass.getModifiers())) {
727                 arrayClass = null;
728             }
729         }
730         ArrayListExtension(Class JavaDoc arrayClass, int length) {
731             // Sanity check the array size, 50K is big enough to start
732
super(length > 50000 ? 50000 : length);
733             this.arrayClass = arrayClass;
734             // Don't use the array class as a hint
735
// if it can't be instantiated
736
if (arrayClass == null ||
737                 arrayClass.isInterface() ||
738                 java.lang.reflect.Modifier.isAbstract(
739                     arrayClass.getModifiers())) {
740                 arrayClass = null;
741             }
742         }
743         /**
744          * Store converted value
745          **/

746         public void setConvertedValue(Class JavaDoc cls, Object JavaDoc value) {
747             if (table == null)
748                 table = new HashMap JavaDoc();
749             table.put(cls, value);
750         }
751         /**
752          * Get previously converted value
753          **/

754         public Object JavaDoc getConvertedValue(Class JavaDoc cls) {
755             if (table == null)
756                 return null;
757             return table.get(cls);
758         }
759
760         /**
761          * Get the destination array class described by the xml
762          **/

763         public Class JavaDoc getDestClass() {
764             return arrayClass;
765         }
766     }
767    
768 }
769
Popular Tags