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.tasks; import static edu.ku.brc.ui.UIRegistry.getResourceString; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.URLEncoder; import java.util.Calendar; import java.util.Hashtable; import java.util.List; import java.util.Vector; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.SwingConstants; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dom4j.Element; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import edu.ku.brc.af.core.AppContextMgr; import edu.ku.brc.af.core.expresssearch.QueryAdjusterForDomain; import edu.ku.brc.af.prefs.AppPreferences; import edu.ku.brc.af.ui.forms.FormDataObjIFace; import edu.ku.brc.helpers.XMLHelper; import edu.ku.brc.specify.config.SpecifyAppContextMgr; import edu.ku.brc.specify.conversion.BasicSQLUtils; import edu.ku.brc.specify.datamodel.Collection; import edu.ku.brc.specify.datamodel.Discipline; import edu.ku.brc.specify.datamodel.Division; import edu.ku.brc.specify.datamodel.Institution; import edu.ku.brc.specify.datamodel.SpecifyUser; import edu.ku.brc.ui.CommandAction; import edu.ku.brc.ui.CommandDispatcher; import edu.ku.brc.ui.IconManager; import edu.ku.brc.ui.UIHelper; import edu.ku.brc.util.Pair; /** * This class sends usage stats. * * @author rods * * @code_status Complete */ public class StatsTrackerTask extends edu.ku.brc.af.tasks.StatsTrackerTask { private static final Logger log = Logger.getLogger(StatsTrackerTask.class); private final static String DATABASE = "Database"; private final static String resourceName = "CollStats"; private boolean hasChanged = false; private JProgressBar progress; private Hashtable<Class<?>, Boolean> tablesHash = new Hashtable<Class<?>, Boolean>(); private Vector<Pair<String, String>> queries = new Vector<Pair<String, String>>(); private Integer specifyUserId = null; private Integer collectionId = null; private Integer disciplineId = null; private Integer divisionId = null; private Integer institutionId = null; private Element rootElement = null; /** * Constructor. */ public StatsTrackerTask() { super(); CommandDispatcher.register(DATABASE, this); } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#initialize() */ @Override public void initialize() { super.initialize(); rootElement = AppContextMgr.getInstance().getResourceAsDOM(resourceName); if (rootElement != null) { List<?> rows = rootElement.selectNodes("/statistics/tables/table"); //$NON-NLS-1$ for (Object obj : rows) { Element statElement = (Element) obj; String tableClassName = XMLHelper.getAttr(statElement, "class", null); if (StringUtils.isNotEmpty(tableClassName)) { Class<?> cls = null; try { cls = Class.forName(tableClassName); tablesHash.put(cls, true); } catch (Exception ex) { edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount(); edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(StatsTrackerTask.class, ex); ex.printStackTrace(); } } } } else { log.error("Couldn't find resource [" + resourceName + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#createClosingFrame() */ @Override protected void showClosingFrame() { if (hasChanged) { ImageIcon img = IconManager.getIcon("SpecifySplash"); CellConstraints cc = new CellConstraints(); PanelBuilder pb = new PanelBuilder(new FormLayout("f:p:g,150px", "f:p:g,2px,p")); pb.setDefaultDialogBorder(); JLabel lbl = new JLabel(img); pb.add(lbl, cc.xyw(1, 1, 2)); lbl = UIHelper.createI18NLabel("SPECIFY_SHUTDOWN", SwingConstants.CENTER); lbl.setFont(lbl.getFont().deriveFont(18.0f)); pb.add(lbl, cc.xy(1, 3)); progress = new JProgressBar(0, 100); pb.add(progress, cc.xy(2, 3)); JFrame frame = new JFrame(); frame.setUndecorated(true); frame.setContentPane(pb.getPanel()); frame.pack(); UIHelper.centerAndShow(frame); } } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#completed() */ @Override protected void completed() { collectionId = null; disciplineId = null; divisionId = null; institutionId = null; queries.clear(); } /** * */ private void getIds() { AppContextMgr acm = AppContextMgr.getInstance(); if (((SpecifyAppContextMgr) acm).hasContext()) { specifyUserId = acm.getClassObject(SpecifyUser.class).getId(); collectionId = acm.getClassObject(Collection.class).getId(); disciplineId = acm.getClassObject(Discipline.class).getId(); divisionId = acm.getClassObject(Division.class).getId(); institutionId = acm.getClassObject(Institution.class).getId(); rootElement = acm.getResourceAsDOM(resourceName); } else { rootElement = null; completed(); } } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#starting() */ @Override protected boolean starting() { if (collectionId == null || queries.size() == 0) { getIds(); queries.clear(); // Need to do this now before all the Cached Objects change // that the QueryAdjusterForDomain uses. if (rootElement != null) { List<?> rows = rootElement.selectNodes("/statistics/stats/stat"); //$NON-NLS-1$ for (Object obj : rows) { Element statElement = (Element) obj; String statsName = XMLHelper.getAttr(statElement, "name", null); if (StringUtils.isNotEmpty(statsName)) { String sqlStr = QueryAdjusterForDomain.getInstance().adjustSQL(statElement.getText()); queries.add(new Pair<String, String>(statsName, sqlStr)); } } } //return true; } return true; } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#getPCLForWorker() */ @Override protected PropertyChangeListener getPCLForWorker() { return new PropertyChangeListener() { public void propertyChange(final PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { if (progress != null) progress.setValue((Integer) evt.getNewValue()); } } }; } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.StatsTrackerTask#sendStats() */ @Override protected void sendStats() throws Exception { super.sendStats(); sendCollectionStats(); sendActivityStats(false); } /** * Collection Statistics about the Collection (synchronously). */ @Override protected Vector<NameValuePair> collectSecondaryStats(final boolean doSendSecondaryStats) { boolean isAnon = false; if (institutionId != null) { isAnon = BasicSQLUtils.getCountAsInt( "SELECT IsAnonymous FROM institution WHERE InstitutionID = " + institutionId) != 0; } if (doSendSecondaryStats || !isAnon) { Vector<NameValuePair> stats = new Vector<NameValuePair>(); appendBasicCollStats(stats); if (hasChanged) { if (progress != null) progress.setIndeterminate(true); if (queries.size() > 0) { int count = 0; double total = queries.size(); for (Pair<String, String> p : queries) { String statsName = p.first; if (StringUtils.isNotEmpty(statsName)) { count++; addStat(statsName, stats, p.second); if (progress != null) progress.setIndeterminate(false); worker.setProgressValue((int) (100.0 * (count / total))); } } worker.setProgressValue(100); } else { log.error("Couldn't find resource [" + resourceName + "]"); //$NON-NLS-1$ //$NON-NLS-2$ } } return stats; } return null; } /** * adds the basic stats about the Institution ... Collection * @param stats the list of stats */ protected void appendBasicCollStats(final Vector<NameValuePair> stats) { if (collectionId == null) { getIds(); } if (specifyUserId != null) { String userName = BasicSQLUtils .querySingleObj("SELECT Name FROM specifyuser WHERE SpecifyUSerID = " + specifyUserId); stats.add(new NameValuePair("specifyuser", fixParam(userName))); //$NON-NLS-1$ } // Gather Collection Counts; if (collectionId != null) { Object[] row = BasicSQLUtils.getRow( "SELECT EstimatedSize, RegNumber, WebSiteURI, WebPortalURI, CollectionName FROM collection WHERE CollectionID = " + collectionId); Integer estSize = (Integer) row[0]; String estSizeStr = estSize != null ? Integer.toString(estSize) : ""; stats.add(new NameValuePair("Collection_estsize", estSizeStr)); //$NON-NLS-1$ stats.add(new NameValuePair("Collection_number", fixParam(row[1]))); //$NON-NLS-1$ stats.add(new NameValuePair("Collection_website", fixParam(row[2]))); //$NON-NLS-1$ stats.add(new NameValuePair("Collection_portal", fixParam(row[3]))); //$NON-NLS-1$ stats.add(new NameValuePair("Collection_name", fixParam(row[4]))); //$NON-NLS-1$ } String fmt = "SELECT RegNumber, Name FROM %s WHERE %s = %d"; if (disciplineId != null) { Object[] row = BasicSQLUtils.getRow(String.format(fmt, "discipline", "DisciplineID", disciplineId)); stats.add(new NameValuePair("Discipline_number", fixParam(row[0]))); //$NON-NLS-1$ stats.add(new NameValuePair("Discipline_name", fixParam(row[1]))); //$NON-NLS-1$ } if (divisionId != null) { Object[] row = BasicSQLUtils.getRow(String.format(fmt, "division", "DivisionID", divisionId)); stats.add(new NameValuePair("Division_number", fixParam(row[0]))); //$NON-NLS-1$ stats.add(new NameValuePair("Division_name", fixParam(row[1]))); //$NON-NLS-1$ } if (institutionId != null) { Object[] row = BasicSQLUtils.getRow(String.format(fmt, "institution", "InstitutionID", institutionId)); stats.add(new NameValuePair("Institution_number", fixParam(row[0]))); //$NON-NLS-1$ stats.add(new NameValuePair("Institution_name", fixParam(row[1]))); //$NON-NLS-1$ } } /** * @param colId * @param colNm * @param regNum * @param sql * @param sb */ private void collectStatsData(final String colNm, final String regNum, final String sql, final StringBuilder sb) { if (sb.length() > 0) sb.append(';'); sb.append(String.format("{%s, %s [", colNm, regNum)); int c = 0; for (Object[] row : BasicSQLUtils.query(sql)) { Integer yr = (Integer) row[0]; Long cnt = (Long) row[1]; if (yr != null) { if (c > 0) sb.append(','); sb.append(String.format("%d=%d", yr, cnt)); } c++; } sb.append("]}"); } /** * @param stats * @param valName * @param value */ private void addEncodedPair(final Vector<NameValuePair> stats, final String valName, final String value) { String val = ""; try { val = URLEncoder.encode(value, "UTF-8"); } catch (Exception ex) { } //System.out.println(String.format("[%s][%s]", valName, val)); stats.add(new NameValuePair(valName, val)); } /** * @param stats */ private void appendCollectingStats(final Vector<NameValuePair> stats) { final String ALL_YEAR_CATS = "ALL_YEAR_CATS_STAT"; final String LAST_COL_YEAR_STAT = "LAST_COL_YEAR_STAT"; //final String LAST_30_DAYS = "LAST_30DAYS_STAT"; int currentYear = Calendar.getInstance().get(Calendar.YEAR); AppPreferences remotePrefs = AppPreferences.getRemote(); int lastColYear = remotePrefs.getInt(LAST_COL_YEAR_STAT, -1); boolean doAllYears = remotePrefs.getBoolean(ALL_YEAR_CATS, true); if (lastColYear != currentYear) // override when it is a new year { doAllYears = true; } StringBuilder allYearsSB = new StringBuilder(); StringBuilder last30DaysSB = new StringBuilder(); for (Object[] colRow : BasicSQLUtils .query("SELECT CollectionID,CollectionName,RegNumber FROM collection")) { Integer colId = (Integer) colRow[0]; String colNm = (String) colRow[1]; String regNum = (String) colRow[2]; if (doAllYears) { String sql = String.format( "SELECT YR,COUNT(YR) FROM (SELECT YEAR(if (CatalogedDate IS NULL, TimestampCreated, CatalogedDate)) AS YR FROM collectionobject WHERE CollectionMemberID = %d) T1 GROUP BY YR ORDER BY YR", colId); collectStatsData(colNm, regNum, sql, allYearsSB); } // Cataloged by Month for current year String tmp = "SELECT MN, COUNT(MN) FROM (SELECT MONTH(DT) MN, YEAR(DT) YR FROM (SELECT if (CatalogedDate IS NULL, TimestampCreated, CatalogedDate) AS DT FROM collectionobject WHERE CollectionMemberID = %d) T1 WHERE YEAR(DT) = %d) T2 GROUP BY MN"; String sql = String.format(tmp, colId, currentYear); collectStatsData(colNm, regNum, sql, last30DaysSB); } if (doAllYears) { addEncodedPair(stats, "catbyyr", allYearsSB.toString()); remotePrefs.putBoolean(ALL_YEAR_CATS, false); remotePrefs.putInt(LAST_COL_YEAR_STAT, currentYear); } addEncodedPair(stats, "catbymn", last30DaysSB.toString()); // Audit Information Vector<Object[]> instRresults = BasicSQLUtils.query("SELECT Name, RegNumber FROM institution"); if (instRresults.size() > 0) { Object[] instRow = instRresults.get(0); String instName = (String) instRow[0]; String regNum = (String) instRow[1]; String[] actionStr = { "ins", "upd", "rmv" }; for (int action = 0; action < 3; action++) { StringBuilder auditSB = new StringBuilder(); String tmp = "SELECT * FROM (SELECT a.TableNum, Count(a.TableNum) as Cnt FROM spauditlog AS a WHERE a.Action = %d GROUP BY a.TableNum) T1 ORDER BY Cnt DESC"; String sql = String.format(tmp, action); collectStatsData(instName, regNum, sql, auditSB); addEncodedPair(stats, "audit_" + actionStr[action], auditSB.toString()); } } } /** * @param cmdActionArg */ private void checkTableType(final CommandAction cmdActionArg) { if (cmdActionArg.getData() instanceof FormDataObjIFace) { FormDataObjIFace data = (FormDataObjIFace) cmdActionArg.getData(); if (tablesHash != null && tablesHash.get(data.getClass()) != null) { hasChanged = true; } } } /** * @throws Exception */ private void sendCollectionStats() throws Exception { String collStatsCheckURL = getResourceString("StatsTrackerTask.COLLSTATSURL"); //$NON-NLS-1$ if (StringUtils.isNotEmpty(collStatsCheckURL)) { Vector<NameValuePair> stats = createPostParameters(false); appendCollectingStats(stats); sendStats(collStatsCheckURL, stats, getClass().getName()); } } /** * @throws Exception */ private void sendActivityStats(final boolean isLoggingIn) throws Exception { String url = getResourceString("StatsTrackerTask.ACTIVITYSURL"); //$NON-NLS-1$ if (StringUtils.isNotEmpty(url)) { Vector<NameValuePair> stats = createPostParameters(false); appendBasicCollStats(stats); stats.add(new NameValuePair("Type", isLoggingIn ? "0" : "1")); //$NON-NLS-1$ sendStats(url, stats, getClass().getName()); } } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.BaseTask#doProcessAppCommands(edu.ku.brc.ui.CommandAction) */ @Override protected void doProcessAppCommands(CommandAction cmdAction) { super.doProcessAppCommands(cmdAction); System.err.println( "************************ Type: " + cmdAction.getType() + " Action: " + cmdAction.getAction()); if (cmdAction.isAction(APP_RESTART_ACT) || cmdAction.isAction(APP_START_ACT)) { try { sendActivityStats(true); } catch (Exception ex) { } } } /* (non-Javadoc) * @see edu.ku.brc.af.tasks.BaseTask#doCommand(edu.ku.brc.ui.CommandAction) */ @Override public void doCommand(final CommandAction cmdActionArg) { super.doCommand(cmdActionArg); if (cmdActionArg.isType(DATABASE)) { checkTableType(cmdActionArg); } } }