1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.xsom.impl.util;
  27 
  28 import com.sun.xml.internal.xsom.XSAnnotation;
  29 import com.sun.xml.internal.xsom.XSAttGroupDecl;
  30 import com.sun.xml.internal.xsom.XSAttributeDecl;
  31 import com.sun.xml.internal.xsom.XSAttributeUse;
  32 import com.sun.xml.internal.xsom.XSComplexType;
  33 import com.sun.xml.internal.xsom.XSContentType;
  34 import com.sun.xml.internal.xsom.XSElementDecl;
  35 import com.sun.xml.internal.xsom.XSFacet;
  36 import com.sun.xml.internal.xsom.XSIdentityConstraint;
  37 import com.sun.xml.internal.xsom.XSListSimpleType;
  38 import com.sun.xml.internal.xsom.XSModelGroup;
  39 import com.sun.xml.internal.xsom.XSModelGroupDecl;
  40 import com.sun.xml.internal.xsom.XSNotation;
  41 import com.sun.xml.internal.xsom.XSParticle;
  42 import com.sun.xml.internal.xsom.XSRestrictionSimpleType;
  43 import com.sun.xml.internal.xsom.XSSchema;
  44 import com.sun.xml.internal.xsom.XSSchemaSet;
  45 import com.sun.xml.internal.xsom.XSSimpleType;
  46 import com.sun.xml.internal.xsom.XSType;
  47 import com.sun.xml.internal.xsom.XSUnionSimpleType;
  48 import com.sun.xml.internal.xsom.XSWildcard;
  49 import com.sun.xml.internal.xsom.XSXPath;
  50 import com.sun.xml.internal.xsom.impl.Const;
  51 import com.sun.xml.internal.xsom.visitor.XSSimpleTypeVisitor;
  52 import com.sun.xml.internal.xsom.visitor.XSTermVisitor;
  53 import com.sun.xml.internal.xsom.visitor.XSVisitor;
  54 import org.xml.sax.Locator;
  55 
  56 import javax.swing.Box;
  57 import javax.swing.Icon;
  58 import javax.swing.JLabel;
  59 import javax.swing.JPanel;
  60 import javax.swing.JTree;
  61 import javax.swing.tree.DefaultMutableTreeNode;
  62 import javax.swing.tree.DefaultTreeModel;
  63 import javax.swing.tree.TreeCellRenderer;
  64 import java.awt.Color;
  65 import java.awt.Component;
  66 import java.awt.FlowLayout;
  67 import java.awt.Font;
  68 import java.awt.Graphics;
  69 import java.math.BigInteger;
  70 import java.text.MessageFormat;
  71 import java.util.Iterator;
  72 
  73 /**
  74  * Generates approximated tree model for XML from a schema component. This is
  75  * not intended to be a fully-fledged round-trippable tree model.
  76  *
  77  * <h2>Usage of this class</h2>
  78  *
  79  * <ol> <li>Create a new instance.</li> <li>Call {@link
  80  * #visit(com.sun.xml.internal.xsom.XSSchemaSet)} function on your schema set.>/li>
  81  * <li>Retrieve the model using {@link #getModel()}. </li></ol>
  82  *
  83  * Every node in the resulting tree is a {@link SchemaTreeTraverser.SchemaTreeNode},
  84  * and the model itself is {@link SchemaTreeTraverser.SchemaTreeModel}. You can
  85  * use {@link SchemaTreeTraverser.SchemaTreeCellRenderer} as a cell renderer for
  86  * your tree.
  87  *
  88  * @author Kirill Grouchnikov (kirillcool@yahoo.com)
  89  */
  90 public class SchemaTreeTraverser implements XSVisitor, XSSimpleTypeVisitor {
  91     /**
  92      * The associated tree model.
  93      */
  94     private SchemaTreeModel model;
  95 
  96     /**
  97      * The current node in the tree.
  98      */
  99     private SchemaTreeNode currNode;
 100 
 101     /**
 102      * Tree model for schema hierarchy tree.
 103      *
 104      * @author Kirill Grouchnikov
 105      */
 106     public static final class SchemaTreeModel extends DefaultTreeModel {
 107         /**
 108          * A simple constructor. Is made private to allow creating the root node
 109          * first.
 110          *
 111          * @param root The root node.
 112          */
 113         private SchemaTreeModel(SchemaRootNode root) {
 114             super(root);
 115         }
 116 
 117         /**
 118          * A factory method for creating a new empty tree.
 119          *
 120          * @return New empty tree model.
 121          */
 122         public static SchemaTreeModel getInstance() {
 123             SchemaRootNode root = new SchemaRootNode();
 124             return new SchemaTreeModel(root);
 125         }
 126 
 127         public void addSchemaNode(SchemaTreeNode node) {
 128             ((SchemaRootNode) this.root).add(node);
 129         }
 130     }
 131 
 132     /**
 133      * The node of the schema hierarchy tree.
 134      *
 135      * @author Kirill Grouchnikov
 136      */
 137     public static class SchemaTreeNode extends DefaultMutableTreeNode {
 138         /**
 139          * File name of the corresponding schema artifact.
 140          */
 141         private String fileName;
 142 
 143         /**
 144          * Line number of the corresponding schema artifact.
 145          */
 146         private int lineNumber;
 147 
 148         /**
 149          * The caption of the corresponding artifact.
 150          */
 151         private String artifactName;
 152 
 153         /**
 154          * Simple constructor.
 155          *
 156          * @param artifactName Artifact name.
 157          * @param locator      Artifact locator.
 158          */
 159         public SchemaTreeNode(String artifactName, Locator locator) {
 160             this.artifactName = artifactName;
 161             if (locator == null) {
 162                 this.fileName = null;
 163             }
 164             else {
 165                 String filename = locator.getSystemId();
 166                 filename = filename.replaceAll("\u002520", " ");
 167                 // strip leading protocol
 168                 if (filename.startsWith("file:/")) {
 169                     filename = filename.substring(6);
 170                 }
 171 
 172                 this.fileName = filename;
 173                 this.lineNumber = locator.getLineNumber() - 1;
 174             }
 175         }
 176 
 177         /**
 178          * Returns the caption for <code>this</code> node.
 179          *
 180          * @return The caption for <code>this</code> node.
 181          */
 182         public String getCaption() {
 183             return this.artifactName;
 184         }
 185 
 186         /**
 187          * @return Returns the file name of the corresponding schema artifact.
 188          */
 189         public String getFileName() {
 190             return fileName;
 191         }
 192 
 193         /**
 194          * @param fileName The file name of the corresponding schema artifact to
 195          *                 set.
 196          */
 197         public void setFileName(String fileName) {
 198             this.fileName = fileName;
 199         }
 200 
 201         /**
 202          * @return Returns the line number of the corresponding schema
 203          *         artifact.
 204          */
 205         public int getLineNumber() {
 206             return lineNumber;
 207         }
 208 
 209         /**
 210          * @param lineNumber The line number of the corresponding schema
 211          *                   artifact to set.
 212          */
 213         public void setLineNumber(int lineNumber) {
 214             this.lineNumber = lineNumber;
 215         }
 216     }
 217 
 218     /**
 219      * The root node of the schema hierarchy tree.
 220      *
 221      * @author Kirill Grouchnikov
 222      */
 223     public static class SchemaRootNode extends SchemaTreeNode {
 224         /**
 225          * A simple constructor.
 226          */
 227         public SchemaRootNode() {
 228             super("Schema set", null);
 229         }
 230     }
 231 
 232 
 233     /**
 234      * Sample cell renderer for the schema tree.
 235      *
 236      * @author Kirill Grouchnikov
 237      */
 238     public static class SchemaTreeCellRenderer extends JPanel implements
 239             TreeCellRenderer {
 240         /**
 241          * The icon label.
 242          */
 243         protected final JLabel iconLabel;
 244 
 245         /**
 246          * The text label
 247          */
 248         protected final JLabel nameLabel;
 249 
 250         /**
 251          * The selection indicator.
 252          */
 253         private boolean isSelected;
 254 
 255         /**
 256          * Background color for selected cells (light brown).
 257          */
 258         public final Color selectedBackground = new Color(255, 244, 232);
 259 
 260 
 261         /**
 262          * Foreground color for selected cells, both text and border (dark
 263          * brown).
 264          */
 265         public final Color selectedForeground = new Color(64, 32, 0);
 266 
 267         /**
 268          * Default font for the text label.
 269          */
 270         public final Font nameFont = new Font("Arial", Font.BOLD, 12);
 271 
 272 
 273         /**
 274          * Simple constructor.
 275          */
 276         public SchemaTreeCellRenderer() {
 277             FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 1, 1);
 278             this.setLayout(fl);
 279             this.iconLabel = new JLabel();
 280             this.iconLabel.setOpaque(false);
 281             this.iconLabel.setBorder(null);
 282             this.add(this.iconLabel);
 283 
 284             // add some space
 285             this.add(Box.createHorizontalStrut(5));
 286 
 287             this.nameLabel = new JLabel();
 288             this.nameLabel.setOpaque(false);
 289             this.nameLabel.setBorder(null);
 290             this.nameLabel.setFont(nameFont);
 291             this.add(this.nameLabel);
 292 
 293             this.isSelected = false;
 294 
 295             this.setOpaque(false);
 296             this.setBorder(null);
 297         }
 298 
 299         /*
 300          * (non-Javadoc)
 301          *
 302          * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
 303          */
 304         public final void paintComponent(Graphics g) {
 305             int width = this.getWidth();
 306             int height = this.getHeight();
 307             if (this.isSelected) {
 308                 g.setColor(selectedBackground);
 309                 g.fillRect(0, 0, width - 1, height - 1);
 310                 g.setColor(selectedForeground);
 311                 g.drawRect(0, 0, width - 1, height - 1);
 312             }
 313             super.paintComponent(g);
 314         }
 315 
 316         /**
 317          * Sets values for the icon and text of <code>this</code> renderer.
 318          *
 319          * @param icon     Icon to show.
 320          * @param caption  Text to show.
 321          * @param selected Selection indicator. If <code>true</code>, the
 322          *                 renderer will be shown with different background and
 323          *                 border settings.
 324          */
 325         protected final void setValues(Icon icon, String caption,
 326                                        boolean selected) {
 327 
 328             this.iconLabel.setIcon(icon);
 329             this.nameLabel.setText(caption);
 330 
 331             this.isSelected = selected;
 332             if (selected) {
 333                 this.nameLabel.setForeground(selectedForeground);
 334             }
 335             else {
 336                 this.nameLabel.setForeground(Color.black);
 337             }
 338         }
 339 
 340         /* (non-Javadoc)
 341          * @see javax.swing.tree.TreeCellRenderer#getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, boolean, boolean, boolean, int, boolean)
 342          */
 343         public final Component getTreeCellRendererComponent(JTree tree, Object value,
 344                                                             boolean selected, boolean expanded, boolean leaf, int row,
 345                                                             boolean hasFocus) {
 346             if (value instanceof SchemaTreeNode) {
 347                 SchemaTreeNode stn = (SchemaTreeNode) value;
 348 
 349                 this.setValues(null, stn.getCaption(), selected);
 350                 return this;
 351             }
 352             throw new IllegalStateException("Unknown node");
 353         }
 354     }
 355 
 356 
 357     /**
 358      * Simple constructor.
 359      */
 360     public SchemaTreeTraverser() {
 361         this.model = SchemaTreeModel.getInstance();
 362         this.currNode = (SchemaTreeNode) this.model.getRoot();
 363     }
 364 
 365     /**
 366      * Retrieves the tree model of <code>this</code> traverser.
 367      *
 368      * @return Tree model of <code>this</code> traverser.
 369      */
 370     public SchemaTreeModel getModel() {
 371         return model;
 372     }
 373 
 374     /**
 375      * Visits the root schema set.
 376      *
 377      * @param s Root schema set.
 378      */
 379     public void visit(XSSchemaSet s) {
 380         for (XSSchema schema : s.getSchemas()) {
 381             schema(schema);
 382         }
 383     }
 384 
 385     /* (non-Javadoc)
 386      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#schema(com.sun.xml.internal.xsom.XSSchema)
 387      */
 388     public void schema(XSSchema s) {
 389         // QUICK HACK: don't print the built-in components
 390         if (s.getTargetNamespace().equals(Const.schemaNamespace)) {
 391             return;
 392         }
 393 
 394         SchemaTreeNode newNode = new SchemaTreeNode("Schema "
 395                 + s.getLocator().getSystemId(), s.getLocator());
 396         this.currNode = newNode;
 397         this.model.addSchemaNode(newNode);
 398 
 399         for (XSAttGroupDecl groupDecl : s.getAttGroupDecls().values()) {
 400             attGroupDecl(groupDecl);
 401         }
 402 
 403         for (XSAttributeDecl attrDecl : s.getAttributeDecls().values()) {
 404             attributeDecl(attrDecl);
 405         }
 406 
 407         for (XSComplexType complexType : s.getComplexTypes().values()) {
 408             complexType(complexType);
 409         }
 410 
 411         for (XSElementDecl elementDecl : s.getElementDecls().values()) {
 412             elementDecl(elementDecl);
 413         }
 414 
 415         for (XSModelGroupDecl modelGroupDecl : s.getModelGroupDecls().values()) {
 416             modelGroupDecl(modelGroupDecl);
 417         }
 418 
 419         for (XSSimpleType simpleType : s.getSimpleTypes().values()) {
 420             simpleType(simpleType);
 421         }
 422     }
 423 
 424     /* (non-Javadoc)
 425      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#attGroupDecl(com.sun.xml.internal.xsom.XSAttGroupDecl)
 426      */
 427     public void attGroupDecl(XSAttGroupDecl decl) {
 428         SchemaTreeNode newNode = new SchemaTreeNode("Attribute group \""
 429                 + decl.getName() + "\"", decl.getLocator());
 430         this.currNode.add(newNode);
 431         this.currNode = newNode;
 432 
 433         Iterator itr;
 434 
 435         itr = decl.iterateAttGroups();
 436         while (itr.hasNext()) {
 437             dumpRef((XSAttGroupDecl) itr.next());
 438         }
 439 
 440         itr = decl.iterateDeclaredAttributeUses();
 441         while (itr.hasNext()) {
 442             attributeUse((XSAttributeUse) itr.next());
 443         }
 444 
 445         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 446     }
 447 
 448     /**
 449      * Creates node of attribute group decalration reference.
 450      *
 451      * @param decl Attribute group decalration reference.
 452      */
 453     public void dumpRef(XSAttGroupDecl decl) {
 454         SchemaTreeNode newNode = new SchemaTreeNode("Attribute group ref \"{"
 455                 + decl.getTargetNamespace() + "}" + decl.getName() + "\"", decl
 456                 .getLocator());
 457         this.currNode.add(newNode);
 458     }
 459 
 460     /* (non-Javadoc)
 461      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#attributeUse(com.sun.xml.internal.xsom.XSAttributeUse)
 462      */
 463     public void attributeUse(XSAttributeUse use) {
 464         XSAttributeDecl decl = use.getDecl();
 465 
 466         String additionalAtts = "";
 467 
 468         if (use.isRequired()) {
 469             additionalAtts += " use=\"required\"";
 470         }
 471         if (use.getFixedValue() != null
 472                 && use.getDecl().getFixedValue() == null) {
 473             additionalAtts += " fixed=\"" + use.getFixedValue() + "\"";
 474         }
 475         if (use.getDefaultValue() != null
 476                 && use.getDecl().getDefaultValue() == null) {
 477             additionalAtts += " default=\"" + use.getDefaultValue() + "\"";
 478         }
 479 
 480         if (decl.isLocal()) {
 481             // this is anonymous attribute use
 482             dump(decl, additionalAtts);
 483         }
 484         else {
 485             // reference to a global one
 486             String str = MessageFormat.format(
 487                     "Attribute ref \"'{'{0}'}'{1}{2}\"", new Object[]{
 488                         decl.getTargetNamespace(), decl.getName(),
 489                         additionalAtts});
 490             SchemaTreeNode newNode = new SchemaTreeNode(str, decl.getLocator());
 491             this.currNode.add(newNode);
 492         }
 493     }
 494 
 495     /* (non-Javadoc)
 496      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#attributeDecl(com.sun.xml.internal.xsom.XSAttributeDecl)
 497      */
 498     public void attributeDecl(XSAttributeDecl decl) {
 499         dump(decl, "");
 500     }
 501 
 502     /**
 503      * Creates node for attribute declaration with additional attributes.
 504      *
 505      * @param decl           Attribute declaration.
 506      * @param additionalAtts Additional attributes.
 507      */
 508     private void dump(XSAttributeDecl decl, String additionalAtts) {
 509         XSSimpleType type = decl.getType();
 510 
 511         String str = MessageFormat.format("Attribute \"{0}\"{1}{2}{3}{4}",
 512                 new Object[]{
 513                     decl.getName(),
 514                     additionalAtts,
 515                     type.isLocal() ? "" : MessageFormat.format(
 516                             " type=\"'{'{0}'}'{1}\"", new Object[]{
 517                                 type.getTargetNamespace(),
 518                                 type.getName()}),
 519                     decl.getFixedValue() == null ? "" : " fixed=\""
 520                 + decl.getFixedValue() + "\"",
 521                     decl.getDefaultValue() == null ? "" : " default=\""
 522                 + decl.getDefaultValue() + "\""});
 523 
 524         SchemaTreeNode newNode = new SchemaTreeNode(str, decl.getLocator());
 525         this.currNode.add(newNode);
 526         this.currNode = newNode;
 527 
 528         if (type.isLocal()) {
 529             simpleType(type);
 530         }
 531         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 532     }
 533 
 534     /* (non-Javadoc)
 535      * @see com.sun.xml.internal.xsom.visitor.XSContentTypeVisitor#simpleType(com.sun.xml.internal.xsom.XSSimpleType)
 536      */
 537     public void simpleType(XSSimpleType type) {
 538 
 539         String str = MessageFormat.format("Simple type {0}",
 540                 new Object[]{type.isLocal() ? "" : " name=\""
 541                 + type.getName() + "\""});
 542 
 543         SchemaTreeNode newNode = new SchemaTreeNode(str, type.getLocator());
 544         this.currNode.add(newNode);
 545         this.currNode = newNode;
 546 
 547         type.visit((XSSimpleTypeVisitor) this);
 548 
 549         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 550     }
 551 
 552     /* (non-Javadoc)
 553      * @see com.sun.xml.internal.xsom.visitor.XSSimpleTypeVisitor#listSimpleType(com.sun.xml.internal.xsom.XSListSimpleType)
 554      */
 555     public void listSimpleType(XSListSimpleType type) {
 556         XSSimpleType itemType = type.getItemType();
 557 
 558         if (itemType.isLocal()) {
 559             SchemaTreeNode newNode = new SchemaTreeNode("List", type
 560                     .getLocator());
 561             this.currNode.add(newNode);
 562             this.currNode = newNode;
 563             simpleType(itemType);
 564             this.currNode = (SchemaTreeNode) this.currNode.getParent();
 565         }
 566         else {
 567             // global type
 568             String str = MessageFormat.format("List itemType=\"'{'{0}'}'{1}\"",
 569                     new Object[]{itemType.getTargetNamespace(),
 570                                  itemType.getName()});
 571             SchemaTreeNode newNode = new SchemaTreeNode(str, itemType
 572                     .getLocator());
 573             this.currNode.add(newNode);
 574         }
 575     }
 576 
 577     /* (non-Javadoc)
 578      * @see com.sun.xml.internal.xsom.visitor.XSSimpleTypeVisitor#unionSimpleType(com.sun.xml.internal.xsom.XSUnionSimpleType)
 579      */
 580     public void unionSimpleType(XSUnionSimpleType type) {
 581         final int len = type.getMemberSize();
 582         StringBuffer ref = new StringBuffer();
 583 
 584         for (int i = 0; i < len; i++) {
 585             XSSimpleType member = type.getMember(i);
 586             if (member.isGlobal()) {
 587                 ref.append(MessageFormat.format(" '{'{0}'}'{1}",
 588                         new Object[]{
 589                             member.getTargetNamespace(),
 590                             member.getName()}));
 591             }
 592         }
 593 
 594         String name = (ref.length() == 0) ? "Union" : ("Union memberTypes=\""
 595                 + ref + "\"");
 596         SchemaTreeNode newNode = new SchemaTreeNode(name, type.getLocator());
 597         this.currNode.add(newNode);
 598         this.currNode = newNode;
 599 
 600         for (int i = 0; i < len; i++) {
 601             XSSimpleType member = type.getMember(i);
 602             if (member.isLocal()) {
 603                 simpleType(member);
 604             }
 605         }
 606         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 607     }
 608 
 609     /* (non-Javadoc)
 610      * @see com.sun.xml.internal.xsom.visitor.XSSimpleTypeVisitor#restrictionSimpleType(com.sun.xml.internal.xsom.XSRestrictionSimpleType)
 611      */
 612     public void restrictionSimpleType(XSRestrictionSimpleType type) {
 613 
 614         if (type.getBaseType() == null) {
 615             // don't print anySimpleType
 616             if (!type.getName().equals("anySimpleType")) {
 617                 throw new InternalError();
 618             }
 619             if (!Const.schemaNamespace.equals(type.getTargetNamespace())) {
 620                 throw new InternalError();
 621             }
 622             return;
 623         }
 624 
 625         XSSimpleType baseType = type.getSimpleBaseType();
 626 
 627         String str = MessageFormat.format("Restriction {0}",
 628                 new Object[]{baseType.isLocal() ? "" : " base=\"{"
 629                 + baseType.getTargetNamespace() + "}"
 630                 + baseType.getName() + "\""});
 631 
 632         SchemaTreeNode newNode = new SchemaTreeNode(str, baseType.getLocator());
 633         this.currNode.add(newNode);
 634         this.currNode = newNode;
 635 
 636         if (baseType.isLocal()) {
 637             simpleType(baseType);
 638         }
 639 
 640         Iterator itr = type.iterateDeclaredFacets();
 641         while (itr.hasNext()) {
 642             facet((XSFacet) itr.next());
 643         }
 644 
 645         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 646     }
 647 
 648     /* (non-Javadoc)
 649      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#facet(com.sun.xml.internal.xsom.XSFacet)
 650      */
 651     public void facet(XSFacet facet) {
 652         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 653                 "{0} value=\"{1}\"", new Object[]{facet.getName(),
 654                                                   facet.getValue(), }),
 655                 facet.getLocator());
 656         this.currNode.add(newNode);
 657     }
 658 
 659     /* (non-Javadoc)
 660      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#notation(com.sun.xml.internal.xsom.XSNotation)
 661      */
 662     public void notation(XSNotation notation) {
 663         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 664                 "Notation name='\"0}\" public =\"{1}\" system=\"{2}\"",
 665                 new Object[]{notation.getName(), notation.getPublicId(),
 666                              notation.getSystemId()}), notation.getLocator());
 667         this.currNode.add(newNode);
 668     }
 669 
 670     /* (non-Javadoc)
 671      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#complexType(com.sun.xml.internal.xsom.XSComplexType)
 672      */
 673     public void complexType(XSComplexType type) {
 674         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 675                 "ComplexType {0}", new Object[]{type.isLocal() ? ""
 676                 : " name=\"" + type.getName() + "\""}), type
 677                 .getLocator());
 678         this.currNode.add(newNode);
 679         this.currNode = newNode;
 680 
 681         // TODO: wildcard
 682 
 683         if (type.getContentType().asSimpleType() != null) {
 684             // simple content
 685             SchemaTreeNode newNode2 = new SchemaTreeNode("Simple content", type
 686                     .getContentType().getLocator());
 687             this.currNode.add(newNode2);
 688             this.currNode = newNode2;
 689 
 690             XSType baseType = type.getBaseType();
 691 
 692             if (type.getDerivationMethod() == XSType.RESTRICTION) {
 693                 // restriction
 694                 String str = MessageFormat.format(
 695                         "Restriction base=\"<{0}>{1}\"", new Object[]{
 696                             baseType.getTargetNamespace(),
 697                             baseType.getName()});
 698                 SchemaTreeNode newNode3 = new SchemaTreeNode(str, baseType
 699                         .getLocator());
 700                 this.currNode.add(newNode3);
 701                 this.currNode = newNode3;
 702 
 703                 dumpComplexTypeAttribute(type);
 704 
 705                 this.currNode = (SchemaTreeNode) this.currNode.getParent();
 706             }
 707             else {
 708                 // extension
 709                 String str = MessageFormat.format(
 710                         "Extension base=\"<{0}>{1}\"", new Object[]{
 711                             baseType.getTargetNamespace(),
 712                             baseType.getName()});
 713                 SchemaTreeNode newNode3 = new SchemaTreeNode(str, baseType
 714                         .getLocator());
 715                 this.currNode.add(newNode3);
 716                 this.currNode = newNode3;
 717 
 718                 // check if have redefine tag
 719                 if ((type.getTargetNamespace().compareTo(
 720                         baseType.getTargetNamespace()) ==
 721                         0)
 722                         && (type.getName().compareTo(baseType.getName()) == 0)) {
 723                     SchemaTreeNode newNodeRedefine = new SchemaTreeNode(
 724                             "redefine", type
 725                             .getLocator());
 726                     this.currNode.add(newNodeRedefine);
 727                     this.currNode = newNodeRedefine;
 728                     baseType.visit(this);
 729                     this.currNode =
 730                             (SchemaTreeNode) newNodeRedefine.getParent();
 731                 }
 732 
 733                 dumpComplexTypeAttribute(type);
 734 
 735                 this.currNode = (SchemaTreeNode) this.currNode.getParent();
 736             }
 737 
 738             this.currNode = (SchemaTreeNode) this.currNode.getParent();
 739         }
 740         else {
 741             // complex content
 742             SchemaTreeNode newNode2 = new SchemaTreeNode("Complex content",
 743                     type.getContentType().getLocator());
 744             this.currNode.add(newNode2);
 745             this.currNode = newNode2;
 746 
 747             XSComplexType baseType = type.getBaseType().asComplexType();
 748 
 749             if (type.getDerivationMethod() == XSType.RESTRICTION) {
 750                 // restriction
 751                 String str = MessageFormat.format(
 752                         "Restriction base=\"<{0}>{1}\"", new Object[]{
 753                             baseType.getTargetNamespace(),
 754                             baseType.getName()});
 755                 SchemaTreeNode newNode3 = new SchemaTreeNode(str,
 756                         baseType.getLocator());
 757                 this.currNode.add(newNode3);
 758                 this.currNode = newNode3;
 759 
 760                 type.getContentType().visit(this);
 761                 dumpComplexTypeAttribute(type);
 762 
 763                 this.currNode = (SchemaTreeNode) this.currNode.getParent();
 764             }
 765             else {
 766                 // extension
 767                 String str = MessageFormat.format(
 768                         "Extension base=\"'{'{0}'}'{1}\"", new Object[]{
 769                             baseType.getTargetNamespace(),
 770                             baseType.getName()});
 771                 SchemaTreeNode newNode3 = new SchemaTreeNode(str,
 772                         baseType.getLocator());
 773                 this.currNode.add(newNode3);
 774                 this.currNode = newNode3;
 775 
 776                 // check if have redefine tag
 777                 if ((type.getTargetNamespace().compareTo(
 778                         baseType.getTargetNamespace()) ==
 779                         0)
 780                         && (type.getName().compareTo(baseType.getName()) == 0)) {
 781                     SchemaTreeNode newNodeRedefine = new SchemaTreeNode(
 782                             "redefine", type
 783                             .getLocator());
 784                     this.currNode.add(newNodeRedefine);
 785                     this.currNode = newNodeRedefine;
 786                     baseType.visit(this);
 787                     this.currNode =
 788                             (SchemaTreeNode) newNodeRedefine.getParent();
 789                 }
 790 
 791                 type.getExplicitContent().visit(this);
 792                 dumpComplexTypeAttribute(type);
 793 
 794                 this.currNode = (SchemaTreeNode) this.currNode.getParent();
 795             }
 796 
 797             this.currNode = (SchemaTreeNode) this.currNode.getParent();
 798         }
 799 
 800         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 801     }
 802 
 803     /**
 804      * Creates node for complex type.
 805      *
 806      * @param type Complex type.
 807      */
 808     private void dumpComplexTypeAttribute(XSComplexType type) {
 809         Iterator itr;
 810 
 811         itr = type.iterateAttGroups();
 812         while (itr.hasNext()) {
 813             dumpRef((XSAttGroupDecl) itr.next());
 814         }
 815 
 816         itr = type.iterateDeclaredAttributeUses();
 817         while (itr.hasNext()) {
 818             attributeUse((XSAttributeUse) itr.next());
 819         }
 820     }
 821 
 822     /* (non-Javadoc)
 823      * @see com.sun.xml.internal.xsom.visitor.XSTermVisitor#elementDecl(com.sun.xml.internal.xsom.XSElementDecl)
 824      */
 825     public void elementDecl(XSElementDecl decl) {
 826         elementDecl(decl, "");
 827     }
 828 
 829     /**
 830      * Creates node for element declaration with additional attributes.
 831      *
 832      * @param decl      Element declaration.
 833      * @param extraAtts Additional attributes.
 834      */
 835     private void elementDecl(XSElementDecl decl, String extraAtts) {
 836         XSType type = decl.getType();
 837 
 838         // TODO: various other attributes
 839 
 840         String str = MessageFormat.format("Element name=\"{0}\"{1}{2}",
 841                 new Object[]{
 842                     decl.getName(),
 843                     type.isLocal() ? "" : " type=\"{"
 844                 + type.getTargetNamespace() + "}"
 845                 + type.getName() + "\"", extraAtts});
 846 
 847         SchemaTreeNode newNode = new SchemaTreeNode(str, decl.getLocator());
 848         this.currNode.add(newNode);
 849         this.currNode = newNode;
 850 
 851         if (type.isLocal()) {
 852             if (type.isLocal()) {
 853                 type.visit(this);
 854             }
 855         }
 856 
 857         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 858     }
 859 
 860     /* (non-Javadoc)
 861      * @see com.sun.xml.internal.xsom.visitor.XSTermVisitor#modelGroupDecl(com.sun.xml.internal.xsom.XSModelGroupDecl)
 862      */
 863     public void modelGroupDecl(XSModelGroupDecl decl) {
 864         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 865                 "Group name=\"{0}\"", new Object[]{decl.getName()}),
 866                 decl.getLocator());
 867         this.currNode.add(newNode);
 868         this.currNode = newNode;
 869 
 870         modelGroup(decl.getModelGroup());
 871 
 872         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 873     }
 874 
 875     /* (non-Javadoc)
 876      * @see com.sun.xml.internal.xsom.visitor.XSTermVisitor#modelGroup(com.sun.xml.internal.xsom.XSModelGroup)
 877      */
 878     public void modelGroup(XSModelGroup group) {
 879         modelGroup(group, "");
 880     }
 881 
 882     /**
 883      * Creates node for model group with additional attributes.
 884      *
 885      * @param group     Model group.
 886      * @param extraAtts Additional attributes.
 887      */
 888     private void modelGroup(XSModelGroup group, String extraAtts) {
 889         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 890                 "{0}{1}", new Object[]{group.getCompositor(), extraAtts}),
 891                 group.getLocator());
 892         this.currNode.add(newNode);
 893         this.currNode = newNode;
 894 
 895         final int len = group.getSize();
 896         for (int i = 0; i < len; i++) {
 897             particle(group.getChild(i));
 898         }
 899 
 900         this.currNode = (SchemaTreeNode) this.currNode.getParent();
 901     }
 902 
 903     /* (non-Javadoc)
 904      * @see com.sun.xml.internal.xsom.visitor.XSContentTypeVisitor#particle(com.sun.xml.internal.xsom.XSParticle)
 905      */
 906     public void particle(XSParticle part) {
 907         BigInteger i;
 908 
 909         StringBuffer buf = new StringBuffer();
 910 
 911         i = part.getMaxOccurs();
 912         if (i.equals(BigInteger.valueOf(XSParticle.UNBOUNDED))) {
 913             buf.append(" maxOccurs=\"unbounded\"");
 914         }
 915         else {
 916             if (!i.equals(BigInteger.ONE)) {
 917                 buf.append(" maxOccurs=\"" + i + "\"");
 918             }
 919         }
 920 
 921         i = part.getMinOccurs();
 922         if (!i.equals(BigInteger.ONE)) {
 923             buf.append(" minOccurs=\"" + i + "\"");
 924         }
 925 
 926         final String extraAtts = buf.toString();
 927 
 928         part.getTerm().visit(new XSTermVisitor() {
 929             public void elementDecl(XSElementDecl decl) {
 930                 if (decl.isLocal()) {
 931                     SchemaTreeTraverser.this.elementDecl(decl, extraAtts);
 932                 }
 933                 else {
 934                     // reference
 935                     SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat
 936                             .format("Element ref=\"'{'{0}'}'{1}\"{2}",
 937                                     new Object[]{decl.getTargetNamespace(),
 938                                                  decl.getName(), extraAtts}),
 939                             decl.getLocator());
 940                     currNode.add(newNode);
 941                 }
 942             }
 943 
 944             public void modelGroupDecl(XSModelGroupDecl decl) {
 945                 // reference
 946                 SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat
 947                         .format("Group ref=\"'{'{0}'}'{1}\"{2}", new Object[]{
 948                             decl.getTargetNamespace(), decl.getName(),
 949                             extraAtts}), decl.getLocator());
 950                 currNode.add(newNode);
 951             }
 952 
 953             public void modelGroup(XSModelGroup group) {
 954                 SchemaTreeTraverser.this.modelGroup(group, extraAtts);
 955             }
 956 
 957             public void wildcard(XSWildcard wc) {
 958                 SchemaTreeTraverser.this.wildcard(wc, extraAtts);
 959             }
 960         });
 961     }
 962 
 963     /* (non-Javadoc)
 964      * @see com.sun.xml.internal.xsom.visitor.XSTermVisitor#wildcard(com.sun.xml.internal.xsom.XSWildcard)
 965      */
 966     public void wildcard(XSWildcard wc) {
 967         wildcard(wc, "");
 968     }
 969 
 970     /**
 971      * Creates node for wild card with additional attributes.
 972      *
 973      * @param wc        Wild card.
 974      * @param extraAtts Additional attributes.
 975      */
 976     private void wildcard(XSWildcard wc, String extraAtts) {
 977         // TODO
 978         SchemaTreeNode newNode = new SchemaTreeNode(MessageFormat.format(
 979                 "Any ", new Object[]{extraAtts}), wc.getLocator());
 980         currNode.add(newNode);
 981     }
 982 
 983     /* (non-Javadoc)
 984      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#annotation(com.sun.xml.internal.xsom.XSAnnotation)
 985      */
 986     public void annotation(XSAnnotation ann) {
 987         // TODO: it would be nice even if we just put <xs:documentation>
 988     }
 989 
 990     /* (non-Javadoc)
 991      * @see com.sun.xml.internal.xsom.visitor.XSContentTypeVisitor#empty(com.sun.xml.internal.xsom.XSContentType)
 992      */
 993     public void empty(XSContentType t) {
 994     }
 995 
 996     /* (non-Javadoc)
 997      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#identityConstraint(com.sun.xml.internal.xsom.XSIdentityConstraint)
 998      */
 999     public void identityConstraint(XSIdentityConstraint ic) {
1000     }
1001 
1002     /* (non-Javadoc)
1003      * @see com.sun.xml.internal.xsom.visitor.XSVisitor#xpath(com.sun.xml.internal.xsom.XSXPath)
1004      */
1005     public void xpath(XSXPath xp) {
1006     }
1007 }