KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > mdr > test > XMIComparator


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.mdr.test;
21
22 import java.util.*;
23 import java.io.*;
24 import java.net.URL JavaDoc;
25
26 import org.xml.sax.*;
27 import org.w3c.dom.*;
28
29 import javax.xml.parsers.*;
30
31 import org.netbeans.lib.jmi.util.*;
32
33 import javax.jmi.reflect.*;
34 import javax.jmi.model.*;
35
36 public class XMIComparator extends Object JavaDoc {
37
38     // a character used to mark start of an element name
39
private static final char ELEMENT_START = '[';
40     // a character used to mark end of an element name
41
private static final char ELEMENT_END = ']';
42     // an auxiliar separator used to create code of a tree
43
private static final char LEFT_SEPARATOR = '(';
44     // an auxiliar separator used to create code of a tree
45
private static final char RIGHT_SEPARATOR = ')';
46     // an auxiliar separator used to enclose a comment
47
private static final char COMMENT_MARKER = '#';
48
49     private CodeComparator codeComparator = new CodeComparator ();
50     
51     // init .....................................................................
52

53     public XMIComparator() {
54     }
55     
56     // methods ..................................................................
57

58     /**
59      * Compares content of two XMI files. Both files are parsed by DOM parser.
60      * Nodes representing content sections are found in created structures and
61      * their content is coded into a String value. The codes equals iff both trees
62      * are isomorphous. Note that (for now) attribute values are not included in tree
63      * codes and that whitespace characters are excluded when content of TEXT_NODE
64      * is added as a part of a resulting code.
65      *
66      * @param streamOne InputSource providing the first XMI documnet
67      * @param streamTwo InputSource providing the second XMI documnet
68      *
69      * @return null if both documents are logically identical, otherwise an error message
70      */

71     public String JavaDoc compareDocuments (InputSource streamOne, InputSource streamTwo) {
72         try {
73             Document docOne = parse (streamOne, null);
74             Document docTwo = parse (streamTwo, null);
75             Node xmiNode = findSubnodeByName (docOne, "XMI");
76             Node contentNode = findSubnodeByName (xmiNode, "XMI.content");
77             String JavaDoc codeOne = treeCode (contentNode);
78             
79             xmiNode = findSubnodeByName (docTwo, "XMI");
80             contentNode = findSubnodeByName (xmiNode, "XMI.content");
81             String JavaDoc codeTwo = treeCode (contentNode);
82             
83             if (removeComments (codeOne).equals (removeComments (codeTwo)))
84                 return null;
85             String JavaDoc el = findDifference (codeOne, codeTwo);
86             return "Trees are not identical, element: " + el;
87         } catch (Exception JavaDoc e) {
88             e.printStackTrace ();
89             return "Cannot parse documnet";
90         }
91     }
92     
93     /**
94      * Finds the first difference in two codes and detects the name of the nearest
95      * element that encloses the detected position.
96      */

97     private String JavaDoc findDifference (String JavaDoc c1, String JavaDoc c2) {
98         int x = 0;
99         int length = Math.min (c1.length (), c2.length ());
100         for (x = 0; x < c1.length (); x++)
101             if (c1.charAt (x) != c2.charAt (x))
102                 break;
103         while (c1.charAt (x) != ELEMENT_START)
104             x--;
105         String JavaDoc name = "";
106         x++;
107         while (c1.charAt (x) != ELEMENT_END) {
108             name = name + c1.charAt (x);
109             x++;
110         }
111         return name;
112     }
113     
114     /**
115      * Returns direct child node given by its name.
116      */

117     private Node findSubnodeByName (Node node, String JavaDoc name) {
118         NodeList subNodes = node.getChildNodes ();
119         for (int x = 0; x < subNodes.getLength (); x++) {
120             Node temp = subNodes.item (x);
121             if (temp.getNodeName ().equals (name))
122                 return temp;
123         } // for
124
return null;
125     }
126         
127     /**
128      * Returns a code for a tree given by its root node.
129      */

130     private String JavaDoc treeCode (Node node) {
131         if (node.getNodeType () == Node.TEXT_NODE) {
132             String JavaDoc text = node.getNodeValue ();
133             String JavaDoc res = "";
134             for (int x = 0; x < text.length (); x++)
135                 if (!Character.isWhitespace (text.charAt (x)))
136                     res = res + text.charAt (x);
137             return res;
138         }
139         if (node.getNodeType () != Node.ELEMENT_NODE)
140             return ""; // ignore non-text and non-element nodes
141
List list = new LinkedList ();
142         String JavaDoc nodeName = node.getNodeName ();
143         NamedNodeMap attrs = node.getAttributes ();
144         String JavaDoc xmiId = null;
145         for (int x = 0; x < attrs.getLength (); x++) {
146             Node attr = attrs.item (x);
147             String JavaDoc name = attr.getNodeName ();
148             if (name.equals ("xmi.id"))
149                 xmiId = attr.getNodeValue ();
150             String JavaDoc value = attr.getNodeValue ();
151             if (value.startsWith ("xmi.")) {
152                 value = "xmi.";
153             } // if
154
list.add (name); // [PENDING] value not added yet !!!
155
} // for
156
String JavaDoc attributesCode = listToString (list);
157         list = new LinkedList ();
158         NodeList subNodes = node.getChildNodes ();
159         for (int x = 0; x < subNodes.getLength (); x++) {
160             String JavaDoc s = treeCode (subNodes.item (x));
161             if (s.length () > 0)
162                 list.add (s);
163         } // for
164
String JavaDoc subNodesCode = listToString (list);
165         String JavaDoc comment = "";
166         if (xmiId != null)
167             comment = " " + COMMENT_MARKER + xmiId + COMMENT_MARKER;
168         return LEFT_SEPARATOR + " " + ELEMENT_START + nodeName + comment + ELEMENT_END + attributesCode +
169             " " + subNodesCode + RIGHT_SEPARATOR;
170     }
171     
172     /**
173      * Sorts all Strings in a List and returns their contatenation.
174      */

175     private String JavaDoc listToString (List list) {
176         Collections.sort (list, codeComparator);
177         String JavaDoc res = "";
178         Iterator iter = list.iterator ();
179         while (iter.hasNext ()) {
180             res = res + " " + (String JavaDoc) iter.next ();
181         }
182         return res;
183     }
184     
185     /**
186      * Parses XMI document into DOM tree structure.
187      */

188     private Document parse (InputSource is, String JavaDoc encoding) throws IOException, SAXException, ParserConfigurationException {
189         Document result = null;
190         DocumentBuilderFactory bfact = DocumentBuilderFactory.newInstance();
191         bfact.setValidating(false);
192         DocumentBuilder docBuilder = bfact.newDocumentBuilder();
193     docBuilder.setEntityResolver(DummyER.getInstance());
194         if (encoding != null) is.setEncoding(encoding);
195         result = docBuilder.parse(is);
196         return result;
197     }
198     
199     private static String JavaDoc removeComments (String JavaDoc code) {
200         StringBuffer JavaDoc res = new StringBuffer JavaDoc (code.length ());
201         boolean inComment = false;
202         for (int x = 0; x < code.length (); x++) {
203             char c = code.charAt (x);
204             if (c == COMMENT_MARKER)
205                 inComment = !inComment;
206             else if (!inComment)
207                 res.append(c);
208         } // for
209
return res.toString ();
210     }
211     
212     // (Dummy) entity resolver class
213
private static class DummyER implements EntityResolver {
214         private static EntityResolver instance = new DummyER();
215
216         public static EntityResolver getInstance() {
217             return instance;
218         }
219
220         public InputSource resolveEntity(String JavaDoc publicID, String JavaDoc systemID) {
221             return new InputSource(new StringReader(""));
222         }
223     }
224         
225     private static class CodeComparator implements Comparator {
226         
227         public int compare(Object JavaDoc obj1, Object JavaDoc obj2) {
228             String JavaDoc s1 = removeComments ((String JavaDoc) obj1);
229             String JavaDoc s2 = removeComments ((String JavaDoc) obj2);
230             return s1.compareTo(s2);
231         }
232                 
233     }
234     
235 }
236
Popular Tags