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.xml.util;
46  
47  import org.castor.xml.BackwardCompatibilityContext;
48  import org.castor.xml.InternalContext;
49  import org.castor.xml.JavaNaming;
50  import org.castor.xml.XMLNaming;
51  import org.exolab.castor.mapping.ClassDescriptor;
52  import org.exolab.castor.mapping.FieldDescriptor;
53  import org.exolab.castor.mapping.MappingException;
54  import org.exolab.castor.mapping.loader.ClassDescriptorImpl;
55  import org.exolab.castor.xml.NodeType;
56  import org.exolab.castor.xml.XMLClassDescriptor;
57  import org.exolab.castor.xml.XMLFieldDescriptor;
58  
59  /**
60   * An adapter class which can turn an ordinary ClassDescriptor into an
61   * XMLClassDescriptor.
62   *
63   * @author <a href="kvisco@intalio.com">Keith Visco</a>
64   * @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
65   */
66  public class XMLClassDescriptorAdapter extends XMLClassDescriptorImpl {
67      private InternalContext _internalContext;
68      
69      public XMLClassDescriptorAdapter() {
70          super();
71          _internalContext = new BackwardCompatibilityContext();
72      }
73  
74      /**
75       * Creates a new XMLClassDescriptorAdapter using the given ClassDescriptor.
76       *
77       * @param classDesc the ClassDescriptor to "adapt"
78       * @param xmlName the XML name for the class
79       */
80      public XMLClassDescriptorAdapter(final ClassDescriptor classDesc, final String xmlName)
81                                  throws org.exolab.castor.mapping.MappingException {
82          this(classDesc, xmlName, null);
83      } //-- XMLClassDescriptor
84  
85      /**
86       * Creates a new XMLClassDescriptorAdapter using the given ClassDescriptor.
87       *
88       * @param classDesc the ClassDescriptor to "adapt"
89       * @param xmlName the XML name for the class
90       * @param primitiveNodeType the NodeType to use for primitives
91       */
92      public XMLClassDescriptorAdapter(final ClassDescriptor classDesc,
93              String xmlName, NodeType primitiveNodeType)
94      throws MappingException {
95          this();
96  
97          if (classDesc == null) {
98              String err = "The ClassDescriptor argument to "
99                  + "XMLClassDescriptorAdapter must not be null.";
100             throw new IllegalArgumentException(err);
101         }
102 
103         if (primitiveNodeType == null) {
104             primitiveNodeType = new BackwardCompatibilityContext().getPrimitiveNodeType();
105         }
106 
107         if (primitiveNodeType == null) {
108             primitiveNodeType = NodeType.Attribute;
109         }
110 
111         process(classDesc, primitiveNodeType);
112         setJavaClass(classDesc.getJavaClass());
113 
114         if (xmlName == null) {
115             if (classDesc instanceof XMLClassDescriptor) {
116                 xmlName = ((XMLClassDescriptor) classDesc).getXMLName();
117             } else {
118                 String clsName = _internalContext.getJavaNaming().getClassName(classDesc.getJavaClass());
119                 xmlName = _internalContext.getXMLNaming().toXMLName(clsName);
120             }
121         }
122         setXMLName(xmlName);
123     }
124 
125     /**
126      * Copies the fieldDescriptors of the given XMLClassDesctiptor into this
127      * XMLClassDescriptor.
128      *
129      * @param classDesc the XMLClassDescriptor to process
130      */
131     private void process(ClassDescriptor classDesc, NodeType primitiveNodeType)
132     throws MappingException {
133         if (classDesc instanceof XMLClassDescriptor) {
134             //-- hopefully this won't happen, but we can't prevent it.
135             process((XMLClassDescriptor)classDesc);
136             return;
137         }
138 
139         //-- handle inheritence
140         XMLClassDescriptor xmlClassDesc = null;
141         ClassDescriptor extendsDesc = classDesc.getExtends();
142         if (extendsDesc != null) {
143             if (extendsDesc instanceof XMLClassDescriptor) {
144                 xmlClassDesc = (XMLClassDescriptor) extendsDesc;
145             } else {
146                 xmlClassDesc = new XMLClassDescriptorAdapter(extendsDesc, null, primitiveNodeType);
147             }
148         }
149         setExtends(xmlClassDesc);
150 
151         FieldDescriptor   identity = classDesc.getIdentity();
152         FieldDescriptor[] fields   = classDesc.getFields();
153 
154         //-- Note from Keith for anyone interested...
155         //-- hack for multiple identities if ClassDescriptor is
156         //-- an implementation of ClassDescriptorImpl...
157         //-- This is really a bug in ClassDescriptorImpl, but
158         //-- since it's shared code between JDO + XML I don't
159         //-- want to change it there until both the XML and JDO
160         //-- folks can both approve the change.
161         if (classDesc instanceof ClassDescriptorImpl) {
162             ClassDescriptorImpl cdImpl = (ClassDescriptorImpl)classDesc;
163             FieldDescriptor[] identities = cdImpl.getIdentities();
164             if ((identities != null) && (identities.length > 1)) {
165                 int size = fields.length + identities.length;
166                 FieldDescriptor[] newFields = new FieldDescriptor[size];
167                 System.arraycopy(fields, 0, newFields, 0, fields.length);
168                 System.arraycopy(identities, 0, newFields, fields.length, identities.length);
169                 fields = newFields;
170             }
171         }
172         //-- End ClassDescriptorImpl fix
173 
174         for (int i = 0; i < fields.length; i++) {
175             FieldDescriptor fieldDesc = fields[i];
176             if (fieldDesc == null) {
177                 continue;
178             }
179             if (fieldDesc instanceof XMLFieldDescriptorImpl) {
180                 if (identity == fieldDesc) {
181                     setIdentity((XMLFieldDescriptorImpl)fieldDesc);
182                     identity = null; //-- clear identity
183                 } else {
184                     addFieldDescriptor((XMLFieldDescriptorImpl)fieldDesc);
185                 }
186             } else {
187                 String name = fieldDesc.getFieldName();
188                 String xmlFieldName = _internalContext.getXMLNaming().toXMLName(name);
189 
190                 if (identity == fieldDesc) {
191                     setIdentity(new XMLFieldDescriptorImpl(fieldDesc,
192                                                           xmlFieldName,
193                                                          NodeType.Attribute,
194                                                          primitiveNodeType));
195                     identity = null; //-- clear identity
196                 } else {
197                     NodeType nodeType = NodeType.Element;
198                     if (isPrimitive(fieldDesc.getFieldType())) {
199                         nodeType = primitiveNodeType;
200                     }
201 
202                     addFieldDescriptor(new XMLFieldDescriptorImpl(fieldDesc,
203                                                                 xmlFieldName,
204                                                                 nodeType,
205                                                                 primitiveNodeType));
206                 }
207             }
208         }
209 
210         //-- Handle Identity if it wasn't already handled. This occurs
211         //-- if the ClassDescriptor implementation doesn't return
212         //-- the identity field as part of the collection of fields
213         //-- returned by getFields (even though it should).
214         if ( identity != null ) {
215             String  xmlFieldName;
216             if ( identity instanceof XMLFieldDescriptor ) {
217                 setIdentity((XMLFieldDescriptor)identity);
218             } else {
219                 xmlFieldName = _internalContext.getXMLNaming().toXMLName(identity.getFieldName());
220                 setIdentity(new XMLFieldDescriptorImpl(identity,
221                                                        xmlFieldName,
222                                                        NodeType.Attribute,
223                                                        primitiveNodeType));
224             }
225         }
226     }
227 
228     /**
229      * Copies the fieldDescriptors of the given XMLClassDesctiptor into this
230      * XMLClassDescriptor.
231      *
232      * @param classDesc the XMLClassDescriptor to process
233      */
234     private void process(XMLClassDescriptor classDesc) {
235         FieldDescriptor identity = classDesc.getIdentity();
236         FieldDescriptor[] fields = classDesc.getFields();
237         for (int i = 0; i < fields.length; i++) {
238             if (identity == fields[i]) {
239                 setIdentity((XMLFieldDescriptor)fields[i]);
240                 identity = null; //-- clear identity
241             } else {
242                 addFieldDescriptor((XMLFieldDescriptor)fields[i]);
243             }
244         }
245 
246         //-- handle identity if not already processed
247         if (identity != null) {
248             setIdentity((XMLFieldDescriptor)identity);
249         }
250         setXMLName(classDesc.getXMLName());
251         setExtendsWithoutFlatten((XMLClassDescriptor) classDesc.getExtends());
252     }
253 }