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 java.util.List;
045: import java.util.ArrayList;
046: import java.util.Iterator;
047:
048: import org.netbeans.modules.schema2beans.*;
049:
050: /**
051: * @see GraphNode
052: *
053: * Roughtly, a GraphLink is used to hold attribute definitions or groupings.
054: */
055: public class GraphLink {
056: /*
057: * The element that this link is associated to. This element might
058: * be referenced by more than one GraphLink object.
059: */
060: GraphNode element;
061:
062: /*
063: * Where this object is coming from.
064: */
065: private GraphLink parent;
066:
067: /*
068: * Point to the next link holding information about the element
069: * in the sequence.
070: *
071: * For example <!ELEMENT elt (a, b, c)>
072: *
073: * If this link element references a, the sibling references a link
074: * object defining the element b.
075: *
076: */
077: private GraphLink sibling;
078:
079: /*
080: * Point to a subnode link defining information about an element
081: * defined in a "one-more level of parenthese".
082: *
083: * For example <!ELEMENT elt (a, (b | c)+, d>
084: *
085: * If this link element references a, the sibling references a link
086: * object defining the element d and the child link element references
087: * a link defining the element b (this link has itself a sibling link
088: * on a link object defining c). Note that the prop of the child link
089: * element will be: SEQUENCE_OR | INSTANCE_1N.
090: *
091: */
092: private GraphLink child;
093:
094: private transient GraphLink lastChild; // cache
095:
096: /*
097: * The prop integers define some properties on the link or element.
098: * The link might either start to define a list of nodes as
099: * a sequence of nodes: a and b and c, or it might define
100: * a list of node choices: a or b or c.
101: *
102: * For example <!ELEMENT elt (a, b, c)> -> sequence
103: * <!ELEMENT elt (a | b | c)> -> choice
104: *
105: *
106: * Also, the set of nodes defined by the link might have some
107: * rules as they should be instanciated (as defined by the ?, * and +
108: * DTD characters).
109: *
110: * propElement applies to the element of this link (one element of the
111: * DTD represented by a unique GraphNode might have different
112: * property values depending where and how the element is referenced
113: * by other elements).
114: * propChildren applies to the set of children of this GraphLink.
115: *
116: * For example, <ELEMENT! elt a?, (b, c, d)+ e>
117: *
118: * The link associated to the element a has the propElement set to the
119: * ? value and the propChildren set to the + value.
120: */
121: int propElement;
122: int propChildren;
123:
124: /**
125: * Name of the java bean property (java class attribute) that we're
126: * defining. If it's null, then we're used for grouping.
127: */
128: String name;
129: private String schemaName = null;
130: private String namespace = null;
131: private String defaultValue;
132: private boolean nillable;
133:
134: private Object object;
135:
136: List extraData = new ArrayList();
137:
138: GraphLink(String name) {
139: // Those are the default values
140: this .propElement = Common.SEQUENCE_AND | Common.TYPE_1;
141: this .propChildren = Common.SEQUENCE_AND | Common.TYPE_1;
142: this .name = name;
143: this .schemaName = name;
144: }
145:
146: GraphLink(String name, String namespace) {
147: // Those are the default values
148: this .propElement = Common.SEQUENCE_AND | Common.TYPE_1;
149: this .propChildren = Common.SEQUENCE_AND | Common.TYPE_1;
150: this .name = name;
151: this .namespace = namespace;
152: this .schemaName = name;
153: }
154:
155: public String getNamespace() {
156: return namespace;
157: }
158:
159: public boolean isUnion() {
160: return element.isUnion();
161: }
162:
163: public void setUnion(boolean value) {
164: element.setUnion(value);
165: }
166:
167: public List getChildren() { // List<GraphLink>
168: List result = new ArrayList();
169: for (GraphLink l = child; l != null; l = l.sibling)
170: result.add(l);
171: return result;
172: }
173:
174: /**
175: * Return our parents children minus this.
176: */
177: public List getSiblings() { // List<GraphLink>
178: List result = new ArrayList();
179: if (parent == null) {
180: // The graph isn't well connected, assume I'm first child.
181: for (GraphLink l = this ; l != null; l = l.sibling)
182: result.add(l);
183: return result;
184: }
185: for (GraphLink l = parent.child; l != null; l = l.sibling) {
186: if (l == this )
187: continue;
188: result.add(l);
189: }
190: return result;
191: }
192:
193: /**
194: * Return our parents children.
195: */
196: public List getSiblingsAndMe() { // List<GraphLink>
197: if (parent == null) {
198: // The graph isn't well connected, assume I'm first child.
199: List result = new ArrayList();
200: for (GraphLink l = this ; l != null; l = l.sibling)
201: result.add(l);
202: return result;
203: }
204: return parent.getChildren();
205: }
206:
207: /**
208: * Get next sibling. This might return null.
209: */
210: public GraphLink getSibling() {
211: return sibling;
212: }
213:
214: public GraphLink getLastSibling() {
215: // Check if our parent has kept track of it.
216: if (parent != null && parent.lastChild != null)
217: return parent.getLastChild();
218: if (sibling == null)
219: return this ;
220: else
221: return sibling.getLastSibling();
222: }
223:
224: /**
225: * This might return null.
226: */
227: public GraphLink getFirstChild() {
228: return child;
229: }
230:
231: /**
232: * This might return null.
233: */
234: public GraphLink getLastChild() {
235: if (lastChild == null) {
236: if (child != null)
237: lastChild = child.getLastSibling();
238: }
239: return lastChild;
240: }
241:
242: /**
243: * Replaces child list.
244: */
245: public void setChild(GraphLink l) {
246: child = l;
247: child.parent = this ;
248: lastChild = null;
249: }
250:
251: private void addSibling(GraphLink l) {
252: if (sibling != null)
253: throw new RuntimeException("I am not the last sibling!");
254: sibling = l;
255: // Siblings share the same parent
256: l.parent = parent;
257: if (parent != null)
258: parent.lastChild = l;
259: }
260:
261: /**
262: * Adds child to end of child list.
263: */
264: public void addChild(GraphLink l) {
265: if (child == null)
266: setChild(l);
267: else
268: child.getLastSibling().addSibling(l);
269: }
270:
271: /**
272: * This might return null.
273: */
274: public GraphLink getParent() {
275: return parent;
276: }
277:
278: private void setParent(GraphLink l) {
279: parent = l;
280: }
281:
282: boolean isSequenceAnd() {
283: // Apply only to the set of children
284: return ((this .propChildren & Common.SEQUENCE_AND) == Common.SEQUENCE_AND);
285: }
286:
287: boolean isSequenceOr() {
288: // Apply only to the set of children
289: return ((this .propChildren & Common.SEQUENCE_OR) == Common.SEQUENCE_OR);
290: }
291:
292: void setSequence(int prop) {
293: this .propChildren = (this .propChildren & Common.MASK_TYPE)
294: | prop;
295: }
296:
297: void setElementInstance(int instance) {
298: this .propElement = (this .propElement & Common.MASK_SEQUENCE)
299: | instance;
300: }
301:
302: int getElementInstance() {
303: return (this .propElement & Common.MASK_INSTANCE);
304: }
305:
306: void setGroupInstance(int instance) {
307: this .propChildren = (this .propChildren & Common.MASK_SEQUENCE)
308: | instance;
309: }
310:
311: int getGroupInstance() {
312: return (this .propChildren & Common.MASK_INSTANCE);
313: }
314:
315: /**
316: * Fill links with GraphLink's that we're mutually exclusive with.
317: */
318: public void getMutuallyExclusiveLinks(List links) { // List<GraphLink>
319: if (parent == null)
320: return;
321: //
322: // Mutual exclusion is caused by xsd:choice or '|': (a|b|c)
323: // From b's perspective, it's mutually exclusive with a and c.
324: // From a's perspective, it's mutually exclusive with b and c, etc.
325: // However, if the groupInstance can be more than 1, then
326: // we're not mutually exclusive: (a|b|c)*
327: //
328: if (parent.isSequenceOr()
329: && (parent.getGroupInstance() == Common.TYPE_1 || parent
330: .getGroupInstance() == Common.TYPE_0_1)) {
331: for (Iterator it = getSiblings().iterator(); it.hasNext();) {
332: GraphLink l = (GraphLink) it.next();
333: l.findAllBelowBranch(links);
334: }
335: }
336: parent.getMutuallyExclusiveLinks(links);
337: }
338:
339: /**
340: * Starting from this GraphLink, fill in all links below it, including
341: * this one.
342: */
343: public void findAllBelowBranch(List links) { // List<GraphLink>
344: links.add(this );
345: if (child != null)
346: child.findAllBelowBranchAndSiblings(links);
347: }
348:
349: public void findAllBelowBranchAndSiblings(List links) { // List<GraphLink>
350: GraphLink l = this ;
351: for (; l != null; l = l.sibling) {
352: links.add(l);
353: if (l.child != null)
354: l.child.findAllBelowBranchAndSiblings(links);
355: }
356: }
357:
358: String getDefaultValue() {
359: return defaultValue;
360: }
361:
362: void setDefaultValue(String d) {
363: defaultValue = d;
364: }
365:
366: void setObject(Object obj) {
367: this .object = obj;
368: }
369:
370: Object getObject() {
371: return this .object;
372: }
373:
374: boolean isNillable() {
375: return nillable;
376: }
377:
378: void setNillable(boolean value) {
379: nillable = value;
380: }
381:
382: String getSchemaName() {
383: return schemaName;
384: }
385:
386: public XPathIterator xPathIterator(String xpath) {
387: return new XPathIterator(this , xpath);
388: }
389:
390: public static class XPathIterator implements java.util.Iterator {
391: private String xpath;
392: private String step;
393: private GraphLink curLink;
394: private int position;
395:
396: public XPathIterator(GraphLink startingLink, String xpath) {
397: this .xpath = xpath;
398: curLink = startingLink;
399: findNextStep();
400: }
401:
402: // Figure out the next step, and advance the state.
403: private void findNextStep() {
404: if (position >= xpath.length()) {
405: step = null;
406: return;
407: }
408: int startingPos = position;
409: for (; position < xpath.length(); ++position) {
410: if (xpath.charAt(position) == '/') {
411: step = xpath.substring(startingPos, position);
412: ++position;
413: if (".".equals(step)) {
414: // skip over intermediate '.'s
415: startingPos = position;
416: } else {
417: return;
418: }
419: }
420: }
421: step = xpath.substring(startingPos, position);
422: if (startingPos > 0 && ".".equals(step)) {
423: step = null;
424: }
425: }
426:
427: public boolean hasNext() {
428: if (step == null)
429: return false;
430: return true;
431: }
432:
433: /**
434: * Returns GraphLink's
435: */
436: public Object next() {
437: if (step == null)
438: throw new java.util.NoSuchElementException();
439: GraphLink result = curLink;
440: while (".".equals(step)) {
441: findNextStep();
442: if (step == null)
443: return result;
444: }
445: // Don't deal with namespaces
446: int colonPos = step.indexOf(':');
447: if (colonPos >= 0)
448: step = step.substring(colonPos + 1, step.length());
449: //System.out.println("step="+step);
450: // Now go look for step
451: result = result.lookForChild(step);
452: if (result == null) {
453: // Not found.
454: step = null;
455: position = xpath.length();
456: return null;
457: }
458: if (result.element == null) {
459: curLink = null;
460: } else {
461: curLink = result.element.getGraphLink();
462: }
463:
464: findNextStep();
465: return result;
466: }
467:
468: public void remove() {
469: throw new UnsupportedOperationException();
470: }
471: }
472:
473: /**
474: * Look amongst out children to see if we have one where
475: * searchName.equals(getSchemaName())
476: */
477: GraphLink lookForChild(String searchName) {
478: /*
479: System.out.println("this="+this);
480: System.out.println("this.element="+this.element);
481: System.out.println("this.schemaName="+this.getSchemaName());
482: System.out.println("this.sibling="+this.sibling);
483: System.out.println("this.child="+this.child);
484: */
485:
486: if (searchName.equals(getSchemaName()))
487: return this ;
488: if (name == null) {
489: //System.out.println("Grouping");
490: if (child != null) {
491: GraphLink childResult = child.lookForChild(searchName);
492: if (childResult != null)
493: return childResult;
494: }
495: }
496: if (sibling != null)
497: return sibling.lookForChild(searchName);
498: if (child != null)
499: return child.lookForChild(searchName);
500: return null;
501: }
502: }
|