View Javadoc
1   package org.codehaus.modello.plugins.xml;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.List;
6   
7   import org.codehaus.modello.ModelloRuntimeException;
8   import org.codehaus.modello.model.ModelClass;
9   import org.codehaus.modello.model.ModelField;
10  import org.codehaus.modello.model.Version;
11  import org.codehaus.modello.plugin.AbstractModelloGenerator;
12  import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
13  import org.codehaus.modello.plugins.xml.metadata.XmlClassMetadata;
14  import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
15  
16  /*
17   * Copyright (c) 2004, Codehaus.org
18   *
19   * Permission is hereby granted, free of charge, to any person obtaining a copy of
20   * this software and associated documentation files (the "Software"), to deal in
21   * the Software without restriction, including without limitation the rights to
22   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
23   * of the Software, and to permit persons to whom the Software is furnished to do
24   * so, subject to the following conditions:
25   *
26   * The above copyright notice and this permission notice shall be included in all
27   * copies or substantial portions of the Software.
28   *
29   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35   * SOFTWARE.
36   */
37  
38  /**
39   * Helper methods to deal with XML representation of the model.
40   *
41   * @author <a href="mailto:hboutemy@codehaus.org">Hervé Boutemy</a>
42   */
43  class XmlModelHelpers {
44      /**
45       * Resolve XML tag name for a class. Note: only root class needs such a resolution.
46       *
47       * @param modelClass the model class
48       * @return the XML tag name for the class
49       */
50      static String resolveTagName(ModelClass modelClass) {
51          XmlClassMetadata xmlClassMetadata = (XmlClassMetadata) modelClass.getMetadata(XmlClassMetadata.ID);
52  
53          String tagName;
54          if ((xmlClassMetadata == null) || (xmlClassMetadata.getTagName() == null)) {
55              tagName = AbstractModelloGenerator.uncapitalise(modelClass.getName());
56          } else {
57              // tag name is overridden by xml.tagName attribute
58              tagName = xmlClassMetadata.getTagName();
59          }
60          return tagName;
61      }
62  
63      /**
64       * Resolve XML tag name for a field.
65       *
66       * @param modelField the model field
67       * @param xmlFieldMetadata the XML metadata of the field
68       * @return the XML tag name for the field
69       */
70      static String resolveTagName(ModelField modelField, XmlFieldMetadata xmlFieldMetadata) {
71          String tagName;
72          if ((xmlFieldMetadata == null) || (xmlFieldMetadata.getTagName() == null)) {
73              tagName = modelField.getName();
74          } else {
75              // tag name is overridden by xml.tagName attribute
76              tagName = xmlFieldMetadata.getTagName();
77          }
78          return tagName;
79      }
80  
81      /**
82       * Resolve XML tag name for an item in an association with many multiplicity.
83       *
84       * @param fieldTagName the XML tag name of the field containing the association
85       * @param xmlAssociationMetadata the XML metadata of the association
86       * @return the XML tag name for items
87       */
88      static String resolveTagName(String fieldTagName, XmlAssociationMetadata xmlAssociationMetadata) {
89          String tagName;
90          if ((xmlAssociationMetadata == null) || (xmlAssociationMetadata.getTagName() == null)) {
91              tagName = AbstractModelloGenerator.singular(fieldTagName);
92          } else {
93              // tag name is overridden by xml.tagName attribute
94              tagName = xmlAssociationMetadata.getTagName();
95          }
96          return tagName;
97      }
98  
99      /**
100      * Get the field which type is <code>Content</code> if any.
101      *
102      * @param modelFields the fields to check
103      * @return the field, or <code>null</code> if no field is <code>Content</code>
104      */
105     static ModelField getContentField(List<ModelField> modelFields) {
106         if (modelFields == null) {
107             return null;
108         }
109         for (ModelField field : modelFields) {
110             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
111 
112             if (xmlFieldMetadata.isContent()) {
113                 return field;
114             }
115         }
116         return null;
117     }
118 
119     /**
120      * Gets all fields that are not marked as XML attribute.
121      *
122      * @param modelFields The collection of model fields from which to extract the XML attributes, must not be
123      *            <code>null</code>.
124      * @return The list of XML attributes fields, can be empty but never <code>null</code>.
125      */
126     static List<ModelField> getXmlAttributeFields(List<ModelField> modelFields) {
127         List<ModelField> xmlAttributeFields = new ArrayList<ModelField>();
128 
129         for (ModelField field : modelFields) {
130             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
131 
132             if (xmlFieldMetadata.isAttribute()) {
133                 xmlAttributeFields.add(field);
134             }
135         }
136 
137         return xmlAttributeFields;
138     }
139 
140     /**
141      * Return the XML fields of this class, with proper XML order and no XML transient fields.
142      *
143      * @param modelClass current class
144      * @param version the version of the class to use
145      * @return the list of XML fields of this class
146      */
147     static List<ModelField> getFieldsForXml(ModelClass modelClass, Version version) {
148         List<ModelClass> classes = new ArrayList<ModelClass>();
149 
150         // get the full inheritance
151         while (modelClass != null) {
152             classes.add(modelClass);
153 
154             String superClass = modelClass.getSuperClass();
155             if (superClass != null) {
156                 // superClass can be located outside (not generated by modello)
157                 modelClass = modelClass.getModel().getClass(superClass, version, true);
158             } else {
159                 modelClass = null;
160             }
161         }
162 
163         List<ModelField> fields = new ArrayList<ModelField>();
164 
165         for (int i = classes.size() - 1; i >= 0; i--) {
166             modelClass = classes.get(i);
167 
168             Iterator<ModelField> parentIter = fields.iterator();
169 
170             fields = new ArrayList<ModelField>();
171 
172             for (ModelField field : modelClass.getFields(version)) {
173                 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
174 
175                 if (xmlFieldMetadata.isTransient()) {
176                     // just ignore xml.transient fields
177                     continue;
178                 }
179 
180                 if (xmlFieldMetadata.getInsertParentFieldsUpTo() != null) {
181                     // insert fields from parent up to the specified field
182                     boolean found = false;
183 
184                     while (!found && parentIter.hasNext()) {
185                         ModelField parentField = parentIter.next();
186 
187                         fields.add(parentField);
188 
189                         found = parentField.getName().equals(xmlFieldMetadata.getInsertParentFieldsUpTo());
190                     }
191 
192                     if (!found) {
193                         // interParentFieldsUpTo not found
194                         throw new ModelloRuntimeException("parent field not found: class " + modelClass.getName()
195                                 + " xml.insertParentFieldUpTo='" + xmlFieldMetadata.getInsertParentFieldsUpTo() + "'");
196                     }
197                 }
198 
199                 fields.add(field);
200             }
201 
202             // add every remaining fields from parent class
203             while (parentIter.hasNext()) {
204                 fields.add(parentIter.next());
205             }
206         }
207 
208         return fields;
209     }
210 }