View Javadoc

1   /*
2    * $Id: ResultTreeModel.java,v 1.23 2007/07/04 19:42:48 edankert Exp $
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  
23  package org.xmlhammer.gui.output;
24  
25  import java.io.IOException;
26  import java.lang.reflect.InvocationTargetException;
27  import java.net.URI;
28  
29  import javax.swing.SwingUtilities;
30  import javax.swing.tree.DefaultTreeModel;
31  import javax.swing.tree.MutableTreeNode;
32  import javax.xml.transform.TransformerException;
33  
34  import org.apache.log4j.Logger;
35  import org.bounce.util.URIUtils;
36  import org.w3c.dom.Attr;
37  import org.w3c.dom.Comment;
38  import org.w3c.dom.Element;
39  import org.w3c.dom.NamedNodeMap;
40  import org.w3c.dom.Node;
41  import org.w3c.dom.ProcessingInstruction;
42  import org.w3c.dom.Text;
43  import org.xml.sax.SAXParseException;
44  import org.xmlhammer.ResultModel;
45  import org.xmlhammer.model.project.Error;
46  import org.xmlhammer.model.project.Fatal;
47  import org.xmlhammer.model.project.Message;
48  import org.xmlhammer.model.project.Output;
49  import org.xmlhammer.model.project.Type;
50  import org.xmlhammer.model.project.Valid;
51  import org.xmlhammer.model.project.Warning;
52  
53  /***
54   * The model for the result tree.
55   * 
56   * @version $Revision: 1.23 $, $Date: 2007/07/04 19:42:48 $
57   * @author Edwin Dankert <edankert@gmail.com>
58   */
59  
60  public class ResultTreeModel extends DefaultTreeModel implements ResultModel {
61  	private static final long serialVersionUID = 1057354554421210781L;
62      private static final int TEXT_LIMIT = 256;
63      private Output output = null;
64      private URI base = null;
65      public int inserted = 0;
66      public int fired = 0;
67  	
68  	public ResultTreeModel(Output output) {
69  		super(new RootNode());
70  		
71          this.output = output;
72  	}
73  	
74      public ResultTreeModel(Output output, URI base) {
75          super(new RootNode());
76          
77          Logger.getLogger(this.getClass()).debug("ResultTreeModel( "+output+", "+base+")");
78  
79          this.output = output;
80          this.base = base;
81      }
82  
83      public void addWarning( URI src, SAXParseException exception) {
84  		Warning warning = new Warning();
85  		
86  		warning.setSrc(src.toString());
87          warning.setClazz(exception.getClass().getName());
88  
89          warning.setMessage( exception.getMessage());
90          warning.setLocalizedMessage( exception.getLocalizedMessage());
91          warning.setLine( exception.getLineNumber());
92          warning.setColumn( exception.getColumnNumber());
93          warning.setSystemId( exception.getSystemId());
94          warning.setPublicId( exception.getPublicId());
95  
96          output.getWarning().add( warning);
97  		
98  		addNode( src, new WarningNode(src, warning));
99  	}
100 
101     public void addWarning( URI src, TransformerException exception) {
102         Warning warning = new Warning();
103         
104         warning.setSrc(src.toString());
105         warning.setClazz(exception.getClass().getName());
106 
107         warning.setMessage( exception.getMessage());
108         warning.setLocalizedMessage( exception.getLocalizedMessage());
109 
110         if (exception.getLocator() != null) {
111             warning.setLine( exception.getLocator().getLineNumber());
112             warning.setColumn( exception.getLocator().getColumnNumber());
113             warning.setSystemId( exception.getLocator().getSystemId());
114             warning.setPublicId( exception.getLocator().getPublicId());
115         } else {
116             warning.setLine(-1);
117             warning.setColumn(-1);
118             warning.setSystemId(null);
119             warning.setPublicId(null);
120         }
121 
122         output.getWarning().add( warning);
123         
124         addNode(src, new WarningNode(src, warning));
125     }
126 
127     public void addValid( URI src) {
128         Valid valid = new Valid();
129         
130         valid.setSrc( src.toString());
131 
132         output.setValid( valid);
133         
134         addValidNode( src, true);
135     }
136 
137     public void addError( URI src, SAXParseException exception) {
138 		Error error = new Error();
139         
140         error.setSrc(URIUtils.toString(src));
141         error.setClazz(exception.getClass().getName());
142 
143         error.setMessage( exception.getMessage());
144         error.setLocalizedMessage( exception.getLocalizedMessage());
145 		error.setLine( exception.getLineNumber());
146 		error.setColumn( exception.getColumnNumber());
147         error.setSystemId( exception.getSystemId());
148         error.setPublicId( exception.getPublicId());
149         
150         output.getError().add( error);
151 		
152 		addNode( src, new ErrorNode(src, error));
153 	}
154 	
155     public void addError( URI src, TransformerException exception) {
156         Error error = new Error();
157         
158         error.setSrc(URIUtils.toString(src));
159         error.setClazz(exception.getClass().getName());
160 
161         error.setMessage( exception.getMessage());
162         error.setLocalizedMessage( exception.getLocalizedMessage());
163         if (exception.getLocator() != null) {
164             error.setLine( exception.getLocator().getLineNumber());
165             error.setColumn( exception.getLocator().getColumnNumber());
166             error.setSystemId( exception.getLocator().getSystemId());
167             error.setPublicId( exception.getLocator().getPublicId());
168         } else {
169             error.setLine(-1);
170             error.setColumn(-1);
171             error.setSystemId(null);
172             error.setPublicId(null);
173         }
174         
175         output.getError().add( error);
176         
177         addNode(src, new ErrorNode(src, error));
178     }
179 
180     public void addFatal( URI src, SAXParseException exception) {
181         Fatal fatal = new Fatal();
182 
183         fatal.setSrc(URIUtils.toString(src));
184         fatal.setClazz(exception.getClass().getName());
185         
186         fatal.setMessage( exception.getMessage());
187         fatal.setLocalizedMessage( exception.getLocalizedMessage());
188         fatal.setLine( exception.getLineNumber());
189         fatal.setColumn( exception.getColumnNumber());
190         fatal.setSystemId( exception.getSystemId());
191         fatal.setPublicId( exception.getPublicId());
192 
193         output.getFatal().add( fatal);
194 
195         addNode( src, new FatalNode(src, fatal));
196 	}
197 
198     public void addFatal( URI src, TransformerException exception) {
199         Fatal fatal = new Fatal();
200 
201         fatal.setSrc(URIUtils.toString(src));
202         fatal.setClazz(exception.getClass().getName());
203         
204         fatal.setMessage( exception.getMessage());
205         fatal.setLocalizedMessage( exception.getLocalizedMessage());
206         
207         if (exception.getLocator() != null) {
208             fatal.setLine( exception.getLocator().getLineNumber());
209             fatal.setColumn( exception.getLocator().getColumnNumber());
210             fatal.setSystemId( exception.getLocator().getSystemId());
211             fatal.setPublicId( exception.getLocator().getPublicId());
212         } else {
213             fatal.setLine(-1);
214             fatal.setColumn(-1);
215             fatal.setSystemId(null);
216             fatal.setPublicId(null);
217         }
218         
219         output.getFatal().add( fatal);
220 
221         addNode( src, new FatalNode(src, fatal));
222     }
223 
224     public void addFatal( URI src, IOException exception) {
225         Fatal fatal = new Fatal();
226         
227         fatal.setSrc(URIUtils.toString(src));
228         fatal.setClazz(exception.getClass().getName());
229 
230         fatal.setMessage( exception.getMessage());
231         fatal.setLocalizedMessage( exception.getLocalizedMessage());
232         fatal.setLine( -1);
233         fatal.setColumn( -1);
234 
235         output.getFatal().add( fatal);
236 
237         addNode( src, new FatalNode(src, fatal));
238 	}
239 
240 	public void addValue( URI src, Object object) {
241 		ResultNode resultNode = null;
242 
243 		if ( object instanceof Element) {
244             resultNode = createElementNode(src, (Element)object);
245 		} else if ( object instanceof Attr) {
246 			resultNode = createAttributeNode( src, (Attr)object);
247 		} else if ( object instanceof Text) {
248             resultNode = createTextNode( src, (Text)object);
249 		} else if ( object instanceof Comment) {
250             resultNode = createCommentNode( src, (Comment)object);
251 		} else if ( object instanceof ProcessingInstruction) {
252             resultNode = createProcessingInstructionNode( src, (ProcessingInstruction)object);
253 		} else if ( object instanceof Boolean) {
254             if (((Boolean)object)) {
255                 resultNode = createBooleanNode( src, (Boolean)object);
256             }
257 		} else if ( object instanceof String) {
258             if (object.toString().length() > 0) {
259                 resultNode = createStringNode( src, (String)object);
260             }
261 		} else if ( object instanceof Number) {
262             if (((Number)object).intValue() != 0) {
263                 resultNode = createNumberNode( src, (Number)object);
264             }
265 		} else {
266             resultNode = createValueNode( src, object);
267 		}
268 
269         if (resultNode != null) {
270             addNode( src, resultNode);
271         }
272 	}
273     
274     private ElementNode createElementNode( URI src, Element element) {
275         org.xmlhammer.model.project.Element value = new org.xmlhammer.model.project.Element();
276 
277         value.setSrc(URIUtils.toString(src));
278 
279         value.setLocalName( element.getLocalName());
280         value.setBaseURI( element.getBaseURI());
281         value.setClazz( element.getClass().getName());
282         value.setNamespaceURI( element.getNamespaceURI());
283         value.setNodeName( element.getNodeName());
284         value.setNodeValue( limitString(element.getNodeValue(), TEXT_LIMIT));
285         value.setPrefix( element.getPrefix());
286         value.setTagName( element.getTagName());
287         value.setTextContent( limitString(element.getTextContent(), TEXT_LIMIT));
288         value.setPath(getPath(element));
289         value.setText(limitString(element.getFirstChild(), TEXT_LIMIT).trim());
290         value.setContext(getContext(element, limitString(element.getFirstChild(), TEXT_LIMIT).trim()));
291         
292         Type type = new Type();
293         type.setName(element.getSchemaTypeInfo().getTypeName());
294         type.setNamespace(element.getSchemaTypeInfo().getTypeNamespace());
295         value.setType( type);
296         
297         return new ElementNode(src, value);
298     }
299     
300     private TextNode createTextNode( URI src, Text text) {
301         org.xmlhammer.model.project.Text value = new org.xmlhammer.model.project.Text();
302 
303         value.setSrc(URIUtils.toString(src));
304 
305         value.setLocalName( text.getLocalName());
306         value.setBaseURI( text.getBaseURI());
307         value.setClazz( text.getClass().getName());
308         value.setNamespaceURI( text.getNamespaceURI());
309         value.setNodeName( text.getNodeName());
310         value.setNodeValue( limitString(text.getNodeValue(), TEXT_LIMIT));
311         value.setPrefix( text.getPrefix());
312         value.setTextContent( limitString(text.getTextContent(), TEXT_LIMIT));
313         value.setPath(getPath(text.getParentNode())+"/text()");
314         value.setContext(getContext(text.getParentNode(), limitString(text.getNodeValue(), TEXT_LIMIT)));
315 
316         value.setData( limitString(text.getData(), TEXT_LIMIT));
317         value.setElementContentWhitespace( text.isElementContentWhitespace());
318         value.setWholeText( text.getWholeText());
319 
320         return new TextNode(src, value);
321     }
322 
323     private AttributeNode createAttributeNode( URI src, Attr attribute) {
324         org.xmlhammer.model.project.Attribute value = new org.xmlhammer.model.project.Attribute();
325 
326         value.setSrc(URIUtils.toString(src));
327 
328         value.setLocalName( attribute.getLocalName());
329         value.setBaseURI( attribute.getBaseURI());
330         value.setClazz( attribute.getClass().getName());
331         value.setNamespaceURI( attribute.getNamespaceURI());
332         value.setNodeName( attribute.getNodeName());
333         value.setNodeValue( attribute.getNodeValue());
334         value.setPrefix( attribute.getPrefix());
335         value.setName( attribute.getName());
336         value.setId( attribute.isId());
337         value.setSpecified( attribute.getSpecified());
338         value.setValue( attribute.getValue());
339         value.setTextContent(attribute.getTextContent());
340         value.setPath(getPath(attribute.getOwnerElement())+"/@"+attribute.getNodeName());
341         value.setContext(getContext(attribute.getOwnerElement(), limitString(attribute.getOwnerElement().getNodeValue(), TEXT_LIMIT)));
342 
343         Type type = new Type();
344         type.setName(attribute.getSchemaTypeInfo().getTypeName());
345         type.setNamespace(attribute.getSchemaTypeInfo().getTypeNamespace());
346         value.setType( type);
347         
348         return new AttributeNode(src, value);
349     }
350 
351     private CommentNode createCommentNode( URI src, Comment comment) {
352         org.xmlhammer.model.project.Comment value = new org.xmlhammer.model.project.Comment();
353 
354         value.setSrc(URIUtils.toString(src));
355 
356         value.setLocalName( comment.getLocalName());
357         value.setBaseURI( comment.getBaseURI());
358         value.setClazz( comment.getClass().getName());
359         value.setNamespaceURI( comment.getNamespaceURI());
360         value.setNodeName( comment.getNodeName());
361         value.setNodeValue( limitString(comment.getNodeValue(), TEXT_LIMIT));
362         value.setPrefix( comment.getPrefix());
363         value.setTextContent( limitString(comment.getTextContent(), TEXT_LIMIT));
364         value.setPath(getPath(comment.getParentNode())+"/comment()");
365         value.setContext(getContext(comment.getParentNode(), writeComment(limitString(comment.getNodeValue(), TEXT_LIMIT))));
366         
367         value.setData( limitString(comment.getData(), TEXT_LIMIT));
368         value.setLength( comment.getLength());
369         
370         return new CommentNode(src, value);
371     }
372 
373     private ProcessingInstructionNode createProcessingInstructionNode( URI src, ProcessingInstruction pi) {
374         org.xmlhammer.model.project.ProcessingInstruction value = new org.xmlhammer.model.project.ProcessingInstruction();
375 
376         value.setSrc(URIUtils.toString(src));
377 
378         value.setLocalName( pi.getLocalName());
379         value.setBaseURI( pi.getBaseURI());
380         value.setClazz( pi.getClass().getName());
381         value.setNamespaceURI( pi.getNamespaceURI());
382         value.setNodeName( pi.getNodeName());
383         value.setNodeValue( limitString(pi.getNodeValue(), TEXT_LIMIT));
384         value.setPrefix( pi.getPrefix());
385         value.setTextContent( limitString(pi.getTextContent(), TEXT_LIMIT));
386         value.setPath(getPath(pi.getParentNode())+"/processing-instruction()");
387         value.setContext(getContext(pi.getParentNode(), writePI(pi)));
388         
389         value.setData( limitString(pi.getData(), TEXT_LIMIT));
390         value.setTarget( pi.getTarget());
391         
392         return new ProcessingInstructionNode(src, value);
393     }
394 
395     private ValueNode createBooleanNode( URI src, Boolean bool) {
396         org.xmlhammer.model.project.Boolean value = new org.xmlhammer.model.project.Boolean();
397 
398         value.setSrc(URIUtils.toString(src));
399         value.setClazz( bool.getClass().getName());
400         value.setValue( bool.toString());
401         
402         return new ValueNode(src, value);
403     }
404 
405     private ValueNode createStringNode( URI src, String string) {
406         org.xmlhammer.model.project.String value = new org.xmlhammer.model.project.String();
407 
408         value.setSrc(URIUtils.toString(src));
409         value.setClazz(string.getClass().getName());
410         value.setValue(string.toString());
411         
412         return new ValueNode(src, value);
413     }
414 
415     private ValueNode createNumberNode( URI src, Number number) {
416         org.xmlhammer.model.project.Number value = new org.xmlhammer.model.project.Number();
417 
418         value.setSrc(URIUtils.toString(src));
419         value.setClazz(number.getClass().getName());
420         value.setValue(number.toString());
421         
422         return new ValueNode(src, value);
423     }
424 
425     private ValueNode createValueNode( URI src, Object object) {
426         org.xmlhammer.model.project.Object value = new org.xmlhammer.model.project.Object();
427 
428         value.setSrc(URIUtils.toString(src));
429         value.setClazz(object.getClass().getName());
430         value.setValue(object.toString());
431         
432         return new ValueNode(src, value);
433     }
434 
435     public void addMessage(URI src, String type, String value) {
436 		Message message = new Message();
437         message.setSrc(URIUtils.toString(src));
438         message.setType(type);
439         message.setValue(value);
440         
441         addNode(src, new MessageNode(src, message));
442 	}
443 	
444 	public Output getOutput() {
445 		return output;
446 	}
447 	
448     // Creates a new valid URINode.
449     private void addValidNode( final URI src, final boolean valid) {
450         try {
451             SwingUtilities.invokeAndWait( new Runnable() {
452                 public void run() {
453                     MutableTreeNode root = resolveDirectory( (MutableTreeNode)getRoot(), base, src);
454                     insertNode( root, new URINode( src, valid));
455                 }
456             });
457         } catch (InterruptedException e) {
458             Logger.getLogger(this.getClass()).error( "Unexpected Error", e);
459         } catch (InvocationTargetException e) {
460             Logger.getLogger(this.getClass()).error( "Unexpected Error", e);
461         }
462     }
463 
464     // gets an existing URINode, creates and adds a new one if no URINode exist.
465 	private void addNode( final URI src, final ResultNode node) { 
466         try {
467             SwingUtilities.invokeAndWait( new Runnable() {
468                 public void run() {
469                     MutableTreeNode root = resolveDirectory( (MutableTreeNode)getRoot(), base, src);
470             
471                     URINode uri = null;
472             		for ( int i = 0; i < root.getChildCount(); i++) {
473             			URINode child = (URINode)root.getChildAt( i);
474             			
475             			if ( child.getURI().equals( src)) {
476             				uri = child;
477             			}
478             		}
479             		
480             		if ( uri == null) {
481             			// Could not find a URI node ...
482             			uri = new URINode( src);
483             			insertNode( root, uri);
484             		}
485             		
486             		insertNode( uri, node);
487                 }
488             });
489         } catch (InterruptedException e) {
490             Logger.getLogger(this.getClass()).error( "Unexpected Error", e);
491         } catch (InvocationTargetException e) {
492             Logger.getLogger(this.getClass()).error( "Unexpected Error", e);
493         }
494 	}
495     
496     private void insertNode( MutableTreeNode parent, ResultNode node) { 
497     	final int index = parent.getChildCount();
498 		parent.insert( node, index);
499 		
500 		int[] newIndexs = new int[1];
501 		newIndexs[0] = index;
502         nodesWereInserted( parent, newIndexs);
503     }
504 
505 //    public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index){
506 //		parent.insert( newChild, index);
507 //		
508 //		int[] newIndexs = new int[1];
509 //		
510 //        newIndexs[0] = index;
511 //
512 //        nodesWereInserted(parent, newIndexs);
513 //    }
514 
515     public MutableTreeNode resolveDirectory( MutableTreeNode node, URI base, URI src) {
516         if ( base != null) {
517             URI relative = base.relativize( src);
518             String rel =relative.toString();
519             
520             if ( rel.contains( "/")) {
521                 URI dir = base.resolve( rel.substring( 0, rel.indexOf( '/')+1));
522                 
523                 URINode uri = null;
524                 for ( int i = 0; i < node.getChildCount(); i++) {
525                     URINode child = (URINode)node.getChildAt( i);
526                                         
527                     if ( child.getURI().toString().equals( dir.toString())) {
528                         uri = child;
529                         break;
530                     }
531                 }
532     
533                 if ( uri != null) {
534                     return resolveDirectory( uri, dir, src);
535                 }
536 
537                 // Could not find a URI node ...
538                 DirectoryNode dirNode = new DirectoryNode( dir);
539                 insertNode( node, dirNode);
540                 return resolveDirectory( dirNode, dir, src);
541             }
542         }
543         
544         return node;
545     }
546     
547     private static String limitString( Node node, int size) {
548         String result = "";
549 
550         if (node instanceof Text) {
551             String value = node.getNodeValue();
552             if ( value != null) {
553                 result = value;
554                 
555                 if ( value.length() > size) {
556                     result = value.substring(0, size-1) + "...";
557                 }
558             }
559         }
560         
561         return result;
562     }
563 
564     private static String limitString( String value, int size) {
565         String result = "";
566         if ( value != null) {
567             result = value;
568             
569             if ( value.length() > size) {
570                 result = value.substring(0, size-1) + "...";
571             }
572         }
573         
574         return result;
575     }
576 
577     private static String getContext(Node node, String content) {
578         if (node instanceof Element) {
579             return getContext( (Element)node, content);
580         }
581         
582         return content;
583     }
584 
585     private static String getContext(Element element, String content) {
586         StringBuffer buffer = new StringBuffer("<");
587         buffer.append(element.getNodeName());
588         
589         NamedNodeMap map = element.getAttributes();
590         for (int i = 0; i < map.getLength(); i++) {
591             Node node = map.item(i);
592             if (node instanceof Attr) {
593                 buffer.append("\n\t");
594                 buffer.append(writeAttribute((Attr)node));
595             }
596         }
597         
598 //        String namespace = element.getNamespaceURI();
599 //        if ( namespace != null && namespace.length() > 0) {
600 //            buffer.append("\n\t");
601 //            buffer.append(writeNamespace(element.getPrefix(), namespace));
602 //        }
603 
604         buffer.append(">");
605         if ( content != null && content.length() > 0) {
606             buffer.append("\n\t");
607             buffer.append( content);
608         }
609         buffer.append("\n</");
610         buffer.append(element.getNodeName());
611         buffer.append(">");
612 
613         return buffer.toString();
614     }
615 
616     private static String writeAttribute(Attr attribute) {
617         StringBuffer buffer = new StringBuffer();
618 
619 //        String namespace = attribute.getNamespaceURI();
620 //        if ( namespace != null && namespace.length() > 0) {
621 //            buffer.append(writeNamespace(attribute.getPrefix(), namespace));
622 //            buffer.append("\n\t");
623 //        }
624         
625         buffer.append(attribute.getNodeName());
626         buffer.append("=\"");
627         buffer.append(attribute.getNodeValue());
628         buffer.append("\"");
629 
630         return buffer.toString();
631     }
632 
633 //    private static String writeNamespace(String prefix, String uri) {
634 //        StringBuffer buffer = new StringBuffer();
635 //        
636 //        if ( uri != null && uri.length() > 0) {
637 //            buffer.append("xmlns");
638 //    
639 //            if ( prefix != null && prefix.length() > 0) {
640 //                buffer.append(":");
641 //                buffer.append(prefix);
642 //            }
643 //    
644 //            buffer.append("=\"");
645 //            buffer.append(uri);
646 //            buffer.append("\"");
647 //        }
648 //
649 //        return buffer.toString();
650 //    }
651 
652     private static String writePI(ProcessingInstruction pi) {
653         StringBuffer buffer = new StringBuffer("<?");
654         
655         buffer.append(pi.getTarget());
656         buffer.append(" ");
657         buffer.append(pi.getData());
658         buffer.append("?>");
659         
660         return buffer.toString();
661     }
662 
663     private static String writeComment(String comment) {
664         StringBuffer buffer = new StringBuffer("<!-- ");
665         
666         buffer.append(comment);
667         buffer.append(" -->");
668         
669         return buffer.toString();
670     }
671 
672     private static String getPath(Node node) {
673         StringBuffer buffer = new StringBuffer();
674 
675         if ( node != null && node instanceof Element) {
676             buffer.append(getPath(node.getParentNode()));
677             buffer.append("/");
678             buffer.append(node.getNodeName());
679         }
680 
681         return buffer.toString();
682     }
683 }