001: /*
002: Copyright (c) 2004-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.model;
030:
031: import org.jibx.binding.util.StringArray;
032:
033: /**
034: * Model component for <i>object</i> attribute group in binding definition.
035: * TODO: Add "create" attribute to say whether object should be created or not
036: *
037: * @author Dennis M. Sosnoski
038: * @version 1.0
039: */
040:
041: public class ObjectAttributes extends AttributeBase {
042: /** Enumeration of allowed attribute names */
043: public static final StringArray s_allowedAttributes = new StringArray(
044: new String[] { "create-type", "factory", "marshaller",
045: "nillable", "post-set", "pre-get", "pre-set",
046: "unmarshaller" });
047:
048: //
049: // Constants and such related to code generation.
050:
051: // recognized marshal hook method (pre-get) signatures.
052: private static final String[] MARSHAL_HOOK_SIGNATURES = {
053: "(Lorg/jibx/runtime/IMarshallingContext;)V",
054: "(Ljava/lang/Object;)V", "()V" };
055:
056: // recognized factory hook method signatures.
057: private static final String[] FACTORY_HOOK_SIGNATURES = {
058: "(Lorg/jibx/runtime/IUnmarshallingContext;)",
059: "(Ljava/lang/Object;)", "()" };
060:
061: // recognized unmarshal hook method (pre-set, post-set) signatures.
062: private static final String[] UNMARSHAL_HOOK_SIGNATURES = {
063: "(Lorg/jibx/runtime/IUnmarshallingContext;)V",
064: "(Ljava/lang/Object;)V", "()V" };
065:
066: // marshaller/unmarshaller definitions
067: private static final String UNMARSHALLER_INTERFACE = "org.jibx.runtime.IUnmarshaller";
068: private static final String MARSHALLER_INTERFACE = "org.jibx.runtime.IMarshaller";
069: private static final String UNMARSHALLER_INTERFACETYPE = "Lorg/jibx/runtime/IUnmarshaller;";
070: private static final String MARSHALLER_INTERFACETYPE = "Lorg/jibx/runtime/IMarshaller;";
071:
072: //
073: // Instance data.
074:
075: /** Factory method name (fully qualified, including package and class). */
076: private String m_factoryName;
077:
078: /** Pre-set method name. */
079: private String m_preSetName;
080:
081: /** Post-set method name. */
082: private String m_postSetName;
083:
084: /** Pre-get method name. */
085: private String m_preGetName;
086:
087: /** Object marshaller class name. */
088: private String m_marshallerName;
089:
090: /** Object unmarshaller class name. */
091: private String m_unmarshallerName;
092:
093: /** Nillable object flag. */
094: private boolean m_isNillable;
095:
096: /** Instance type for creation (fully qualified, including package and
097: class). */
098: private String m_createType;
099:
100: /** Factory method information. */
101: private IClassItem m_factoryItem;
102:
103: /** Pre-set method information. */
104: private IClassItem m_preSetItem;
105:
106: /** Post-set method information. */
107: private IClassItem m_postSetItem;
108:
109: /** Pre-get method information. */
110: private IClassItem m_preGetItem;
111:
112: /** Object marshaller class. */
113: private IClass m_marshallerClass;
114:
115: /** Object unmarshaller class. */
116: private IClass m_unmarshallerClass;
117:
118: /** Class to use for new instance creation. */
119: private IClass m_createClass;
120:
121: /**
122: * Constructor.
123: *
124: * @param element owning element
125: */
126: public ObjectAttributes() {
127: }
128:
129: /**
130: * Get factory method name.
131: *
132: * @return fully-qualified factory class and method name (or
133: * <code>null</code> if none)
134: */
135: public String getFactoryName() {
136: return m_factoryName;
137: }
138:
139: /**
140: * Get factory method information. This method is only usable after a
141: * call to {@link #validate}.
142: *
143: * @return factory method information (or <code>null</code> if none)
144: */
145: public IClassItem getFactory() {
146: return m_factoryItem;
147: }
148:
149: /**
150: * Set factory method name.
151: *
152: * @param name fully qualified class and method name for object factory
153: */
154: public void setFactoryName(String name) {
155: m_factoryName = name;
156: }
157:
158: /**
159: * Get pre-set method name.
160: *
161: * @return pre-set method name (or <code>null</code> if none)
162: */
163: public String getPresetName() {
164: return m_preSetName;
165: }
166:
167: /**
168: * Get pre-set method information. This method is only usable after a
169: * call to {@link #validate}.
170: *
171: * @return pre-set method information (or <code>null</code> if none)
172: */
173: public IClassItem getPreset() {
174: return m_preSetItem;
175: }
176:
177: /**
178: * Set pre-set method name.
179: *
180: * @param name member method name to be called before unmarshalling
181: */
182: public void setPresetName(String name) {
183: m_preSetName = name;
184: }
185:
186: /**
187: * Get post-set method name.
188: *
189: * @return post-set method name (or <code>null</code> if none)
190: */
191: public String getPostsetName() {
192: return m_postSetName;
193: }
194:
195: /**
196: * Get post-set method information. This method is only usable after a
197: * call to {@link #validate}.
198: *
199: * @return post-set method information (or <code>null</code> if none)
200: */
201: public IClassItem getPostset() {
202: return m_postSetItem;
203: }
204:
205: /**
206: * Set post-set method name.
207: *
208: * @param name member method name to be called after unmarshalling
209: */
210: public void setPostsetName(String name) {
211: m_postSetName = name;
212: }
213:
214: /**
215: * Get pre-get method name.
216: *
217: * @return pre-get method name (or <code>null</code> if none)
218: */
219: public String getPregetName() {
220: return m_preGetName;
221: }
222:
223: /**
224: * Get pre-get method information. This method is only usable after a
225: * call to {@link #validate}.
226: *
227: * @return pre-get method information (or <code>null</code> if none)
228: */
229: public IClassItem getPreget() {
230: return m_preGetItem;
231: }
232:
233: /**
234: * Set pre-get method name.
235: *
236: * @param name member method name to be called before marshalling
237: */
238: public void setPreget(String name) {
239: m_preGetName = name;
240: }
241:
242: /**
243: * Get marshaller class name.
244: *
245: * @return marshaller class name (or <code>null</code> if none)
246: */
247: public String getMarshallerName() {
248: return m_marshallerName;
249: }
250:
251: /**
252: * Get marshaller class information. This method is only usable after a
253: * call to {@link #validate}.
254: *
255: * @return class information for marshaller (or <code>null</code> if none)
256: */
257: public IClass getMarshaller() {
258: return m_marshallerClass;
259: }
260:
261: /**
262: * Set marshaller class name.
263: *
264: * @param name class name to be used for marshalling
265: */
266: public void setMarshallerName(String name) {
267: m_marshallerName = name;
268: }
269:
270: /**
271: * Get unmarshaller class name.
272: *
273: * @return unmarshaller class name (or <code>null</code> if none)
274: */
275: public String getUnmarshallerName() {
276: return m_unmarshallerName;
277: }
278:
279: /**
280: * Get unmarshaller class information. This method is only usable after a
281: * call to {@link #validate}.
282: *
283: * @return class information for unmarshaller (or <code>null</code> if none)
284: */
285: public IClass getUnmarshaller() {
286: return m_unmarshallerClass;
287: }
288:
289: /**
290: * Set unmarshaller class name.
291: *
292: * @param name class name to be used for unmarshalling
293: */
294: public void setUnmarshallerName(String name) {
295: m_unmarshallerName = name;
296: }
297:
298: /**
299: * Check if nillable object.
300: *
301: * @return nillable flag
302: */
303: public boolean isNillable() {
304: return m_isNillable;
305: }
306:
307: /**
308: * Set nillable flag.
309: *
310: * @param nillable flag
311: */
312: public void setNillable(boolean nillable) {
313: m_isNillable = nillable;
314: }
315:
316: /**
317: * Get type to be used for creating new instance.
318: *
319: * @return class name for type to be created (or <code>null</code> if none)
320: */
321: public String getCreateType() {
322: return m_createType;
323: }
324:
325: /**
326: * Get new instance creation class information. This method is only usable
327: * after a call to {@link #validate}.
328: *
329: * @return class information for type to be created (or <code>null</code> if
330: * none)
331: */
332: public IClass getCreateClass() {
333: return m_createClass;
334: }
335:
336: /**
337: * Set new instance type class name.
338: *
339: * @param name class name to be used for creating new instance
340: */
341: public void setCreateType(String name) {
342: m_createType = name;
343: }
344:
345: /* (non-Javadoc)
346: * @see org.jibx.binding.model.AttributeBase#prevalidate(org.jibx.binding.model.ValidationContext)
347: */
348: public void prevalidate(ValidationContext vctx) {
349:
350: // first check for actual object association
351: IClass iclas;
352: ElementBase element = vctx.getParentElement(0);
353: if (element instanceof StructureElementBase) {
354: if (!((StructureElementBase) element).hasObject()) {
355: if (m_factoryName != null) {
356: vctx
357: .addWarning("No object for structure; factory attribute ignored");
358: m_factoryName = null;
359: }
360: if (m_preSetName != null) {
361: vctx
362: .addWarning("No object for structure; pre-set attribute ignored");
363: m_preSetName = null;
364: }
365: if (m_preGetName != null) {
366: vctx
367: .addWarning("No object for structure; pre-get attribute ignored");
368: m_preGetName = null;
369: }
370: if (m_postSetName != null) {
371: vctx
372: .addWarning("No object for structure; post-set attribute ignored");
373: m_postSetName = null;
374: }
375: if (m_marshallerName != null) {
376: vctx
377: .addWarning("No object for structure; marshaller attribute ignored");
378: m_marshallerName = null;
379: }
380: if (m_unmarshallerName != null) {
381: vctx
382: .addWarning("No object for structure; unmarshaller attribute ignored");
383: m_unmarshallerName = null;
384: }
385: if (m_createType != null) {
386: vctx
387: .addWarning("No object for structure; create-type attribute ignored");
388: m_createType = null;
389: }
390: if (m_isNillable) {
391: vctx
392: .addError("No object for structure; nillable attribute forbidden");
393: m_isNillable = false;
394: }
395: return;
396: } else {
397: iclas = ((StructureElementBase) element).getType();
398: }
399: } else if (element instanceof MappingElement) {
400: iclas = ((MappingElement) element).getHandledClass();
401: } else {
402: throw new IllegalStateException(
403: "Unknown element for object attributes");
404: }
405: String type = iclas.getName();
406:
407: // first check for marshaller and unmarshaller classes
408: if (m_marshallerName != null) {
409: if (vctx.isOutBinding()) {
410: IClass mclas = vctx.getClassInfo(m_marshallerName);
411: if (mclas == null) {
412: vctx.addError("Marshaller class "
413: + m_marshallerName + " not found");
414: } else if (!mclas
415: .isImplements(MARSHALLER_INTERFACETYPE)) {
416: vctx.addError("Marshaller class "
417: + m_marshallerName
418: + " does not implement interface "
419: + MARSHALLER_INTERFACE);
420: } else {
421: m_marshallerClass = mclas;
422: }
423: } else {
424: vctx
425: .addWarning("marshaller attribute ignored for input-only binding");
426: }
427: }
428: if (m_unmarshallerName != null) {
429: if (vctx.isInBinding()) {
430:
431: // get the unmarshaller information
432: IClass uclas = vctx.getClassInfo(m_unmarshallerName);
433: if (uclas == null) {
434: vctx.addError("Unmarshaller class "
435: + m_unmarshallerName + " not found");
436: } else if (!uclas
437: .isImplements(UNMARSHALLER_INTERFACETYPE)) {
438: vctx.addError("Unmarshaller class "
439: + m_unmarshallerName
440: + " does not implement interface "
441: + UNMARSHALLER_INTERFACE);
442: } else {
443: m_unmarshallerClass = uclas;
444: }
445:
446: // check for incompatible attributes
447: if (m_factoryName != null) {
448: vctx
449: .addWarning("unmarshaller supplied, factory attribute ignored");
450: m_factoryName = null;
451: }
452: if (m_createType != null) {
453: vctx
454: .addWarning("unmarshaller supplied, create-type attribute ignored");
455: m_createType = null;
456: }
457: } else {
458: vctx
459: .addWarning("unmarshaller attribute ignored for output-only binding");
460: }
461: }
462:
463: // make sure both are supplied if either is supplied
464: if (vctx.isInBinding() && vctx.isOutBinding()) {
465: if (m_unmarshallerName != null && m_marshallerName == null) {
466: vctx
467: .addError("Marshaller is required if unmarshaller is supplied");
468: } else if (m_marshallerName != null
469: && m_unmarshallerName == null) {
470: vctx
471: .addError("Unmarshaller is required if marshaller is supplied");
472: }
473: }
474:
475: // next check for factory supplied
476: if (m_factoryName != null) {
477: if (vctx.isInBinding()) {
478:
479: // find factory method and verify signature
480: m_factoryItem = ClassUtils.findStaticMethod(
481: m_factoryName, FACTORY_HOOK_SIGNATURES, vctx);
482: if (m_factoryItem == null) {
483: vctx.addError("Static factory method "
484: + m_factoryName + " not found");
485: } else {
486: String ftype = m_factoryItem.getTypeName();
487: if (!ClassUtils.isAssignable(ftype, type, vctx)
488: && !ClassUtils.isAssignable(type, ftype,
489: vctx))
490: vctx
491: .addError("Static factory method "
492: + m_factoryName
493: + " return type is not compatible with "
494: + type);
495: }
496:
497: // check for incompatible attributes
498: if (m_createType != null) {
499: vctx
500: .addWarning("unmarshaller supplied, create-type attribute ignored");
501: m_createType = null;
502: }
503:
504: } else {
505: vctx
506: .addWarning("factory attribute ignored for output-only binding");
507: }
508: }
509:
510: // check for create-type attribute
511: if (m_createType != null) {
512: if (vctx.isInBinding()) {
513:
514: // find create type class and verify compatibility
515: m_createClass = vctx.getClassInfo(m_createType);
516: if (m_createClass == null) {
517: vctx.addError("create-type class " + m_createType
518: + " not found");
519: } else {
520: if (!ClassUtils.isAssignable(m_createType, type,
521: vctx)
522: && !ClassUtils.isAssignable(type,
523: m_createType, vctx))
524: vctx
525: .addError("create-type "
526: + m_createType
527: + " is not compatible with expected type "
528: + type);
529: }
530:
531: } else {
532: vctx
533: .addWarning("create-type attribute ignored for output-only binding");
534: }
535: }
536:
537: // handle pre-set, post-set, and pre-get methods
538: if (vctx.isInBinding()) {
539: if (m_preSetName != null) {
540: m_preSetItem = iclas.getMethod(m_preSetName,
541: UNMARSHAL_HOOK_SIGNATURES);
542: if (m_preSetItem == null) {
543: vctx.addError("Nonstatic pre-set method "
544: + m_preSetName + " not found");
545: }
546: }
547: if (m_postSetName != null) {
548: m_postSetItem = iclas.getMethod(m_postSetName,
549: UNMARSHAL_HOOK_SIGNATURES);
550: if (m_postSetItem == null) {
551: vctx.addError("Nonstatic post-set method "
552: + m_postSetName + " not found");
553: }
554: }
555: }
556: if (vctx.isOutBinding()) {
557: if (m_preGetName != null) {
558: m_preGetItem = iclas.getMethod(m_preGetName,
559: MARSHAL_HOOK_SIGNATURES);
560: if (m_preGetItem == null) {
561: vctx.addError("Nonstatic pre-get method "
562: + m_preGetName + " not found");
563: }
564: }
565: }
566: }
567: }
|