001: /*
002: Copyright (c) 2003-2007, 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.jibx.binding.classes.*;
032: import org.jibx.runtime.JiBXException;
033:
034: /**
035: * Component decorator for element definition. This associates an element name
036: * with a component.
037: *
038: * @author Dennis M. Sosnoski
039: */
040: public class ElementWrapper implements IComponent {
041: //
042: // Constants and such related to code generation.
043:
044: private static final String UNMARSHAL_PARSESTARTATTRIBUTES = "org.jibx.runtime.impl.UnmarshallingContext.parseToStartTag";
045: private static final String UNMARSHAL_PARSESTARTNOATTRIBUTES = "org.jibx.runtime.impl.UnmarshallingContext.parsePastStartTag";
046: private static final String UNMARSHAL_PARSEPASTSTART = "org.jibx.runtime.impl.UnmarshallingContext.parsePastStartTag";
047: private static final String UNMARSHAL_PARSESTARTSIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
048: private static final String UNMARSHAL_PARSEENDMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.parsePastCurrentEndTag";
049: private static final String UNMARSHAL_PARSEENDSIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
050: private static final String UNMARSHAL_ISATMETHOD = "org.jibx.runtime.IUnmarshallingContext.isAt";
051: private static final String UNMARSHAL_ISATSIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)Z";
052: private static final String UNMARSHAL_SKIPELEMENTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.parsePastElement";
053: private static final String UNMARSHAL_SKIPELEMENTSIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
054: private static final String MARSHAL_WRITESTARTNAMESPACES = "org.jibx.runtime.impl.MarshallingContext.startTagNamespaces";
055: private static final String MARSHAL_STARTNAMESPACESSIGNATURE = "(ILjava/lang/String;[I[Ljava/lang/String;)"
056: + "Lorg/jibx/runtime/impl/MarshallingContext;";
057: private static final String MARSHAL_WRITESTARTATTRIBUTES = "org.jibx.runtime.impl.MarshallingContext.startTagAttributes";
058: private static final String MARSHAL_WRITESTARTNOATTRIBUTES = "org.jibx.runtime.impl.MarshallingContext.startTag";
059: private static final String MARSHAL_WRITESTARTSIGNATURE = "(ILjava/lang/String;)Lorg/jibx/runtime/impl/MarshallingContext;";
060: private static final String MARSHAL_CLOSESTARTCONTENT = "org.jibx.runtime.impl.MarshallingContext.closeStartContent";
061: private static final String MARSHAL_CLOSESTARTEMPTY = "org.jibx.runtime.impl.MarshallingContext.closeStartEmpty";
062: private static final String MARSHAL_CLOSESTARTSIGNATURE = "()Lorg/jibx/runtime/impl/MarshallingContext;";
063: private static final String MARSHAL_WRITEENDMETHOD = "org.jibx.runtime.impl.MarshallingContext.endTag";
064: private static final String MARSHAL_WRITEENDSIGNATURE = "(ILjava/lang/String;)Lorg/jibx/runtime/impl/MarshallingContext;";
065: private static final String UNMARSHAL_PARSE_TO_START_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseToStartTag";
066: private static final String UNMARSHAL_PARSE_TO_START_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
067: protected static final String UNMARSHAL_ATTRIBUTE_BOOLEAN_NAME = "org.jibx.runtime.impl.UnmarshallingContext.attributeBoolean";
068: protected static final String UNMARSHAL_ATTRIBUTE_BOOLEAN_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;Z)Z";
069: private static final String UNMARSHAL_SKIP_NAME = "org.jibx.runtime.impl.UnmarshallingContext.skipElement";
070: private static final String UNMARSHAL_SKIP_SIGNATURE = "()V";
071: protected static final String MARSHAL_STARTTAG_ATTRIBUTES = "org.jibx.runtime.impl.MarshallingContext.startTagAttributes";
072: protected static final String MARSHAL_STARTTAG_SIGNATURE = "(ILjava/lang/String;)Lorg/jibx/runtime/impl/MarshallingContext;";
073: protected static final String MARSHAL_CLOSESTART_EMPTY = "org.jibx.runtime.impl.MarshallingContext.closeStartEmpty";
074: protected static final String MARSHAL_CLOSESTART_EMPTY_SIGNATURE = "()Lorg/jibx/runtime/impl/MarshallingContext;";
075: protected static final String MARSHAL_ATTRIBUTE = "org.jibx.runtime.impl.MarshallingContext.attribute";
076: protected static final String MARSHAL_SIGNATURE = "(ILjava/lang/String;Ljava/lang/String;)"
077: + "Lorg/jibx/runtime/impl/MarshallingContext;";
078: private static final String MARSHALLING_CONTEXT = "org.jibx.runtime.impl.MarshallingContext";
079: private static final String UNMARSHALLING_CONTEXT = "org.jibx.runtime.impl.UnmarshallingContext";
080:
081: //
082: // Actual instance data.
083:
084: /** Property value binding component. */
085: private final IComponent m_component;
086:
087: /** Binding definition context. */
088: private final DefinitionContext m_defContext;
089:
090: /** Element name information. */
091: private final NameDefinition m_name;
092:
093: /** Flag for nillable element. */
094: private final boolean m_isNillable;
095:
096: /** Flag for value from collection (TODO: fix this in update). */
097: private boolean m_directAccess;
098:
099: /** Flag for optional ignored element (TODO: fix this in update). */
100: private boolean m_optionalIgnored;
101:
102: /** Flag for optional normal element (TODO: fix this in update). */
103: private boolean m_optionalNormal;
104:
105: /** Flag for optional structure object (TODO: fix this in update). */
106: private boolean m_structureObject;
107:
108: /**
109: * Constructor.
110: *
111: * @param defc definition context for this component
112: * @param name element name definition
113: * @param wrap wrapped binding component (may be <code>null</code>, in the
114: * case of a throwaway component)
115: * @param nillable flag for nillable element
116: */
117: public ElementWrapper(DefinitionContext defc, NameDefinition name,
118: IComponent wrap, boolean nillable) {
119: m_defContext = defc;
120: m_name = name;
121: m_component = wrap;
122: m_isNillable = nillable;
123: }
124:
125: /**
126: * Set the direct access flag. This controls a variation in the code
127: * generation to handle values loaded from a collection.
128: *
129: * @param direct <code>true</code> if direct access from collection,
130: * <code>false</code> if not
131: */
132: public void setDirect(boolean direct) {
133: m_directAccess = direct;
134: }
135:
136: /**
137: * Set flag for an optional ignored element.
138: *
139: * @param opt <code>true</code> if optional ignored element,
140: * <code>false</code> if not
141: */
142: public void setOptionalIgnored(boolean opt) {
143: m_optionalIgnored = opt;
144: }
145:
146: /**
147: * Set flag for an optional structure object.
148: *
149: * @param opt <code>true</code> if optional structure object,
150: * <code>false</code> if not
151: */
152: public void setStructureObject(boolean opt) {
153: m_structureObject = opt;
154: }
155:
156: /**
157: * Set flag for an optional normal element.
158: *
159: * @param opt <code>true</code> if optional normal element,
160: * <code>false</code> if not
161: */
162: public void setOptionalNormal(boolean opt) {
163: m_optionalNormal = opt;
164: }
165:
166: //
167: // IComponent interface method definitions
168:
169: public boolean isOptional() {
170: return m_optionalNormal || m_optionalIgnored;
171: }
172:
173: public boolean hasAttribute() {
174: return false;
175: }
176:
177: public void genAttrPresentTest(ContextMethodBuilder mb) {
178: throw new IllegalStateException(
179: "Internal error - no attributes from child element");
180: }
181:
182: public void genAttributeUnmarshal(ContextMethodBuilder mb) {
183: throw new IllegalStateException(
184: "Internal error - no attributes from child element");
185: }
186:
187: public void genAttributeMarshal(ContextMethodBuilder mb) {
188: throw new IllegalStateException(
189: "Internal error - no attributes from child element");
190: }
191:
192: public boolean hasContent() {
193: return true;
194: }
195:
196: public void genContentPresentTest(ContextMethodBuilder mb)
197: throws JiBXException {
198:
199: // create call to unmarshalling context method with namespace and
200: // name, then return result directly
201: mb.loadContext();
202: m_name.genPushUriPair(mb);
203: mb.appendCallInterface(UNMARSHAL_ISATMETHOD,
204: UNMARSHAL_ISATSIGNATURE);
205: }
206:
207: public void genContentUnmarshal(ContextMethodBuilder mb)
208: throws JiBXException {
209:
210: // check for optional empty wrapper present
211: BranchWrapper ifmiss = null;
212: if (isOptional()) {
213: genContentPresentTest(mb);
214: ifmiss = mb.appendIFEQ(this );
215: }
216: BranchWrapper ifnil = null;
217: if (m_isNillable) {
218:
219: // make sure we're at the element
220: mb.loadContext(UNMARSHALLING_CONTEXT);
221: m_name.genPushUriPair(mb);
222: mb.appendCallVirtual(UNMARSHAL_PARSE_TO_START_NAME,
223: UNMARSHAL_PARSE_TO_START_SIGNATURE);
224:
225: // check for xsi:nil="true"
226: mb.loadContext(UNMARSHALLING_CONTEXT);
227: mb
228: .appendLoadConstant("http://www.w3.org/2001/XMLSchema-instance");
229: mb.appendLoadConstant("nil");
230: mb.appendICONST_0();
231: mb.appendCallVirtual(UNMARSHAL_ATTRIBUTE_BOOLEAN_NAME,
232: UNMARSHAL_ATTRIBUTE_BOOLEAN_SIGNATURE);
233: BranchWrapper notnil = mb.appendIFEQ(this );
234:
235: // skip past the element before jumping to end
236: mb.loadContext(UNMARSHALLING_CONTEXT);
237: mb.appendCallVirtual(UNMARSHAL_SKIP_NAME,
238: UNMARSHAL_SKIP_SIGNATURE);
239: ifnil = mb.appendUnconditionalBranch(this );
240: mb.targetNext(notnil);
241: }
242:
243: // set up flags for controlling code generation paths
244: boolean attr = m_component != null
245: && m_component.hasAttribute();
246: boolean cont = m_component != null && m_component.hasContent();
247:
248: // load the unmarshalling context followed by the namespace URI and
249: // element name.
250: mb.loadContext(UNMARSHALLING_CONTEXT);
251: m_name.genPushUriPair(mb);
252:
253: // check type of unmarshalling behavior required
254: if (attr) {
255:
256: // unmarshal start tag with attribute(s)
257: mb.appendCallVirtual(UNMARSHAL_PARSESTARTATTRIBUTES,
258: UNMARSHAL_PARSESTARTSIGNATURE);
259: m_component.genAttributeUnmarshal(mb);
260:
261: // generate code to parse past the start tag with another call
262: // to unmarshalling context
263: mb.loadContext(UNMARSHALLING_CONTEXT);
264: m_name.genPushUriPair(mb);
265: mb.appendCallVirtual(UNMARSHAL_PARSEPASTSTART,
266: UNMARSHAL_PARSESTARTSIGNATURE);
267:
268: } else if (cont) {
269:
270: // unmarshal start tag without attributes
271: mb.appendCallVirtual(UNMARSHAL_PARSESTARTNOATTRIBUTES,
272: UNMARSHAL_PARSESTARTSIGNATURE);
273:
274: } else {
275:
276: // unmarshal element discarding all content
277: mb.appendCallVirtual(UNMARSHAL_SKIPELEMENTMETHOD,
278: UNMARSHAL_SKIPELEMENTSIGNATURE);
279: }
280:
281: // unmarshal child content
282: if (cont) {
283: m_component.genContentUnmarshal(mb);
284: }
285:
286: // next add code to push context, namespace and name, and call
287: // method to parse past end tag
288: if (attr || cont) {
289: mb.loadContext(UNMARSHALLING_CONTEXT);
290: m_name.genPushUriPair(mb);
291: mb.appendCallVirtual(UNMARSHAL_PARSEENDMETHOD,
292: UNMARSHAL_PARSEENDSIGNATURE);
293: }
294:
295: // check if need code to handle missing or nil element
296: if (ifmiss != null || ifnil != null) {
297:
298: // handle branch conditions, jumping around code to set null
299: BranchWrapper toend = mb.appendUnconditionalBranch(this );
300: mb.targetNext(ifmiss);
301: mb.targetNext(ifnil);
302:
303: // generate code to store null to property
304: if (m_component instanceof ComponentProperty) {
305: PropertyDefinition prop = ((ComponentProperty) m_component)
306: .getProperty();
307: if (!prop.isImplicit()) {
308: mb.loadObject();
309: mb.appendACONST_NULL();
310: prop.genStore(mb);
311: } else {
312: mb.appendACONST_NULL();
313: }
314: } else {
315: mb.appendPOP();
316: mb.appendACONST_NULL();
317: }
318: mb.targetNext(toend);
319:
320: }
321: }
322:
323: public void genContentMarshal(ContextMethodBuilder mb)
324: throws JiBXException {
325:
326: // nothing to be done if optional ignored element
327: if (!m_optionalIgnored) {
328: BranchWrapper ifmiss = null;
329: if (m_isNillable) {
330:
331: // check for null object
332: BranchWrapper ifhit;
333: if (m_directAccess
334: || !(m_component instanceof ComponentProperty)) {
335: mb.appendDUP();
336: ifhit = mb.appendIFNONNULL(this );
337: mb.appendPOP();
338: } else {
339: PropertyDefinition prop = ((ComponentProperty) m_component)
340: .getProperty();
341: mb.loadObject();
342: prop.genLoad(mb);
343: ifhit = mb.appendIFNONNULL(this );
344: }
345:
346: // generate empty element with xsi:nil="true"
347: mb.loadContext(MARSHALLING_CONTEXT);
348: m_name.genPushIndexPair(mb);
349: mb.appendCallVirtual(MARSHAL_STARTTAG_ATTRIBUTES,
350: MARSHAL_STARTTAG_SIGNATURE);
351: mb.appendLoadConstant(2);
352: mb.appendLoadConstant("nil");
353: mb.appendLoadConstant("true");
354: mb.appendCallVirtual(MARSHAL_ATTRIBUTE,
355: MARSHAL_SIGNATURE);
356: mb.appendCallVirtual(MARSHAL_CLOSESTART_EMPTY,
357: MARSHAL_CLOSESTART_EMPTY_SIGNATURE);
358: mb.appendPOP();
359: ifmiss = mb.appendUnconditionalBranch(this );
360: mb.targetNext(ifhit);
361: }
362:
363: // set up flags for controlling code generation paths
364: boolean attr = m_component != null
365: && m_component.hasAttribute();
366: boolean cont = m_component != null
367: && m_component.hasContent();
368: boolean needns = !m_structureObject
369: && m_defContext.hasNamespace();
370:
371: // duplicate object reference on stack if both attribute(s) and
372: // content
373: if (attr && cont) {
374: mb.appendDUP();
375: }
376:
377: // load the context followed by namespace index and element name
378: mb.loadContext(MARSHALLING_CONTEXT);
379: m_name.genPushIndexPair(mb);
380:
381: // check type of marshalling behavior required
382: if (attr || needns) {
383:
384: // check for namespace definition required
385: if (needns) {
386:
387: // marshal start tag with namespace(s)
388: m_defContext.genLoadNamespaces(mb);
389: mb.appendCallVirtual(MARSHAL_WRITESTARTNAMESPACES,
390: MARSHAL_STARTNAMESPACESSIGNATURE);
391:
392: } else {
393:
394: // marshal start tag with attribute(s)
395: mb.appendCallVirtual(MARSHAL_WRITESTARTATTRIBUTES,
396: MARSHAL_WRITESTARTSIGNATURE);
397:
398: }
399:
400: // handle attributes other than namespace declarations
401: if (attr) {
402:
403: // discard marshalling context from stack
404: mb.appendPOP();
405: m_component.genAttributeMarshal(mb);
406: mb.loadContext(MARSHALLING_CONTEXT);
407: }
408:
409: // generate code to close the start tag with another call
410: // to marshalling context
411: if (cont) {
412: mb.appendCallVirtual(MARSHAL_CLOSESTARTCONTENT,
413: MARSHAL_CLOSESTARTSIGNATURE);
414: } else {
415: mb.appendCallVirtual(MARSHAL_CLOSESTARTEMPTY,
416: MARSHAL_CLOSESTARTSIGNATURE);
417: }
418:
419: } else if (cont) {
420:
421: // marshal start tag without attributes
422: mb.appendCallVirtual(MARSHAL_WRITESTARTNOATTRIBUTES,
423: MARSHAL_WRITESTARTSIGNATURE);
424:
425: } else {
426:
427: // marshal empty tag
428: mb.appendCallVirtual(MARSHAL_WRITESTARTATTRIBUTES,
429: MARSHAL_WRITESTARTSIGNATURE);
430: mb.appendCallVirtual(MARSHAL_CLOSESTARTEMPTY,
431: MARSHAL_CLOSESTARTSIGNATURE);
432:
433: }
434:
435: // handle child content if present
436: if (cont) {
437: mb.appendPOP();
438: m_component.genContentMarshal(mb);
439: mb.loadContext(MARSHALLING_CONTEXT);
440: m_name.genPushIndexPair(mb);
441: mb.appendCallVirtual(MARSHAL_WRITEENDMETHOD,
442: MARSHAL_WRITEENDSIGNATURE);
443: }
444: mb.appendPOP();
445: mb.targetNext(ifmiss);
446: }
447: }
448:
449: public void genNewInstance(ContextMethodBuilder mb)
450: throws JiBXException {
451: if (m_component == null) {
452: throw new IllegalStateException(
453: "Internal error - no wrapped component");
454: } else {
455: m_component.genNewInstance(mb);
456: }
457: }
458:
459: public String getType() {
460: if (m_component == null) {
461: throw new IllegalStateException(
462: "Internal error - no wrapped component");
463: } else {
464: return m_component.getType();
465: }
466: }
467:
468: public boolean hasId() {
469: if (m_component == null) {
470: return false;
471: } else {
472: return m_component.hasId();
473: }
474: }
475:
476: public void genLoadId(ContextMethodBuilder mb) throws JiBXException {
477: if (m_component == null) {
478: throw new IllegalStateException(
479: "Internal error - no wrapped component");
480: } else {
481: m_component.genLoadId(mb);
482: }
483: }
484:
485: public NameDefinition getWrapperName() {
486: return m_name;
487: }
488:
489: public void setLinkages() throws JiBXException {
490: m_name.fixNamespace(m_defContext);
491: if (m_component != null) {
492: m_component.setLinkages();
493: }
494: }
495:
496: // DEBUG
497: public void print(int depth) {
498: BindingDefinition.indent(depth);
499: System.out.println(toString());
500: if (m_component != null) {
501: m_component.print(depth + 1);
502: }
503: }
504:
505: public String toString() {
506: StringBuffer buff = new StringBuffer("element wrapper");
507: if (m_name != null) {
508: buff.append(' ');
509: buff.append(m_name.toString());
510: }
511: if (m_directAccess) {
512: buff.append(" direct");
513: }
514: if (m_optionalIgnored) {
515: buff.append(" optional ignored");
516: }
517: if (m_optionalNormal) {
518: buff.append(" optional");
519: }
520: if (m_structureObject) {
521: buff.append(" structure object");
522: }
523: return buff.toString();
524: }
525: }
|