View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.util.designer;
5   
6   import net.sourceforge.pmd.PMD;
7   import net.sourceforge.pmd.RuleContext;
8   import net.sourceforge.pmd.RuleSet;
9   import net.sourceforge.pmd.TargetJDK1_4;
10  import net.sourceforge.pmd.TargetJDK1_5;
11  import net.sourceforge.pmd.TargetJDKVersion;
12  import net.sourceforge.pmd.ast.ASTCompilationUnit;
13  import net.sourceforge.pmd.ast.JavaParser;
14  import net.sourceforge.pmd.ast.ParseException;
15  import net.sourceforge.pmd.ast.SimpleNode;
16  import net.sourceforge.pmd.jaxen.DocumentNavigator;
17  import org.apache.xml.serialize.OutputFormat;
18  import org.apache.xml.serialize.XMLSerializer;
19  import org.jaxen.BaseXPath;
20  import org.jaxen.JaxenException;
21  import org.jaxen.XPath;
22  
23  import javax.swing.*;
24  import java.awt.BorderLayout;
25  import java.awt.Color;
26  import java.awt.FlowLayout;
27  import java.awt.Toolkit;
28  import java.awt.datatransfer.Clipboard;
29  import java.awt.datatransfer.ClipboardOwner;
30  import java.awt.datatransfer.StringSelection;
31  import java.awt.datatransfer.Transferable;
32  import java.awt.event.ActionEvent;
33  import java.awt.event.ActionListener;
34  import java.awt.event.KeyEvent;
35  import java.io.IOException;
36  import java.io.StringReader;
37  import java.io.StringWriter;
38  import java.util.Iterator;
39  import java.util.List;
40  
41  public class Designer implements ClipboardOwner {
42  
43      private JavaParser createParser() {
44          return getJDKVersion().createParser(new StringReader(codeEditorPane.getText()));
45      }
46  
47      private TargetJDKVersion getJDKVersion() {
48          if (jdk14MenuItem.isSelected()) {
49              return new TargetJDK1_4();
50          }
51          return new TargetJDK1_5();
52      }
53  
54      private class ShowListener implements ActionListener {
55          public void actionPerformed(ActionEvent ae) {
56              MyPrintStream ps = new MyPrintStream();
57              System.setOut(ps);
58              try {
59                  ASTCompilationUnit lastCompilationUnit = createParser().CompilationUnit();
60                  lastCompilationUnit.dump("");
61                  astArea.setText(ps.getString());
62              } catch (ParseException pe) {
63                  astArea.setText(pe.fillInStackTrace().getMessage());
64              }
65          }
66      }
67  
68      private class DFAListener implements ActionListener {
69          public void actionPerformed(ActionEvent ae) {
70              try {
71                  DFAGraphRule dfaGraphRule = new DFAGraphRule();
72                  RuleSet rs = new RuleSet();
73                  rs.addRule(dfaGraphRule);
74                  RuleContext ctx = new RuleContext();
75                  ctx.setSourceCodeFilename("[no filename]");
76                  StringReader reader = new StringReader(codeEditorPane.getText());
77                  new PMD(getJDKVersion()).processFile(reader, rs, ctx);
78                  List methods = dfaGraphRule.getMethods();
79                  if (!methods.isEmpty()) {
80                      dfaPanel.resetTo(methods, codeEditorPane);
81                      dfaPanel.repaint();
82                  }
83              } catch (Exception e) {
84                  e.printStackTrace();
85              }
86          }
87  
88      }
89  
90      private class XPathListener implements ActionListener {
91          public void actionPerformed(ActionEvent ae) {
92              xpathResults.clear();
93              if (xpathQueryArea.getText().length() == 0) {
94                  xpathResults.addElement("XPath query field is empty");
95                  xpathResultList.repaint();
96                  codeEditorPane.requestFocus();
97                  return;
98              }
99              JavaParser parser = createParser();
100             try {
101                 XPath xpath = new BaseXPath(xpathQueryArea.getText(), new DocumentNavigator());
102                 ASTCompilationUnit c = parser.CompilationUnit();
103                 for (Iterator iter = xpath.selectNodes(c).iterator(); iter.hasNext();) {
104                     StringBuffer sb = new StringBuffer();
105                     SimpleNode node = (SimpleNode) iter.next();
106                     String name = node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1);
107                     String line = " at line " + String.valueOf(node.getBeginLine());
108                     sb.append(name).append(line).append(System.getProperty("line.separator"));
109                     xpathResults.addElement(sb.toString().trim());
110                 }
111                 if (xpathResults.isEmpty()) {
112                     xpathResults.addElement("No matching nodes " + System.currentTimeMillis());
113                 }
114             } catch (ParseException pe) {
115                 xpathResults.addElement(pe.fillInStackTrace().getMessage());
116             } catch (JaxenException je) {
117                 xpathResults.addElement(je.fillInStackTrace().getMessage());
118             }
119             xpathResultList.repaint();
120             xpathQueryArea.requestFocus();
121         }
122     }
123 
124 
125     private final CodeEditorTextPane codeEditorPane = new CodeEditorTextPane();
126     private final JTextArea astArea = new JTextArea();
127     private DefaultListModel xpathResults = new DefaultListModel();
128     private final JList xpathResultList = new JList(xpathResults);
129     private final JTextArea xpathQueryArea = new JTextArea(15, 30);
130     private final JFrame frame = new JFrame("PMD Rule Designer");
131     private final DFAPanel dfaPanel = new DFAPanel();
132     private JRadioButtonMenuItem jdk14MenuItem;
133     private JRadioButtonMenuItem jdk15MenuItem;
134 
135     public Designer() {
136         JSplitPane controlSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(codeEditorPane), createXPathQueryPanel());
137         JSplitPane resultsSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, createASTPanel(), createXPathResultPanel());
138         
139         JTabbedPane tabbed = new JTabbedPane();
140         tabbed.addTab("Abstract Syntax Tree / XPath", resultsSplitPane);
141         tabbed.addTab("Data Flow Analysis", dfaPanel);
142         try {
143             // Remove when minimal runtime support is >= JDK 1.4
144             if (JTabbedPane.class.getMethod("setMnemonicAt", new Class[]{Integer.TYPE, Integer.TYPE}) != null) {
145                 // Compatible with >= JDK 1.4
146                 tabbed.setMnemonicAt(0, KeyEvent.VK_A);
147                 tabbed.setMnemonicAt(1, KeyEvent.VK_D);
148             }
149         } catch (NoSuchMethodException nsme) {} // Runtime is < JDK 1.4
150 
151         JSplitPane containerSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, controlSplitPane, tabbed);
152         containerSplitPane.setContinuousLayout(true);
153 
154         JMenuBar menuBar = createMenuBar();
155         frame.setJMenuBar(menuBar);
156         frame.getContentPane().add(containerSplitPane);
157         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
158 
159         int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
160         int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
161         frame.setSize(screenHeight - (screenHeight/4), screenHeight - (screenHeight/4));
162         frame.setLocation((screenWidth / 2) - frame.getWidth() / 2, (screenHeight / 2) - frame.getHeight() / 2);
163         frame.setVisible(true);
164         frame.pack();
165         frame.show();
166         resultsSplitPane.setDividerLocation(resultsSplitPane.getMaximumDividerLocation() - (resultsSplitPane.getMaximumDividerLocation() / 2));
167         //containerSplitPane.setDividerLocation(containerSplitPane.getMaximumDividerLocation() / 2);
168     }
169 
170     private JMenuBar createMenuBar() {
171         JMenuBar menuBar = new JMenuBar();
172         JMenu menu = new JMenu("JDK");
173         ButtonGroup group = new ButtonGroup();
174         jdk14MenuItem = new JRadioButtonMenuItem("JDK 1.4");
175         jdk14MenuItem.setSelected(true);
176         group.add(jdk14MenuItem);
177         menu.add(jdk14MenuItem);
178         jdk15MenuItem = new JRadioButtonMenuItem("JDK 1.5");
179         jdk15MenuItem.setSelected(true);
180         group.add(jdk15MenuItem);
181         menu.add(jdk15MenuItem);
182         menuBar.add(menu);
183 
184         JMenu actionsMenu = new JMenu("Actions");
185         JMenuItem copyXMLItem = new JMenuItem("Copy xml to clipboard");
186         copyXMLItem.addActionListener(new ActionListener() {
187             public void actionPerformed(ActionEvent e) {
188                 copyXmlToClipboard();
189             }
190         });
191         actionsMenu.add(copyXMLItem);
192         JMenuItem createRuleXMLItem = new JMenuItem("Create rule XML");
193         createRuleXMLItem.addActionListener(new ActionListener() {
194             public void actionPerformed(ActionEvent e) {
195                 createRuleXML();
196             }
197         });
198         actionsMenu.add(createRuleXMLItem);
199         menuBar.add(actionsMenu);
200         return menuBar;
201     }
202 
203 
204 
205     private void createRuleXML() {
206         JPanel rulenamePanel = new JPanel();
207         rulenamePanel.setLayout(new FlowLayout());
208         rulenamePanel.add(new JLabel("Rule name"));
209         final JTextField rulenameField = new JTextField(30);
210         rulenamePanel.add(rulenameField);
211         JPanel rulemsgPanel = new JPanel();
212         rulemsgPanel.setLayout(new FlowLayout());
213         rulemsgPanel.add(new JLabel("Rule msg"));
214         final JTextField rulemsgField = new JTextField(60);
215         rulemsgPanel.add(rulemsgField);
216         JPanel ruledescPanel = new JPanel();
217         ruledescPanel.setLayout(new FlowLayout());
218         ruledescPanel.add(new JLabel("Rule desc"));
219         final JTextField ruledescField = new JTextField(60);
220         ruledescPanel.add(ruledescField);
221         JPanel ruleXMLPanel = new JPanel();
222         final JTextArea ruleXMLArea = new JTextArea(30, 50);
223         ruleXMLPanel.add(ruleXMLArea);
224         JButton go = new JButton("Create rule XML");
225         go.addActionListener(new ActionListener() {
226             public void actionPerformed(ActionEvent e) {
227                 StringBuffer sb = new StringBuffer();
228                 sb.append("<rule  name=\"" + rulenameField.getText() + "\"" + PMD.EOL);
229                 sb.append("  message=\"" + rulemsgField.getText() + "\"" + PMD.EOL);
230                 sb.append("  class=\"" + (xpathQueryArea.getText().length() == 0 ? "" : "net.sourceforge.pmd.rules.XPathRule") + "\">" + PMD.EOL);
231                 sb.append("  <description>" + PMD.EOL);
232                 sb.append("  " + ruledescField.getText() + PMD.EOL);
233                 sb.append("  </description>" + PMD.EOL);
234                 if (xpathQueryArea.getText().length()!=0) {
235                     sb.append("  <properties>" + PMD.EOL);
236                     sb.append("    <property name=\"xpath\">" + PMD.EOL);
237                     sb.append("    <value>" + PMD.EOL);
238                     sb.append("<![CDATA[" + PMD.EOL);
239                     sb.append(xpathQueryArea.getText() + PMD.EOL);
240                     sb.append("]]>" + PMD.EOL);
241                     sb.append("    </value>" + PMD.EOL);
242                     sb.append("    </property>" + PMD.EOL);
243                     sb.append("  </properties>" + PMD.EOL);
244                 }
245                 sb.append("  <priority>3</priority>" + PMD.EOL);
246                 sb.append("  <example>" + PMD.EOL);
247                 sb.append("<![CDATA[" + PMD.EOL);
248                 sb.append(codeEditorPane.getText());
249                 sb.append("]]>" + PMD.EOL);
250                 sb.append("  </example>" + PMD.EOL);
251                 sb.append("</rule>" + PMD.EOL);
252 
253                 ruleXMLArea.setText(sb.toString());
254             }
255         });
256 
257         JPanel fieldsPanel = new JPanel();
258         fieldsPanel.setLayout(new BorderLayout());
259         fieldsPanel.add(rulenamePanel,  BorderLayout.NORTH);
260         fieldsPanel.add(rulemsgPanel,  BorderLayout.CENTER);
261         fieldsPanel.add(ruledescPanel, BorderLayout.SOUTH);
262 
263         JPanel fieldBtnPanel = new JPanel();
264         fieldBtnPanel.setLayout(new BorderLayout());
265         fieldBtnPanel.add(fieldsPanel, BorderLayout.NORTH);
266         fieldBtnPanel.add(go, BorderLayout.SOUTH);
267 
268         JPanel outer = new JPanel(new BorderLayout());
269         outer.add(fieldBtnPanel, BorderLayout.NORTH);
270         outer.add(ruleXMLPanel, BorderLayout.SOUTH);
271 
272         JDialog d = new JDialog(frame);
273         d.setSize(200,300);
274         d.getContentPane().add(outer);
275         int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
276         int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
277         d.setLocation((screenWidth / 2) - frame.getWidth() / 2, (screenHeight / 2) - frame.getHeight() / 2);
278         d.setVisible(true);
279         d.pack();
280         d.show();
281     }
282 
283     private JComponent createASTPanel() {
284         astArea.setRows(10);
285         astArea.setColumns(20);
286         JScrollPane astScrollPane = new JScrollPane(astArea);
287         return astScrollPane;
288     }
289 
290     private JComponent createXPathResultPanel() {
291         xpathResults.addElement("No results yet");
292         xpathResultList.setBorder(BorderFactory.createLineBorder(Color.black));
293         xpathResultList.setFixedCellWidth(300);
294         JScrollPane scrollPane = new JScrollPane();
295         scrollPane.getViewport().setView(xpathResultList);
296         return scrollPane;
297     }
298 
299     private JPanel createXPathQueryPanel() {
300         JPanel p = new JPanel();
301         p.setLayout(new BorderLayout());
302         xpathQueryArea.setBorder(BorderFactory.createLineBorder(Color.black));
303         JScrollPane scrollPane = new JScrollPane(xpathQueryArea);
304         scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
305         scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
306         final JButton b = createGoButton();
307         
308         p.add(new JLabel("XPath Query (if any)"), BorderLayout.NORTH);
309         p.add(scrollPane, BorderLayout.CENTER);
310         p.add(b, BorderLayout.SOUTH);
311         
312         return p;
313     }
314 
315     private JButton createGoButton() {
316         JButton b = new JButton("Go");
317         b.setMnemonic('g');
318         b.addActionListener(new ShowListener());
319         b.addActionListener(codeEditorPane);
320         b.addActionListener(new XPathListener());
321         b.addActionListener(new DFAListener());
322         return b;
323     }
324 
325     public static void main(String[] args) {
326         new Designer();
327     }
328 
329     private final void copyXmlToClipboard() {
330         if (codeEditorPane.getText()!=null && codeEditorPane.getText().trim().length()>0) {
331             ASTCompilationUnit cu = createParser().CompilationUnit();
332             String xml = "";
333             if (cu!=null) {
334                 try {
335                     xml = getXmlString( cu );
336                 } catch (IOException e) {
337                     e.printStackTrace();
338                     xml = "Error trying to construct XML representation";
339                 }
340             }
341             Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(xml), this);
342         } 
343     }
344 
345     /***
346      * Returns an unformatted xml string (without the declaration)
347      *
348      * @param node
349      * @return
350      * @throws java.io.IOException
351      */
352     private String getXmlString(SimpleNode node) throws IOException {
353         StringWriter writer = new StringWriter();
354         XMLSerializer xmlSerializer = new XMLSerializer(writer, new OutputFormat("XML", "UTF-8", true));
355         xmlSerializer.asDOMSerializer();
356         xmlSerializer.serialize(node.asXml());
357         return writer.toString();
358     }
359 
360     public void lostOwnership(Clipboard clipboard, Transferable contents) {}
361 }