001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.schema2beansdev;
043:
044: import org.netbeans.modules.schema2beans.*;
045:
046: import java.util.*;
047:
048: /**
049: * This class is a node of the schema graph that the TreeBuilder is creating
050: * from the parsed schema. For every type we get 1 GraphNode. Every java
051: * bean property (or java class attribute), has an associated GraphLink.
052: * Groupings are represented in GraphLink's.
053: *
054: * Each element of the graph tree is a node (root, intermediate node and
055: * leaves). Each node references a GraphLink object which takes care
056: * of linking the different nodes of the graph.
057: *
058: * The schema instances information (*, + or ?) and the relationship
059: * as a sequence (,) or choice (|) information are held in the GraphLink
060: * object. There is only one GraphNode instance of an element in the graph
061: * event if the element is referenced by several graph links.
062: *
063: * A GrapNode is a leaf if its element GraphLink is null.
064: *
065: * To see a pretty graph of GraphNode's and GraphLink's, run with these
066: * options: -t dot -genDotGraph out.dot
067: * And run `dotty out.dot`.
068: *
069: * <xsd:element name="bill">
070: * <xsd:complexType>
071: * <xsd:sequence maxOccurs="unbounded">
072: * <xsd:element name="shipTo" type="addressType"/>
073: * <xsd:element name="billTo" type="addressType"/>
074: * </xsd:sequence>
075: * </xsd:complexType>
076: * </xsd:element>
077: * ...
078: * 1 GraphNode for type "bill"
079: * 1 GraphLink for xsd:sequence (storing the grouping info)
080: * 1 GraphNode for type "addressType"
081: * 1 GraphLink for "shipTo" java bean property
082: * 1 GraphLink for "billTo" java bean property
083: */
084: public class GraphNode {
085: /**
086: * The name of the element as it appears in the schema. In a DTD, this
087: * is unique within the tree since each DTD element
088: * can only be defined once. An XML Schema may reuse an element name.
089: */
090: private String name;
091: private String namespace = null;
092:
093: /**
094: * The unique name of the element in the schema.
095: */
096: private String uniqueName;
097:
098: /**
099: * The reference to the link structure defining all the siblings and
100: * subnode of this element, as defined in the DTD.
101: *
102: * For example, if we have <!ELEMENT a (b?, (c | d)+)>
103: * This GraphNode name is a, and the link points to a GraphLink
104: * object reference the GraphNode b and pointing to another
105: * graphLink object (a subnode link), defining the (c | d)
106: * declaration:
107: *
108: * Node[a]
109: * |------> Link(null, ',')
110: * |
111: * / \
112: * / \
113: * V V
114: * Link(b, '?')->Node(b) Link(null, '+')
115: * |
116: * Link(null, '|')
117: * / \
118: * / \
119: * V V
120: * Link(c)->Node(c) Link(d)->Node(d)
121: *
122: * @see GraphLink
123: *
124: */
125: private GraphLink link;
126:
127: /**
128: * Set to true by the TreeBuilder class when the schema parser calls back
129: * with the element name definition. (This is object might be created
130: * when referenced, before the element definition is found in the DTD)
131: * If this stays false, then it's created outside of our code generation
132: * (e.g., java.lang.String).
133: */
134: private boolean created;
135:
136: /**
137: * Number of time this node is referenced in the graph.
138: */
139: private int refCount;
140:
141: /**
142: * Object reference where the bean builder can store whatever it needs
143: */
144: private Object object;
145:
146: /**
147: * List of the attributes associated to this element (might be null)
148: */
149: private List attributes;
150:
151: // Used to mark an element to avoid infinite loop for recurse parsing
152: private boolean marked;
153:
154: // Used to suggest what type the of the property should be, only
155: // really useful on leaf nodes.
156: private String javaType;
157:
158: private Map extendedProperties = new LinkedHashMap();
159:
160: private Set extraData = new LinkedHashSet();
161: private boolean isUnion = false;
162: private boolean isAbstract = false;
163:
164: private GraphNode extendsNode;
165: private GraphNode alias;
166:
167: GraphNode(String name, String uniqueName) {
168: //System.out.println("Created GraphNode "+uniqueName+" name="+name);
169: setName(name);
170: this .uniqueName = uniqueName;
171: this .created = false;
172: this .attributes = null;
173: this .marked = false;
174: }
175:
176: void addAttribute(AttrProp attr) {
177: if (alias != null) {
178: alias.addAttribute(attr);
179: return;
180: }
181: if (this .attributes == null)
182: this .attributes = new ArrayList();
183: this .attributes.add(attr);
184: //attr.setSourceGraphNode(this);
185: }
186:
187: AttrProp[] getAttributes() {
188: if (alias != null) {
189: return alias.getAttributes();
190: }
191: int size = 0;
192:
193: if (this .attributes != null)
194: size = this .attributes.size();
195:
196: AttrProp[] ret = new AttrProp[size];
197:
198: if (size > 0)
199: return (AttrProp[]) this .attributes.toArray(ret);
200: else
201: return ret;
202: }
203:
204: void setObject(Object obj) {
205: this .object = obj;
206: }
207:
208: Object getObject() {
209: return this .object;
210: }
211:
212: String getNameWithNamespace() {
213: if (namespace == null)
214: return name;
215: return "{" + namespace + "}" + name;
216: }
217:
218: /**
219: * This method will return the name without any namespace info.
220: */
221: String getName() {
222: return name;
223: }
224:
225: /**
226: * May return null.
227: */
228: String getNamespace() {
229: if (alias != null)
230: return alias.getNamespace();
231: return namespace;
232: }
233:
234: void setName(String name) {
235: // separate out the namespace
236: if (name.charAt(0) == '{') {
237: int closingBracket = name.indexOf('}');
238: this .name = name.substring(closingBracket + 1, name
239: .length());
240: this .namespace = name.substring(1, closingBracket);
241: } else {
242: this .name = name;
243: this .namespace = null;
244: }
245: }
246:
247: GraphLink getGraphLink() {
248: if (alias != null)
249: return alias.getGraphLink();
250: return this .link;
251: }
252:
253: void setGraphLink(GraphLink l) {
254: if (alias != null) {
255: alias.setGraphLink(l);
256: return;
257: }
258: link = l;
259: }
260:
261: void setMarked(boolean value) {
262: if (alias != null) {
263: alias.setMarked(value);
264: return;
265: }
266: marked = value;
267: }
268:
269: boolean getMarked() {
270: if (alias != null) {
271: return alias.getMarked();
272: }
273: return marked;
274: }
275:
276: boolean isAbstract() {
277: return isAbstract;
278: }
279:
280: void setAbstract(boolean value) {
281: isAbstract = value;
282: }
283:
284: void setCreated(boolean value) {
285: if (alias != null) {
286: alias.setCreated(value);
287: return;
288: }
289: created = value;
290: }
291:
292: boolean isCreated() {
293: if (alias != null) {
294: return alias.isCreated();
295: }
296: return created;
297: }
298:
299: /**
300: * These are generic properties that the schema parser wants to pass
301: * to the code generation phase.
302: */
303: public void setExtendedProperty(String name, Object value) {
304: if (alias != null) {
305: alias.setExtendedProperty(name, value);
306: return;
307: }
308: extendedProperties.put(name, value);
309: }
310:
311: /**
312: * These are generic properties that the schema parser wants to pass
313: * to the code generation phase.
314: */
315: public Object getExtendedProperty(String name) {
316: if (alias != null) {
317: return alias.getExtendedProperty(name);
318: }
319: return extendedProperties.get(name);
320: }
321:
322: void incrRefCount() {
323: /*
324: if (alias != null) {
325: alias.incrRefCount();
326: return;
327: }
328: */
329: ++refCount;
330: }
331:
332: int getRefCount() {
333: /*
334: if (alias != null) {
335: return alias.getRefCount();
336: }
337: */
338: return refCount;
339: }
340:
341: void setAlias(GraphNode n) {
342: alias = n;
343: }
344:
345: GraphNode getAlias() {
346: return alias;
347: }
348:
349: /**
350: * Returns the list of all the GraphNodes used directly by this
351: * element (this represent all the elements used to declare the
352: * current GraphNode definition in the DTD (only one level
353: * of the subtree of this element).
354: */
355: GraphNode[] getNodes() {
356: if (alias != null)
357: return alias.getNodes();
358: Map list = new HashMap();
359: gatherElements(this .link, list);
360: GraphNode[] ret = new GraphNode[list.size()];
361: return (GraphNode[]) list.values().toArray(ret);
362: }
363:
364: //
365: // Fill the hash table with the elements referenced by this element
366: // (All the elements in the right part of the DTD declaration)
367: //
368: private void gatherElements(GraphLink l, Map list) {
369: while (l != null) {
370: if (l.element != null)
371: list.put(l.element.getName(), l.element);
372:
373: gatherElements(l.getFirstChild(), list);
374:
375: l = l.getSibling();
376: }
377: }
378:
379: public void setJavaType(String jt) {
380: if (alias != null) {
381: alias.setJavaType(jt);
382: return;
383: }
384: javaType = jt;
385: }
386:
387: public String getJavaType() {
388: if (alias != null) {
389: return alias.getJavaType();
390: }
391: return javaType;
392: }
393:
394: public void setExtension(GraphNode extendsNode) {
395: if (alias != null) {
396: alias.setExtension(extendsNode);
397: return;
398: }
399: this .extendsNode = extendsNode;
400: }
401:
402: public GraphNode getExtension() {
403: if (alias != null)
404: return alias.extendsNode;
405: return extendsNode;
406: }
407:
408: public boolean isUnion() {
409: return isUnion;
410: }
411:
412: public void setUnion(boolean value) {
413: isUnion = value;
414: }
415:
416: public void addExtraData(Object data) {
417: extraData.add(data);
418: }
419:
420: public void addExtraDataIncludeAlias(Object data) {
421: extraData.add(data);
422: if (alias != null)
423: alias.addExtraData(data);
424: }
425:
426: public Object searchExtraData(Class type) {
427: for (Iterator it = extraData.iterator(); it.hasNext();) {
428: Object o = it.next();
429: //System.out.println("searchExtraData: o="+o);
430: if (type.isAssignableFrom(o.getClass()))
431: return o;
432: }
433: return null;
434: }
435:
436: public Iterator extraDataIterator() {
437: return extraData.iterator();
438: }
439:
440: public Set getExtraData() {
441: return extraData;
442: }
443:
444: public String toString() {
445: if (alias != null) {
446: return name + " (is a " + alias.toString() + ")";
447: }
448: return getNameWithNamespace();
449: }
450: }
|