Source code: org/apache/axis/wsdl/symbolTable/TypeEntry.java
1 /*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.axis.wsdl.symbolTable;
17
18 import org.apache.axis.utils.Messages;
19 import org.w3c.dom.Node;
20
21 import javax.xml.namespace.QName;
22 import java.io.IOException;
23 import java.io.Serializable;
24 import java.util.HashSet;
25 import java.util.Vector;
26
27 /**
28 * This class represents a wsdl types entry that is supported by the WSDL2Java emitter.
29 * A TypeEntry has a QName representing its XML name and a name, which in the
30 * WSDL2Java back end is its full java name. The TypeEntry may also have a Node,
31 * which locates the definition of the emit type in the xml.
32 * A TypeEntry object extends SymTabEntry and is built by the SymbolTable class for
33 * each supported root complexType, simpleType, and elements that are
34 * defined or encountered.
35 * <p/>
36 * SymTabEntry
37 * |
38 * TypeEntry
39 * / \
40 * Type Element
41 * | |
42 * (BaseType, (DefinedElement,
43 * CollectionType CollectionElement,
44 * DefinedType, UndefinedElement)
45 * UndefinedType)
46 * <p/>
47 * UndefinedType and UndefinedElement are placeholders when the real type or element
48 * is not encountered yet. Both of these implement the Undefined interface.
49 * <p/>
50 * A TypeEntry whose java (or other language) name depends on an Undefined type, will
51 * have its name initialization deferred until the Undefined type is replaced with
52 * a defined type. The updateUndefined() method is invoked by the UndefinedDelegate to
53 * update the information.
54 * <p/>
55 * Each TypeEntry whose language name depends on another TypeEntry will have the refType
56 * field set. For example:
57 * <element name="foo" type="bar" />
58 * The TypeEntry for "foo" will have a refType set to the TypeEntry of "bar".
59 * <p/>
60 * Another Example:
61 * <xsd:complexType name="hobbyArray">
62 * <xsd:complexContent>
63 * <xsd:restriction base="soapenc:Array">
64 * <xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
65 * </xsd:restriction>
66 * </xsd:complexContent>
67 * </xsd:complexType>
68 * The TypeEntry for "hobbyArray" will have a refType that locates the TypeEntry for xsd:string
69 * and the dims field will be "[]"
70 *
71 * @author Rich Scheuerle (scheu@us.ibm.com)
72 */
73 public abstract class TypeEntry extends SymTabEntry implements Serializable {
74
75 /** Field node */
76 protected Node node; // Node
77
78 /** Field refType */
79 protected TypeEntry refType; // Some TypeEntries refer to other types.
80
81 /** Field dims */
82 protected String dims = ""; // If refType is an element, dims indicates
83
84 // the array dims (for example "[]").
85
86 protected boolean underlTypeNillable = false; // if this is an array, underlTypeNillable indicates
87 // whether the underlying type of the array is nillable.
88
89 protected QName componentType = null; // If this is an array, the component type
90
91 /** If this TypeEntry represents an array with elements inside a "wrapper"
92 * this field can optionally change the inner QName (default is <item>).
93 */
94 protected QName itemQName = null;
95
96 /** Field undefined */
97 protected boolean undefined; // If refType is an Undefined type
98
99 // (or has a refType that is Undefined)
100 // then the undefined flag is set.
101 // The name cannot be determined
102 // until the Undefined type is found.
103
104 /** Field isBaseType */
105 protected boolean isBaseType; // Indicates if represented by a
106
107 // primitive or util class
108
109 /** Field isSimpleType */
110 protected boolean isSimpleType =
111 false; // Indicates if this type is a simple type
112
113 /** Field onlyLiteralReference */
114 protected boolean onlyLiteralReference = false; // Indicates
115
116 /** Field types */
117 protected HashSet types = null;
118
119 /** contained elements in the schema's type definition */
120 protected Vector containedElements;
121
122 /** contained attributes in the schema's type definition */
123 protected Vector containedAttributes;
124
125 // whether this type is only referenced
126 // via a binding's literal use.
127
128 /**
129 * Create a TypeEntry object for an xml construct that references another type.
130 * Defer processing until refType is known.
131 *
132 * @param pqName
133 * @param refType
134 * @param pNode
135 * @param dims
136 */
137 protected TypeEntry(QName pqName, TypeEntry refType, Node pNode,
138 String dims) {
139
140 super(pqName);
141
142 node = pNode;
143 this.undefined = refType.undefined;
144 this.refType = refType;
145
146 if (dims == null) {
147 dims = "";
148 }
149
150 this.dims = dims;
151
152 if (refType.undefined) {
153
154 // Need to defer processing until known.
155 TypeEntry uType = refType;
156
157 while (!(uType instanceof Undefined)) {
158 uType = uType.refType;
159 }
160
161 ((Undefined) uType).register(this);
162 } else {
163 isBaseType = (refType.isBaseType && refType.dims.equals("")
164 && dims.equals(""));
165 }
166 }
167
168 /**
169 * Create a TypeEntry object for an xml construct that is not a base type
170 *
171 * @param pqName
172 * @param pNode
173 */
174 protected TypeEntry(QName pqName, Node pNode) {
175
176 super(pqName);
177
178 node = pNode;
179 refType = null;
180 undefined = false;
181 dims = "";
182 isBaseType = false;
183 }
184
185 /**
186 * Create a TypeEntry object for an xml construct name that represents a base type
187 *
188 * @param pqName
189 */
190 protected TypeEntry(QName pqName) {
191
192 super(pqName);
193
194 node = null;
195 undefined = false;
196 dims = "";
197 isBaseType = true;
198 }
199
200 /**
201 * Query the node for this type.
202 *
203 * @return
204 */
205 public Node getNode() {
206 return node;
207 }
208
209 /**
210 * Returns the Base Type Name.
211 * For example if the Type represents a schema integer, "int" is returned.
212 * If this is a user defined type, null is returned.
213 *
214 * @return
215 */
216 public String getBaseType() {
217
218 if (isBaseType) {
219 return name;
220 } else {
221 return null;
222 }
223 }
224
225 /**
226 * Method isBaseType
227 *
228 * @return
229 */
230 public boolean isBaseType() {
231 return isBaseType;
232 }
233
234 /**
235 * Method setBaseType
236 *
237 * @param baseType
238 */
239 public void setBaseType(boolean baseType) {
240 isBaseType = baseType;
241 }
242
243 /**
244 * Method isSimpleType
245 *
246 * @return
247 */
248 public boolean isSimpleType() {
249 return isSimpleType;
250 }
251
252 /**
253 * Method setSimpleType
254 *
255 * @param simpleType
256 */
257 public void setSimpleType(boolean simpleType) {
258 isSimpleType = simpleType;
259 }
260
261 /**
262 * Is this type references ONLY as a literal type? If a binding's
263 * message's soapBody says: use="literal", then a type is referenced
264 * literally. Note that that type's contained types (ie., an address
265 * contains a phone#) are not referenced literally. Since a type
266 * that is ONLY referenced as a literal may cause a generator to act
267 * differently (like WSDL2Java), this extra reference distinction is
268 * needed.
269 *
270 * @return
271 */
272 public boolean isOnlyLiteralReferenced() {
273 return onlyLiteralReference;
274 } // isOnlyLiteralReferenced
275
276 /**
277 * Set the isOnlyLiteralReference flag.
278 *
279 * @param set
280 */
281 public void setOnlyLiteralReference(boolean set) {
282 onlyLiteralReference = set;
283 } // setOnlyLiteralRefeerence
284
285 /**
286 * getUndefinedTypeRef returns the Undefined TypeEntry that this entry depends on or NULL.
287 *
288 * @return
289 */
290 protected TypeEntry getUndefinedTypeRef() {
291
292 if (this instanceof Undefined) {
293 return this;
294 }
295
296 if (undefined && (refType != null)) {
297 if (refType.undefined) {
298 TypeEntry uType = refType;
299
300 while (!(uType instanceof Undefined)) {
301 uType = uType.refType;
302 }
303
304 return uType;
305 }
306 }
307
308 return null;
309 }
310
311 /**
312 * UpdateUndefined is called when the ref TypeEntry is finally known.
313 *
314 * @param oldRef The TypeEntry representing the Undefined TypeEntry
315 * @param newRef The replacement TypeEntry
316 * @return true if TypeEntry is changed in any way.
317 * @throws IOException
318 */
319 protected boolean updateUndefined(TypeEntry oldRef, TypeEntry newRef)
320 throws IOException {
321
322 boolean changedState = false;
323
324 // Replace refType with the new one if applicable
325 if (refType == oldRef) {
326 refType = newRef;
327 changedState = true;
328
329 // Detect a loop
330 TypeEntry te = refType;
331
332 while ((te != null) && (te != this)) {
333 te = te.refType;
334 }
335
336 if (te == this) {
337
338 // Detected a loop.
339 undefined = false;
340 isBaseType = false;
341 node = null;
342
343 throw new IOException(
344 Messages.getMessage(
345 "undefinedloop00", getQName().toString()));
346 }
347 }
348
349 // Update information if refType is now defined
350 if ((refType != null) && undefined && (refType.undefined == false)) {
351 undefined = false;
352 changedState = true;
353 isBaseType = (refType.isBaseType && refType.dims.equals("")
354 && dims.equals(""));
355 }
356
357 return changedState;
358 }
359
360 /**
361 * If this type references another type, return that type, otherwise return null.
362 *
363 * @return
364 */
365 public TypeEntry getRefType() {
366 return refType;
367 } // getRefType
368
369 /**
370 * Method setRefType
371 *
372 * @param refType
373 */
374 public void setRefType(TypeEntry refType) {
375 this.refType = refType;
376 }
377
378 /**
379 * Return the dimensions of this type, which can be 0 or more "[]".
380 *
381 * @return
382 */
383 public String getDimensions() {
384 return dims;
385 } // getDimensions
386
387 /**
388 * Return whether the underlying type is nillable if this is an array type.
389 * @return true if it is an array and nillable
390 */
391 public boolean getUnderlTypeNillable() {
392 // refType could refer to array with underlying nillable
393 // type - set the underlTypeNillable to true if this is
394 // the case.
395 if (!underlTypeNillable
396 && !getDimensions().equals("")
397 && refType != null) {
398 underlTypeNillable = refType.getUnderlTypeNillable();
399 }
400 return underlTypeNillable;
401 }
402
403 /**
404 * Set the boolean indicating whether underlying type of array is nillable.
405 */
406 public void setUnderlTypeNillable(boolean underlTypeNillable) {
407 this.underlTypeNillable = underlTypeNillable;
408 }
409
410 /**
411 * Return the QName of the component if this is an array type
412 * @return QName of array elements or null
413 */
414 public QName getComponentType()
415 {
416 return componentType;
417 }
418
419 /**
420 * Set the QName of the component if this is an array type
421 */
422 public void setComponentType(QName componentType)
423 {
424 this.componentType = componentType;
425 }
426
427 public QName getItemQName() {
428 return itemQName;
429 }
430
431 public void setItemQName(QName itemQName) {
432 this.itemQName = itemQName;
433 }
434
435 /**
436 * Get string representation.
437 *
438 * @return
439 */
440 public String toString() {
441 return toString("");
442 }
443
444 /**
445 * Get string representation with indentation
446 *
447 * @param indent
448 * @return
449 */
450 protected String toString(String indent) {
451
452 String refString = indent + "RefType: null \n";
453
454 if (refType != null) {
455 refString = indent + "RefType:\n" + refType.toString(indent + " ")
456 + "\n";
457 }
458
459 return super.toString(indent)
460 + indent + "Class: " + this.getClass().getName() + "\n"
461 + indent + "Base?: " + isBaseType + "\n"
462 + indent + "Undefined?: " + undefined + "\n"
463 + indent + "isSimpleType? " + isSimpleType + "\n"
464 + indent + "Node: " + getNode() + "\n"
465 + indent + "Dims: " + dims + "\n"
466 + indent + "isOnlyLiteralReferenced: " + onlyLiteralReference + "\n"
467 + refString;
468 }
469
470 /**
471 * This method returns a set of all the nested types.
472 * Nested types are types declared within this TypeEntry (or descendents)
473 * plus any extended types and the extended type nested types
474 * The elements of the returned HashSet are Types.
475 *
476 * @param symbolTable is the symbolTable
477 * @param derivedFlag should be set if all dependendent derived types should also be
478 * returned.
479 * @return
480 */
481 public HashSet getNestedTypes(SymbolTable symbolTable,
482 boolean derivedFlag) {
483 if( types == null) {
484 types = Utils.getNestedTypes(this, symbolTable, derivedFlag);
485 }
486 return types;
487 } // getNestedTypes
488
489 /**
490 * @return Returns the containedAttributes.
491 */
492 public Vector getContainedAttributes() {
493 return containedAttributes;
494 }
495 /**
496 * @param containedAttributes The containedAttributes to set.
497 */
498 public void setContainedAttributes(Vector containedAttributes) {
499 this.containedAttributes = containedAttributes;
500 }
501 /**
502 * @return Returns the containedElements.
503 */
504 public Vector getContainedElements() {
505 return containedElements;
506 }
507 /**
508 * @param containedElements The containedElements to set.
509 */
510 public void setContainedElements(Vector containedElements) {
511 this.containedElements = containedElements;
512 }
513 }