package viewer; import javax.swing.*; import gui.*; import sj.lang.ListExpr; import java.awt.*; import java.awt.event.*; import tools.Reporter; import java.util.*; enum Type {STRING,INT,REAL,BOOL,TEXT,GENERIC}; /** This class is a SecondoViewer usuable for querying predefined functions. * In fact, this viewer displays no objects. **/ public class FunctionParamViewer extends SecondoViewer{ private JPanel paramPanel; // panel including the params and the send button private JComboBox functions; // selection for functions private ListExpr objectList; // lists of objects in the database private JPanel emptyPanel; // displayed if no function is selected private JPanel currentPanel; // pointer to the currently display panel private ActionListener theActionListener; // actionListener for sending a qury to Secondo private String funName; // name of the currently selected function private JComboBox selectDBCB; // combobox for database selection private JComboBox selectFunDescCB; // combobox for selecting the table containing functions descriptions private JComboBox selectParamDescCB; // combobox for selecting the table containing parameter descriptions private String funDescTable; // name of the selected table with fucntion descriptions private HashMap funDescMap; // mapping from function name to function description private String paramDescTable; // name of the table for parameter descriptions private HashMap< String, HashMap > paramDescMap; // mapping function name -> (mapping param name -> param description private tools.HTMLDialog helpDialog; private MenuVector mv; private final int maxFunDesc = 1000; private final int maxParamDesc = 10000; /** Constructs a new FunctionParamViewer. **/ public FunctionParamViewer(){ paramPanel = new JPanel(); setLayout(new BorderLayout()); add(paramPanel, BorderLayout.CENTER); JPanel controlPanel = new JPanel(); controlPanel.setLayout(new GridLayout(2,5)); controlPanel.add(new JLabel("Update DB list")); controlPanel.add(new JLabel("Database")); controlPanel.add(new JLabel("fun descriptions")); controlPanel.add(new JLabel("param descriptions")); controlPanel.add(new JLabel("use function")); JButton updateDbBtn = new JButton("update DB"); controlPanel.add(updateDbBtn); updateDbBtn.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent evt){ updateDB(); } }); selectDBCB = new JComboBox(); selectDBCB.addItem("none"); controlPanel.add(selectDBCB); selectDBCB.addItemListener(new ItemListener(){ public void itemStateChanged(ItemEvent evt){ if(evt.getStateChange() == ItemEvent.SELECTED){ Object o = evt.getItem(); if(o==null){ selectDB(null); } else { selectDB(o.toString()); } } } }); selectFunDescCB = new JComboBox(); selectFunDescCB.addItem("none"); controlPanel.add(selectFunDescCB); selectFunDescCB.addItemListener(new ItemListener(){ public void itemStateChanged(ItemEvent evt){ if(evt.getStateChange() == ItemEvent.SELECTED){ Object o = evt.getItem(); if(o==null){ selectFunDesc(null); } else { selectFunDesc(o.toString()); } } } }); selectParamDescCB = new JComboBox(); selectParamDescCB.addItem("none"); controlPanel.add(selectParamDescCB); selectParamDescCB.addItemListener(new ItemListener(){ public void itemStateChanged(ItemEvent evt){ if(evt.getStateChange() == ItemEvent.SELECTED){ Object o = evt.getItem(); if(o==null){ selectParamDesc(null); } else { selectParamDesc(o.toString()); } } } }); functions = new JComboBox(); functions.addItem("none"); controlPanel.add(functions); functions.addItemListener(new ItemListener(){ public void itemStateChanged(ItemEvent evt){ if(evt.getStateChange()==ItemEvent.SELECTED){ buildPanel(); } else { setEmpty(); } } }); add(controlPanel,BorderLayout.SOUTH); emptyPanel = new JPanel(); currentPanel = emptyPanel; paramPanel.add(currentPanel); theActionListener = new ActionListener(){ public void actionPerformed(ActionEvent evt){ doQuery(); } }; helpDialog = new tools.HTMLDialog("Help"); helpDialog.setText(getHelpText()); JMenu menu = new JMenu("FunctionParamViewer"); JMenuItem helpItem = new JMenuItem("Help"); helpItem.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent evt){ helpDialog.setVisible(true); } }); menu.add(helpItem); mv = new MenuVector(); mv.addMenu(menu); } private String getHelpText(){ String res = ""; res += "\n"; res += "\n"; res += ""; res += "\n"; res += "\n"; res += "

FunctionParamViewer

\n"; res += "

Propose of this Viewer

\n"; res +="
\n"; res += "This viewer is intended to perform predefined functions stored in " + " a database. If the database is well prepared, the user will find some " + "functions as well as table describing the functionality of these functions " + " and there parameters.
\n" + " The viewer does not display any Secondo objects. If a query is send to " + " the Secondo DBMS, an appropriate viewer for this result will be chosen."; res +="
\n"; res += "

Usage of this Viewer

\n"; res += "
\n"; res += "This viewer can be used in several steps:
" + "
    " + "
  1. Press the update Button
    " + " This retrieves the avaiable databases of Secondo and inserts them into the selection box
  2. \n" + "
  3. Select the database
    " + " After selecting a database, this database is scanned for function objects and tables" + " providing desctiptions for functions and parameters. All candidate tables are " + " inserted into the corresponding selection boxes.
  4. " + "
  5. Selection of function and parameter descriptions
    " + " Using the selection boxes, one can choose the tables containing the descriptions" + " for fucntions and their parameters.
  6. " + "
  7. Selection of the function
    " + " During selection of the fucntion, tool tips are provided giving information about the " + " the functions where the mouse is over. If there is no tool tip, either the is no " + " table selected containing function descriptions or the selected table does not " + " have any information about this function.
    " + " After selecting a certain function, the main area is filled with control elements" + " for entering the parameters of the selected function.
  8. " + "
  9. Entering Parameters
    " + " After selecting a function, the main area contains for each parameter of this function" + " a row consisting of four columns.
    " + " The first columns contains the name of this parameter, the second column is a text field" + " for entering constant values, the third column is a selection box for selecting database objects as parameter," + " and the last column describes the type of this parameter.
    " + " Note: The content of the text field is only used, if the database object selection is "const"." + " The "send query" called the function stored in the Secondo system using the entered parameter.
  10. " + "
"; res += "
\n"; res += "

For Database Administrators

\n"; res += " To use a database with this viewer for querying, at least one function must be provided. " + " Each function should be described in a table. Even auxiliary functions should be described, e.g. " + " with "For internal use only".
" + " For function descriptions a table with two attributes is used. The first attribute has to be of " + " type string and represents the name of the function to describe." + " The second attribute can be of type string or of type text and contains the description of this function.
" + " Parameter descriptions are stored in another table with three attributes. " + " The first two attributes have to be of type string and refer to the function name and the parameter name, respectively.
" + " The third attribute contains the description of this parameter and has to be of type string or text.

" + " For reasons of storage management, the size of describing tables is restricted. " + " The maximum size of the table for function descriptions is " + maxFunDesc + " and the size of the table " + " describing the parameters of all functions is restricted to " + maxParamDesc+".
" + " The viewer only uses the table scheme for detecting if it contains fucntion or parameter descriptions. " + " It's recommended to have only the describing tables with this type or these table have speaking names. "; res += "\n"; res += "\n"; return res; } /** retrieves the available databases, * and resets all other contents. **/ private void updateDB(){ // clean all combo boxes selectDBCB.removeAllItems(); selectFunDescCB.removeAllItems(); selectParamDescCB.removeAllItems(); functions.removeAllItems(); selectDBCB.addItem("none"); selectFunDescCB.addItem("none"); selectParamDescCB.addItem("none"); functions.addItem("none"); ListExpr databases = VC.getCommandResult("list databases"); if(databases==null){ Reporter.showError("Retrieving available databases failed. \n May be you are not connected to a Secondo server"); return; } databases = databases.second().second(); // ignore inquiry and databases while(!databases.isEmpty()){ selectDBCB.addItem(databases.first().toString()); databases = databases.rest(); } selectDBCB.setSelectedIndex(0); // select "none" } /** Select a database. * The objects stored in the database are get from the server and * analysed to be a description table or a function. **/ private void selectDB( String dbName){ selectFunDescCB.removeAllItems(); selectParamDescCB.removeAllItems(); functions.removeAllItems(); selectFunDescCB.addItem("none"); selectParamDescCB.addItem("none"); functions.addItem("none"); if(dbName==null || dbName.equals("none")){ return; } int openOk = VC.execCommand("{close database | open database "+dbName+" }"); if(openOk!=0){ Reporter.showError("Could not open database " + dbName); return; } // get content of the database ListExpr objects = VC.getCommandResult("list objects"); if(objects==null){ Reporter.showError("Could not retrieve function. \n May be, no database is opened"); return; } objectList = objects.second().second().rest(); retrieveFunDesc(); retrieveParamDesc(); retrieveFunctions(); } /** Retrieves all objects having type rel(tuple( string, string)) or rel(tuple(string, text)) * and inserts the names to fundescCB * when calling this functions, objectList must be up to date. */ private void retrieveFunDesc(){ ListExpr olist = objectList; selectFunDescCB.removeAllItems(); selectFunDescCB.addItem("none"); while(!olist.isEmpty()){ ListExpr o = olist.first(); olist = olist.rest(); ListExpr name = o.second(); ListExpr type = o.fourth(); if(isFunDescType(type)){ selectFunDescCB.addItem(name.toString()); } } } /** Checks whether a type corresponds to a function description table. * This means, the type must be a relation having tuples with two attributes. * The first attribute is the name of the fucntion and must be of type string. * The second attribute is assumed to be a description for the function and must * be of type string or of type text. **/ private boolean isFunDescType(ListExpr type){ if(type.listLength()==1){ type = type.first(); } if(type.listLength()==2 && isSymbol(type.first(),"rel")){ type = type.second(); if(type.listLength()==2 && isSymbol(type.first(),"tuple")){ ListExpr attrList = type.second(); if(attrList.listLength()==2){ ListExpr attr1 = attrList.first(); ListExpr attr2 = attrList.second(); if( attr1.listLength()==2 && attr2.listLength()==2 && isSymbol(attr1.second(),"string") && (isSymbol(attr2.second(),"string") || isSymbol(attr2.second(),"text"))){ return true; } } } } return false; } /** Scans the list of objects in the database and inserts * possible parameter description tables into the according combobox. **/ private void retrieveParamDesc(){ ListExpr olist = objectList; selectParamDescCB.removeAllItems(); selectParamDescCB.addItem("none"); while(!olist.isEmpty()){ ListExpr o = olist.first(); olist = olist.rest(); ListExpr name = o.second(); ListExpr type = o.fourth(); if(isParamDescType(type)){ selectParamDescCB.addItem(name.toString()); } } } /** Checks whether a given type is possible a parameter description. * In this case, the type must be a relation containing tuples with three * attributes. The first attribute is the name of the function and has to * be of type string. The second attribute is the name of the parameter * of this function and has also to be of type string. The third attribute * contains the description of this parameter and has to be of type string * or of typoe text. **/ private boolean isParamDescType(ListExpr type){ if(type.listLength()==1){ type = type.first(); } if(type.listLength()==2 && isSymbol(type.first(),"rel")){ type = type.second(); if(type.listLength()==2 && isSymbol(type.first(),"tuple")){ ListExpr attrList = type.second(); if(attrList.listLength()==3){ ListExpr attr1 = attrList.first(); ListExpr attr2 = attrList.second(); ListExpr attr3 = attrList.third(); if( attr1.listLength()==2 && attr2.listLength()==2 && attr3.listLength()==2 && isSymbol(attr1.second(),"string") && isSymbol(attr2.second(),"string") && (isSymbol(attr3.second(),"string") || isSymbol(attr3.second(),"text"))){ return true; } } } } return false; } /** Returns the string value of a list of type string, text or symbol. **/ private static String getText(ListExpr e){ if(e.atomType()==ListExpr.STRING_ATOM){ return e.stringValue(); } if(e.atomType()==ListExpr.TEXT_ATOM){ return e.textValue(); } if(e.atomType()==ListExpr.SYMBOL_ATOM){ return e.symbolValue(); } return null; } /** Selects the table used for function descriptions. * All functions in the function combobox are extended * by a tooltip text if a description of this function is * available. **/ private void selectFunDesc(String tableName){ funDescTable = null; funDescMap = null; functions.setToolTipText(null); if(tableName == null || tableName.equals("none")){ return; } ListExpr tableCount = VC.getCommandResult("query " + tableName + " count"); if(tableCount==null){ Reporter.showError("Could not retrieve size of function description table " + tableName); return; } int tc = tableCount.second().intValue(); funDescTable = tableName; funDescMap = new HashMap(); if(tc <= maxFunDesc){ // retrieve the complete table ListExpr table = VC.getCommandResult("query " + tableName); if(table==null){ Reporter.writeError("Could not retrieve table " + tableName); return; } ListExpr type = table.first(); ListExpr value = table.second(); if(!isFunDescType(type)){ Reporter.writeError("Table " + tableName + " has a wrong type \n (press update button and open the db again)"); return; } while(!value.isEmpty()){ ListExpr tuple = value.first(); value = value.rest(); String fn = getText(tuple.first()); String fd = getText(tuple.second()); funDescMap.put(fn,fd); } } else { Reporter.writeError("The table for function descriptions " + tableName + " is too big"); return; } // addToolTips ad the functions combobox DefaultListCellRenderer functionsTT = new DefaultListCellRenderer(){ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){ JComponent comp = (JComponent) super.getListCellRendererComponent(list,value,index,isSelected, cellHasFocus); if(index > -1 && value!=null && !value.toString().equals("none") && funDescMap!=null) { String desc = funDescMap.get(value.toString().trim()); list.setToolTipText(desc); } else { list.setToolTipText(null); } return comp; } }; Object o = functions.getSelectedItem(); if(o==null){ functions.setToolTipText(null); } else { String d = funDescMap.get(o.toString().trim()); functions.setToolTipText(d); } functions.setRenderer(functionsTT); } /** Selects the table of the parameter descriptions. * The content of this table is collected in the paramDescMap mapping. **/ private void selectParamDesc(String tableName){ if(tableName == null || tableName.equals("none")){ paramDescTable = null; paramDescMap = null; changeParamToolTips(); return; } paramDescTable = tableName; paramDescMap = new HashMap >(); ListExpr tableCount = VC.getCommandResult("query " + tableName + " count"); if(tableCount==null){ Reporter.showError("Could not retrieve size of parameter description table " + tableName); changeParamToolTips(); return; } int tc = tableCount.second().intValue(); if(tc <= maxParamDesc){ // retrieve the complete table ListExpr table = VC.getCommandResult("query " + tableName); if(table==null){ Reporter.writeError("Could not retrieve table " + tableName); changeParamToolTips(); return; } ListExpr type = table.first(); ListExpr value = table.second(); if(!isParamDescType(type)){ Reporter.writeError("Table " + tableName + " has a wrong type \n (press update button and open the db again)"); changeParamToolTips(); return; } while(!value.isEmpty()){ ListExpr tuple = value.first(); value = value.rest(); String fn = getText(tuple.first()); String an = getText(tuple.second()); String ad = getText(tuple.third()); HashMap funMap = paramDescMap.get(fn); if(funMap!=null){ funMap.put(an,ad); } else { funMap = new HashMap(); funMap.put(an,ad); paramDescMap.put(fn,funMap); } } changeParamToolTips(); } else { Reporter.writeError("The table for parameter descriptions " + tableName + " is too big"); changeParamToolTips(); return; } } /** Changes the tooltips for parameters according to the selection. **/ private void changeParamToolTips(){ int c = currentPanel.getComponentCount(); for(int i=0;i0){ query += ", "; } query += pp.getParamString(); params++; } } query += ")"; if(!VC.execUserCommand(query)){ Reporter.showInfo("problem in query found"); } } /** Scans the list of objects for functions and inserts there * names into the corresponding combo box. **/ private void retrieveFunctions(){ ListExpr olist = objectList; while(!olist.isEmpty()){ ListExpr o = olist.first(); ListExpr name = o.second(); ListExpr type = o.fourth(); if(type.listLength()>0 ){ ListExpr mt = type.first(); if(mt.listLength()>2){ mt = mt.first(); if(mt.atomType()==ListExpr.SYMBOL_ATOM && mt.symbolValue().equals("map")){ String n = name.toString(); functions.addItem(n); } } } olist=olist.rest(); } functions.setSelectedIndex(0); } /** Calls validate recursively. **/ public static void validate(Container c){ c.invalidate(); Component[] childs = c.getComponents(); for(int i=0;i funMap = paramDescMap.get(funName); if(funMap == null){ return; } String d = funMap.get(name); nameLabel.setToolTipText(d); typeLabel.setToolTipText(d); } /** Called when the selected db objects has been changed. **/ private void changeObject(){ String s = dbObjects.getSelectedItem().toString(); if(s.equals("const")){ constField.setEnabled(true); } else { constField.setEnabled(false); } } /** returns the parameter for embedding in a query. **/ public String getParamString() { String s = dbObjects.getSelectedItem().toString(); if(!s.equals("const")){ return s; } String c = constField.getText(); switch(stype){ case STRING : c = c.replaceAll("\\\"","\\\\\""); return "\""+c+"\""; case INT : return c.trim(); case REAL : return c.trim(); case BOOL : return c.toUpperCase().trim(); case TEXT : c = c.replaceAll("'","\\\\'"); return "'"+c+"'"; default : return "[const " + exactType+" value " + c+ "]"; } } /** checks whether the content is ok. **/ public boolean checkContent(){ if(!dbObjects.getSelectedItem().toString().equals("const")){ return true; } String c = constField.getText(); switch(stype){ case STRING : return c.length() < 48; case INT : try{Integer.parseInt(c.trim()); return true;} catch(Exception e){ return false; } case REAL : try{Double.parseDouble(c.trim()); return true;} catch(Exception e){ return false; } case BOOL : c = c.toUpperCase().trim(); return c.equals("TRUE") || c.equals("FALSE"); case TEXT : return true; default : ListExpr l = new ListExpr(); return l.readFromString(c)==0; } } /** extracts the main type from a type description. **/ String mainType(ListExpr l){ while(l.atomType()!=ListExpr.SYMBOL_ATOM){ l = l.first(); } return l.toString(); } /** Returns the name of this parameter. **/ public String getName() { return name; } } }