001: /*
002: Copyright (c) 2004-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.model;
030:
031: import org.jibx.binding.util.StringArray;
032: import org.jibx.runtime.EnumSet;
033: import org.jibx.runtime.IUnmarshallingContext;
034: import org.jibx.runtime.JiBXException;
035: import org.jibx.runtime.QName;
036:
037: /**
038: * Model component for <b>value</b> element. This element defines a value that
039: * can be represented as a simple text string, which may be expressed as an
040: * attribute, element, or text component of the XML document.
041: *
042: * @author Dennis M. Sosnoski
043: */
044: public class ValueElement extends ElementBase implements IComponent {
045: /** Enumeration of allowed attribute names */
046: public static final StringArray s_allowedAttributes = new StringArray(
047: new String[] { "constant", "format", "ident", "nillable",
048: "style" }, new StringArray(new StringArray(
049: NameAttributes.s_allowedAttributes,
050: PropertyAttributes.s_allowedAttributes),
051: StringAttributes.s_allowedAttributes));
052:
053: //
054: // Value set information
055:
056: public static final int CDATA_STYLE = 2;
057: public static final int TEXT_STYLE = 3;
058:
059: private static final EnumSet s_styleEnum = new EnumSet(
060: NestingAttributes.s_styleEnum, CDATA_STYLE, new String[] {
061: "cdata", "text" });
062:
063: public static final int NONE_IDENT = 0;
064: public static final int DEF_IDENT = 1;
065: public static final int REF_IDENT = 2;
066: /* public static final int AUTO_IDENT = 3; */
067:
068: /*package*/static final EnumSet s_identEnum = new EnumSet(
069: NONE_IDENT,
070: new String[] { "none", "def", "ref"/*, "auto"*/});
071:
072: //
073: // Instance data
074:
075: /** Supplied constant value. */
076: private String m_constantValue;
077:
078: /** Supplied style name. */
079: private String m_styleName;
080:
081: /** Actual selected style. */
082: private int m_styleIndex;
083:
084: /** Supplied identity name. */
085: private String m_identName = s_identEnum.getName(NONE_IDENT);
086:
087: /** Nillable object flag. */
088: private boolean m_isNillable;
089:
090: /** Actual selected identity. */
091: private int m_identIndex;
092:
093: /** Name attributes information for value. */
094: private NameAttributes m_nameAttrs;
095:
096: /** Property attributes information for value. */
097: private PropertyAttributes m_propertyAttrs;
098:
099: /** String attributes information for value. */
100: private StringAttributes m_stringAttrs;
101:
102: /**
103: * Constructor.
104: */
105: public ValueElement() {
106: super (VALUE_ELEMENT);
107: m_nameAttrs = new NameAttributes();
108: m_propertyAttrs = new PropertyAttributes();
109: m_stringAttrs = new StringAttributes();
110: }
111:
112: /**
113: * Get constant value.
114: *
115: * @return constant value, or <code>null</code> if not a constant
116: */
117: public String getConstantValue() {
118: return m_constantValue;
119: }
120:
121: /**
122: * Set constant value.
123: *
124: * @param value constant value, or <code>null</code> if not a constant
125: */
126: public void setConstantValue(String value) {
127: m_constantValue = value;
128: }
129:
130: /**
131: * Get style string value.
132: *
133: * @return style string value
134: */
135: public String getStyleName() {
136: return m_styleName;
137: }
138:
139: /**
140: * Get style value. This call is only meaningful after validation.
141: *
142: * @return style value
143: */
144: public int getStyle() {
145: return m_styleIndex;
146: }
147:
148: /**
149: * Set style name.
150: *
151: * @param name style name (<code>null</code> if to use inherited default)
152: */
153: public void setStyleName(String name) {
154: m_styleName = name;
155: }
156:
157: /**
158: * Get name for style that applies to this value. This call is only
159: * meaningful after validation.
160: *
161: * @return name for style
162: */
163: public String getEffectiveStyleName() {
164: return s_styleEnum.getName(m_styleIndex);
165: }
166:
167: /**
168: * Set style that applies to this value. If the specified style is different
169: * from the nested default it is applied directly, otherwise this value is
170: * configured to use the default. This method should therefore only be used
171: * when the nested settings are considered fixed.
172: * TODO: implement this with parent links
173: *
174: * @param style style value
175: */
176: public void setEffectiveStyle(int style) {
177: m_styleIndex = style;
178: m_styleName = s_styleEnum.getName(style);
179: }
180:
181: /**
182: * Get identity string value.
183: *
184: * @return identity string value
185: */
186: public String getIdentName() {
187: return m_identName;
188: }
189:
190: /**
191: * Get identity value. This call is only meaningful after validation.
192: *
193: * @return identity value
194: */
195: public int getIdent() {
196: return m_identIndex;
197: }
198:
199: /**
200: * Set identity name.
201: *
202: * @param name identity name
203: */
204: public void setIdentName(String name) {
205: m_identName = name;
206: }
207:
208: //
209: // Name attribute delegate methods
210:
211: /**
212: * Get name.
213: *
214: * @return name text
215: */
216: public String getName() {
217: return m_nameAttrs.getName();
218: }
219:
220: /**
221: * Set name.
222: *
223: * @param name text for name
224: */
225: public void setName(String name) {
226: m_nameAttrs.setName(name);
227: }
228:
229: /**
230: * Get specified namespace URI.
231: *
232: * @return namespace URI (<code>null</code> if not set)
233: */
234: public String getUri() {
235: return m_nameAttrs.getUri();
236: }
237:
238: /**
239: * Set namespace URI.
240: *
241: * @param uri namespace URI (<code>null</code> if not set)
242: */
243: public void setUri(String uri) {
244: m_nameAttrs.setUri(uri);
245: }
246:
247: /**
248: * Get specified namespace prefix.
249: *
250: * @return namespace prefix (<code>null</code> if not set)
251: */
252: public String getPrefix() {
253: return m_nameAttrs.getPrefix();
254: }
255:
256: /**
257: * Set namespace prefix.
258: *
259: * @param prefix namespace prefix (<code>null</code> if not set)
260: */
261: public void setPrefix(String prefix) {
262: m_nameAttrs.setPrefix(prefix);
263: }
264:
265: /**
266: * Get effective namespace information. This call is only meaningful after
267: * validation.
268: *
269: * @return effective namespace information
270: */
271: public NamespaceElement getNamespace() {
272: return m_nameAttrs.getNamespace();
273: }
274:
275: //
276: // Property attribute delegate methods
277:
278: /**
279: * Get usage name.
280: *
281: * @return usage name
282: */
283: public String getUsageName() {
284: return m_propertyAttrs.getUsageName();
285: }
286:
287: /**
288: * Get usage value. This call is only meaningful after validation.
289: *
290: * @return usage value
291: */
292: public int getUsage() {
293: return m_propertyAttrs.getUsage();
294: }
295:
296: /**
297: * Set usage name.
298: *
299: * @param name usage name
300: */
301: public void setUsageName(String name) {
302: m_propertyAttrs.setUsageName(name);
303: }
304:
305: /**
306: * Set usage value.
307: *
308: * @param use value
309: */
310: public void setUsage(int use) {
311: m_propertyAttrs.setUsage(use);
312: }
313:
314: /**
315: * Check if property is defined. This method is only meaningful after
316: * validation.
317: *
318: * @return <code>true</code> if property defined, <code>false</code> if not
319: */
320: public boolean hasProperty() {
321: return m_propertyAttrs.hasProperty();
322: }
323:
324: /**
325: * Get declared type name. This call is only meaningful after validation.
326: *
327: * @return type name (or <code>null</code> if none)
328: */
329: public String getDeclaredType() {
330: return m_propertyAttrs.getDeclaredType();
331: }
332:
333: /**
334: * Set declared type name.
335: *
336: * @param type name (or <code>null</code> if none)
337: */
338: public void setDeclaredType(String type) {
339: m_propertyAttrs.setDeclaredType(type);
340: }
341:
342: /**
343: * Get field name.
344: *
345: * @return field name (or <code>null</code> if none)
346: */
347: public String getFieldName() {
348: return m_propertyAttrs.getFieldName();
349: }
350:
351: /**
352: * Get field information. This call is only meaningful after validation.
353: *
354: * @return field information (or <code>null</code> if none)
355: */
356: public IClassItem getField() {
357: return m_propertyAttrs.getField();
358: }
359:
360: /**
361: * Set field name.
362: *
363: * @param field field name (or <code>null</code> if none)
364: */
365: public void setFieldName(String field) {
366: m_propertyAttrs.setFieldName(field);
367: }
368:
369: /**
370: * Get test method name.
371: *
372: * @return test method name (or <code>null</code> if none)
373: */
374: public String getTestName() {
375: return m_propertyAttrs.getTestName();
376: }
377:
378: /**
379: * Get test method information. This call is only meaningful after
380: * validation.
381: *
382: * @return test method information (or <code>null</code> if none)
383: */
384: public IClassItem getTest() {
385: return m_propertyAttrs.getTest();
386: }
387:
388: /**
389: * Set test method name.
390: *
391: * @param test test method name (or <code>null</code> if none)
392: */
393: public void setTestName(String test) {
394: m_propertyAttrs.setTestName(test);
395: }
396:
397: /**
398: * Get get method name.
399: *
400: * @return get method name (or <code>null</code> if none)
401: */
402: public String getGetName() {
403: return m_propertyAttrs.getGetName();
404: }
405:
406: /**
407: * Get get method information. This call is only meaningful after
408: * validation.
409: *
410: * @return get method information (or <code>null</code> if none)
411: */
412: public IClassItem getGet() {
413: return m_propertyAttrs.getGet();
414: }
415:
416: /**
417: * Get type for value loaded to stack. This call is only meaningful after
418: * validation.
419: *
420: * @return get value type (or <code>null</code> if none)
421: */
422: public IClass getGetType() {
423: return m_propertyAttrs.getGetType();
424: }
425:
426: /**
427: * Set get method name.
428: *
429: * @param get get method name (or <code>null</code> if none)
430: */
431: public void setGetName(String get) {
432: m_propertyAttrs.setGetName(get);
433: }
434:
435: /**
436: * Get set method name.
437: *
438: * @return set method name (or <code>null</code> if none)
439: */
440: public String getSetName() {
441: return m_propertyAttrs.getSetName();
442: }
443:
444: /**
445: * Get set method information. This call is only meaningful after
446: * validation.
447: *
448: * @return set method information (or <code>null</code> if none)
449: */
450: public IClassItem getSet() {
451: return m_propertyAttrs.getSet();
452: }
453:
454: /**
455: * Get type for value stored from stack. This call is only meaningful after
456: * validation.
457: *
458: * @return set value type (or <code>null</code> if none)
459: */
460: public IClass getSetType() {
461: return m_propertyAttrs.getSetType();
462: }
463:
464: /**
465: * Set set method name.
466: *
467: * @param set set method name (or <code>null</code> if none)
468: */
469: public void setSetName(String set) {
470: m_propertyAttrs.setSetName(set);
471: }
472:
473: /**
474: * Check if nillable object.
475: *
476: * @return nillable flag
477: */
478: public boolean isNillable() {
479: return m_isNillable;
480: }
481:
482: /**
483: * Set nillable flag.
484: *
485: * @param nillable flag
486: */
487: public void setNillable(boolean nillable) {
488: m_isNillable = nillable;
489: }
490:
491: /**
492: * Check if this value implicitly uses the containing object. This call
493: * is only meaningful after prevalidation.
494: *
495: * @return <code>true</code> if using the containing object,
496: * <code>false</code> if own value
497: */
498: public boolean isImplicit() {
499: return m_propertyAttrs.isImplicit();
500: }
501:
502: //
503: // String attribute delegate methods
504:
505: /**
506: * Get default value text.
507: *
508: * @return default value text
509: */
510: public String getDefaultText() {
511: return m_stringAttrs.getDefaultText();
512: }
513:
514: /**
515: * Get default value. This call is only meaningful after validation.
516: *
517: * @return default value object
518: */
519: public Object getDefault() {
520: return m_stringAttrs.getDefault();
521: }
522:
523: /**
524: * Set default value text.
525: *
526: * @param value default value text
527: */
528: public void setDefaultText(String value) {
529: m_stringAttrs.setDefaultText(value);
530: }
531:
532: /**
533: * Get base format name.
534: *
535: * @return referenced base format
536: */
537: public String getFormatName() {
538: return m_stringAttrs.getFormatName();
539: }
540:
541: /**
542: * Set base format name.
543: *
544: * @param name referenced base format
545: */
546: public void setFormatName(String name) {
547: m_stringAttrs.setFormatName(name);
548: }
549:
550: /**
551: * Get format qualified name.
552: *
553: * @return format qualified name (<code>null</code> if none)
554: */
555: public QName getFormatQName() {
556: return m_stringAttrs.getFormatQName();
557: }
558:
559: /**
560: * Set format qualified name. This method changes the label value to match
561: * the qualified name.
562: *
563: * @return format qualified name (<code>null</code> if none)
564: */
565: public void setFormatQName(QName qname) {
566: m_stringAttrs.setFormatQName(qname);
567: }
568:
569: /**
570: * Get serializer name.
571: *
572: * @return fully qualified class and method name for serializer (or
573: * <code>null</code> if none)
574: */
575: public String getSerializerName() {
576: return m_stringAttrs.getSerializerName();
577: }
578:
579: /**
580: * Get serializer method information. This call is only meaningful after
581: * validation.
582: *
583: * @return serializer information (or <code>null</code> if none)
584: */
585: public IClassItem getSerializer() {
586: return m_stringAttrs.getSerializer();
587: }
588:
589: /**
590: * Set serializer method name.
591: *
592: * @param fully qualified class and method name for serializer
593: */
594: public void setSerializerName(String name) {
595: m_stringAttrs.setSerializerName(name);
596: }
597:
598: /**
599: * Get deserializer name.
600: *
601: * @return fully qualified class and method name for deserializer (or
602: * <code>null</code> if none)
603: */
604: public String getDeserializerName() {
605: return m_stringAttrs.getDeserializerName();
606: }
607:
608: /**
609: * Get deserializer method information. This call is only meaningful after
610: * validation.
611: *
612: * @return deserializer information (or <code>null</code> if none)
613: */
614: public IClassItem getDeserializer() {
615: return m_stringAttrs.getDeserializer();
616: }
617:
618: /**
619: * Set deserializer method name.
620: *
621: * @param fully qualified class and method name for deserializer
622: */
623: public void setDeserializerName(String name) {
624: m_stringAttrs.setDeserializerName(name);
625: }
626:
627: //
628: // IComponent implementation methods (also delegated name methods)
629:
630: /* (non-Javadoc)
631: * @see org.jibx.binding.model.IComponent#hasAttribute()
632: */
633: public boolean hasAttribute() {
634: return m_styleIndex == NestingAttributes.ATTRIBUTE_STYLE;
635: }
636:
637: /* (non-Javadoc)
638: * @see org.jibx.binding.model.IComponent#hasContent()
639: */
640: public boolean hasContent() {
641: return m_styleIndex != NestingAttributes.ATTRIBUTE_STYLE;
642: }
643:
644: /* (non-Javadoc)
645: * @see org.jibx.binding.model.IComponent#isOptional()
646: */
647: public boolean isOptional() {
648: return m_propertyAttrs.getUsage() == PropertyAttributes.OPTIONAL_USAGE;
649: }
650:
651: /* (non-Javadoc)
652: * @see org.jibx.binding.model.IComponent#hasName()
653: */
654: public boolean hasName() {
655: return m_nameAttrs.getName() != null;
656: }
657:
658: /* (non-Javadoc)
659: * @see org.jibx.binding.model.IComponent#getType()
660: */
661: public IClass getType() {
662: return m_propertyAttrs.getType();
663: }
664:
665: //
666: // Validation methods
667:
668: /**
669: * Make sure all attributes are defined.
670: *
671: * @param uctx unmarshalling context
672: * @exception JiBXException on unmarshalling error
673: */
674: private void preSet(IUnmarshallingContext uctx)
675: throws JiBXException {
676: validateAttributes(uctx, s_allowedAttributes);
677: }
678:
679: /* (non-Javadoc)
680: * @see org.jibx.binding.model.ElementBase#prevalidate(org.jibx.binding.model.ValidationContext)
681: */
682: public void prevalidate(ValidationContext vctx) {
683:
684: // set the style value
685: if (m_styleName != null) {
686: m_styleIndex = s_styleEnum.getValue(m_styleName);
687: if (m_styleIndex < 0) {
688: vctx.addError("Value \"" + m_styleName
689: + "\" is not a valid choice for style");
690: }
691: } else {
692: m_styleIndex = vctx.getParentElement().getDefaultStyle();
693: }
694:
695: // validate ID classification
696: m_identIndex = s_identEnum.getValue(m_identName);
697: if (m_identIndex < 0) {
698: vctx.addError("Value \"" + m_identName
699: + " is not a valid choice for ident");
700: }
701:
702: // validate basic attribute groups
703: m_propertyAttrs.prevalidate(vctx);
704: m_nameAttrs
705: .setIsAttribute(m_styleIndex == NestingAttributes.ATTRIBUTE_STYLE);
706: m_nameAttrs.prevalidate(vctx);
707: if (m_styleIndex == CDATA_STYLE || m_styleIndex == TEXT_STYLE) {
708: if (m_nameAttrs.getName() != null) {
709: vctx
710: .addFatal("Values with \"text\" or \"cdata\" style "
711: + "cannot have names");
712: }
713: } else {
714: if (m_nameAttrs.getName() == null) {
715: vctx
716: .addFatal("Missing required name for element or attribute value");
717: }
718: }
719:
720: // make sure value is not constant
721: if (m_constantValue == null) {
722:
723: // make sure nillable only for optional element with object
724: if (m_isNillable) {
725: if (m_styleIndex != NestingAttributes.ELEMENT_STYLE) {
726: vctx
727: .addFatal("nillable can only be used with element style");
728: }
729: }
730:
731: // process ID classification
732: if (m_identIndex == DEF_IDENT/* || m_identIndex == AUTO_IDENT*/) {
733: boolean valid = false;
734: IClass gclas = m_propertyAttrs.getGetType();
735: if (gclas != null) {
736: String gtype = gclas.getName();
737: if (gtype.equals("java.lang.String")) {
738: vctx.getContextObject().setIdChild(this , vctx);
739: valid = true;
740: }
741: }
742: if (!valid) {
743: vctx.addError("ID property must supply a "
744: + "java.lang.String value");
745: }
746: }
747:
748: // check string attributes only if valid to this point
749: if (!vctx.isSkipped(this )) {
750:
751: // handle string attributes based on identity type
752: if (m_identIndex == REF_IDENT) {
753: if (m_propertyAttrs.isImplicit()) {
754: vctx
755: .addFatal("No property value - ID reference can only "
756: + "be used with a property of the appropriate type");
757: }
758: if (m_stringAttrs.getDeserializerName() != null
759: || m_stringAttrs.getSerializerName() != null
760: || m_stringAttrs.getFormatName() != null
761: || m_stringAttrs.getDefaultText() != null) {
762: vctx
763: .addWarning("String attributes serializer, "
764: + "deserializer, format, and default are "
765: + "prohibited with ID references");
766: }
767: } else {
768: m_stringAttrs.setType(m_propertyAttrs.getType());
769: m_stringAttrs.prevalidate(vctx);
770: }
771: super .prevalidate(vctx);
772: }
773:
774: } else {
775:
776: // check prohibited attributes with constant value
777: if (m_identIndex != NONE_IDENT) {
778: vctx
779: .addFatal("ident value must be \"none\" for constant");
780: } else if (m_propertyAttrs.hasProperty()
781: || m_propertyAttrs.getDeclaredType() != null) {
782: vctx
783: .addFatal("Property attributes cannot be used with constant");
784: } else if (m_stringAttrs.getDefaultText() != null
785: || m_stringAttrs.getDeserializerName() != null
786: || m_stringAttrs.getSerializerName() != null
787: || m_stringAttrs.getFormatName() != null) {
788: vctx
789: .addFatal("String attributes cannot be used with constant");
790: } else if (m_isNillable) {
791: vctx.addFatal("nillable cannot be used with constant");
792: }
793: }
794: }
795:
796: /* (non-Javadoc)
797: * @see org.jibx.binding.model.ElementBase#validate(org.jibx.binding.model.ValidationContext)
798: */
799: public void validate(ValidationContext vctx) {
800:
801: // validate basic attributes
802: m_nameAttrs.validate(vctx);
803: m_propertyAttrs.validate(vctx);
804: if (!vctx.isSkipped(this )) {
805:
806: // check identity references for compatible objects
807: if (m_identIndex == REF_IDENT) {
808: String type = m_propertyAttrs.getType().getName();
809: if (!vctx.getBindingRoot().isIdClass(type)) {
810: vctx
811: .addError("No ID definitions for compatible type");
812: }
813: }
814: super.validate(vctx);
815: }
816: }
817: }
|