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 }