package com.openMap1.mapper.query; import java.awt.Color; import java.util.Iterator; import java.util.StringTokenizer; import java.util.Vector; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.util.XMLUtil; public class MatchResult { // three types of match result public static int MATCHED_PAIRS = 0; public static int UNMATCHED_LEFT = 1; public static int UNMATCHED_RIGHT = 2; private int resultType; public int resultType() {return resultType;} public static String[] matchColumnNames = {"Match","Pair","Score"}; private String matchQueryText = ""; public String getMatchQueryText() {return matchQueryText;} public Vector<Vector<CellContent>> matchResults; public MatchSource matchSource() {return matchSource;} private MatchSource matchSource; /** * make a new MatchResults object with no results yet in it * @param resultType */ public MatchResult(int resultType) { this.resultType = resultType; matchResults = new Vector<Vector<CellContent>>(); } /** * clear any results previously saved in this MatchResult */ public void clear() { matchResults = new Vector<Vector<CellContent>>(); } /** * called from class Matcher, after a match invoked from a match window, to save the * results here so they can be shown in the Query Results view. * Adds the new match results to any already held here. * @param matchQueryText * @param matchQueryParser * @param newMatchResults */ public void saveMatchResult(String matchQueryText,MatchSource matchSource,Vector<Vector<CellContent>> newMatchResults) throws MapperException { if (matchQueryText == null) throw new MapperException("No query text when saving match result"); this.matchQueryText = matchQueryText; this.matchSource = matchSource; for (int i = 0; i < newMatchResults.size(); i++) matchResults.add(newMatchResults.get(i)); } /** * Populate the XML Document with the match results, in the same format as * is output from the Query Results View * @param doc empty Document to be populated * @param useShortColumnNames if true, omit package name and class name before property name, in column headers * and in tag names for cells */ public Element resultTree(Document doc, boolean useShortColumnNames) throws MapperException { Element root = doc.createElement("ViewContents"); boolean addMatchColumns = true; Vector<String> headers = makeTableHeaders(matchSource, addMatchColumns); Element headerEl = makeHeader(headers,doc,useShortColumnNames); root.appendChild(headerEl); Element content = makeContent(headers,doc,useShortColumnNames); root.appendChild(content); return root; } /** * Populate the XML Document with the match results, in the same format as * is output from the Query Results View, but with rows rearranged for the web service: * - the right-hand record comes first * - if it matches with more than one left-hand record, do no show repeats of the right-hand record * @param doc empty Document to be populated * @param useShortColumnNames if true, omit package name and class name before property name, in column headers * and in tag names for cells */ public Element webServiceResultTree(Document doc, boolean useShortColumnNames) throws MapperException { Element root = doc.createElement("ViewContents"); boolean addMatchColumns = true; Vector<String> headers = makeTableHeaders(matchSource, addMatchColumns); Element headerEl = makeHeader(headers,doc,useShortColumnNames); root.appendChild(headerEl); Element content = makeWebServiceContent(headers,doc,useShortColumnNames); root.appendChild(content); return root; } /** * make the header element of a result tree * @param headers * @param doc * @param useShortColumnNames * @return * @throws MapperException */ private Element makeHeader (Vector<String> headers, Document doc, boolean useShortColumnNames) throws MapperException { Element headerEl = doc.createElement("TableColumns"); for (int i = 0; i < headers.size(); i++) { String columnName = maybeShorten(headers.get(i),useShortColumnNames); Element columnEl = XMLUtil.textElement(doc, "column", columnName); headerEl.appendChild(columnEl); } return headerEl; } /** * make the body of a result tree * @param headers * @param doc * @param useShortColumnNames * @return * @throws MapperException */ private Element makeContent (Vector<String> headers, Document doc, boolean useShortColumnNames) throws MapperException { Element content = doc.createElement("TableContent"); for (int rowIndex = 0; rowIndex < matchResults.size(); rowIndex++) { Vector<CellContent> row = matchResults.get(rowIndex); if (row.size() != headers.size()) throw new MapperException("Row " + rowIndex + " has size " + row.size() + " not equal to header size " + headers.size()); Element rowEl = doc.createElement("row"); content.appendChild(rowEl); for (int cellIndex = 0; cellIndex < row.size(); cellIndex++) { CellContent cellContent = row.get(cellIndex); String tagName = maybeShorten(headers.get(cellIndex),useShortColumnNames); Element cellEl = XMLUtil.textElement(doc,tagName , cellContent.getText()); rowEl.appendChild(cellEl); } } return content; } /** * make the body of a result tree * @param headers * @param doc * @param useShortColumnNames * @return * @throws MapperException */ private Element makeWebServiceContent (Vector<String> headers, Document doc, boolean useShortColumnNames) throws MapperException { Element content = doc.createElement("TableContent"); for (int rowIndex = 0; rowIndex < matchResults.size(); rowIndex++) { // alter the row index to rearrange and omit rows int alteredRowIndex = alteredIndex(rowIndex); if (alteredRowIndex > -1) // if row is not omitted.... { Vector<CellContent> row = matchResults.get(alteredRowIndex); if (row.size() != headers.size()) throw new MapperException("Row " + rowIndex + " has size " + row.size() + " not equal to header size " + headers.size()); Element rowEl = doc.createElement("row"); content.appendChild(rowEl); for (int cellIndex = 0; cellIndex < row.size(); cellIndex++) { CellContent cellContent = row.get(cellIndex); String tagName = maybeShorten(headers.get(cellIndex),useShortColumnNames); Element cellEl = XMLUtil.textElement(doc,tagName , cellContent.getText()); rowEl.appendChild(cellEl); } } } return content; } /** * for output to the web service, rearrange the rows of the table so the RHS row comes first, and * omit some rows to omit repeats of the RHS row. */ private int alteredIndex(int index) { int alteredIndex = index; // make the first row (LHS record, index 0) come second, and the second row (RHS record, index 1) come first if (index == 0) alteredIndex = 1; if (index == 1) alteredIndex = 0; // miss out subsequent rows with odd index 3,5,..., as these are repeats of the RHS record if ((index > 2) && (index - 2*(index/2) > 0)) alteredIndex = -1; return alteredIndex; } /** * * @param fullName * @param doShorten * @return if doShorten is true, only the part after the last '.'; otherwise the full name, * except excluding package names */ private String maybeShorten(String fullName, boolean doShorten) { String result = ""; StringTokenizer st = new StringTokenizer(fullName,"."); // if there is a package name before the class name, always remove it if (st.countTokens() == 3) st.nextToken(); // if we are shortening, remove any class name if ((st.countTokens() == 2) && doShorten) st.nextToken(); while (st.hasMoreTokens()) { result = result + st.nextToken(); // '.' after class name and before property name if (st.hasMoreTokens()) result = result + "."; } return result; } /** * Works out table header names in exactly the same way as QueryResultView.MakeTableColumns * @param queryParser * @param addPairColumn * @param addScoreColumn * @return */ private Vector<String> makeTableHeaders(MatchSource matchSource, boolean addMatchColumns) { Vector<String> headers = new Vector<String>(); // fixed columns at the front headers.add("Codes"); if (addMatchColumns) for (int i = 0; i < matchColumnNames.length;i++) headers.add(matchColumnNames[i]); // columns from the query Vector<String[]> headerRow = matchSource.getColumnHeaders(); for (int c = 0; c < headerRow.size(); c++) { String[] header = headerRow.get(c); headers.add(header[0] + "." + header[1]); } return headers; } static public Vector<CellContent> addFrontCell(Vector<CellContent> row, String frontCell) { Vector<CellContent> newRow = new Vector<CellContent>(); CellContent firstCell = new CellContent(frontCell,Color.black); newRow.add(firstCell); for (Iterator<CellContent> ir = row.iterator();ir.hasNext();) newRow.add(ir.next()); return newRow; } }