View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * This file was originally developed by Keith Visco during the course
44   * of employment at Intalio Inc.
45   * Portions of this file developed by Keith Visco after Jan 19 2005 are
46   * Copyright (C) 2005 Keith Visco. All Rights Reserverd.
47   *
48   * $Id$
49   */
50  package org.exolab.castor.builder.info;
51  
52  import java.util.HashMap;
53  import java.util.HashSet;
54  import java.util.LinkedList;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.Set;
58  
59  import org.castor.core.nature.PropertyHolder;
60  import org.exolab.castor.builder.factory.FieldMemberAndAccessorFactory;
61  import org.exolab.castor.builder.info.nature.XMLInfoNature;
62  import org.exolab.castor.builder.types.XSType;
63  import org.exolab.javasource.JType;
64  
65  /**
66   * A class for representing field members of a class. FieldInfo objects hold all
67   * the information required about a member in order to be able to produce
68   * XML data binding (marshal/unmarshal) and validation code.
69   *
70   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
71   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
72   */
73  public class FieldInfo implements XMLInfo, PropertyHolder {
74      /**
75       * Map holding the properties set and read by Natures.
76       */
77      private Map<String, Object> _properties = new HashMap<String, Object>();
78      
79      /**
80       * Set holding applicable natures.
81       */
82      private Set<String> _natures = new HashSet<String>();
83      
84      /** The Read / Getter method flag. */
85      public static final int READ_METHOD              = 1;
86      /** The Write / Setter method flag. */
87      public static final int WRITE_METHOD             = 2;
88      /** The Read and Write methods flags. */
89      public static final int READ_WRITE_METHODS       = 3;
90  
91      /** Method prefixes for "Add" methods. */
92      protected static final String METHOD_PREFIX_ADD    = "add";
93      /** Method prefixes for "Delete" methods. */
94      protected static final String METHOD_PREFIX_DELETE = "delete";
95      /** Method prefixes for "Get" methods. */
96      protected static final String METHOD_PREFIX_GET    = "get";
97      /** Method prefixes for "Has" methods. */
98      protected static final String METHOD_PREFIX_HAS    = "has";
99      /** Method prefixes for "Set" methods. */
100     protected static final String METHOD_PREFIX_SET    = "set";
101     /** Method prefixes for "Is" methods. */
102     protected static final String METHOD_PREFIX_IS     = "is";
103 
104     /** The Java name for Members described by this FieldInfo. */
105     private String _name       = null;
106 
107     /**
108      * {@link ClassInfo} instance which 'own' (declares) this
109      * {@link FieldInfo}.
110      */
111     private ClassInfo _declaringClassInfo = null;
112     
113     /** JavaDoc comment. */
114     private String _comment    = null;
115 
116     /** The default value for this FieldInfo. */
117     private String _default    = null;
118     /** The fixed production for this FieldInfo. */
119     private String _fixed      = null;
120     /** A flag to indicate a final member. */
121     private boolean _final     = false;
122     /** The methods flags, indicates which methods to create. */
123     private int _methods = READ_WRITE_METHODS;
124     /** A reference to the FieldInfo instance within the same class. */
125     private FieldInfo _fieldInfoReference = null;
126     /** A flag to indicate a static member. */
127     private boolean _static    = false;
128     /** Flags whether or not the a MarshalDescriptor should be created for this FieldInfo. */
129     private boolean _transient = false;
130     /** A flag to indicate a bound property. */
131     private boolean _bound = false;
132     /** A flag to indicate a container field. */
133     private boolean _isContainer = false;
134     /**
135      * The fully qualified name of the XMLFieldHandler (if any)
136      * to use in the generated descriptor.
137      */
138     private String _fieldHandler;
139     /** A boolean to indicate that this field represents a "nillable" field. */
140     private boolean _nillable = false;
141     /** The fully qualified name of the Validator (if any) to use in the generated descriptor. */
142     private String _validator;
143     /** Visibility of this FieldInfo. */
144     private String _visibility = "private";
145     
146     /** 
147      * Factory responsible for creating a {@link JField} out of a 
148      * {@link FieldInfo}.
149      */
150     private FieldMemberAndAccessorFactory _memberAndAccessorFactory;
151     
152     /**
153      * Holds the possible substitution groups for this class.
154      */
155     private List<String> _substitutionGroupMembers = new LinkedList<String>();
156 
157     /**
158      * Creates a new FieldInfo with the given XML Schema type and the given
159      * member name. Adds the {@link XMLInfoNature} for legacy compliance.
160      *
161      * @param type
162      *            the XML Schema type of this member
163      * @param name
164      *            the name of the member
165      * @param memberAndAccessorFactory 
166      *            the FieldMemberAndAccessorFactory to be used
167      */
168     public FieldInfo(final XSType type, final String name, 
169             final FieldMemberAndAccessorFactory memberAndAccessorFactory) {
170         this._name    = name;
171         this._memberAndAccessorFactory = memberAndAccessorFactory;
172         this.addNature(XMLInfoNature.class.getName());
173         XMLInfoNature xmlNature = new XMLInfoNature(this);
174         xmlNature.setSchemaType(type);
175     } //-- FieldInfo
176 
177 
178     /**
179      * Returns the FieldMemberAndAccessorFactory instance to use to create 
180      * a JField out of this FieldInfo.
181      * @return the suitable FieldMemberAndAccessorFactory
182      */
183     public FieldMemberAndAccessorFactory getMemberAndAccessorFactory() {
184         return _memberAndAccessorFactory;
185     }
186 
187     /**
188      * Returns the default value for this FieldInfo.
189      *
190      * @return the default value for this FieldInfo, or null if no default value
191      *         was set;
192      */
193     public final String getDefaultValue() {
194         return _default;
195     }
196 
197     /**
198      * Returns the fixed production for this FieldInfo, or null if no fixed
199      * value has been specified.
200      * <p>
201      * NOTE: Fixed values are NOT the same as default values
202      *
203      * @return the fixed value for this FieldInfo
204      */
205     public final String getFixedValue() {
206         return _fixed;
207     }
208 
209     /**
210      * Returns the name of the delete method for this FieldInfo.
211      * @return the name of the delete method for this FieldInfo.
212      */
213     public final String getDeleteMethodName() {
214         return METHOD_PREFIX_DELETE + getMethodSuffix();
215     } //-- getDeleteMethodName
216 
217     /**
218      * Returns the name of the has method for this FieldInfo.
219      * @return the name of the has method for this FieldInfo.
220      */
221     public final String getHasMethodName() {
222         return METHOD_PREFIX_HAS + getMethodSuffix();
223     } //-- getHasMethodName
224 
225     /**
226      * Returns the name of the read method for this FieldInfo.
227      * @return the name of the read method for this FieldInfo.
228      */
229     public final String getReadMethodName() {
230         return METHOD_PREFIX_GET + getMethodSuffix();
231     } //-- getReadMethodName
232 
233    /**
234     * Returns the fully qualified name of the Validator to use.
235     *
236     * @return the fully qualified name of the Validator to use.
237     */
238     public final String getValidator() {
239         return _validator;
240     }
241 
242     /**
243      * Returns the name of the write method for this FieldInfo.
244      * @return the name of the write method for this FieldInfo.
245      */
246     public final String getWriteMethodName() {
247         if (new XMLInfoNature(this).isMultivalued()) {
248             return METHOD_PREFIX_ADD + getMethodSuffix();
249         }
250         return METHOD_PREFIX_SET + getMethodSuffix();
251     } //-- getWriteMethodName
252     
253     /**
254      * Get the 'is' method for this FieldInfo. 
255      * 
256      * @return the name of the 'is' method for this FieldInfo
257      */
258     public final String getIsMethodName() {
259         return METHOD_PREFIX_IS + getMethodSuffix();
260     }
261 
262    /**
263     * Returns the fully qualified name of the XMLFieldHandler to use.
264     *
265     * @return the fully qualified name of the XMLFieldHandler to use.
266     */
267     public final String getXMLFieldHandler() {
268         return _fieldHandler;
269     }
270 
271     /**
272      * Returns the comment associated with this Member.
273      *
274      * @return the comment associated with this Member, or null.
275      * if one has not been set.
276      */
277     public final String getComment() {
278         return _comment;
279     } //-- getComment
280 
281     /**
282      * Returns the methods flag that indicates which.
283      *
284      * methods will be created.
285      *
286      * @return the methods flag
287      */
288     public final int getMethods() {
289         return _methods;
290     } //-- getMethods
291 
292     /**
293      * Returns the name of this FieldInfo.
294      *
295      * @return the name of this FieldInfo.
296      */
297     public final String getName() {
298         return this._name;
299     } //-- getName
300 
301     /**
302      * Returns true if this FieldInfo represents a bound property.
303      *
304      * @return true if this FieldInfo represents a bound property.
305      */
306     public final boolean isBound() {
307         return _bound;
308     } //-- isBound
309 
310     /**
311      * Returns true if this FieldInfo describes a container class. A container
312      * class is a class which should not be marshalled as XML, but whose members
313      * should be.
314      *
315      * @return true if this ClassInfo describes a container class.
316      */
317     public final boolean isContainer() {
318         return _isContainer;
319     } //-- isContainer
320 
321     /**
322      * Returns true if the "has" and "delete" methods are needed for the field
323      * associated with this FieldInfo.
324      *
325      * @return true if the has and delete methods are needed.
326      */
327     public final boolean requiresHasAndDeleteMethods() {
328         XSType xsType = new XMLInfoNature(this).getSchemaType();
329         JType jType  = xsType.getJType();
330         return ((!xsType.isEnumerated()) && jType.isPrimitive());
331     } //-- requiresHasAndDeleteMethods
332 
333     /**
334      * Returns true if this field represents a nillable field. A nillable field
335      * is a field that can have null content (see XML Schema 1.0 definition of
336      * nillable).
337      *
338      * @return true if nillable, otherwise false.
339      * @see #setNillable(boolean)
340      */
341      public final boolean isNillable() {
342          return _nillable;
343      } //-- isNillable
344 
345     /**
346      * Returns true if this FieldInfo is a transient member. Transient members
347      * are members which should be ignored by the Marshalling framework.
348      *
349      * @return true if this FieldInfo is transient.
350      */
351     public final boolean isTransient() {
352         return (_transient || _final || _static);
353     } //-- isTransient
354 
355     /**
356      * Sets the comment for this Member.
357      * @param comment the comment or description for this Member
358      */
359     public final void setComment(final String comment) {
360         _comment = comment;
361     } //-- setComment
362 
363     /**
364      * Returns the ClassInfo to which this Member was declared, for inheritance reasons.
365      * @return the ClassInfo to which this Member was declared.
366      */
367     public final ClassInfo getDeclaringClassInfo() {
368         return this._declaringClassInfo;
369     } //-- getDeclaringClassInfo
370 
371     /**
372      * Sets whether or not this FieldInfo represents a bound property.
373      *
374      * @param bound the flag when true indicates that this FieldInfo represents a
375      *        bound property.
376      */
377     public final void setBound(final boolean bound) {
378         _bound = bound;
379     } //-- setBound
380 
381     /**
382      * Sets whether or not this FieldInfo describes a container field. A
383      * container field is a field which should not be marshalled directly as
384      * XML, but whose members should be. By default this is false.
385      *
386      * @param isContainer
387      *            the boolean value when true indicates this class should be a
388      *            container class.
389      */
390     public final void setContainer(final boolean isContainer) {
391         _isContainer = isContainer;
392     } //-- setContainer
393 
394     /**
395      * Sets the {@link ClassInfo} of the class that declares this field.
396      * @param declaringClassInfo The {@link ClassInfo} of the declaring class.
397      */
398     public final void setDeclaringClassInfo(final ClassInfo declaringClassInfo) {
399         this._declaringClassInfo = declaringClassInfo;
400     }
401 
402     /**
403      * Sets the default value for this FieldInfo.
404      * @param defaultValue the default value
405      */
406     public final void setDefaultValue(final String defaultValue) {
407         this._default = defaultValue;
408     }
409 
410     /**
411      * Sets the "final" status of this FieldInfo. Final members are also
412      * transient.
413      *
414      * @param isFinal
415      *            the boolean indicating the final status, if true this
416      *            FieldInfo will be treated as final.
417      */
418     public final void setFinal(final boolean isFinal) {
419         this._final = isFinal;
420     } //-- isFinal
421 
422     /**
423      * Sets the fixed value in which instances of this field type must lexically
424      * match. NOTE: This is not the same as default value!
425      *
426      * @param fixedValue
427      *            the fixed production for this FieldInfo
428      */
429     public final void setFixedValue(final String fixedValue) {
430         this._fixed = fixedValue;
431     } //-- setFixedValue
432 
433     /**
434      * Sets which methods to create: READ_METHOD, WRITE_METHOD,
435      * READ_WRITE_METHODS.
436      *
437      * @param methods a flag describing which methods to create.
438      */
439     public final void setMethods(final int methods) {
440         _methods = methods;
441     } //-- setMethods
442 
443     /**
444      * Sets whether or not this field can be nillable.
445      *
446      * @param nillable
447      *            a boolean that when true means the field may be nil.
448      * @see #isNillable()
449      */
450     public final void setNillable(final boolean nillable) {
451         _nillable = nillable;
452     } //-- setNillable
453 
454     /**
455      * Sets the name of the field within the same class that is a reference to
456      * this field.
457      *
458      * @param fieldInfo {@link FieldInfo} for the referencing field (within the same class).
459      */
460     public final void setFieldInfoReference(final FieldInfo fieldInfo) {
461         _fieldInfoReference = fieldInfo;
462     }
463 
464     /**
465      * Sets the "static" status of this FieldInfo. Static members are also
466      * transient.
467      *
468      * @param isStatic the boolean indicating the static status, if true this
469      *        FieldInfo will be treated as static
470      */
471     public final void setStatic(final boolean isStatic) {
472         this._static = isStatic;
473     } //-- setStatic
474 
475     /**
476      * Sets the transient status of this FieldInfo.
477      *
478      * @param isTransient the boolean indicating the transient status, if true this
479      *        FieldInfo will be treated as transient
480      */
481     public final void setTransient(final boolean isTransient) {
482         this._transient = isTransient;
483     } //-- setTransient
484 
485     /**
486      * Sets the name of the Validator to use.
487      *
488      * @param validator the fully qualified name of the validator to use.
489      */
490     public final void setValidator(final String validator) {
491         _validator = validator;
492     }
493 
494     /**
495      * Sets the name of the XMLfieldHandler to use.
496      *
497      * @param handler the fully qualified name of the handler to use.
498      */
499     public final void setXMLFieldHandler(final String handler) {
500         _fieldHandler = handler;
501     }
502 
503     /**
504      * Returns the method suffix for creating method names.
505      *
506      * @return the method suffix used when creating method names.
507      */
508     public String getMethodSuffix() {
509         if (_name.startsWith("_")) {
510             return _memberAndAccessorFactory.getJavaNaming().toJavaClassName(_name.substring(1));
511         }
512         return _memberAndAccessorFactory.getJavaNaming().toJavaClassName(_name);
513     }
514 
515     /**
516      * Sets the visibility of this FieldInfo.
517      *
518      * @param visibility the visibility of this FieldInfo.
519      */
520     public final void setVisibility(final String visibility) {
521         _visibility = visibility;
522     }
523 
524     /**
525      * Sets the possible substitution groups for this class.
526      * @param substitutionGroupMembers Possible substitution groups for this class.
527      */
528     public void setSubstitutionGroupMembers(final List<String> substitutionGroupMembers) {
529         this._substitutionGroupMembers = substitutionGroupMembers;
530     }
531 
532     /**
533      * Returns the possible substitution groups for this class.
534      * @return the possible substitution groups for this class.
535      */
536     public List<String> getSubstitutionGroupMembers() {
537         return this._substitutionGroupMembers;
538     }
539     
540     /**
541      * Indicates whether this field is static.
542      * @return True if this field is static.
543      */
544     public boolean isStatic() {
545         return _static;
546     }
547 
548     /**
549      * Indicates whether this field is final.
550      * @return True if this field is final.
551      */
552     public boolean isFinal() {
553         return _final;
554     }
555 
556     /**
557      * Returns this field's 'visibility'.
558      * @return This field's visibility.
559      */
560     public Object getVisibility() {
561         return _visibility;
562     }
563 
564     /**
565      * Returns the reference to the {@link FieldInfo} instance within the same class.
566      * @return the reference to the {@link FieldInfo} instance 
567      */
568     public FieldInfo getFieldInfoReference() {
569         return _fieldInfoReference;
570     }
571     
572     /**
573      * @see org.exolab.castor.builder.info.nature.PropertyHolder#
574      *      getProperty(java.lang.String)
575      * @param name
576      *            of the property
577      * @return value of the property
578      */
579     public final Object getProperty(final String name) {
580         return _properties.get(name);
581     }
582 
583     /**
584      * @see org.exolab.castor.builder.info.nature.PropertyHolder#
585      *      setProperty(java.lang.String, java.lang.Object)
586      * @param name
587      *            of the property
588      * @param value
589      *            of the property
590      */
591     public final void setProperty(final String name, final Object value) {
592         _properties.put(name, value);
593     }
594 
595     /**
596      * @see org.exolab.castor.builder.info.nature.NatureExtendable#
597      *      addNature(java.lang.String)
598      * @param nature
599      *            ID of the Nature
600      */
601     public final void addNature(final String nature) {
602         _natures.add(nature);
603     }
604 
605     /**
606      * @see org.exolab.castor.builder.info.nature.NatureExtendable#
607      *      hasNature(java.lang.String)
608      * @param nature
609      *            ID of the Nature
610      * @return true if the Nature ID was added.
611      */
612     public final boolean hasNature(final String nature) {
613         return _natures.contains(nature);
614     }
615     
616 }