View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.util.viewer.model;
5   
6   import java.io.StringReader;
7   import java.util.ArrayList;
8   import java.util.List;
9   import java.util.logging.Level;
10  import java.util.logging.Logger;
11  
12  import net.sourceforge.pmd.lang.LanguageVersion;
13  import net.sourceforge.pmd.lang.LanguageVersionHandler;
14  import net.sourceforge.pmd.lang.ast.Node;
15  import net.sourceforge.pmd.lang.ast.ParseException;
16  import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator;
17  
18  import org.jaxen.BaseXPath;
19  import org.jaxen.JaxenException;
20  import org.jaxen.XPath;
21  
22  public class ViewerModel {
23      private final static Logger LOGGER = Logger.getLogger(ViewerModel.class.getName()); 
24  
25      private List<ViewerModelListener> listeners;
26      private Node rootNode;
27      private List<Node> evaluationResults;
28  
29      public ViewerModel() {
30          listeners = new ArrayList<>(5);
31      }
32  
33      public Node getRootNode() {
34  	return rootNode;
35      }
36  
37      /**
38       * commits source code to the model.
39       * all existing source will be replaced
40       */
41      public void commitSource(String source, LanguageVersion languageVersion) {
42  	LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
43  	Node node =  languageVersionHandler
44  		.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null, new StringReader(source));
45  	rootNode = node;
46  	fireViewerModelEvent(new ViewerModelEvent(this, ViewerModelEvent.CODE_RECOMPILED));
47      }
48  
49      /**
50       * determines whether the model has a compiled tree at it's disposal
51       *
52       * @return true if there is an AST, false otherwise
53       */
54      public boolean hasCompiledTree() {
55  	return rootNode != null;
56      }
57  
58      /**
59       * evaluates the given XPath expression against the current tree
60       *
61       * @param xPath     XPath expression to be evaluated
62       * @param evaluator object which requests the evaluation
63       */
64      public void evaluateXPathExpression(String xPath, Object evaluator) throws ParseException, JaxenException {
65  	try 
66  	{
67  	    if (LOGGER.isLoggable(Level.FINEST)) {
68      	LOGGER.finest("xPath="+xPath);
69      	LOGGER.finest("evaluator="+evaluator);
70  	    }
71  	XPath xpath = new BaseXPath(xPath, new DocumentNavigator());
72  	if (LOGGER.isLoggable(Level.FINEST)) {
73      	LOGGER.finest("xpath="+xpath);
74      	LOGGER.finest("rootNode="+rootNode);
75  	}
76  	try
77  	{
78  		evaluationResults = xpath.selectNodes(rootNode);
79  	}
80  	catch (Exception e)
81  	{
82  		LOGGER.finest("selectNodes problem:");
83  		e.printStackTrace(System.err);
84  	}
85  	if (LOGGER.isLoggable(Level.FINEST)) {
86  	    LOGGER.finest("evaluationResults="+evaluationResults);
87  	}
88  	fireViewerModelEvent(new ViewerModelEvent(evaluator, ViewerModelEvent.PATH_EXPRESSION_EVALUATED));
89  	}
90  	catch (JaxenException je)
91  	{
92  	 je.printStackTrace(System.err);
93           throw je;
94  	}
95      }
96  
97      /**
98       * retrieves the results of last evaluation
99       *
100      * @return a list containing the nodes selected by the last XPath expression
101      *         <p/>
102      *         evaluation
103      */
104     public List<Node> getLastEvaluationResults() {
105 	return evaluationResults;
106     }
107 
108     /**
109      * selects the given node in the AST
110      *
111      * @param node     node to be selected
112      * @param selector object which requests the selection
113      */
114     public void selectNode(Node node, Object selector) {
115 	fireViewerModelEvent(new ViewerModelEvent(selector, ViewerModelEvent.NODE_SELECTED, node));
116     }
117 
118     /**
119      * appends the given fragment to the XPath expression
120      *
121      * @param pathFragment fragment to be added
122      * @param appender     object that is trying to append the fragment
123      */
124     public void appendToXPathExpression(String pathFragment, Object appender) {
125 	fireViewerModelEvent(new ViewerModelEvent(appender, ViewerModelEvent.PATH_EXPRESSION_APPENDED, pathFragment));
126     }
127 
128     public void addViewerModelListener(ViewerModelListener l) {
129 	listeners.add(l);
130     }
131 
132     public void removeViewerModelListener(ViewerModelListener l) {
133 	listeners.remove(l);
134     }
135 
136     protected void fireViewerModelEvent(ViewerModelEvent e) {
137 	for (int i = 0; i < listeners.size(); i++) {
138 	    listeners.get(i).viewerModelChanged(e);
139 	}
140     }
141 }