Package com.eviware.soapui.support.xml

Source Code of com.eviware.soapui.support.xml.XmlObjectTreeModel$XmlTreeNode

/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/

package com.eviware.soapui.support.xml;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreePath;
import javax.xml.namespace.QName;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaGlobalElement;
import org.apache.xmlbeans.SchemaParticle;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlCursor.TokenType;
import org.apache.xmlbeans.XmlLineNumber;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
import com.eviware.soapui.support.types.StringToStringMap;

public class XmlObjectTreeModel implements TreeTableModel {
    private XmlObject xmlObject;
    private Set<TreeModelListener> listeners = new HashSet<TreeModelListener>();
    private XmlCursor cursor;
    private Map<XmlObject, XmlTreeNode> treeNodeMap = new HashMap<XmlObject, XmlTreeNode>();

    public final static Class<?> hierarchicalColumnClass = TreeTableModel.class;
    private SchemaTypeSystem typeSystem;
    private RootXmlTreeNode root;
    @SuppressWarnings("unused")
    private final static Logger log = Logger.getLogger(XmlObjectTreeModel.class);

    public XmlObjectTreeModel(XmlObject xmlObject) {
        this(XmlBeans.getBuiltinTypeSystem(), xmlObject);
    }

    public XmlObjectTreeModel() {
        this(XmlObject.Factory.newInstance());
    }

    public XmlObjectTreeModel(SchemaTypeSystem typeSystem, XmlObject xmlObject) {
        if (typeSystem == null) {
            typeSystem = XmlBeans.getBuiltinTypeSystem();
        }

        this.typeSystem = typeSystem;
        this.xmlObject = xmlObject;
        init();
    }

    public XmlObjectTreeModel(SchemaTypeSystem typeSystem) {
        this(typeSystem, XmlObject.Factory.newInstance());
    }

    private void init() {
        cursor = null;

        if (xmlObject != null) {
            cursor = xmlObject.newCursor();
            cursor.toStartDoc();
        }

        root = new RootXmlTreeNode(cursor);
    }

    public SchemaTypeSystem getTypeSystem() {
        return typeSystem;
    }

    public void setTypeSystem(SchemaTypeSystem typeSystem) {
        if (typeSystem == null) {
            typeSystem = XmlBeans.getBuiltinTypeSystem();
        }

        this.typeSystem = typeSystem;
    }

    public XmlObject getXmlObject() {
        return xmlObject;
    }

    public void setXmlObject(XmlObject xmlObject) {
        if (cursor != null) {
            cursor.dispose();
        }

        this.xmlObject = xmlObject;
        init();

        XmlTreeNode xmlTreeNode = ((XmlTreeNode) getRoot());
        fireTreeStructureChanged(xmlTreeNode);
    }

    protected void fireTreeStructureChanged(XmlTreeNode rootNode) {
        for (TreeModelListener listener : listeners) {
            listener.treeStructureChanged(new XmlTreeTableModelEvent(this, rootNode.getTreePath(), -1));
        }
    }

    public Class<?> getColumnClass(int arg0) {
        return arg0 == 0 ? hierarchicalColumnClass : XmlTreeNode.class;
    }

    public int getColumnCount() {
        return 3;
    }

    public String getColumnName(int arg0) {
        return null;
    }

    public Object getValueAt(Object arg0, int arg1) {
        return arg0; // ((XmlTreeNode)arg0).getValue( arg1 );
    }

    public boolean isCellEditable(Object arg0, int arg1) {
        return ((XmlTreeNode) arg0).isEditable(arg1);
    }

    public void setValueAt(Object arg0, Object arg1, int arg2) {
        XmlTreeNode treeNode = (XmlTreeNode) arg1;
        if (treeNode.setValue(arg2, arg0)) {
            fireTreeNodeChanged(treeNode, arg2);
        }
    }

    protected void fireTreeNodeChanged(XmlTreeNode treeNode, int column) {
        for (TreeModelListener listener : listeners) {
            listener.treeNodesChanged(new XmlTreeTableModelEvent(this, treeNode.getTreePath(), column));
        }
    }

    public void addTreeModelListener(TreeModelListener l) {
        listeners.add(l);
    }

    public Object getChild(Object parent, int index) {
        return ((XmlTreeNode) parent).getChild(index);
    }

    public int getChildCount(Object parent) {
        return ((XmlTreeNode) parent).getChildCount();
    }

    public int getIndexOfChild(Object parent, Object child) {
        return ((XmlTreeNode) parent).getIndexOfChild((XmlTreeNode) child);
    }

    public Object getRoot() {
        return getRootNode();
    }

    public RootXmlTreeNode getRootNode() {
        return root;
    }

    public boolean isLeaf(Object node) {
        return ((XmlTreeNode) node).isLeaf();
    }

    public void removeTreeModelListener(TreeModelListener l) {
        listeners.remove(l);
    }

    public void valueForPathChanged(TreePath path, Object newValue) {
    }

    private class TreeBookmark extends XmlCursor.XmlBookmark {
    }

    public interface XmlTreeNode {
        public int getChildCount();

        public XmlTreeNode getChild(int ix);

        public int getIndexOfChild(XmlTreeNode childNode);

        public String getNodeName();

        public String getNodeText();

        public boolean isEditable(int column);

        public boolean isLeaf();

        public boolean setValue(int column, Object value);

        public XmlLineNumber getNodeLineNumber();

        public XmlLineNumber getValueLineNumber();

        public XmlObject getXmlObject();

        public Node getDomNode();

        public TreePath getTreePath();

        public XmlTreeNode getParent();

        public SchemaType getSchemaType();

        public String getDocumentation();
    }

    private abstract class AbstractXmlTreeNode implements XmlTreeNode {
        protected Node node;
        protected TreeBookmark bm;
        private final XmlTreeNode parent;
        private XmlLineNumber lineNumber;
        protected SchemaType schemaType;
        protected String documentation;

        @SuppressWarnings("unchecked")
        protected AbstractXmlTreeNode(XmlCursor cursor, XmlTreeNode parent) {
            this.parent = parent;

            if (cursor != null) {
                node = cursor.getDomNode();

                ArrayList list = new ArrayList();
                cursor.getAllBookmarkRefs(list);

                for (Object o : list) {
                    if (o instanceof XmlLineNumber) {
                        lineNumber = (XmlLineNumber) o;
                    }
                }

                bm = new TreeBookmark();
                cursor.setBookmark(bm);

                treeNodeMap.put(cursor.getObject(), this);
            }
        }

        protected SchemaType findSchemaType() {
            if (cursor == null) {
                return null;
            }

            positionCursor(cursor);

            SchemaType resultType = null;
            XmlObject xo = cursor.getObject();
            if (xo != null) {
                Node domNode = xo.getDomNode();

                // check for xsi:type
                if (domNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element elm = (Element) domNode;
                    String xsiType = elm.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
                    if (xsiType != null && xsiType.length() > 0) {
                        resultType = findXsiType(xsiType);
                    }
                }

                if (resultType == null) {
                    resultType = typeSystem.findType(xo.schemaType().getName());
                }

                if (resultType == null) {
                    resultType = xo.schemaType();
                }

                if (resultType.isNoType()) {
                    QName nm = cursor.getName();

                    if (parent != null && parent.getSchemaType() != null) {
                        SchemaType parentSchemaType = parent.getSchemaType();
                        SchemaParticle contentModel = parentSchemaType.getContentModel();

                        if (contentModel != null) {
                            SchemaParticle[] children = contentModel.getParticleChildren();

                            for (int c = 0; children != null && c < children.length; c++) {
                                if (nm.equals(children[c].getName())) {
                                    resultType = children[c].getType();
                                    documentation = SchemaUtils.getDocumentation(resultType);
                                    break;
                                }
                            }

                            if (resultType.isNoType() && nm.equals(contentModel.getName())) {
                                resultType = contentModel.getType();
                            }

                            if (resultType.isNoType()) {
                                SchemaType[] anonymousTypes = parentSchemaType.getAnonymousTypes();
                                for (int c = 0; anonymousTypes != null && c < anonymousTypes.length; c++) {
                                    QName name = anonymousTypes[c].getName();
                                    if (name != null && name.equals(nm)) {
                                        resultType = anonymousTypes[c];
                                        break;
                                    } else if (anonymousTypes[c].getContainerField().getName().equals(nm)) {
                                        resultType = anonymousTypes[c].getContainerField().getType();
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    if (resultType.isNoType()) {
                        SchemaGlobalElement elm = typeSystem.findElement(nm);
                        if (elm != null) {
                            resultType = elm.getType();
                        } else if (typeSystem.findDocumentType(nm) != null) {
                            resultType = typeSystem.findDocumentType(nm);
                        }
                    }
                }
            }

            if (resultType == null) {
                resultType = XmlAnyTypeImpl.type;
            }

            if (documentation == null) {
                documentation = SchemaUtils.getDocumentation(resultType);
            }

            return resultType;
        }

        @SuppressWarnings("unused")
        protected String getUserInfo(SchemaType schemaType) {
            if (schemaType.getAnnotation() != null) {
                XmlObject[] userInformation = schemaType.getAnnotation().getUserInformation();
                if (userInformation != null && userInformation.length > 0) {
                    return userInformation[0].toString(); // XmlUtils.getElementText(
                    // ( Element )
                    // userInformation[0].getDomNode());
                }
            }

            return null;
        }

        public String getDocumentation() {
            return documentation;
        }

        private SchemaType findXsiType(String xsiType) {
            SchemaType resultType;
            int ix = xsiType.indexOf(':');
            QName name = null;

            if (ix == -1) {
                name = new QName(xsiType);
                resultType = typeSystem.findType(name);
            } else {
                StringToStringMap map = new StringToStringMap();
                cursor.getAllNamespaces(map);

                name = new QName(map.get(xsiType.substring(0, ix)), xsiType.substring(ix + 1));
                resultType = typeSystem.findType(name);
            }

            return resultType;
        }

        public XmlTreeNode getParent() {
            return parent;
        }

        protected void positionCursor(XmlCursor cursor) {
            cursor.toBookmark(bm);
        }

        public XmlTreeNode getChild(int ix) {
            return null;
        }

        public int getChildCount() {
            return 0;
        }

        public int getIndexOfChild(XmlTreeNode childNode) {
            return -1;
        }

        @SuppressWarnings("unused")
        public Object getValue(int column) {
            if (column == 0) {
                return getNodeName();
            } else if (column == 1) {
                return getNodeText();
            }

            return null;
        }

        public Node getDomNode() {
            return node;
        }

        public String getNodeName() {
            return node == null ? null : node.getNodeName();
        }

        public String getNodeText() {
            if (node == null) {
                return null;
            }

            String nodeValue = node.getNodeValue();
            return nodeValue == null ? null : nodeValue.trim();
        }

        public boolean isEditable(int column) {
            return false;
        }

        public boolean isLeaf() {
            return getChildCount() == 0;
        }

        public boolean setValue(int column, Object value) {
            return false;
        }

        public String toString() {
            return getNodeName();
        }

        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj instanceof AbstractXmlTreeNode) {
                return ((AbstractXmlTreeNode) obj).node == this.node;
            } else {
                return super.equals(obj);
            }
        }

        public XmlLineNumber getNodeLineNumber() {
            return lineNumber;
        }

        public XmlLineNumber getValueLineNumber() {
            return lineNumber;
        }

        public XmlObject getXmlObject() {
            if (cursor != null && cursor.toBookmark(bm)) {
                XmlObject object = cursor.getObject();

                if (object != null) {
                    return object;
                } else if (parent != null) {
                    return parent.getXmlObject();
                }
            }

            return null;
        }

        public TreePath getTreePath() {
            List<XmlTreeNode> nodes = new ArrayList<XmlTreeNode>();
            nodes.add(this);

            XmlTreeNode node = this;

            while (node.getParent() != null) {
                nodes.add(0, node.getParent());
                node = node.getParent();
            }

            return new TreePath(nodes.toArray());
        }

        public SchemaType getSchemaType() {
            if (schemaType == null) {
                schemaType = findSchemaType();
            }

            return schemaType;
        }
    }

    public class RootXmlTreeNode extends AbstractXmlTreeNode {
        private ElementXmlTreeNode rootNode;

        protected RootXmlTreeNode(XmlCursor cursor) {
            super(cursor, null);

            if (cursor != null) {
                cursor.toFirstContentToken();
                rootNode = new ElementXmlTreeNode(cursor, this);
            }
        }

        public XmlTreeNode getChild(int ix) {
            return ix == 0 ? rootNode : null;
        }

        public int getChildCount() {
            return rootNode == null ? 0 : 1;
        }

        public int getIndexOfChild(XmlTreeNode childNode) {
            return childNode == rootNode ? 0 : -1;
        }
    }

    public class ElementXmlTreeNode extends AbstractXmlTreeNode {
        private LinkedList<XmlTreeNode> elements = new LinkedList<XmlTreeNode>();
        private TextXmlTreeNode textTreeNode;
        private int attrCount;

        protected ElementXmlTreeNode(XmlCursor cursor, XmlTreeNode parent) {
            super(cursor, parent);

            TokenType token = cursor.toNextToken();
            while (token == TokenType.ATTR || token == TokenType.NAMESPACE) {
                if (token == TokenType.ATTR) {
                    elements.add(new AttributeXmlTreeNode(cursor, this));
                }

                token = cursor.toNextToken();
            }

            attrCount = elements.size();

            positionCursor(cursor);
            cursor.toFirstContentToken();

            while (true) {
                while (cursor.isComment() || cursor.isProcinst()) {
                    cursor.toNextToken();
                }

                if (cursor.isContainer()) {
                    elements.add(new ElementXmlTreeNode(cursor, this));
                    cursor.toEndToken();
                    cursor.toNextToken();
                }

                if (cursor.isText()) {
                    elements.add(new TextXmlTreeNode(cursor, this));
                    cursor.toNextToken();
                }

                if (cursor.isEnd() || cursor.isEnddoc()) {
                    break;
                }
            }

            if (elements.size() == attrCount + 1 && (elements.get(attrCount) instanceof TextXmlTreeNode)) {
                textTreeNode = (TextXmlTreeNode) elements.remove(attrCount);
            } else {
                for (int c = attrCount; c < elements.size(); c++) {
                    if (elements.get(c) instanceof TextXmlTreeNode) {
                        TextXmlTreeNode treeNode = (TextXmlTreeNode) elements.get(c);
                        String text = treeNode.getNodeText().trim();
                        if (text.length() == 0) {
                            elements.remove(c);
                            c--;
                        }
                    }
                }
            }

            positionCursor(cursor);
        }

        public XmlTreeNode getChild(int ix) {
            return elements.get(ix);
        }

        public boolean isEditable(int column) {
            return column == 1 && elements.size() == attrCount;
        }

        public boolean setValue(int column, Object value) {
            if (column == 1) {
                if (textTreeNode != null) {
                    textTreeNode.setValue(1, value);
                } else {
                    positionCursor(cursor);
                    cursor.toEndToken();
                    cursor.insertChars(value.toString());
                    positionCursor(cursor);
                    cursor.toFirstContentToken();

                    textTreeNode = new TextXmlTreeNode(cursor, this);
                }
            }
            return column == 1;
        }

        public int getChildCount() {
            return elements.size();
        }

        public int getIndexOfChild(XmlTreeNode childNode) {
            return elements.indexOf(childNode);
        }

        public String getNodeText() {
            return textTreeNode == null ? "" : textTreeNode.getNodeText();
        }

        public XmlLineNumber getValueLineNumber() {
            return textTreeNode == null ? super.getValueLineNumber() : textTreeNode.getValueLineNumber();
        }
    }

    public class AttributeXmlTreeNode extends AbstractXmlTreeNode {
        private boolean checkedType;

        protected AttributeXmlTreeNode(XmlCursor cursor, ElementXmlTreeNode parent) {
            super(cursor, parent);
        }

        public String getNodeName() {
            return "@" + super.getNodeName();
        }

        public XmlLineNumber getNodeLineNumber() {
            return getParent().getNodeLineNumber();
        }

        public boolean isEditable(int column) {
            return column == 1;
        }

        public boolean setValue(int column, Object value) {
            if (column == 1) {
                node.setNodeValue(value.toString());
            }

            return column == 1;
        }

        public SchemaType getSchemaType() {
            if (schemaType == null && !checkedType) {
                SchemaType parentSchemaType = getParent().getSchemaType();
                if (parentSchemaType != null) {
                    positionCursor(cursor);
                    SchemaProperty attributeProperty = parentSchemaType.getAttributeProperty(cursor.getName());
                    if (attributeProperty != null) {
                        schemaType = attributeProperty.getType();
                        documentation = SchemaUtils.getDocumentation(schemaType);

                        // SchemaAnnotation annotation = schemaType.getAnnotation();
                        // if( annotation != null )
                        // {
                        // XmlObject[] userInformation =
                        // annotation.getUserInformation();
                        // if( userInformation != null && userInformation.length > 0 )
                        // {
                        // //userInformation[0].toString(); //XmlUtils.getElementText(
                        // ( Element ) userInformation[0].getDomNode());
                        // }
                        // }
                    }
                }

                checkedType = true;
            }

            return schemaType;
        }
    }

    public class TextXmlTreeNode extends AbstractXmlTreeNode {
        protected TextXmlTreeNode(XmlCursor cursor, ElementXmlTreeNode parent) {
            super(cursor, parent);
        }

        public boolean isEditable(int column) {
            return column == 1;
        }

        public boolean setValue(int column, Object value) {
            if (column == 1 && node != null) {
                node.setNodeValue(value.toString());
            }

            return column == 1;
        }

        public TreePath getTreePath() {
            return super.getTreePath().getParentPath();
        }
    }

    public TreePath findXmlTreeNode(int line, int column) {
        line++;

        XmlTreeNode treeNode = findXmlTreeNode(root, line, column);
        if (treeNode instanceof AttributeXmlTreeNode) {
            return treeNode.getParent().getTreePath();
        } else if (treeNode != null) {
            return treeNode.getTreePath();
        }

        return null;
    }

    private XmlTreeNode findXmlTreeNode(XmlTreeNode treeNode, int line, int column) {
        for (int c = 0; c < treeNode.getChildCount(); c++) {
            XmlTreeNode child = treeNode.getChild(c);
            XmlLineNumber ln = child.getNodeLineNumber();
            if (ln != null && (line < ln.getLine() || (line == ln.getLine() && column <= ln.getColumn()))) {
                if (c == 0) {
                    return treeNode;
                } else {
                    return findXmlTreeNode(treeNode.getChild(c - 1), line, column);
                }
            }
        }

        if (treeNode.getChildCount() > 0) {
            return findXmlTreeNode(treeNode.getChild(treeNode.getChildCount() - 1), line, column);
        }

        return treeNode;
    }

    public class XmlTreeTableModelEvent extends TreeModelEvent {
        private final int column;

        public XmlTreeTableModelEvent(Object source, Object[] path, int[] childIndices, Object[] children, int column) {
            super(source, path, childIndices, children);
            this.column = column;
        }

        public XmlTreeTableModelEvent(Object source, Object[] path, int column) {
            super(source, path);
            this.column = column;
        }

        public XmlTreeTableModelEvent(Object source, TreePath path, int[] childIndices, Object[] children, int column) {
            super(source, path, childIndices, children);
            this.column = column;
        }

        public XmlTreeTableModelEvent(Object source, TreePath path, int column) {
            super(source, path);
            this.column = column;
        }

        public int getColumn() {
            return column;
        }
    }

    public XmlTreeNode getXmlTreeNode(XmlObject object) {
        return treeNodeMap.get(object);
    }

    public XmlTreeNode[] selectTreeNodes(String xpath) {
        XmlObject[] nodes = xmlObject.selectPath(xpath);
        List<XmlTreeNode> result = new ArrayList<XmlTreeNode>();

        for (XmlObject xmlObject : nodes) {
            XmlTreeNode tn = getXmlTreeNode(xmlObject);
            if (tn != null) {
                result.add(tn);
            }
        }

        return result.toArray(new XmlTreeNode[result.size()]);
    }

    public void release() {
        typeSystem = null;
        treeNodeMap.clear();

        listeners.clear();
    }

    public int getHierarchicalColumn() {
        return 0;
    }
}
TOP

Related Classes of com.eviware.soapui.support.xml.XmlObjectTreeModel$XmlTreeNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.