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