| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.mrql; |
| |
| import org.apache.mrql.gen.*; |
| import java.util.Enumeration; |
| import java.io.*; |
| import javax.swing.*; |
| import javax.swing.JTree.*; |
| import javax.swing.tree.*; |
| import javax.swing.event.*; |
| import java.awt.*; |
| import java.awt.event.*; |
| |
| |
| /* The MRQL debugger that uses the lineage generated in Provenance.gen */ |
| public class Debugger extends JPanel implements TreeSelectionListener { |
| final MRData result; |
| final JTree tree; |
| final JTextField search = new JTextField(20); |
| private static volatile boolean exit = false; |
| Trees exprs; |
| |
| /** wrapped strings to be colored red */ |
| private final static class TaggedString { |
| public String value; |
| TaggedString ( String value ) { this.value = value; } |
| public String toString () { return value; } |
| } |
| |
| public Debugger ( MRData result_value, Trees exprs ) { |
| super(new GridLayout(1,0)); |
| result = result_value; |
| this.exprs = exprs; |
| JToolBar toolBar = new JToolBar(""); |
| toolBar.setPreferredSize(new Dimension(1000,40)); |
| JButton button = new JButton(); |
| button.setActionCommand("Previous"); |
| button.setText("prev"); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed ( ActionEvent e ) { |
| } |
| }); |
| button.setVisible(false); |
| toolBar.add(button); |
| button = new JButton(); |
| button.setActionCommand("Next"); |
| button.setText("next"); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed ( ActionEvent e ) { |
| } |
| }); |
| button.setVisible(false); |
| toolBar.add(button); |
| toolBar.add(Box.createRigidArea(new Dimension(400,0))); |
| button = new JButton(); |
| button.setActionCommand("Clear"); |
| button.setText("clear"); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed ( ActionEvent e ) { |
| search.setText(""); |
| DefaultTreeModel model = (DefaultTreeModel)tree.getModel(); |
| DefaultMutableTreeNode root = createNode(result,"",""); |
| root.setUserObject("results"); |
| model.setRoot(root); |
| model.reload(root); |
| } |
| }); |
| toolBar.add(button); |
| toolBar.add(search); |
| button = new JButton(); |
| button.setActionCommand("SearchOutput"); |
| button.setText("Search Output"); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed ( ActionEvent e ) { |
| if (!search.getText().equals("")) { |
| DefaultTreeModel model = (DefaultTreeModel)tree.getModel(); |
| DefaultMutableTreeNode root = createNode(result,search.getText(),""); |
| root.setUserObject("search output results"); |
| model.setRoot(root); |
| model.reload(root); |
| } |
| } |
| }); |
| toolBar.add(button); |
| button = new JButton(); |
| button.setActionCommand("SearchInput"); |
| button.setText("Search Input"); |
| button.addActionListener(new ActionListener() { |
| public void actionPerformed ( ActionEvent e ) { |
| if (!search.getText().equals("")) { |
| DefaultTreeModel model = (DefaultTreeModel)tree.getModel(); |
| DefaultMutableTreeNode root = createNode(result,"",search.getText()); |
| root.setUserObject("search input results"); |
| model.setRoot(root); |
| model.reload(root); |
| } |
| } |
| }); |
| toolBar.add(button); |
| tree = new JTree(createNode(result,"","")); |
| JScrollPane sp = new JScrollPane(tree,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, |
| JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); |
| sp.setPreferredSize(new Dimension(1000,2000)); |
| sp.getVerticalScrollBar().setPreferredSize(new Dimension(20,0)); |
| tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); |
| Font currentFont = tree.getFont(); |
| tree.setFont(new Font(currentFont.getName(), |
| currentFont.getStyle(), |
| (int)(currentFont.getSize()*1.5))); |
| DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() { |
| public Component getTreeCellRendererComponent |
| ( JTree tree, Object value, boolean sel, boolean exp, |
| boolean leaf, int row, boolean hasFocus ) { |
| super.getTreeCellRendererComponent(tree,value,sel,exp,leaf,row,hasFocus); |
| // tagged strings are red |
| if (((DefaultMutableTreeNode)value).getUserObject() instanceof TaggedString) |
| setForeground(Color.red); |
| return this; |
| } |
| }; |
| renderer.setLeafIcon(null); |
| renderer.setOpenIcon(null); |
| renderer.setClosedIcon(null); |
| tree.setCellRenderer(renderer); |
| tree.addTreeSelectionListener(this); |
| setLayout(new BorderLayout()); |
| add(toolBar,BorderLayout.NORTH); |
| add(sp,BorderLayout.CENTER); |
| } |
| |
| public void valueChanged ( TreeSelectionEvent e ) { } |
| |
| private String exprNode ( Tree e ) { |
| match e { |
| case call(source,_,`path,...): |
| return "source: "+path; |
| case call(`f,...): |
| return f.toString(); |
| case cmap(lambda(`v,_),_): |
| return "cmap "+v; |
| case groupBy(_): |
| return "groupBy"; |
| case coGroup(...): |
| return "coGroup"; |
| case reduce(`m,...): |
| return "reduce("+m+")"; |
| case project(`v,`a): |
| return exprNode(v)+"."+a; |
| case nth(`x,`n): |
| return exprNode(x)+"#"+n; |
| case `f(...): |
| return f; |
| }; |
| return e.toString(); |
| } |
| |
| private DefaultMutableTreeNode create_node ( MRData value, int n, String inputSearch ) { |
| if (value instanceof Tuple) { |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode("input "+n); |
| DefaultMutableTreeNode child = provenanceNode(value,inputSearch); |
| if (child.getUserObject() instanceof TaggedString) |
| node.setUserObject(new TaggedString("input "+n)); |
| node.add(child); |
| return node; |
| } else if (value instanceof Bag) { |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode("input "+n); |
| boolean matched = false; |
| for ( MRData e: (Bag)value ) { |
| DefaultMutableTreeNode child = provenanceNode(e,inputSearch); |
| matched |= child.getUserObject() instanceof TaggedString; |
| node.add(child); |
| }; |
| if (matched) |
| node.setUserObject(new TaggedString("input "+n)); |
| return node; |
| } else return new DefaultMutableTreeNode(value.toString()); |
| } |
| |
| private DefaultMutableTreeNode provenanceNode ( MRData value, String inputSearch ) { |
| Tuple p = ((Tuple)value); |
| MRData v = p.get(1); |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode(v.toString()); |
| Tree opr = exprs.nth(((MR_int)p.get(0)).get()); |
| node.add(new DefaultMutableTreeNode(exprNode(opr))); |
| boolean matched = false; |
| for ( int i = 2; i < p.size(); i++ ) { |
| DefaultMutableTreeNode child = create_node(p.get(i),i-1,inputSearch); |
| node.add(child); |
| matched |= child.getUserObject() instanceof TaggedString; |
| }; |
| if (matched) |
| node.setUserObject(new TaggedString(v.toString())); |
| else match opr { |
| case call(source,...): |
| if (!inputSearch.equals("") && v.toString().contains(inputSearch)) |
| node.setUserObject(new TaggedString(v.toString())); |
| }; |
| return node; |
| } |
| |
| private DefaultMutableTreeNode createNode ( MRData value, String outputSearch, String inputSearch ) { |
| if (value instanceof Bag) { |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode("results"); |
| for ( MRData e: (Bag)value ) |
| if (outputSearch.equals("") || ((Tuple)e).get(0).toString().contains(outputSearch)) { |
| DefaultMutableTreeNode child = provenanceNode(((Tuple)e).get(1),inputSearch); |
| if (inputSearch.equals("") || (child.getUserObject() instanceof TaggedString)) |
| node.add(child); |
| }; |
| return node; |
| } else if (value instanceof MR_dataset) { |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode("results"); |
| for ( MRData e: ((MR_dataset)value).dataset().take(Config.max_bag_size_print) ) |
| if (outputSearch.equals("") || ((Tuple)e).get(0).toString().contains(outputSearch)) { |
| DefaultMutableTreeNode child = provenanceNode(((Tuple)e).get(1),inputSearch); |
| if (inputSearch.equals("") || (child.getUserObject() instanceof TaggedString)) |
| node.add(child); |
| }; |
| return node; |
| } else { |
| DefaultMutableTreeNode node = new DefaultMutableTreeNode(((Tuple)value).get(0).toString()); |
| node.add(provenanceNode(((Tuple)value).get(1),inputSearch)); |
| return node; |
| } |
| } |
| |
| private static void createAndShowGUI ( MRData lineage, Tree tp, Trees exprs ) { |
| final JFrame frame = new JFrame("MRQL debugger"); |
| frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); |
| frame.addWindowListener(new WindowListener() { |
| public void windowClosing ( WindowEvent e ) { |
| frame.setVisible(false); |
| frame.dispose(); |
| exit = true; |
| } |
| public void windowActivated ( WindowEvent e ) {} |
| public void windowClosed ( WindowEvent e ) {} |
| public void windowDeactivated ( WindowEvent e ) {} |
| public void windowDeiconified ( WindowEvent e ) {} |
| public void windowIconified ( WindowEvent e ) {} |
| public void windowOpened ( WindowEvent e ) {} |
| }); |
| frame.add(new Debugger(lineage,exprs)); |
| frame.pack(); |
| frame.setVisible(true); |
| } |
| |
| /** use the MRQL debugger on a query result |
| * @param lineage the query result extended with lineage |
| * @param type the result type |
| * @param exprs the expr terms used in the lineage |
| */ |
| public static void debug ( final MRData lineage, final Tree type, final Trees exprs ) { |
| try { |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run () { |
| createAndShowGUI(lineage,type,exprs); |
| } |
| }); |
| exit = false; |
| while (!exit) |
| Thread.sleep(1000); |
| } catch (Exception ex) { |
| } |
| } |
| } |