Java tutorial
/**Copyright (C) 2011 the University of Pittsburgh * Author: Thomas Maher * * 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 3 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, see <http://www.gnu.org/licenses/> */ package edu.pitt.dbmi.facebase.hd; import java.sql.ResultSet; import java.util.List; import java.util.ArrayList; import java.util.Date; import java.util.Map; import java.util.LinkedHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import org.json.simple.*; import org.json.simple.parser.*; import edu.pitt.dbmi.facebase.hd.domain.InstructionQueueItem; import edu.pitt.dbmi.facebase.hd.MySQLHibernateConfiguration; import org.apache.log4j.Logger; /** Communicates with Hub's mysql database fb_queue--gathers new queue items and updates queue record with progress information. * Uses Hibernate to interact with Hub's mysql fb_queue table of queue items (user requests for human data) * * @author Facebase Java Authors, http://www.facebase.org/ */ public class InstructionQueueManager { private static final Logger log = Logger.getLogger("edu.pitt.dbmi.facebase.hd.InstructionQueueManager.class"); private static MySQLHibernateConfiguration conf = null; /** Sets up Hibernate connection to Hub server's mysqlDB */ public InstructionQueueManager(String fbDbUser, String fbPasswd, String fbJdbcUrl) { conf = new MySQLHibernateConfiguration(fbDbUser, fbPasswd, fbJdbcUrl); } /** Retrieves new queue items from Hub's DB * Calls getNewQueueItems() * * @return list of queue items found with status='request' */ List<InstructionQueueItem> queryInstructions() { log.debug("InstructionQueueManager.queryInstructions() called."); Session session = null; Transaction transaction = null; List<InstructionQueueItem> items = new ArrayList<InstructionQueueItem>(); try { session = conf.openSession(); items = getNewQueueItems(session); session.flush(); session.close(); } catch (Throwable t) { String errorString = "InstructionQueueManager caught a t in queryInstructions() " + t.toString(); String logString = t.getMessage(); edu.pitt.dbmi.facebase.hd.HumanDataController.addError(errorString, logString); log.error(errorString, t); handleThrowable(t, session, transaction); } return (items); } /** Retrieves new queue items from Hub's DB * Makes a Criteria to get only rows where status="request" * Sets status="pending" for the most recent record, the one about to be processes by this application. * * @param session the Hibernate session object * @return list of queue items found with status='request' */ List<InstructionQueueItem> getNewQueueItems(Session session) { log.debug("InstructionQueueManager.getNewQueueItems() called."); Transaction transaction = null; transaction = session.beginTransaction(); Criteria c = session.createCriteria(InstructionQueueItem.class).add(Restrictions.like("status", "request")) .addOrder(Order.asc("created")); List<InstructionQueueItem> results = c.list(); if (results.size() > 0) { InstructionQueueItem iqitemp = results.get(0); iqitemp.setStatus("pending"); long unixEpicTime = System.currentTimeMillis() / 1000L; iqitemp.setReceived(unixEpicTime); session.save(iqitemp); transaction.commit(); } return (results); } /** Retrieves queue items from Hub's DB by queue id * Makes a Criteria to get only rows where qid=CURRENT-qid (ie. one row) * * @param session the Hibernate session object * @param qid the id of the QueueItem (and the row in the table) being processed * @return list of queue items found with qid=CURRENT-qid' (list should have exactly one member). */ List<InstructionQueueItem> getPendingQueueItems(Session session, long qid) { log.debug("InstructionQueueManager.getPendingQueueItems() called"); Criteria c = session.createCriteria(InstructionQueueItem.class).add(Restrictions.like("qid", qid)); List<InstructionQueueItem> results = c.list(); return (results); } /** Tell's Hub DB how much data is being packaged * Writes the value (in bytes) of the size of the files requests to the "results" column in the database in JSON format. * Tells the Hub DB how big (and therefore how long to process) the requested data is. * * @param session the Hibernate session object * @param qid the id of the QueueItem (and the row in the table) being processed * @return true if successful */ boolean updateInstructionSize(long size, long qid) { log.debug("InstructionQueueManager.updateInstructionSize() called."); Session session = null; Transaction transaction = null; try { session = conf.openSession(); transaction = session.beginTransaction(); List<InstructionQueueItem> items = getPendingQueueItems(session, qid); String sizeString = (new Long(size)).toString(); Map resultsJSON = new LinkedHashMap(); resultsJSON.put("size", sizeString); String jsonResultsString = JSONValue.toJSONString(resultsJSON); if (items != null && items.size() >= 1) { InstructionQueueItem item = items.get(0); item.setResults(jsonResultsString); session.update(item); transaction.commit(); } session.close(); return true; } catch (Throwable t) { String errorString = "InstructionQueueManager caught a t in updateInstructionSize(): " + t.toString(); String logString = t.getMessage(); edu.pitt.dbmi.facebase.hd.HumanDataController.addError(errorString, logString); log.error(errorString, t); handleThrowable(t, session, transaction); } return false; } /** Tell's Hub DB about the results of the queue processing effort * Called after processing of the queue item and construction of the TrueCrypt volume is complete. * Tells Hub where TrueCrypt volume is located, when processing finished, and any error reporting; sets status * Sets status='complete' or status='error' in fb_queue row for this queue item * Sets Completed=unixEpicTime in fb_queue row for this queue item * Sets results=ComplexJSONstring holding path, logs, messages. That string would look like this: * <pre> * { * "path": "/path/to/file/3DData1-2-11-35username.tc", * "log": "", * "messages": [ * "File 1102.obj was not found and not included in your zip file.", * "Blah blah blah" * ] * } * <pre> * * @param trueCryptFilename the full path name of the trueCrypt file (ie. /var/downloads/FBdata.tc) * @param size total size of TrueCrypt file * @param qid the queue id of the item that was processed * @param errors list of human-readable errors that were encountered (if nonzero, the status will be set to "error", otherwise status="complete". * @param logs list of detailed error information that was gathered (usually with Exception.getMessage()). * @return true if successful */ boolean updateInstructionToCompleted(String trueCryptFilename, long size, long qid, ArrayList<String> errors, ArrayList<String> logs) { log.debug("InstructionQueueManager.updateInstructionToCompleted() called."); Session session = null; Transaction transaction = null; long unixEpicTime = System.currentTimeMillis() / 1000L; try { session = conf.openSession(); transaction = session.beginTransaction(); List<InstructionQueueItem> items = getPendingQueueItems(session, qid); String sizeString = (new Long(size)).toString(); //LIKE THIS: jsonResultsString = "{\"path\":\""+trueCryptFilename+"\",\"log\":\"\",\"messages\":[\""+errorsString+"\"],\"size\":\""+sizeString+"\"}"; Map resultsJSON = new LinkedHashMap(); resultsJSON.put("path", trueCryptFilename); resultsJSON.put("size", sizeString); JSONArray messagesJSON = new JSONArray(); JSONArray logsJSON = new JSONArray(); for (String message : errors) { messagesJSON.add(message); } resultsJSON.put("messages", messagesJSON); for (String log : logs) { logsJSON.add(log); } resultsJSON.put("log", logsJSON); //LIKE THIS: jsonResultsString = resultsJSON.toString();...but toString() won't work...need toJSONString(): String jsonResultsString = JSONValue.toJSONString(resultsJSON); if (items != null && items.size() >= 1) { InstructionQueueItem item = items.get(0); if (errors.isEmpty()) { item.setStatus("complete"); } else { item.setStatus("error"); } item.setResults(jsonResultsString); item.setCompleted(unixEpicTime); session.update(item); transaction.commit(); } session.close(); return true; } catch (Throwable t) { String errorString = "InstructionQueueManager caught a t in updateInstructionsToCompleted()" + t.toString(); String logString = t.getMessage(); edu.pitt.dbmi.facebase.hd.HumanDataController.addError(errorString, logString); log.error(errorString, t); handleThrowable(t, session, transaction); } return false; } /** Deals with exceptions gracefully * Called from catch clause * * @param t the exception * @param sessionHd Hibernate session * @param transactionHd Hibernate's Transaction object, for rolling back unfinished transactions */ static void handleThrowable(Throwable t, Session session, Transaction transaction) { log.error("An unexpected error occured while talking to a database.", t); if (transaction != null) { try { transaction.rollback(); } catch (Throwable t1) { log.error("Unable to rollback a transaction.", t1); } } if (session != null) { try { session.close(); } catch (Throwable t2) { log.error("Unable to close a session.", t2); } } } }