Java tutorial
/* Copyright (C) 2015, University of Kansas Center for Research * * Specify Software Project, specify@ku.edu, Biodiversity Institute, * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package edu.ku.brc.specify.dbsupport.cleanuptools; import static edu.ku.brc.ui.UIRegistry.getResourceString; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Vector; import org.apache.commons.lang.StringUtils; import edu.ku.brc.af.core.db.DBFieldInfo; import edu.ku.brc.af.core.db.DBTableIdMgr; import edu.ku.brc.af.core.db.DBTableInfo; import edu.ku.brc.af.ui.forms.FormHelper; import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterIFace; import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterMgr; import edu.ku.brc.specify.conversion.BasicSQLUtils; import edu.ku.brc.specify.datamodel.DataModelObjBase; /** * @author rods * * @code_status Alpha * * Aug 6, 2012 * */ public class MultipleRecordComparer { protected boolean isParent; protected DBTableInfo tblInfo; protected DBTableInfo parentTI; protected FindItemInfo fii; protected int numColsWithData = 0; protected boolean hasColmnsOfDataThatsDiff = false; protected boolean hasKidsDataThatsDiff = false; protected boolean isSingleRowIncluded = false; protected Vector<DBFieldInfo> columns = new Vector<DBFieldInfo>(); protected Vector<DBFieldInfo> hiddenCols = new Vector<DBFieldInfo>(); protected boolean[] colHasData = null; protected boolean[] colIsSame = null; protected Vector<Object[]> dataItems = new Vector<Object[]>(); protected Vector<MergeInfoItem> mergeItems = new Vector<MergeInfoItem>(); // for formatting private HashMap<DBFieldInfo, Integer> colToIndexMap = new HashMap<DBFieldInfo, Integer>(); private Vector<DisplayColInfo> displayCols = new Vector<DisplayColInfo>(); private boolean isSingleCol = true; private int indexForTitle = -1; private DataModelObjBase displayObj = null; // Children Tables protected ArrayList<MultipleRecordComparer> kids = new ArrayList<MultipleRecordComparer>(); /** * @param fii * @param parentTableId * @param tableIds */ public MultipleRecordComparer(final FindItemInfo fii, final int parentTableId, final int... tableIds) { super(); this.fii = fii; this.tblInfo = DBTableIdMgr.getInstance().getInfoById(parentTableId); for (int tblId : tableIds) { MultipleRecordComparer mrc = new MultipleRecordComparer(fii, tblInfo, tblId); kids.add(mrc); } this.isParent = true; } /** * @param fii * @param parentTI * @param tableId */ public MultipleRecordComparer(final FindItemInfo fii, final DBTableInfo parentTI, final int tableId) { super(); this.fii = fii; this.parentTI = parentTI; this.tblInfo = DBTableIdMgr.getInstance().getInfoById(tableId); this.isParent = false; } /** * @param isSingleIncl one value for each sub-panel indicating whether only one row should be used. */ public void setSingleRowIncluded(final boolean... isSingleIncl) { if (isParent) { if (kids.size() == isSingleIncl.length) { for (int i = 0; i < isSingleIncl.length; i++) { kids.get(i).setSingleRowIncluded(isSingleIncl[i]); } } } else if (isSingleIncl.length == 1) { this.isSingleRowIncluded = isSingleIncl[0]; } } /** * @return the isSingleRowIncluded */ public boolean isSingleRowIncluded() { return isSingleRowIncluded; } /** * @param fii * @return */ private boolean containsFieldInfo(final DBFieldInfo fii) { for (DisplayColInfo dci : displayCols) { if (dci.getFi() == fii) { return true; } } return false; } /** * */ public boolean loadData() { boolean isVerbose = true; columns.clear(); int numSQLCols = 0; for (DisplayColInfo dci : displayCols) { if (dci.isIncludeSQLOnly()) { columns.add(dci.getFi()); numSQLCols++; } } for (DBFieldInfo fi : tblInfo.getFields()) { if (containsFieldInfo(fi)) { columns.insertElementAt(fi, numSQLCols); } else if (fi.isHidden()) { hiddenCols.add(fi); } else { columns.add(fi); } } HashSet<Integer> inclColsIndexSet = new HashSet<Integer>(); int index = 0; for (DBFieldInfo fi : columns) { if (containsFieldInfo(fi)) { inclColsIndexSet.add(index); } index++; } //---------------------------------------------- // Build SELECT //---------------------------------------------- StringBuilder cols = new StringBuilder(); for (DBFieldInfo fi : columns) { if (cols.length() > 0) cols.append(","); cols.append(fi.getColumn()); } // Load Data DBTableInfo ti = parentTI != null ? parentTI : tblInfo; final String sql = String.format("SELECT %s, %s FROM %s WHERE %s in %s", cols.toString(), tblInfo.getIdColumnName(), tblInfo.getName(), ti.getIdColumnName(), fii.getInClause(true)); if (isVerbose) System.out.println("Data ------------\n" + sql); dataItems = BasicSQLUtils.query(sql); if (dataItems.size() > 0) { //---------------------------------------------- // First check to see which columns have data //---------------------------------------------- for (Object[] row : dataItems) { if (colHasData == null) { colHasData = new boolean[row.length]; // all columns (including id) for (int i = 0; i < row.length; i++) colHasData[i] = false; } for (int i = 0; i < row.length; i++) { if (inclColsIndexSet.contains(i)) { colHasData[i] = true; } else if (row[i] != null) { if (row[i] instanceof String) { colHasData[i] = StringUtils.isNotEmpty((String) row[i]); } else { colHasData[i] = true; } } if (isVerbose) System.out.print(row[i] + ", "); } if (isVerbose) System.out.println(); } if (isVerbose) System.out.println("------------" + sql); //for (int j=0;j<hasData.length;j++) System.out.print(j+" "+hasData[j]+", "); //System.out.println(); // Now check to see if the value in the each column are the same. colIsSame = new boolean[colHasData.length]; // Don't check last column for (int i = 0; i < colHasData.length - 1; i++) { if (colHasData[i]) { colIsSame[i] = false; if (!inclColsIndexSet.contains(i)) { colIsSame[i] = true; Object value = null; for (Object[] row : dataItems) { Object otherVal = row[i]; if (value == null) { if (otherVal != null) { value = otherVal; } } else if (value != null) { if (!value.equals(otherVal)) { colIsSame[i] = false; break; } } } } else { if (isVerbose) System.out.println("Skipping " + i); } } else { colIsSame[i] = true; } } if (displayCols.size() > 0) { int inx = 0; for (DBFieldInfo fldCol : columns) { if (containsFieldInfo(fldCol)) { colToIndexMap.put(fldCol, inx); } inx++; } indexForTitle = colToIndexMap.size() > 0 ? colToIndexMap.values().iterator().next() : -1; // for singles only } // for (Integer index : colToIndexMap.values()) // { // colIsSame[index] = false; // } //System.out.println(String.format("Cols %d hd: %d", columns.size(), hasData.length)); Vector<DBFieldInfo> oldColumns = new Vector<DBFieldInfo>(columns); // does not include ID column columns.clear(); // Add 'Is Included to data model if (isParent) { DBFieldInfo fldInfo = new DBFieldInfo(tblInfo, "FALSE", "MergedInto", "boolean", 1, true, true, false, false, false, null); fldInfo.setTitle(getResourceString("CLNUP_MERGE_INTO")); columns.add(fldInfo); fldInfo = new DBFieldInfo(tblInfo, "FALSE", "MergedFrom", "boolean", 1, true, true, false, false, false, null); fldInfo.setTitle(getResourceString("CLNUP_MERGE_FROM")); columns.add(fldInfo); if (indexForTitle > -1) indexForTitle += 2; } else { DBFieldInfo isInclFld = new DBFieldInfo(tblInfo, "FALSE", "IsIncluded", "boolean", 1, true, true, false, false, false, null); isInclFld.setTitle(getResourceString("CLNUP_MERGE_ISINCL")); columns.add(isInclFld); if (indexForTitle > -1) indexForTitle++; } if (isVerbose) { for (int j = 0; j < colIsSame.length; j++) System.out.print(String.format("%3d", j)); System.out.println(); for (int j = 0; j < colHasData.length; j++) System.out.print(String.format(" %s", colHasData[j] ? "Y" : "N")); System.out.println(" (Has Data)"); for (int j = 0; j < colIsSame.length; j++) System.out.print(String.format(" %s", colIsSame[j] ? "Y" : "N")); System.out.println(" (Is Same)"); } numColsWithData = 0; for (int i = 0; i < colHasData.length - 1; i++) { if (isVerbose) System.out.println(i + " -> " + (colHasData[i] && !colIsSame[i]) + " Has: " + colHasData[i] + " !SM: " + !colIsSame[i] + " " + oldColumns.get(i).getTitle()); if (colHasData[i] && !colIsSame[i]) { numColsWithData++; columns.add(oldColumns.get(i)); if (isVerbose) System.out.println(i + " Added: " + oldColumns.get(i).getTitle()); } } hasColmnsOfDataThatsDiff = numColsWithData > 0; if (hasColmnsOfDataThatsDiff) { numColsWithData += 2; // For IsIncluded and IdColumn if (isParent) numColsWithData++; Vector<Object[]> oldDataItems = new Vector<Object[]>(dataItems); dataItems.clear(); for (Object[] row : oldDataItems) { int inx = 0; Object[] newRow = new Object[numColsWithData]; newRow[inx++] = false; // isIncluded or Merged Into if (isParent) newRow[inx++] = false; // Merged From for (int i = 0; i < row.length; i++) { //if (isVerbose) System.out.println(i+" -> "+(colHasData[i] && !colIsSame[i])+" "+colHasData[i]+" "+!colIsSame[i]); if (colHasData[i] && !colIsSame[i]) { newRow[inx++] = row[i]; } } dataItems.add(newRow); } if (isVerbose) { for (int j = 0; j < columns.size(); j++) System.out.print(j + " " + columns.get(j).getTitle() + ", "); System.out.println(); System.out.println(String.format("Cols %d hd: %d", columns.size(), colHasData.length)); } } } hasKidsDataThatsDiff = false; for (MultipleRecordComparer mrc : kids) { if (mrc.loadData()) { hasKidsDataThatsDiff = true; } } return hasColmnsOfDataThatsDiff; } /** * Adds column to display. * @param col column name */ public void addDisplayColumn(final String colName) { DBFieldInfo fi = tblInfo.getFieldByColumnName(colName); if (fi != null) { displayCols.add(new DisplayColInfo(fi, false)); } } /** * @param colName * @param colTitle * @param sql */ // public void addDisplayColumn(final String colName, // final String colTitle, // final String sql) // { // DBFieldInfo fi = new DBFieldInfo(tblInfo, sql, colName, "text", 256, true, true, false, false, false, null); // if (fi != null) // { // fi.setTitle(colTitle); // displayCols.add(new DisplayColInfo(fi, true)); // } // } /** * @return */ public String getTitle() { if (dataItems.size() > 0 && isParent) { Object[] firstRow = dataItems.get(0); return getFormattedTitle(firstRow); } return "N/A"; } /** * @return */ public String getFormattedTitle(final Object[] rowData) { if ((isSingleCol || isParent) && indexForTitle > -1 && rowData[indexForTitle] != null) { return rowData[indexForTitle].toString(); } if (displayCols.size() > 0) { if (displayObj == null) { try { displayObj = (DataModelObjBase) tblInfo.getClassObj().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } if (displayObj != null) { for (DisplayColInfo dci : displayCols) { if (!dci.isIncludeSQLOnly()) { int inx = colToIndexMap.get(dci.getFi()); FormHelper.setValue(displayObj, dci.getFi().getColumn(), rowData[inx]); } } UIFieldFormatterIFace formatter = UIFieldFormatterMgr.getInstance() .getFormatter(tblInfo.getDataObjFormatter()); Object fmtObj = formatter != null ? formatter.formatToUI(displayObj) : null; return fmtObj != null ? fmtObj.toString() : displayObj.getIdentityTitle(); } } return fii.toString(); } /** * @return the numColsWithData */ public int getNumColsWithData() { return numColsWithData; } /** * @return the hasColmnsOfData */ public boolean hasColmnsOfDataThatsDiff() { return hasColmnsOfDataThatsDiff; } /** * @return the hasKidsData */ public boolean hasKidsDataThatsDiff() { return hasKidsDataThatsDiff; } /** * @return the hasKidsData */ public boolean hasKids() { return kids != null && kids.size() > 0; } /** * @return the kids */ public List<MultipleRecordComparer> getKids() { return kids; } /** * @return the columns */ public List<DBFieldInfo> getColumns() { return columns; } /** * @return the fii */ public FindItemInfo getFindItemInfo() { return fii; } /** * @return true if there are records */ public boolean hasRecords() { return dataItems != null && dataItems.size() > 0; } /** * @return the dataItems */ public Vector<Object[]> getDataItems() { return dataItems; } /** * @return the tblInfo */ public DBTableInfo getTblInfo() { return tblInfo; } /** * @return the isParent */ public boolean isParent() { return isParent; } //---------------------------------------------------------------------------- class DisplayColInfo { private DBFieldInfo fi; private boolean includeSQLOnly; /** * @param fi * @param includeSQLOnly */ public DisplayColInfo(DBFieldInfo fi, boolean includeSQLOnly) { super(); this.fi = fi; this.includeSQLOnly = includeSQLOnly; } /** * @return the fi */ public DBFieldInfo getFi() { return fi; } /** * @return the includeSQLOnly */ public boolean isIncludeSQLOnly() { return includeSQLOnly; } } }