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-2003 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  package org.exolab.castor.builder.descriptors;
46  
47  import org.exolab.castor.builder.BuilderConfiguration;
48  import org.exolab.castor.builder.SGTypes;
49  import org.exolab.castor.xml.XMLConstants;
50  import org.exolab.javasource.JAnnotation;
51  import org.exolab.javasource.JAnnotationType;
52  import org.exolab.javasource.JClass;
53  import org.exolab.javasource.JConstructor;
54  import org.exolab.javasource.JField;
55  import org.exolab.javasource.JMethod;
56  import org.exolab.javasource.JPrimitiveType;
57  import org.exolab.javasource.JSourceCode;
58  import org.exolab.javasource.JType;
59  
60  /**
61   * A class which defines the necessary methods for generating ClassDescriptor
62   * source files.
63   *
64   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
65   * @version $Revision$ $Date: 2006-03-10 15:42:54 -0700 (Fri, 10 Mar 2006) $
66   */
67  public final class DescriptorJClass extends JClass {
68  
69      /** Class Descriptors extend this base class. */
70      private static final String XMLCLASS_DESCRIPTOR_IMPL =
71          "org.exolab.castor.xml.util.XMLClassDescriptorImpl";
72  
73      private static final String MAPPING_ACCESS_MODE = "org.exolab.castor.mapping.AccessMode";
74  
75      /** Field descriptors implement this interface from org.exolab.castor.mapping. */
76      private static final JClass FIELD_DESCRIPTOR_CLASS;
77  
78      /** Field descriptors implement this interface from org.exolab.castor.xml. */
79      private static final JClass XML_FIELD_DESCRIPTOR_CLASS;
80      /** Type validators implement this interface from org.exolab.castor.xml. */
81      private static final JType  TYPE_VALIDATOR_CLASS;
82  
83      static {
84          FIELD_DESCRIPTOR_CLASS     = new JClass("org.exolab.castor.mapping.FieldDescriptor");
85          XML_FIELD_DESCRIPTOR_CLASS = new JClass("org.exolab.castor.xml.XMLFieldDescriptor");
86          TYPE_VALIDATOR_CLASS       = new JClass("org.exolab.castor.xml.TypeValidator");
87      }
88  
89      /** The type being described by the Descriptor class we'll generate. */
90      private final JClass               _type;
91      /** Source Builder configuration. */
92      private final BuilderConfiguration _config;
93  
94      /**
95       * Constructs a DescriptorJClass.
96       * @param config Builder Configuration
97       * @param className name of this descriptor class
98       * @param type the type that is described by this descriptor
99       */
100     public DescriptorJClass(final BuilderConfiguration config, final String className,
101                             final JClass type) {
102         super(className);
103         this._config = config;
104         this._type   = type;
105         init();
106     } //-- DescriptorJClass
107 
108     //-------------------/
109     //- Private Methods -/
110     //-------------------/
111 
112     /**
113      * Initializes this DescriptorJClass with the required methods.
114      */
115     private void init() {
116         // Make sure that the Descriptor is extended XMLClassDescriptor even when
117         // the user has specified a super class for all the generated classes
118         String superClass = null;
119         if (_config != null) {
120             superClass = _config.getProperty(BuilderConfiguration.Property.SUPER_CLASS, null);
121         }
122 
123         boolean extended = false;
124 
125         if (_type.getSuperClassQualifiedName() == null
126             || _type.getSuperClassQualifiedName().equals(superClass)) {
127             setSuperClass(XMLCLASS_DESCRIPTOR_IMPL);
128         } else {
129             if (_type.getSuperClass() == null) {
130                 setSuperClass(null);
131             } else {
132                 extended = true;
133                 setSuperClass(getSuperClassName());
134             }
135         }
136         superClass = null;
137 
138         if (_type.getPackageName() != null && _type.getPackageName().length() > 0) {
139             addImport(_type.getName());
140         }
141 
142         addField(new JField(JType.BOOLEAN, "_elementDefinition"));
143 
144         addField(new JField(SGTypes.STRING, "_nsPrefix"));
145         addField(new JField(SGTypes.STRING, "_nsURI"));
146         addField(new JField(SGTypes.STRING, "_xmlName"));
147         //-- if there is a super class, the identity field must remain
148         //-- the same than the one in the super class
149         addField(new JField(XML_FIELD_DESCRIPTOR_CLASS, "_identity"));
150 
151         //-- create default constructor
152         addDefaultConstructor(extended);
153 
154         //jsc.add("Class[] emptyClassArgs = new Class[0];");
155         //jsc.add("Class[] classArgs = new Class[1];");
156 
157         //---------------------------------------------/
158         //- Methods Defined by XMLClassDescriptorImpl -/
159         //---------------------------------------------/
160 
161         addXMLClassDescriptorImplOverrides();
162 
163         //-----------------------------------------/
164         //- Methods Defined by XMLClassDescriptor -/
165         //-----------------------------------------/
166 
167         addXMLClassDescriptorOverrides();
168 
169         //--------------------------------------/
170         //- Methods defined by ClassDescriptor -/
171         //--------------------------------------/
172 
173         addClassDescriptorOverrides(extended);
174     } //-- createSource
175 
176     /**
177      * Returns the qualified class name of the super class, adjusted to add the
178      * 'descriptors' sub-package.
179      * @return Returns the qualified class name of the super class
180      */
181     private String getSuperClassName() {
182         final String superClassName;
183         if (_type.getSuperClass().getPackageName() == null
184                 || _type.getSuperClass().getPackageName().equals("")) {
185             if (getPackageName() == null) {
186                 // no target package specified --> do not append package (=null)
187                 superClassName = _type.getSuperClass().getLocalName()
188                         + XMLConstants.DESCRIPTOR_SUFFIX;
189             } else {
190                 // target package specified --> simply use it
191                 superClassName = getPackageName() + "." + _type.getSuperClass().getLocalName()
192                         + XMLConstants.DESCRIPTOR_SUFFIX;
193             }
194         } else {
195             superClassName = _type.getSuperClass().getPackageName()
196                     + "." + XMLConstants.DESCRIPTOR_PACKAGE + "."
197                     + _type.getSuperClass().getLocalName() +  XMLConstants.DESCRIPTOR_SUFFIX;
198         }
199         return superClassName;
200     }
201 
202     /**
203      * Adds our default constructor.
204      * @param extended true if we extend another class and thus need to call super()
205      */
206     private void addDefaultConstructor(final boolean extended) {
207         addConstructor(createConstructor());
208         JConstructor cons = getConstructor(0);
209         JSourceCode jsc = cons.getSourceCode();
210         jsc.add("super();");
211 
212         if (extended) {
213             //-- add base class (for validation)
214             jsc.add("setExtendsWithoutFlatten(");
215             jsc.append("new ");
216             jsc.append(getSuperClassQualifiedName());
217             jsc.append("());");
218         }
219     }
220 
221     /**
222      * Adds the methods we override from.
223      * {@link org.exolab.castor.xml.util.XMLClassDescriptorImpl}
224      */
225     private void addXMLClassDescriptorImplOverrides() {
226         //-- create isElementDefinition method
227         JMethod getElementDefinition = new JMethod("isElementDefinition", JType.BOOLEAN,
228                                "true if XML schema definition of this Class is that of a global\n"
229                                + "element or element with anonymous type definition.");
230         JSourceCode jsc = getElementDefinition.getSourceCode();
231         jsc.add("return _elementDefinition;");
232         addMethod(getElementDefinition);
233     }
234 
235     /**
236      * Adds the methods we override from.
237      * {@link org.exolab.castor.xml.XMLClassDescriptor}
238      */
239     private void addXMLClassDescriptorOverrides() {
240         JMethod method;
241         JSourceCode jsc;
242         //-- create getNameSpacePrefix method
243         method = new JMethod("getNameSpacePrefix", SGTypes.STRING,
244                              "the namespace prefix to use when marshaling as XML.");
245 
246         if (_config.useJava50()) {
247             method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
248         }
249 
250         jsc = method.getSourceCode();
251         jsc.add("return _nsPrefix;");
252         addMethod(method);
253 
254         //-- create getNameSpaceURI method
255         method = new JMethod("getNameSpaceURI", SGTypes.STRING,
256                              "the namespace URI used when marshaling and unmarshaling as XML.");
257 
258         if (_config.useJava50()) {
259             method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
260         }
261 
262         jsc = method.getSourceCode();
263         jsc.add("return _nsURI;");
264         addMethod(method);
265 
266         //-- create getValidator method
267         method = new JMethod("getValidator", TYPE_VALIDATOR_CLASS,
268                              "a specific validator for the class described"
269                              + " by this ClassDescriptor.");
270 
271         if (_config.useJava50()) {
272             method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
273         }
274 
275         jsc = method.getSourceCode();
276         jsc.add("return this;");
277         addMethod(method);
278 
279         //-- create getXMLName method
280         method = new JMethod("getXMLName", SGTypes.STRING,
281                              "the XML Name for the Class being described.");
282 
283         if (_config.useJava50()) {
284             method.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
285         }
286 
287         jsc = method.getSourceCode();
288         jsc.add("return _xmlName;");
289         addMethod(method);
290     }
291 
292     /**
293      * Adds the methods we override from.
294      * {@link org.exolab.castor.mapping.ClassDescriptor}
295      * @param extended true if we extend another class and thus need to call super()
296      */
297     private void addClassDescriptorOverrides(final boolean extended) {
298         JSourceCode jsc;
299 
300         //-- create getAccessMode method
301         JClass amClass = new JClass(MAPPING_ACCESS_MODE);
302         JMethod getAccessMode = new JMethod("getAccessMode", amClass,
303                                      "the access mode specified for this class.");
304 
305         if (_config.useJava50()) {
306             getAccessMode.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
307         }
308 
309         jsc = getAccessMode.getSourceCode();
310         jsc.add("return null;");
311         addMethod(getAccessMode);
312 
313         //-- create getIdentity method
314         JMethod getIdentity = new JMethod("getIdentity", FIELD_DESCRIPTOR_CLASS,
315                                    "the identity field, null if this class has no identity.");
316 
317         if (_config.useJava50()) {
318             getIdentity.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
319         }
320 
321         jsc = getIdentity.getSourceCode();
322         if (extended) {
323             jsc.add("if (_identity == null) {");
324             jsc.indent();
325             jsc.add("return super.getIdentity();");
326             jsc.unindent();
327             jsc.add("}");
328         }
329         jsc.add("return _identity;");
330 
331         //--don't add the type to the import list
332         addMethod(getIdentity, false);
333 
334         //-- create getJavaClass method
335         JMethod getJavaClass = new JMethod("getJavaClass", SGTypes.CLASS,
336                                     "the Java class represented by this descriptor.");
337 
338         if (_config.useJava50()) {
339             getJavaClass.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
340         }
341 
342         jsc = getJavaClass.getSourceCode();
343         jsc.add("return ");
344         jsc.append(classType(_type));
345         jsc.append(";");
346 
347         //--don't add the type to the import list
348         addMethod(getJavaClass, false);
349     }
350 
351     /**
352      * Returns the Class type (as a String) for the given XSType.
353      *
354      * @param jType
355      *            the JType we are to return the class name of
356      * @return the Class name (as a String) for the given XSType
357      */
358     private static String classType(final JType jType) {
359         if (jType.isPrimitive()) {
360             JPrimitiveType primitive = (JPrimitiveType) jType;
361             return primitive.getWrapperName() + ".TYPE";
362         }
363         return jType.toString() + ".class";
364     } //-- classType
365 
366 } //-- DescriptorJClass