001: /*
002: Copyright (c) 2003-2005, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.binding.def;
030:
031: import org.apache.bcel.generic.*;
032:
033: import org.jibx.binding.classes.*;
034: import org.jibx.runtime.JiBXException;
035:
036: /**
037: * Collection binding definition. This handles one or more child components,
038: * which may be ordered or unordered.
039: *
040: * @author Dennis M. Sosnoski
041: * @version 1.0
042: */
043: public class NestedCollection extends NestedBase {
044: //
045: // Method definitions used in code generation
046:
047: private static final String GROWARRAY_METHOD = "org.jibx.runtime.Utility.growArray";
048: private static final String GROWARRAY_SIGNATURE = "(Ljava/lang/Object;)Ljava/lang/Object;";
049: private static final String RESIZEARRAY_METHOD = "org.jibx.runtime.Utility.resizeArray";
050: private static final String RESIZEARRAY_SIGNATURE = "(ILjava/lang/Object;)Ljava/lang/Object;";
051: private static final String CHECK_ISSTART_NAME = "org.jibx.runtime.impl.UnmarshallingContext.isStart";
052: private static final String CHECK_ISSTART_SIGNATURE = "()Z";
053: private static final String SKIP_ELEMENT_NAME = "org.jibx.runtime.impl.UnmarshallingContext.skipElement";
054: private static final String SKIP_ELEMENT_SIGNATURE = "()V";
055:
056: //
057: // Actual instance data.
058:
059: /** Fully qualified class name of values from collection. */
060: private final String m_itemType;
061:
062: /** Strategy for generating code to load item from collection. */
063: private final CollectionLoad m_loadStrategy;
064:
065: /** Strategy for generating code to store item to collection. */
066: private final CollectionStore m_storeStrategy;
067:
068: /** Optional component flag. */
069: private final boolean m_isOptional;
070:
071: /**
072: * Constructor.
073: *
074: * @param parent containing binding definition context
075: * @param objc current object context
076: * @param ord ordered content flag
077: * @param opt optional component flag
078: * @param flex flexible element handling flag
079: * @param type fully qualified class name of values from collection (may be
080: * <code>null</code>, if child content present)
081: * @param load collection load code generation strategy
082: * @param store collection store code generation strategy
083: */
084: public NestedCollection(IContainer parent, IContextObj objc,
085: boolean ord, boolean opt, boolean flex, String type,
086: CollectionLoad load, CollectionStore store) {
087: super (parent, objc, ord, flex, false);
088: m_itemType = type;
089: m_loadStrategy = load;
090: m_storeStrategy = store;
091: m_isOptional = opt;
092: }
093:
094: /**
095: * Get the collection item type.
096: *
097: * @return item type
098: */
099: public String getItemType() {
100: return m_itemType;
101: }
102:
103: //
104: // IComponent interface method definitions
105:
106: public boolean hasAttribute() {
107: return false;
108: }
109:
110: public void genAttrPresentTest(ContextMethodBuilder mb) {
111: throw new IllegalStateException(
112: "Internal error - no attributes present");
113: }
114:
115: public void genAttributeUnmarshal(ContextMethodBuilder mb) {
116: throw new IllegalStateException(
117: "Internal error - no attributes present");
118: }
119:
120: public void genAttributeMarshal(ContextMethodBuilder mb) {
121: throw new IllegalStateException(
122: "Internal error - no attributes present");
123: }
124:
125: public boolean hasContent() {
126: return m_contents.size() > 0;
127: }
128:
129: public void genContentUnmarshal(ContextMethodBuilder mb)
130: throws JiBXException {
131: if (m_contents.size() > 0) {
132:
133: // set up common handling and check for ordered or unordered content
134: m_storeStrategy.genStoreInit(mb);
135: BranchWrapper link = null;
136: int count = m_contents.size();
137: if (m_isOrdered) {
138:
139: // just generate unmarshal code for each component in order
140: for (int i = 0; i < count; i++) {
141:
142: // start with branch target for loop and link from last type
143: if (link != null) {
144: mb.initStackState(link);
145: }
146: BranchTarget start = mb.appendTargetNOP();
147: if (link != null) {
148: link.setTarget(start, mb);
149: }
150:
151: // generate code to check if an element matching this
152: // component type is present
153: IComponent child = (IComponent) m_contents.get(i);
154: child.genContentPresentTest(mb);
155: link = mb.appendIFEQ(this );
156:
157: // follow with code to unmarshal the component and store to
158: // collection, ending with loop back to start of this
159: // component
160: child.genContentUnmarshal(mb);
161: if (m_itemType != null
162: && !ClassItem.isPrimitive(m_itemType)) {
163: mb.appendCreateCast(m_itemType);
164: }
165: m_storeStrategy.genStoreItem(mb);
166: mb.appendUnconditionalBranch(this ).setTarget(start,
167: mb);
168: }
169:
170: } else {
171:
172: // generate unmarshal loop code that checks for each component,
173: // branching to the next component until one is found and
174: // exiting the loop only when no component is matched
175: BranchTarget first = mb.appendTargetNOP();
176: for (int i = 0; i < count; i++) {
177: if (link != null) {
178: mb.targetNext(link);
179: }
180: IComponent child = (IComponent) m_contents.get(i);
181: child.genContentPresentTest(mb);
182: link = mb.appendIFEQ(this );
183: child.genContentUnmarshal(mb);
184: if (m_itemType != null
185: && !ClassItem.isPrimitive(m_itemType)) {
186: mb.appendCreateCast(m_itemType);
187: }
188: m_storeStrategy.genStoreItem(mb);
189: mb.appendUnconditionalBranch(this ).setTarget(first,
190: mb);
191: }
192:
193: // handle fall through condition depending on flexible flag
194: if (m_isFlexible) {
195:
196: // exit loop if not positioned at element start
197: mb.targetNext(link);
198: mb.loadContext();
199: mb.appendCallVirtual(CHECK_ISSTART_NAME,
200: CHECK_ISSTART_SIGNATURE);
201: link = mb.appendIFEQ(this );
202:
203: // ignore unknown element and loop back to start
204: mb.loadContext();
205: mb.appendCallVirtual(SKIP_ELEMENT_NAME,
206: SKIP_ELEMENT_SIGNATURE);
207: mb.appendUnconditionalBranch(this ).setTarget(first,
208: mb);
209:
210: }
211: }
212:
213: // patch final test failure branch to fall through loop
214: mb.targetNext(link);
215: m_storeStrategy.genStoreDone(mb);
216:
217: } else {
218: throw new IllegalStateException(
219: "Internal error - no content present");
220: }
221: }
222:
223: public void genContentMarshal(ContextMethodBuilder mb)
224: throws JiBXException {
225: if (m_contents.size() > 0) {
226:
227: // set up common handling of unknown item and collection empty
228: BranchWrapper[] ifempties;
229: BranchWrapper link = null;
230: m_loadStrategy.genLoadInit(mb);
231:
232: // check for ordered or unordered content
233: int count = m_contents.size();
234: if (m_isOrdered) {
235:
236: // generate marshal code for each component type in order, with
237: // an exception generated if the end of the possible component
238: // list is reached with anything left in the collection
239: ifempties = new BranchWrapper[count];
240: for (int i = 0; i < count; i++) {
241:
242: // start generated code with loading next value from
243: // collection
244: if (link != null) {
245: mb.initStackState(link, 1);
246: }
247: BranchTarget start = mb.appendTargetNOP();
248: ifempties[i] = m_loadStrategy.genLoadItem(mb);
249: mb.targetNext(link);
250:
251: // if multiple types are included in content, append code to
252: // check if item type matches this component
253: IComponent child = (IComponent) m_contents.get(i);
254: String type = child.getType();
255: if (count > 1) {
256: mb.appendDUP();
257: mb.appendInstanceOf(type);
258: link = mb.appendIFEQ(this );
259: }
260: if ((!"java.lang.Object".equals(type) && !ClassItem
261: .isPrimitive(type))) {
262: mb.appendCreateCast(type);
263: }
264:
265: // finish with code to marshal the component, looping back
266: // to start of block for more of same type
267: child.genContentMarshal(mb);
268: mb.appendUnconditionalBranch(this ).setTarget(start,
269: mb);
270: }
271:
272: } else {
273:
274: // generate marshal loop code that loads an item from the
275: // collection and then checks to see if it matches a component
276: // type, branching to the next component until a match is found
277: // (or generating an exception on no match)
278: BranchTarget start = mb.appendTargetNOP();
279: ifempties = new BranchWrapper[1];
280: ifempties[0] = m_loadStrategy.genLoadItem(mb);
281: for (int i = 0; i < count; i++) {
282:
283: // start by setting target for branch from last component
284: mb.targetNext(link);
285:
286: // if multiple types are included in content, append code to
287: // check if item type matches this component
288: IComponent child = (IComponent) m_contents.get(i);
289: String type = child.getType();
290: if (count > 1
291: || (!"java.lang.Object".equals(type) && !ClassItem
292: .isPrimitive(type))) {
293: mb.appendDUP();
294: mb.appendInstanceOf(type);
295: link = mb.appendIFEQ(this );
296: mb.appendCreateCast(type);
297: }
298:
299: // finish with code to marshal the component, branching back
300: // to start of loop
301: child.genContentMarshal(mb);
302: mb.appendUnconditionalBranch(this ).setTarget(start,
303: mb);
304: }
305:
306: }
307:
308: // patch final test failure branch to generate an exception
309: if (link != null) {
310:
311: // instruction sequence for exception is create new exception
312: // object, build message in StringBuffer using type of item
313: // from stack, convert StringBuffer to String, invoke the
314: // exeception constructor with the String, and finally throw
315: // the exception
316: mb.targetNext(link);
317: mb.appendCreateNew("java.lang.StringBuffer");
318: mb.appendDUP();
319: mb.appendLoadConstant("Collection item of type ");
320: mb.appendCallInit("java.lang.StringBuffer",
321: "(Ljava/lang/String;)V");
322: mb.appendSWAP();
323: mb.appendDUP();
324: BranchWrapper ifnull = mb.appendIFNULL(this );
325: mb.appendCallVirtual("java.lang.Object.getClass",
326: "()Ljava/lang/Class;");
327: mb.appendCallVirtual("java.lang.Class.getName",
328: "()Ljava/lang/String;");
329: BranchWrapper toend = mb
330: .appendUnconditionalBranch(this );
331: mb.targetNext(ifnull);
332: mb.appendPOP();
333: mb.appendLoadConstant("NULL");
334: mb.targetNext(toend);
335: mb.appendCallVirtual("java.lang.StringBuffer.append",
336: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
337: mb.appendLoadConstant(" has no binding defined");
338: mb.appendCallVirtual("java.lang.StringBuffer.append",
339: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
340: mb.appendCallVirtual("java.lang.StringBuffer.toString",
341: "()Ljava/lang/String;");
342: mb
343: .appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
344: mb.appendDUP_X1();
345: mb.appendSWAP();
346: mb.appendCallInit(
347: MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
348: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
349: mb.appendThrow();
350: }
351:
352: // finish by setting target for collection empty case(s)
353: m_loadStrategy.genLoadDone(mb);
354: mb.targetNext(ifempties);
355:
356: } else {
357: throw new IllegalStateException(
358: "Internal error - no content present");
359: }
360: }
361:
362: public boolean hasId() {
363: return false;
364: }
365:
366: public void genLoadId(ContextMethodBuilder mb) throws JiBXException {
367: throw new IllegalStateException("No ID child");
368: }
369:
370: public NameDefinition getWrapperName() {
371: return null;
372: }
373:
374: public boolean isOptional() {
375: return m_isOptional;
376: }
377:
378: public void setLinkages() throws JiBXException {
379: for (int i = 0; i < m_contents.size(); i++) {
380: ((IComponent) m_contents.get(i)).setLinkages();
381: }
382: }
383:
384: // DEBUG
385: public void print(int depth) {
386: BindingDefinition.indent(depth);
387: System.out.print("collection "
388: + (m_isOrdered ? "ordered" : "unordered"));
389: if (m_itemType != null) {
390: System.out.print(" (" + m_itemType + ")");
391: }
392: if (isFlexible()) {
393: System.out.print(", flexible");
394: }
395: System.out.println();
396: for (int i = 0; i < m_contents.size(); i++) {
397: IComponent comp = (IComponent) m_contents.get(i);
398: comp.print(depth + 1);
399: }
400: }
401:
402: /**
403: * Base class for collection item load strategy. The implementation class
404: * must handle the appropriate form of code generation for the type of
405: * collection being used.
406: */
407: /*package*/static abstract class CollectionBase {
408: /** Double word value flag. */
409: private final boolean m_isDoubleWord;
410:
411: /**
412: * Constructor.
413: *
414: * @param doubword double word value flag
415: */
416: protected CollectionBase(boolean doubword) {
417: m_isDoubleWord = doubword;
418: }
419:
420: /**
421: * Append the appropriate instruction to swap the top of the stack
422: * (which must be a single-word value) with an item value (which may
423: * be one or two words, as configured for this collection).
424: *
425: * @param mb method
426: */
427: protected void appendSWAP(MethodBuilder mb) {
428: if (m_isDoubleWord) {
429: mb.appendSWAP1For2();
430: } else {
431: mb.appendSWAP();
432: }
433: }
434:
435: /**
436: * Append the appropriate instruction to pop the item value (which may
437: * be one or two words, as configured for this collection) from the top
438: * of the stack.
439: *
440: * @param mb method
441: */
442: protected void appendPOP(MethodBuilder mb) {
443: if (m_isDoubleWord) {
444: mb.appendPOP2();
445: } else {
446: mb.appendPOP();
447: }
448: }
449: }
450:
451: /**
452: * Base class for collection item load strategy. The implementation class
453: * must handle the appropriate form of code generation for the type of
454: * collection being used.
455: */
456: /*package*/static abstract class CollectionLoad extends
457: CollectionBase {
458: /**
459: * Constructor.
460: *
461: * @param add method used to add item to collection
462: * @param doubword double word value flag
463: * @param ret value returned by add flag
464: */
465: protected CollectionLoad(boolean doubword) {
466: super (doubword);
467: }
468:
469: /**
470: * Generate code to initialize collection for loading items. This
471: * generates the necessary code for handling the initialization. It
472: * must be called before attempting to call the {@link #genLoadItem}
473: * method. The base class implementation does nothing.
474: *
475: * @param mb method builder
476: * @throws JiBXException if error in configuration
477: */
478: protected void genLoadInit(ContextMethodBuilder mb)
479: throws JiBXException {
480: }
481:
482: /**
483: * Generate code to load next item from collection. This generates the
484: * necessary code for handling the load operation, leaving the item on
485: * the stack. The {@link #genLoadInit} method must be called before
486: * calling this method, and the {@link #genLoadDone} method must be
487: * called after the last call to this method. This method must be
488: * overridden by each subclass.
489: *
490: * @param mb method builder
491: * @return branch wrapper for case of done with collection
492: * @throws JiBXException if error in configuration
493: */
494: protected abstract BranchWrapper genLoadItem(
495: ContextMethodBuilder mb) throws JiBXException;
496:
497: /**
498: * Generate code to clean up after loading items from collection. This
499: * generates the necessary code for handling the clean up. It must be
500: * called after the last call to {@link #genLoadItem}. The base class
501: * implementation does nothing.
502: *
503: * @param mb method builder
504: * @throws JiBXException if error in configuration
505: */
506: protected void genLoadDone(ContextMethodBuilder mb)
507: throws JiBXException {
508: }
509: }
510:
511: /**
512: * Base class for collection item store strategy. The implementation class
513: * must handle the appropriate form of code generation for the type of
514: * collection being used.
515: */
516: /*package*/static abstract class CollectionStore extends
517: CollectionBase {
518: /**
519: * Constructor.
520: *
521: * @param doubword double word value flag
522: */
523: protected CollectionStore(boolean doubword) {
524: super (doubword);
525: }
526:
527: /**
528: * Generate code to initialize collection for storing items. This
529: * generates the necessary code for handling the initialization,
530: * including creating the collection object if appropriate. It must be
531: * called before attempting to call the {@link #genStoreItem} method.
532: * The base class implementation does nothing.
533: *
534: * @param mb method builder
535: * @throws JiBXException if error in configuration
536: */
537: protected void genStoreInit(ContextMethodBuilder mb)
538: throws JiBXException {
539: }
540:
541: /**
542: * Generate code to store next item to collection. This generates the
543: * necessary code for handling the store operation, removing the item
544: * from the stack. The {@link #genStoreInit} method must be called
545: * before calling this method, and the {@link #genStoreDone} method must
546: * be called after the last call to this method. This method must be
547: * overridden by each subclass.
548: *
549: * @param mb method builder
550: * @throws JiBXException if error in configuration
551: */
552: protected abstract void genStoreItem(ContextMethodBuilder mb)
553: throws JiBXException;
554:
555: /**
556: * Generate code to clean up after storing items to collection. This
557: * generates the necessary code for handling the clean up. It must be
558: * called after the last call to {@link #genStoreItem}. The base class
559: * implementation does nothing.
560: *
561: * @param mb method builder
562: * @throws JiBXException if error in configuration
563: */
564: protected void genStoreDone(ContextMethodBuilder mb)
565: throws JiBXException {
566: }
567: }
568:
569: /**
570: * Collection item load strategy for collection with items accessed by
571: * index number.
572: */
573: /*package*/static class IndexedLoad extends CollectionLoad {
574: /** Method used to get count of items in collection. */
575: private final ClassItem m_sizeMethod;
576:
577: /** Method used to get items by index from collection. */
578: private final ClassItem m_getMethod;
579:
580: /**
581: * Constructor.
582: *
583: * @param size method used to get count of items in collection
584: * @param doubword double word value flag
585: * @param get method used to retrieve items by index from collection
586: */
587: /*package*/IndexedLoad(ClassItem size, boolean doubword,
588: ClassItem get) {
589: super (doubword);
590: m_sizeMethod = size;
591: m_getMethod = get;
592: }
593:
594: protected void genLoadInit(ContextMethodBuilder mb)
595: throws JiBXException {
596:
597: // create index local with appended code to set initial value
598: mb.appendLoadConstant(-1);
599: mb.defineSlot(m_getMethod, Type.INT);
600:
601: // create size local with appended code to set initial value from
602: // collection method call
603: if (!m_sizeMethod.isStatic()) {
604: mb.loadObject();
605: }
606: mb.appendCall(m_sizeMethod);
607: mb.defineSlot(m_sizeMethod, Type.INT);
608: }
609:
610: protected BranchWrapper genLoadItem(ContextMethodBuilder mb)
611: throws JiBXException {
612:
613: // start by getting local variable slots for the index and size
614: int islot = mb.getSlot(m_getMethod);
615: int sslot = mb.getSlot(m_sizeMethod);
616:
617: // append code to first increment index, then check for end of
618: // collection reached
619: mb.appendIncrementLocal(1, islot);
620: mb.appendLoadLocal(islot);
621: mb.appendLoadLocal(sslot);
622: mb.appendISUB();
623: BranchWrapper ifempty = mb.appendIFGE(this );
624:
625: // finish by calling collection method to load item at current index
626: // position
627: if (!m_getMethod.isStatic()) {
628: mb.loadObject();
629: }
630: mb.appendLoadLocal(islot);
631: mb.appendCall(m_getMethod);
632: return ifempty;
633: }
634:
635: protected void genLoadDone(ContextMethodBuilder mb)
636: throws JiBXException {
637: mb.freeSlot(m_getMethod);
638: mb.freeSlot(m_sizeMethod);
639: }
640: }
641:
642: /**
643: * Collection item store strategy for collection with items set by
644: * index number.
645: */
646: /*package*/static class IndexedStore extends CollectionStore {
647: /** Method used to set items by index in collection. */
648: private final ClassItem m_setMethod;
649:
650: /** Flag for method returns result. */
651: private final boolean m_isReturned;
652:
653: /**
654: * Constructor.
655: *
656: * @param set method used to store items by index in collection
657: * @param doubword double word value flag
658: * @param ret value returned by add flag
659: */
660: /*package*/IndexedStore(ClassItem set, boolean doubword,
661: boolean ret) {
662: super (doubword);
663: m_setMethod = set;
664: m_isReturned = ret;
665: }
666:
667: protected void genStoreInit(ContextMethodBuilder mb)
668: throws JiBXException {
669:
670: // create index local with appended code to set initial value
671: mb.appendLoadConstant(-1);
672: mb.defineSlot(m_setMethod, Type.INT);
673: }
674:
675: protected void genStoreItem(ContextMethodBuilder mb)
676: throws JiBXException {
677:
678: // start by getting local variable slot for the index
679: int islot = mb.getSlot(m_setMethod);
680:
681: // append code to first load object and swap with item, then
682: // increment index and swap copy with item, and finally call
683: // collection method to store item at new index position
684: if (!m_setMethod.isStatic()) {
685: mb.loadObject();
686: appendSWAP(mb);
687: }
688: mb.appendIncrementLocal(1, islot);
689: mb.appendLoadLocal(islot);
690: appendSWAP(mb);
691: mb.appendCall(m_setMethod);
692: if (m_isReturned) {
693: appendPOP(mb);
694: }
695: }
696:
697: protected void genStoreDone(ContextMethodBuilder mb)
698: throws JiBXException {
699: mb.freeSlot(m_setMethod);
700: }
701: }
702:
703: /**
704: * Collection item load strategy for collection with items accessed by
705: * iterator or enumeration.
706: */
707: /*package*/static class IteratorLoad extends CollectionLoad {
708: /** Method used to get iterator for collection. */
709: private final ClassItem m_iterMethod;
710:
711: /** Fully qualified method name to test if more in iteration. */
712: private final String m_moreName;
713:
714: /** Fully qualified method name to get next item in iteration. */
715: private final String m_nextName;
716:
717: /**
718: * Constructor.
719: *
720: * @param iter method to get iterator or enumerator from collection
721: * @param doubword double word value flag
722: * @param more fully qualified method name to test if more in iteration
723: * @param next fully qualified method name to get next item in iteration
724: */
725: /*package*/IteratorLoad(ClassItem iter, boolean doubword,
726: String more, String next) {
727: super (doubword);
728: m_iterMethod = iter;
729: m_moreName = more;
730: m_nextName = next;
731: }
732:
733: protected void genLoadInit(ContextMethodBuilder mb)
734: throws JiBXException {
735:
736: // create iterator local with appended code to set initial value
737: if (!m_iterMethod.isStatic()) {
738: mb.loadObject();
739: }
740: mb.appendCall(m_iterMethod);
741: mb.defineSlot(m_iterMethod, Type
742: .getType("Ljava/util/Iterator;"));
743: }
744:
745: protected BranchWrapper genLoadItem(ContextMethodBuilder mb)
746: throws JiBXException {
747:
748: // start with code to load and test iterator
749: int islot = mb.getSlot(m_iterMethod);
750: mb.appendLoadLocal(islot);
751: mb.appendCallInterface(m_moreName, "()Z");
752: BranchWrapper ifempty = mb.appendIFEQ(this );
753:
754: // append code to get next item from iterator
755: mb.appendLoadLocal(islot);
756: mb.appendCallInterface(m_nextName, "()Ljava/lang/Object;");
757: return ifempty;
758: }
759:
760: protected void genLoadDone(ContextMethodBuilder mb)
761: throws JiBXException {
762: mb.freeSlot(m_iterMethod);
763: }
764: }
765:
766: /**
767: * Collection item store strategy for collection with add method.
768: */
769: /*package*/static class AddStore extends CollectionStore {
770: /** Method used to add item to collection. */
771: private final ClassItem m_addMethod;
772:
773: /** Flag for method returns result. */
774: private final boolean m_isReturned;
775:
776: /**
777: * Constructor.
778: *
779: * @param add method used to add item to collection
780: * @param doubword double word value flag
781: * @param ret value returned by add flag
782: */
783: /*package*/AddStore(ClassItem add, boolean doubword,
784: boolean ret) {
785: super (doubword);
786: m_addMethod = add;
787: m_isReturned = ret;
788: }
789:
790: protected void genStoreItem(ContextMethodBuilder mb)
791: throws JiBXException {
792:
793: // append code to call collection method to add the item
794: if (!m_addMethod.isStatic()) {
795: mb.loadObject();
796: appendSWAP(mb);
797: }
798: mb.appendCall(m_addMethod);
799: if (m_isReturned) {
800: appendPOP(mb);
801: }
802: }
803: }
804:
805: /**
806: * Collection item load strategy for array.
807: */
808: /*package*/static class ArrayLoad extends CollectionLoad {
809: /** Array item type. */
810: private final String m_itemType;
811:
812: /** Handle for referencing loop counter local variable. */
813: private Object m_slotHandle = new Object();
814:
815: /**
816: * Constructor.
817: *
818: * @param itype array item type
819: * @param doubword double word value flag
820: */
821: /*package*/ArrayLoad(String itype, boolean doubword) {
822: super (doubword);
823: m_itemType = itype;
824: }
825:
826: protected void genLoadInit(ContextMethodBuilder mb)
827: throws JiBXException {
828:
829: // create index local with initial value -1
830: mb.appendLoadConstant(-1);
831: mb.defineSlot(m_slotHandle, Type.INT);
832: }
833:
834: protected BranchWrapper genLoadItem(ContextMethodBuilder mb)
835: throws JiBXException {
836:
837: // start by getting local variable slots for the index
838: int islot = mb.getSlot(m_slotHandle);
839:
840: // append code to first increment index, then check for end of
841: // collection reached
842: mb.appendIncrementLocal(1, islot);
843: mb.appendLoadLocal(islot);
844: mb.loadObject();
845: mb.appendARRAYLENGTH();
846: mb.appendISUB();
847: BranchWrapper ifempty = mb.appendIFGE(this );
848:
849: // finish by loading array item at current index position
850: mb.loadObject();
851: mb.appendLoadLocal(islot);
852: mb.appendALOAD(m_itemType);
853: return ifempty;
854: }
855:
856: protected void genLoadDone(ContextMethodBuilder mb)
857: throws JiBXException {
858: mb.freeSlot(m_slotHandle);
859: }
860: }
861:
862: /**
863: * Collection item store strategy for array.
864: */
865: /*package*/static class ArrayStore extends CollectionStore {
866: /** Array item type. */
867: private final String m_itemType;
868:
869: /**
870: * Constructor.
871: *
872: * @param itype array item type
873: * @param doubword double word value flag
874: */
875: /*package*/ArrayStore(String itype, boolean doubword) {
876: super (doubword);
877: m_itemType = itype;
878: }
879:
880: protected void genStoreInit(ContextMethodBuilder mb)
881: throws JiBXException {
882:
883: // create index local with initial value -1
884: mb.appendLoadConstant(-1);
885: mb.defineSlot(m_itemType, Type.INT);
886: }
887:
888: protected void genStoreItem(ContextMethodBuilder mb)
889: throws JiBXException {
890:
891: // start by getting local variable slot for the index
892: int islot = mb.getSlot(m_itemType);
893:
894: // append code to first increment index and check array size
895: mb.appendIncrementLocal(1, islot);
896: mb.appendLoadLocal(islot);
897: mb.loadObject();
898: mb.appendARRAYLENGTH();
899: mb.appendISUB();
900: BranchWrapper ifnotfull = mb.appendIFLT(this );
901:
902: // grow the array size to make room for more values
903: mb.loadObject();
904: mb.appendCallStatic(GROWARRAY_METHOD, GROWARRAY_SIGNATURE);
905: mb.storeObject();
906:
907: // swap the array reference with the item, swap index with item, and
908: // finally store item at new index position
909: mb.targetNext(ifnotfull);
910: mb.loadObject();
911: appendSWAP(mb);
912: mb.appendLoadLocal(islot);
913: appendSWAP(mb);
914: if (!ClassItem.isPrimitive(m_itemType)) {
915: mb.appendCreateCast(m_itemType);
916: }
917: mb.appendASTORE(m_itemType);
918: }
919:
920: protected void genStoreDone(ContextMethodBuilder mb)
921: throws JiBXException {
922:
923: // resize the array to match actual item count
924: int islot = mb.getSlot(m_itemType);
925: mb.appendIncrementLocal(1, islot);
926: mb.appendLoadLocal(islot);
927: mb.loadObject();
928: mb.appendCallStatic(RESIZEARRAY_METHOD,
929: RESIZEARRAY_SIGNATURE);
930: mb.storeObject();
931: mb.freeSlot(m_itemType);
932: }
933: }
934: }
|