package viewer.chess; import sj.lang.*; import java.lang.*; import java.lang.reflect.*; import javax.swing.*; import javax.swing.event.*; import java.awt.Dimension; import java.awt.event.*; import java.awt.*; import java.util.*; /** * This class provides the functionality to create a secondo or optimizer query from a PositionData object and the meta data of a chessgame. As a subclass of JPanel * also it provides the view for editing the query. * Furthermore this class sends small queries to secondo to find out which relations contain a chessgame. Since this functioniality needs another viewer method invoking and object creation are done via the java.lang.reflect package. Thus even if the other viewer is not available the QueryBuilder class would still be compilable without errors */ public class QueryBuilder extends JPanel implements ChangeListener { /** * class name needed to get a secondo interface */ private static final String SECONDO_INTERFACE_PROVIDER_CLASS = "gui.MainWindow"; /** * method name to get the secondo interface */ private static final String GET_SECONDOINTERFACE_METHOD = "getUpdateInterface"; /** * class name of the secondo interface */ private static final String SECONDO_INTERFACE_CLASS = "sj.lang.UpdateInterface"; /** * method name of the secondo interface class to submit a query to it */ private static final String SECONDO_QUERY_METHOD = "secondo"; /** * names of the parameter classes needed to invoke the secondo query method */ private static final String[] PARAMETER_CLASSES = {"java.lang.String","sj.lang.ListExpr","sj.lang.IntByReference", "sj.lang.IntByReference", "java.lang.StringBuffer"}; /** * class of the secondo interface */ private Class secondoInterfaceClass; /** * the secondo interface as an Object */ private Object secondoInterface; /** * the method to execute the query */ private Method commandExecutionMethod; /** * parameter classes for the query method */ private Class[] parameters; /** * text fields to enter the relations and attributes if it is not possible to get them from secondo */ private JTextField relationsText, attributesText; /** * the textfield where the query is displayed */ private JTextArea queryText ; /** * two lists containing the chessObjects and the indexes in the current database if queries to secondo can be done */ private ArrayList chessObjects, indices; /** * list containing possible relations and chessgame attributes if these can be obtained from secondo */ private JList relationsList, attributesList; /** * layout boxes */ private Box withSecInterface, withoutSecInterface, upper, lower, content, upper2; /** * true if queries to secondo can be send and return other values than empty lists, false otherwise */ private boolean hasSecondoInterface; /** * selection */ private ButtonGroup selection; /** * shows the two kinds of possible queries: secondo and optimizer */ private JTabbedPane tabPane; /** * layout box */ private Box positionOptions; /** * checkboxes giving the possibilty to create a query on the meta data, the position or both */ private JCheckBox metaSelection, positionSelection; /** * check for only similiar positions */ private JRadioButton similiar; /** * check for exactly matching positions */ private JRadioButton equal; /** * textfields for entering specified position numbers for queries */ private JTextField from; private JTextField to; /** * checkbox to decide whether the query should look for positions after a specified move number */ private JCheckBox afterMove; /** * PositionDeliverer to get the position used for the query from */ private PositionDeliverer positionDeliverer; /** * MetaDataDeliverer to get the meta data used for querying from */ private MetaDataDeliverer metaDeliverer; /** * constructor which needs a PositionDeliverer and a MetaDataDeliverer to get the position and the meta data. */ public QueryBuilder(PositionDeliverer positionDeliverer, MetaDataDeliverer metaDeliverer) { try //try if it is possible to get a secondo interface { Class secondoProvider = Class.forName(SECONDO_INTERFACE_PROVIDER_CLASS); Class[] paramTypes = new Class[0]; Method secondoInterfaceMethod = secondoProvider.getMethod(GET_SECONDOINTERFACE_METHOD, paramTypes); Object[] params = new Object[0]; secondoInterface = secondoInterfaceMethod.invoke(null, params); secondoInterfaceClass = Class.forName(SECONDO_INTERFACE_CLASS); parameters = new Class[PARAMETER_CLASSES.length]; for (int i=0;i< PARAMETER_CLASSES.length;i++) { parameters[i] = Class.forName(PARAMETER_CLASSES[i]); } commandExecutionMethod = secondoInterfaceClass.getMethod(SECONDO_QUERY_METHOD, parameters); } catch (Exception e) {} finally { this.metaDeliverer = metaDeliverer; this.positionDeliverer = positionDeliverer; this.initView(); } } /** * this method tries to obtain the objects in the current database containing a chessgame. Returns true if successful false otherwise. optimizerUsed indicates if the optimizer should be used to create a query. If so there are special filters needed to get only the StandardChessRel relations. */ private boolean getChessObjects(boolean optimizerUsed) { try { ListExpr result = tryExecuteQuery("list objects", new ListExpr(), new StringBuffer()); if(result == null || result.isEmpty() ) //if there is no restul returns false return false; ArrayList objects = new ArrayList(); this.getObjects(objects, result); if(objects.isEmpty()) return false; indices = filterNonIndexes(objects); //get the filters objects = this.filterNonRelations(objects); //filter objects not being a relation objects = this.filterNonChessGames(objects); //filter relations not containing a chessgame if(optimizerUsed) { objects = this.filterNonStandardChessRelations(objects); //filter relations that are not standard chess relations (optimizer query) } chessObjects = objects; if(chessObjects.isEmpty()) //if there are no more objects left return false; //return false return true; //true otherwise } catch(Exception e) { return false; } } /** * this method is called to show the queryBuilderInterface. */ public void showQueryBuilder() { Box showBox = tabPane.getSelectedIndex()==0?upper:upper2; Box showNoBox = tabPane.getSelectedIndex()==0?upper2:upper; showNoBox.removeAll(); //remove everything from the tab not seen showNoBox.validate(); try { if(!this.getChessObjects(tabPane.getSelectedIndex()!=0)) //try to get the chess objects if fails then an Exception is thrown throw new Exception(); relationsList.setListData(getChessRelationNames()); //if fails not the lists are put on the upper part of the box relationsList.setSelectedIndex(0); showBox.removeAll(); showBox.add(withSecInterface); showBox.validate(); hasSecondoInterface = true; } catch (Exception e) { showBox.removeAll(); //if it is not possible to obtain objects from secondo the plainer view is shown showBox.add(withoutSecInterface); showBox.validate(); hasSecondoInterface = false; } } /** * returns the names of the relations containing a chessgame */ private String[] getChessRelationNames() throws Exception { if (chessObjects != null) { Object[] objects = chessObjects.toArray(); String[] names = new String[objects.length]; for (int i=0; i< objects.length;i++) { names[i] = ((ListExpr)objects[i]).second().writeListExprToString().trim(); } return names; } return null; } /** * returns the names of the indexes for the 'relation relationsName'. The indexes' names have to be according to the name convention of indexes. E.g an index for 'attribute' of the relation 'RELATION' would have to be calles 'rELATION_attribute' with a leading lower case character and a underscore between relation name and attribute. */ private String[] getRelationsIndexNames(String relationsName) throws Exception { ArrayList out = new ArrayList(); String[] indexes = getIndicesNames(); boolean equalAttributes = true; String name = relationsName; char[] nameChar = name.toCharArray(); nameChar[0] = Character.toLowerCase(nameChar[0]); name = new String(nameChar)+"_"; for (int i= 0;i=2) list = list.second(); if(list != null && !list.isEmpty()&&list.listLength()>=2) list = list.second(); if(list != null && !list.isEmpty()&&list.listLength()>=2) list = list.rest(); while(list != null && !list.isEmpty()) { objects.add(list.first()); list = list.rest(); } } /** * this method returns an arraylist that contains those values of 'objects' which are relations */ private ArrayList filterNonRelations(ArrayList objects) throws Exception { ArrayList out = new ArrayList(); Object[] theObjects = objects.toArray(); ListExpr current, relation; boolean remove; for (int i=0; i= "); query.append(from); query.append("] "); } query.append("filter [.tempPos includes[ "); query.append(position.toString()); query.append("]]"); if(exact) { query.append( " filter ["); //if exact matching is needed query.append(position.toString()); query.append(" includes [.tempPos]] "); } query.append("remove[tempPos] sort rdup "); } /** * appends the part of the query where the meta tags are compared to each other */ private void createMetaQueryPart(String attribute, StringBuffer query) { HashMap metaVals = metaDeliverer.getMetaVals(); Object[] keys = metaVals.keySet().toArray(); for (int i=0;i< keys.length; i++) { query.append("filter [."); query.append(attribute); query.append(" getkey[\""); query.append(ChessToolKit.convertKeyStringToListFormat((String)keys[i])); query.append("\"] = \""); query.append((String)metaVals.get(keys[i])); query.append("\"] "); } } /** * this method returns the constant position needed in the query */ private String createConstPosition() { PositionData currentPosition = positionDeliverer.getCurrentPosition(); StringBuffer position = new StringBuffer(); position.append("[const position value"); position.append('('); position.append('0'); position.append(currentPosition.toListString()); position.append(')'); position.append(']'); return position.toString(); } /** * appends the where clause of the optimizer query to the StringBuffer */ private void createMetaQueryPartOptimizer(StringBuffer query) { HashMap metaVals = metaDeliverer.getMetaVals(); Object[] keys = metaVals.keySet().toArray(); if(keys.length > 0) { query.append("where ["); for (int i=0; i< keys.length;i++) { query.append(keys[i]); query.append("=\""); query.append((String)metaVals.get(keys[i])); query.append('\"'); if((i+1) < keys.length) query.append(", "); } query.append(']'); } } /** * This method creates an Optimizer query on the edited meta data and shows it in the QueryBuilder */ public void createOptimizerQuery() { StringBuffer query = new StringBuffer(); String relation, attribute; if(hasSecondoInterface) { relation = ((String)relationsList.getSelectedValue()).toLowerCase(); attribute = ((String)attributesList.getSelectedValue()).toLowerCase(); } else { relation = relationsText.getText().toLowerCase(); attribute = attributesText.getText().toLowerCase(); } query.append("sql select "); query.append(attribute); query.append(" from "); query.append(relation); query.append(' '); createMetaQueryPartOptimizer(query); query.append('.'); queryText.setText(query.toString()); } /** * This method creates a Secondo query. if position is true the query is based on the edited position on the chess board in the QueryBuilder. if meta is true the query is based on the edited meta tags in the QueryBuilder (if both are true the query is based on both). If exact is true the position has to be exactly matching, if from and to are not null there are only those positions requested between from and to. */ public void createSecondoQuery(boolean exact, boolean position,boolean meta, String from, String to) { StringBuffer query = new StringBuffer(); String relation, attribute; if(hasSecondoInterface) { relation = (String)relationsList.getSelectedValue(); attribute = (String)attributesList.getSelectedValue(); } else { relation = relationsText.getText(); attribute = attributesText.getText(); } query.append("query "); query.append(relation); query.append(" feed "); if (position) { try { createPositionQueryPart(exact, from, to, query, attribute); } catch(Exception e) { queryText.setText("Error: you entered a wrong text!"); return; } } if(meta) { createMetaQueryPart(attribute, query); } query.append("consume"); queryText.setText(query.toString()); } public void stateChanged(ChangeEvent e) { this.showQueryBuilder(); } }