View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  package org.exolab.castor.builder.descriptors;
36  
37  import org.exolab.castor.builder.BuilderConfiguration;
38  import org.exolab.castor.builder.SGTypes;
39  import org.exolab.castor.xml.XMLConstants;
40  import org.exolab.javasource.JAnnotation;
41  import org.exolab.javasource.JAnnotationType;
42  import org.exolab.javasource.JClass;
43  import org.exolab.javasource.JConstructor;
44  import org.exolab.javasource.JField;
45  import org.exolab.javasource.JMethod;
46  import org.exolab.javasource.JPrimitiveType;
47  import org.exolab.javasource.JSourceCode;
48  import org.exolab.javasource.JType;
49  
50  /**
51   * A class which defines the necessary methods for generating ClassDescriptor source files.
52   *
53   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
54   * @version $Revision$ $Date: 2006-03-10 15:42:54 -0700 (Fri, 10 Mar 2006) $
55   */
56  public final class DescriptorJClass extends JClass {
57  
58    /** Class Descriptors extend this base class. */
59    private static final String XMLCLASS_DESCRIPTOR_IMPL =
60        "org.exolab.castor.xml.util.XMLClassDescriptorImpl";
61  
62    private static final String MAPPING_ACCESS_MODE = "org.exolab.castor.mapping.AccessMode";
63  
64    /** Field descriptors implement this interface from org.exolab.castor.mapping. */
65    private static final JClass FIELD_DESCRIPTOR_CLASS;
66  
67    /** Field descriptors implement this interface from org.exolab.castor.xml. */
68    private static final JClass XML_FIELD_DESCRIPTOR_CLASS;
69    /** Type validators implement this interface from org.exolab.castor.xml. */
70    private static final JType TYPE_VALIDATOR_CLASS;
71  
72    static {
73      FIELD_DESCRIPTOR_CLASS = new JClass("org.exolab.castor.mapping.FieldDescriptor");
74      XML_FIELD_DESCRIPTOR_CLASS = new JClass("org.exolab.castor.xml.XMLFieldDescriptor");
75      TYPE_VALIDATOR_CLASS = new JClass("org.exolab.castor.xml.TypeValidator");
76    }
77  
78    /** The type being described by the Descriptor class we'll generate. */
79    private final JClass _type;
80    /** Source Builder configuration. */
81    private final BuilderConfiguration _config;
82  
83    /**
84     * Constructs a DescriptorJClass.
85     * 
86     * @param config Builder Configuration
87     * @param className name of this descriptor class
88     * @param type the type that is described by this descriptor
89     */
90    public DescriptorJClass(final BuilderConfiguration config, final String className,
91        final JClass type) {
92      super(className);
93      this._config = config;
94      this._type = type;
95      init();
96    } // -- DescriptorJClass
97  
98    // -------------------/
99    // - Private Methods -/
100   // -------------------/
101 
102   /**
103    * Initializes this DescriptorJClass with the required methods.
104    */
105   private void init() {
106     // Make sure that the Descriptor is extended XMLClassDescriptor even when
107     // the user has specified a super class for all the generated classes
108     String superClass = null;
109     if (_config != null) {
110       superClass = _config.getProperty(BuilderConfiguration.Property.SUPER_CLASS, null);
111     }
112 
113     boolean extended = false;
114 
115     if (_type.getSuperClassQualifiedName() == null
116         || _type.getSuperClassQualifiedName().equals(superClass)) {
117       setSuperClass(XMLCLASS_DESCRIPTOR_IMPL);
118     } else {
119       if (_type.getSuperClass() == null) {
120         setSuperClass(null);
121       } else {
122         extended = true;
123         setSuperClass(getSuperClassName());
124       }
125     }
126     superClass = null;
127 
128     if (_type.getPackageName() != null && _type.getPackageName().length() > 0) {
129       addImport(_type.getName());
130     }
131 
132     addField(new JField(JType.BOOLEAN, "_elementDefinition"));
133 
134     addField(new JField(SGTypes.STRING, "_nsPrefix"));
135     addField(new JField(SGTypes.STRING, "_nsURI"));
136     addField(new JField(SGTypes.STRING, "_xmlName"));
137     // -- if there is a super class, the identity field must remain
138     // -- the same than the one in the super class
139     addField(new JField(XML_FIELD_DESCRIPTOR_CLASS, "_identity"));
140 
141     // -- create default constructor
142     addDefaultConstructor(extended);
143 
144     // jsc.add("Class[] emptyClassArgs = new Class[0];");
145     // jsc.add("Class[] classArgs = new Class[1];");
146 
147     // ---------------------------------------------/
148     // - Methods Defined by XMLClassDescriptorImpl -/
149     // ---------------------------------------------/
150 
151     addXMLClassDescriptorImplOverrides();
152 
153     // -----------------------------------------/
154     // - Methods Defined by XMLClassDescriptor -/
155     // -----------------------------------------/
156 
157     addXMLClassDescriptorOverrides();
158 
159     // --------------------------------------/
160     // - Methods defined by ClassDescriptor -/
161     // --------------------------------------/
162 
163     addClassDescriptorOverrides(extended);
164   } // -- createSource
165 
166   /**
167    * Returns the qualified class name of the super class, adjusted to add the 'descriptors'
168    * sub-package.
169    * 
170    * @return Returns the qualified class name of the super class
171    */
172   private String getSuperClassName() {
173     final String superClassName;
174     if (_type.getSuperClass().getPackageName() == null
175         || _type.getSuperClass().getPackageName().equals("")) {
176       if (getPackageName() == null) {
177         // no target package specified --> do not append package (=null)
178         superClassName = _type.getSuperClass().getLocalName() + XMLConstants.DESCRIPTOR_SUFFIX;
179       } else {
180         // target package specified --> simply use it
181         superClassName = getPackageName() + "." + _type.getSuperClass().getLocalName()
182             + XMLConstants.DESCRIPTOR_SUFFIX;
183       }
184     } else {
185       superClassName =
186           _type.getSuperClass().getPackageName() + "." + XMLConstants.DESCRIPTOR_PACKAGE + "."
187               + _type.getSuperClass().getLocalName() + XMLConstants.DESCRIPTOR_SUFFIX;
188     }
189     return superClassName;
190   }
191 
192   /**
193    * Adds our default constructor.
194    * 
195    * @param extended true if we extend another class and thus need to call super()
196    */
197   private void addDefaultConstructor(final boolean extended) {
198     addConstructor(createConstructor());
199     JConstructor cons = getConstructor(0);
200     JSourceCode jsc = cons.getSourceCode();
201     jsc.add("super();");
202 
203     if (extended) {
204       // -- add base class (for validation)
205       jsc.add("setExtendsWithoutFlatten(");
206       jsc.append("new ");
207       jsc.append(getSuperClassQualifiedName());
208       jsc.append("());");
209     }
210   }
211 
212   /**
213    * Adds the methods we override from. {@link org.exolab.castor.xml.util.XMLClassDescriptorImpl}
214    */
215   private void addXMLClassDescriptorImplOverrides() {
216     // -- create isElementDefinition method
217     JMethod getElementDefinition = new JMethod("isElementDefinition", JType.BOOLEAN,
218         "true if XML schema definition of this Class is that of a global\n"
219             + "element or element with anonymous type definition.");
220     JSourceCode jsc = getElementDefinition.getSourceCode();
221     jsc.add("return _elementDefinition;");
222     addMethod(getElementDefinition);
223   }
224 
225   /**
226    * Adds the methods we override from. {@link org.exolab.castor.xml.XMLClassDescriptor}
227    */
228   private void addXMLClassDescriptorOverrides() {
229     JMethod method;
230     JSourceCode jsc;
231     // -- create getNameSpacePrefix method
232     method = new JMethod("getNameSpacePrefix", SGTypes.STRING,
233         "the namespace prefix to use when marshaling as XML.");
234 
235     if (_config.useJava50()) {
236       method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
237     }
238 
239     jsc = method.getSourceCode();
240     jsc.add("return _nsPrefix;");
241     addMethod(method);
242 
243     // -- create getNameSpaceURI method
244     method = new JMethod("getNameSpaceURI", SGTypes.STRING,
245         "the namespace URI used when marshaling and unmarshaling as XML.");
246 
247     if (_config.useJava50()) {
248       method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
249     }
250 
251     jsc = method.getSourceCode();
252     jsc.add("return _nsURI;");
253     addMethod(method);
254 
255     // -- create getValidator method
256     method = new JMethod("getValidator", TYPE_VALIDATOR_CLASS,
257         "a specific validator for the class described" + " by this ClassDescriptor.");
258 
259     if (_config.useJava50()) {
260       method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
261     }
262 
263     jsc = method.getSourceCode();
264     jsc.add("return this;");
265     addMethod(method);
266 
267     // -- create getXMLName method
268     method =
269         new JMethod("getXMLName", SGTypes.STRING, "the XML Name for the Class being described.");
270 
271     if (_config.useJava50()) {
272       method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
273     }
274 
275     jsc = method.getSourceCode();
276     jsc.add("return _xmlName;");
277     addMethod(method);
278   }
279 
280   /**
281    * Adds the methods we override from. {@link org.exolab.castor.mapping.ClassDescriptor}
282    * 
283    * @param extended true if we extend another class and thus need to call super()
284    */
285   private void addClassDescriptorOverrides(final boolean extended) {
286     JSourceCode jsc;
287 
288     // -- create getAccessMode method
289     JClass amClass = new JClass(MAPPING_ACCESS_MODE);
290     JMethod getAccessMode =
291         new JMethod("getAccessMode", amClass, "the access mode specified for this class.");
292 
293     if (_config.useJava50()) {
294       getAccessMode.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
295     }
296 
297     jsc = getAccessMode.getSourceCode();
298     jsc.add("return null;");
299     addMethod(getAccessMode);
300 
301     // -- create getIdentity method
302     JMethod getIdentity = new JMethod("getIdentity", FIELD_DESCRIPTOR_CLASS,
303         "the identity field, null if this class has no identity.");
304 
305     if (_config.useJava50()) {
306       getIdentity.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
307     }
308 
309     jsc = getIdentity.getSourceCode();
310     if (extended) {
311       jsc.add("if (_identity == null) {");
312       jsc.indent();
313       jsc.add("return super.getIdentity();");
314       jsc.unindent();
315       jsc.add("}");
316     }
317     jsc.add("return _identity;");
318 
319     // --don't add the type to the import list
320     addMethod(getIdentity, false);
321 
322     // -- create getJavaClass method
323     JMethod getJavaClass = new JMethod("getJavaClass", SGTypes.CLASS,
324         "the Java class represented by this descriptor.");
325 
326     if (_config.useJava50()) {
327       getJavaClass.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
328     }
329 
330     jsc = getJavaClass.getSourceCode();
331     jsc.add("return ");
332     jsc.append(classType(_type));
333     jsc.append(";");
334 
335     // --don't add the type to the import list
336     addMethod(getJavaClass, false);
337   }
338 
339   /**
340    * Returns the Class type (as a String) for the given XSType.
341    *
342    * @param jType the JType we are to return the class name of
343    * @return the Class name (as a String) for the given XSType
344    */
345   private static String classType(final JType jType) {
346     if (jType.isPrimitive()) {
347       JPrimitiveType primitive = (JPrimitiveType) jType;
348       return primitive.getWrapperName() + ".TYPE";
349     }
350     return jType.toString() + ".class";
351   } // -- classType
352 
353 } // -- DescriptorJClass