Various bug fixes and improvements to the checker code, from Grace Carpenter, Jim Downing and Nathan Sarr

git-svn-id: http://scm.dspace.org/svn/repo/trunk@1412 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Jim Downing
2006-01-30 13:22:55 +00:00
parent b8a54bbaa9
commit 6c35684c85
26 changed files with 503 additions and 437 deletions

View File

@@ -73,3 +73,12 @@ log4j.appender.A1.MaxBackupIndex=500
# A1 uses PatternLayout. # A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c @ %m%n log4j.appender.A1.layout.ConversionPattern=%d %-5p %c @ %m%n
# A2 is the log for the Checker
log4j.category.org.dspace.checker=INFO, A2
log4j.appender.A2=org.apache.log4j.RollingFileAppender
log4j.appender.A2.File=@@log.dir@@/checker.log
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%m%n
log4j.appender.A2.MaxFileSize=1048576
log4j.appender.A2.MaxBackupIndex=500

View File

@@ -49,6 +49,7 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser; import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.checker.BitstreamDispatcher; import org.dspace.checker.BitstreamDispatcher;
import org.dspace.checker.BitstreamInfoDAO;
import org.dspace.checker.CheckerCommand; import org.dspace.checker.CheckerCommand;
import org.dspace.checker.HandleDispatcher; import org.dspace.checker.HandleDispatcher;
import org.dspace.checker.LimitedCountDispatcher; import org.dspace.checker.LimitedCountDispatcher;
@@ -113,14 +114,14 @@ public class ChecksumChecker
// create an options object and populate it // create an options object and populate it
Options options = new Options(); Options options = new Options();
options.addOption("l", "looping", false, "Loop through bitstreams"); options.addOption("l", "looping", false, "Loop once through bitstreams");
options.addOption("L", "continuous", false, options.addOption("L", "continuous", false,
"Continuously loop through bitstreams"); "Loop continuously through bitstreams");
options.addOption("h", "help", false, "Help"); options.addOption("h", "help", false, "Help");
options.addOption("d", "duration", true, "Checking duration"); options.addOption("d", "duration", true, "Checking duration");
options.addOption("c", "count", true, "Check count"); options.addOption("c", "count", true, "Check count");
options.addOption("a", "handle", true, "Specify a handle to check"); options.addOption("a", "handle", true, "Specify a handle to check");
options.addOption("e", "errors", false, "Report Errors Only"); options.addOption("v", "verbose", false, "Report all processing");
OptionBuilder.withArgName("bitstream-ids").hasArgs().withDescription( OptionBuilder.withArgName("bitstream-ids").hasArgs().withDescription(
"Space separated list of bitstream ids"); "Space separated list of bitstream ids");
@@ -176,88 +177,81 @@ public class ChecksumChecker
Date processStart = Calendar.getInstance().getTime(); Date processStart = Calendar.getInstance().getTime();
BitstreamDispatcher dispatcher = null; BitstreamDispatcher dispatcher = null;
if (line.getOptions().length == 0)
// process should loop infinitely through
// most_recent_checksum table
if (line.hasOption('l'))
{ {
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher( dispatcher = new SimpleDispatcher(new BitstreamInfoDAO(), processStart, false);
processStart, false), 1);
} }
else else if (line.hasOption('L'))
{ {
// process should loop infinitely through dispatcher = new SimpleDispatcher(new BitstreamInfoDAO(), processStart, true);
// most_recent_checksum table }
if (line.hasOption('l')) else if (line.hasOption('b'))
{ {
dispatcher = new SimpleDispatcher(processStart, false); // check only specified bitstream(s)
} String[] ids = line.getOptionValues('b');
else if (line.hasOption('L')) List idList = new ArrayList(ids.length);
{
dispatcher = new SimpleDispatcher(processStart, true);
}
else if (line.hasOption('b'))
{
// check only specified bitstream(s)
String[] ids = line.getOptionValues('b');
List idList = new ArrayList(ids.length);
for (int i = 0; i < ids.length; i++) for (int i = 0; i < ids.length; i++)
{
try
{
idList.add(new Integer(ids[i]));
}
catch (NumberFormatException nfe)
{
System.err.println("The following argument: " + ids[i]
+ " is not an integer");
System.exit(0);
}
}
dispatcher = new ListDispatcher(idList);
}
else if (line.hasOption('a'))
{ {
dispatcher = new HandleDispatcher(line.getOptionValue('a'));
}
else if (line.hasOption('d'))
{
// run checker process for specified duration
try try
{ {
dispatcher = new LimitedDurationDispatcher( idList.add(new Integer(ids[i]));
new SimpleDispatcher(processStart, true), new Date(
System.currentTimeMillis()
+ Utils.parseDuration(line
.getOptionValue('d'))));
} }
catch (Exception e) catch (NumberFormatException nfe)
{ {
LOG.fatal("Couldn't parse " + line.getOptionValue('d') System.err.println("The following argument: " + ids[i]
+ " as a duration: ", e); + " is not an integer");
System.exit(0); System.exit(0);
} }
} }
else if (line.hasOption('c')) dispatcher = new ListDispatcher(idList);
}
else if (line.hasOption('a'))
{
dispatcher = new HandleDispatcher(new BitstreamInfoDAO(), line.getOptionValue('a'));
}
else if (line.hasOption('d'))
{
// run checker process for specified duration
try
{ {
// run checker process for specified number of bitstreams dispatcher = new LimitedDurationDispatcher(
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher( new SimpleDispatcher(new BitstreamInfoDAO(), processStart, true), new Date(
processStart, false)); System.currentTimeMillis()
+ Utils.parseDuration(line
.getOptionValue('d'))));
}
catch (Exception e)
{
LOG.fatal("Couldn't parse " + line.getOptionValue('d')
+ " as a duration: ", e);
System.exit(0);
} }
} }
else if (line.hasOption('c'))
if (dispatcher == null)
{ {
System.out int count = new Integer(line.getOptionValue('c')).intValue();
.println("Error: insufficient option commands to run checker.");
printHelp(options); // run checker process for specified number of bitstreams
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
new BitstreamInfoDAO(), processStart, false), count);
} }
else
{
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
new BitstreamInfoDAO(), processStart, false), 1);
}
ResultsLogger logger = new ResultsLogger(processStart); ResultsLogger logger = new ResultsLogger(processStart);
CheckerCommand checker = new CheckerCommand(); CheckerCommand checker = new CheckerCommand();
// report errors only // verbose reporting
if (line.hasOption('e')) if (line.hasOption('v'))
{ {
checker.setReportErrorsOnly(true); checker.setReportVerbose(true);
} }
checker.configureLog(); checker.configureLog();
checker.setProcessStartDate(processStart); checker.setProcessStartDate(processStart);
@@ -283,14 +277,14 @@ public class ChecksumChecker
+ " OR ChecksumChecker -d 2h"); + " OR ChecksumChecker -d 2h");
System.out System.out
.println("\nSpecify bitstream IDs: ChecksumChecker -b 13 15 17 20"); .println("\nSpecify bitstream IDs: ChecksumChecker -b 13 15 17 20");
System.out.println("\nLoop through all bitstreams: " System.out.println("\nLoop once through all bitstreams: "
+ "ChecksumChecker -l"); + "ChecksumChecker -l");
System.out System.out
.println("\nLoop through all bitstreams continuously: ChecksumChecker -L"); .println("\nLoop continuously through all bitstreams: ChecksumChecker -L");
System.out System.out
.println("\nCheck a defined number of bitstreams: ChecksumChecker -c 10"); .println("\nCheck a defined number of bitstreams: ChecksumChecker -c 10");
System.out.println("Default (no arguments) is '-c 1'"); System.out.println("\nReport all processing (verbose)(default reports only errors): ChecksumChecker -v");
System.out.println("\nReport errors only in logs: ChecksumChecker -e"); System.out.println("\nDefault (no arguments) is equivalent to '-c 1'");
System.exit(0); System.exit(0);
} }

View File

@@ -46,6 +46,9 @@ import org.dspace.storage.bitstore.BitstreamStorageManager;
* </p> * </p>
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class BitstreamDAO public class BitstreamDAO
{ {

View File

@@ -33,7 +33,6 @@
*/ */
package org.dspace.checker; package org.dspace.checker;
import java.sql.SQLException;
/** /**
* <p> * <p>
@@ -54,8 +53,10 @@ import java.sql.SQLException;
* </ol> * </ol>
* *
* *
* @author Nate Sarr
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public interface BitstreamDispatcher public interface BitstreamDispatcher
{ {
@@ -72,10 +73,6 @@ public interface BitstreamDispatcher
* @return the next bitstream id, or BitstreamDispatcher.SENTINEL if there * @return the next bitstream id, or BitstreamDispatcher.SENTINEL if there
* isn't another value * isn't another value
* *
* @throws SQLException
* if there is some problem querying a database
*
* @todo This should probably wrap the SQL exception
*/ */
public int next() throws SQLException; public int next();
} }

View File

@@ -42,7 +42,9 @@ import java.util.Date;
* </p> * </p>
* *
* @author Jim Downing * @author Jim Downing
* @author Nate Sarr * @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public final class BitstreamInfo public final class BitstreamInfo
{ {

View File

@@ -38,7 +38,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.storage.rdbms.DatabaseManager; import org.dspace.storage.rdbms.DatabaseManager;
@@ -50,11 +52,19 @@ import org.dspace.storage.rdbms.DatabaseManager;
* checker. * checker.
* </p> * </p>
* *
* @author Nate Sarr
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public final class BitstreamInfoDAO extends DAOSupport public final class BitstreamInfoDAO extends DAOSupport
{ {
/**
* This value should be returned by <code>next()</code> to indicate that
* there are no more values.
*/
public static int SENTINEL = -1;
/** Query that gets bitstream information for a specified ID. */ /** Query that gets bitstream information for a specified ID. */
private static final String FIND_BY_BITSTREAM_ID = "select bitstream.deleted, bitstream.store_number, bitstream.size_bytes, " private static final String FIND_BY_BITSTREAM_ID = "select bitstream.deleted, bitstream.store_number, bitstream.size_bytes, "
+ "bitstreamformatregistry.short_description, bitstream.bitstream_id, " + "bitstreamformatregistry.short_description, bitstream.bitstream_id, "
@@ -88,27 +98,6 @@ public final class BitstreamInfoDAO extends DAOSupport
+ "select 'x' from most_recent_checksum " + "select 'x' from most_recent_checksum "
+ "where most_recent_checksum.bitstream_id = bitstream.bitstream_id );"; + "where most_recent_checksum.bitstream_id = bitstream.bitstream_id );";
/**
* Query that select a specified bitstream from bitstream table and inserts
* it into the most_recent_checksum table if it does not already exist.
*/
private static final String INSERT_MISSING_CHECKSUM_BITSTREAM = "insert into most_recent_checksum ( "
+ "bitstream_id, to_be_processed, expected_checksum, current_checksum, "
+ "last_process_start_date, last_process_end_date, "
+ "checksum_algorithm, matched_prev_checksum, result ) "
+ "select bitstream.bitstream_id, "
+ "true, "
+ "CASE WHEN bitstream.checksum IS NULL THEN '' ELSE bitstream.checksum END, "
+ "?, "
+ "?, "
+ "CASE WHEN bitstream.checksum_algorithm IS NULL "
+ "THEN 'MD5' ELSE bitstream.checksum_algorithm END, true, "
+ "CASE WHEN bitstream.deleted = true THEN 'BITSTREAM_MARKED_DELETED' else 'CHECKSUM_MATCH' END "
+ "from bitstream where bitstream.bitstream_id = ? "
+ "and not exists( "
+ "select 'x' from most_recent_checksum "
+ "where most_recent_checksum.bitstream_id = ? );";
/** /**
* Query that updates most_recent_checksum table with checksum result for * Query that updates most_recent_checksum table with checksum result for
* specified bitstream ID. * specified bitstream ID.
@@ -123,6 +112,42 @@ public final class BitstreamInfoDAO extends DAOSupport
private static final String DELETE_BITSTREAM_INFO = "Delete from most_recent_checksum " private static final String DELETE_BITSTREAM_INFO = "Delete from most_recent_checksum "
+ "where bitstream_id = ?"; + "where bitstream_id = ?";
/**
* This selects the next bitstream in order of last processing end date. The
* timestamp is truncated to milliseconds this is because the Date for java
* does not support nanoseconds and milliseconds were considered accurate
* enough
*/
public static final String GET_OLDEST_BITSTREAM = "select bitstream_id "
+ "from most_recent_checksum " + "where to_be_processed = true "
+ "order by date_trunc('milliseconds', last_process_end_date), "
+ "bitstream_id " + "ASC LIMIT 1";
/**
* Selects the next bitstream in order of last processing end date, ensuring
* that no bitstream is checked more than once since the date parameter
* used.
*/
public static final String GET_OLDEST_BITSTREAM_DATE = "select bitstream_id "
+ "from most_recent_checksum "
+ "where to_be_processed = true "
+ "and last_process_start_date < ? "
+ "order by date_trunc('milliseconds', last_process_end_date), "
+ "bitstream_id " + "ASC LIMIT 1";
/** SQL query to retrieve bitstreams for a given item. */
private static final String ITEM_BITSTREAMS = "SELECT b2b.bitstream_id "
+ "FROM bundle2bitstream b2b, item2bundle i2b WHERE "
+ "b2b.bundle_id=i2b.bundle_id AND i2b.item_id=?";
/** SQL query to retrieve bitstreams for a given collection. */
private static final String COLLECTION_BITSTREAMS = "SELECT b2b.bitstream_id "
+ "FROM bundle2bitstream b2b, item2bundle i2b, collection2item c2i WHERE "
+ "b2b.bundle_id=i2b.bundle_id AND c2i.item_id=i2b.item_id AND c2i.collection_id=?";
/** SQL query to retrieve bitstreams for a given community. */
private static final String COMMUNITY_BITSTREAMS = "SELECT b2b.bitstream_id FROM bundle2bitstream b2b, item2bundle i2b, collection2item c2i, community2collection c2c WHERE b2b.bundle_id=i2b.bundle_id AND c2i.item_id=i2b.item_id AND c2c.collection_id=c2i.collection_id AND c2c.community_id=?";
/** Standard Log4J logger. */ /** Standard Log4J logger. */
private static final Logger LOG = Logger.getLogger(BitstreamInfoDAO.class); private static final Logger LOG = Logger.getLogger(BitstreamInfoDAO.class);
@@ -257,13 +282,12 @@ public final class BitstreamInfoDAO extends DAOSupport
try try
{ {
LOG.debug("updateing missing bitstreams"); LOG.debug("updating missing bitstreams");
conn = DatabaseManager.getConnection(); conn = DatabaseManager.getConnection();
stmt = conn.prepareStatement(INSERT_MISSING_CHECKSUM_BITSTREAMS); stmt = conn.prepareStatement(INSERT_MISSING_CHECKSUM_BITSTREAMS);
stmt.setTimestamp(1, new java.sql.Timestamp(new Date().getTime())); stmt.setTimestamp(1, new java.sql.Timestamp(new Date().getTime()));
stmt.setTimestamp(2, new java.sql.Timestamp(new Date().getTime())); stmt.setTimestamp(2, new java.sql.Timestamp(new Date().getTime()));
stmt.executeUpdate(); stmt.executeUpdate();
LOG.debug("Committing update");
checksumHistoryDAO.updateMissingBitstreams(conn); checksumHistoryDAO.updateMissingBitstreams(conn);
conn.commit(); conn.commit();
@@ -327,64 +351,6 @@ public final class BitstreamInfoDAO extends DAOSupport
return numDeleted; return numDeleted;
} }
/**
* Queries the bitstream table for the specified bitstream ID and inserts it
* into the most_recent_checksum table if it does not already exist.
*
* @param id
* the bitstream id.
*
* @return true if the bitstream was found and updated
*/
public boolean updateMissingBitstream(int id)
{
Connection conn = null;
PreparedStatement stmt = null;
boolean bitstreamFound = false;
try
{
conn = DatabaseManager.getConnection();
stmt = conn.prepareStatement(INSERT_MISSING_CHECKSUM_BITSTREAM);
stmt.setTimestamp(1, new java.sql.Timestamp(new Date().getTime()));
stmt.setTimestamp(2, new java.sql.Timestamp(new Date().getTime()));
stmt.setInt(3, id);
stmt.setInt(4, id);
int rowsUpdated = stmt.executeUpdate();
if (rowsUpdated == 1)
{
bitstreamFound = true;
}
if (rowsUpdated > 1)
{
conn.rollback();
throw new IllegalStateException(
"Too many rows updated! Number of rows updated: "
+ rowsUpdated
+ " only one row should be updated for bitstream id "
+ id);
}
conn.commit();
}
catch (SQLException e)
{
LOG.error("Problem with inserting missing bitstream. "
+ e.getMessage(), e);
throw new RuntimeException("Problem inserting missing bitstream. "
+ e.getMessage(), e);
}
finally
{
cleanup(stmt, conn);
}
return bitstreamFound;
}
public int deleteBitstreamInfoWithHistory(int id) public int deleteBitstreamInfoWithHistory(int id)
{ {
Connection conn = null; Connection conn = null;
@@ -411,4 +377,219 @@ public final class BitstreamInfoDAO extends DAOSupport
return numDeleted; return numDeleted;
} }
/**
* Get the oldest bitstream in the most recent checksum table. If more than
* one found the first one in the result set is returned.
*
* @return the bitstream id or -1 if the no bitstreams are found
*
*/
public int getOldestBitstream()
{
Connection conn = null;
PreparedStatement prepStmt = null;
ResultSet rs = null;
try
{
conn = DatabaseManager.getConnection();
prepStmt = conn.prepareStatement(GET_OLDEST_BITSTREAM);
rs = prepStmt.executeQuery();
if (rs.next())
{
return rs.getInt(1);
}
else
{
return SENTINEL;
}
}
catch (SQLException e)
{
LOG.error("Problem with get oldest bitstream " + e.getMessage(), e);
throw new RuntimeException("Oldest bitstream error. "
+ e.getMessage(), e);
}
finally
{
cleanup(prepStmt, conn);
}
}
/**
* Returns the oldest bistream that in the set of bitstreams that are less
* than the specified date. If no bitstreams are found -1 is returned.
*
* @param lessThanDate
* @return id of olded bitstream or -1 if not bistreams are found
*/
public int getOldestBitstream(Timestamp lessThanDate)
{
Connection conn = null;
PreparedStatement prepStmt = null;
ResultSet rs = null;
try
{
conn = DatabaseManager.getConnection();
prepStmt = conn.prepareStatement(GET_OLDEST_BITSTREAM_DATE);
prepStmt.setTimestamp(1, lessThanDate);
rs = prepStmt.executeQuery();
if (rs.next())
{
return rs.getInt(1);
}
else
{
return SENTINEL;
}
}
catch (SQLException e)
{
LOG.error("get oldest bitstream less than date " + e.getMessage(),
e);
throw new RuntimeException("get oldest bitstream less than date. "
+ e.getMessage(), e);
}
finally
{
cleanup(prepStmt, conn);
}
}
/**
* Get the bitstream ids for a given Item
*
* @param itemId
* @return the list of bitstream ids for this item
*/
public List getItemBitstreams(int itemId)
{
List ids = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = DatabaseManager.getConnection();
ps = conn.prepareStatement(ITEM_BITSTREAMS);
ps.setInt(1, itemId);
rs = ps.executeQuery();
while (rs.next())
{
ids.add(new Integer(rs.getInt(1)));
}
}
catch (SQLException e)
{
LOG.error("get item bitstreams " + e.getMessage(), e);
throw new RuntimeException(
"get item bitstreams. " + e.getMessage(), e);
}
finally
{
cleanup(ps, conn, rs);
}
return ids;
}
/**
* Get the bitstream ids for a given collection
*
* @param itemId
* @return the list of bitstream ids for this item
*/
public List getCollectionBitstreams(int collectionId)
{
List ids = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = DatabaseManager.getConnection();
ps = conn.prepareStatement(COLLECTION_BITSTREAMS);
ps.setInt(1, collectionId);
rs = ps.executeQuery();
while (rs.next())
{
ids.add(new Integer(rs.getInt(1)));
}
}
catch (SQLException e)
{
LOG.error("get item bitstreams " + e.getMessage(), e);
throw new RuntimeException(
"get item bitstreams. " + e.getMessage(), e);
}
finally
{
cleanup(ps, conn, rs);
}
return ids;
}
/**
* Get the bitstream ids for a given community
*
* @param itemId
* @return the list of bitstream ids for this item
*/
public List getCommunityBitstreams(int communityId)
{
List ids = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = DatabaseManager.getConnection();
ps = conn.prepareStatement(COMMUNITY_BITSTREAMS);
ps.setInt(1, communityId);
rs = ps.executeQuery();
while (rs.next())
{
ids.add(new Integer(rs.getInt(1)));
}
}
catch (SQLException e)
{
LOG.error("get item bitstreams " + e.getMessage(), e);
throw new RuntimeException(
"get item bitstreams. " + e.getMessage(), e);
}
finally
{
cleanup(ps, conn, rs);
}
return ids;
}
} }

View File

@@ -54,9 +54,10 @@ import org.dspace.core.Utils;
* against the last calculated checksum for that bitstream. * against the last calculated checksum for that bitstream.
* </p> * </p>
* *
* @author Nate Sarr
* @author Grace Carpenter
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* *
* @todo the accessor methods are currently unused - are they useful? * @todo the accessor methods are currently unused - are they useful?
* @todo check for any existing resource problems * @todo check for any existing resource problems
@@ -96,8 +97,8 @@ public final class CheckerCommand
*/ */
private ChecksumResultsCollector collector = null; private ChecksumResultsCollector collector = null;
/** Report only errors */ /** Report all processing */
private boolean reportErrorsOnly = false; private boolean reportVerbose = false;
/** /**
* Default constructor uses DSpace plugin manager to construct dependencies. * Default constructor uses DSpace plugin manager to construct dependencies.
@@ -135,37 +136,25 @@ public final class CheckerCommand
collector = new ResultsLogger(processStartDate); collector = new ResultsLogger(processStartDate);
} }
// loop through bitstreams and check
try
{
bitstreamInfoDAO.updateMissingBitstreams();
int id = dispatcher.next();
LOG.debug("Processing bitstream id = " + id);
while (id != BitstreamDispatcher.SENTINEL)
{
BitstreamInfo info = checkBitstream(id);
if (reportErrorsOnly
&& (info.getChecksumCheckResult() == ChecksumCheckResults.CHECKSUM_MATCH))
{
// NO-OP do not report good checksums
}
else
{
collector.collect(info);
}
id = dispatcher.next();
}
}
catch (SQLException e)
{
LOG.error("Next bitstream metadata could not be retrieved. ", e);
}
// update missing bitstreams that were entered into the // update missing bitstreams that were entered into the
// bitstream table - this always done. // bitstream table - this always done.
bitstreamInfoDAO.updateMissingBitstreams(); bitstreamInfoDAO.updateMissingBitstreams();
int id = dispatcher.next();
while (id != BitstreamDispatcher.SENTINEL)
{
LOG.debug("Processing bitstream id = " + id);
BitstreamInfo info = checkBitstream(id);
if (reportVerbose
|| (info.getChecksumCheckResult() != ChecksumCheckResults.CHECKSUM_MATCH))
{
collector.collect(info);
}
id = dispatcher.next();
}
} }
/** /**
@@ -181,15 +170,6 @@ public final class CheckerCommand
// get bitstream info from bitstream table // get bitstream info from bitstream table
BitstreamInfo info = bitstreamInfoDAO.findByBitstreamId(id); BitstreamInfo info = bitstreamInfoDAO.findByBitstreamId(id);
// make sure bitstream and most_recent_checksum in sync for the id
if (info == null)
{
if (bitstreamInfoDAO.updateMissingBitstream(id))
{
info = bitstreamInfoDAO.findByBitstreamId(id);
}
}
// requested id was not found in bitstream // requested id was not found in bitstream
// or most_recent_checksum table // or most_recent_checksum table
if (info == null) if (info == null)
@@ -480,9 +460,9 @@ public final class CheckerCommand
* *
* @return true if only errors reported * @return true if only errors reported
*/ */
public boolean isReportErrorsOnly() public boolean isReportVerbose()
{ {
return reportErrorsOnly; return reportVerbose;
} }
/** /**
@@ -491,8 +471,8 @@ public final class CheckerCommand
* @param reportErrorsOnly * @param reportErrorsOnly
* true to report only errors in the logs. * true to report only errors in the logs.
*/ */
public void setReportErrorsOnly(boolean reportErrorsOnly) public void setReportVerbose(boolean reportVerbose)
{ {
this.reportErrorsOnly = reportErrorsOnly; this.reportVerbose = reportVerbose;
} }
} }

View File

@@ -37,8 +37,10 @@ package org.dspace.checker;
* Enumeration of ChecksumCheckResults containing constants for checksum * Enumeration of ChecksumCheckResults containing constants for checksum
* comparison result that must correspond to values in checksum_result table. * comparison result that must correspond to values in checksum_result table.
* *
* @author Grace Carpenter
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* *
* @todo Refactor these as properties of ChecksumChecker? * @todo Refactor these as properties of ChecksumChecker?
*/ */

View File

@@ -40,7 +40,10 @@ import java.util.Date;
* Represents a history record for the bitstream. * Represents a history record for the bitstream.
* </p> * </p>
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class ChecksumHistory public class ChecksumHistory
{ {

View File

@@ -19,8 +19,10 @@ import org.dspace.storage.rdbms.DatabaseManager;
* </p> * </p>
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr * @author Nathan Sarr
* *
*
*/ */
public class ChecksumHistoryDAO extends DAOSupport public class ChecksumHistoryDAO extends DAOSupport
{ {
@@ -149,7 +151,7 @@ public class ChecksumHistoryDAO extends DAOSupport
/** /**
* @param conn * @param conn
*/ */
protected void updateMissingBitstreams(Connection conn) protected void updateMissingBitstreams(Connection conn) throws SQLException
{ {
PreparedStatement stmt = null; PreparedStatement stmt = null;
try try
@@ -163,10 +165,9 @@ public class ChecksumHistoryDAO extends DAOSupport
throw new RuntimeException("Problem updating missing history. " throw new RuntimeException("Problem updating missing history. "
+ e.getMessage(), e); + e.getMessage(), e);
} }
finally finally
{ {
cleanup(stmt, conn); cleanup(stmt);
} }
} }

View File

@@ -49,7 +49,10 @@ import org.dspace.storage.rdbms.DatabaseManager;
* Database Access for the checksum results information. * Database Access for the checksum results information.
* </p> * </p>
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public final class ChecksumResultDAO extends DAOSupport public final class ChecksumResultDAO extends DAOSupport
{ {

View File

@@ -37,6 +37,9 @@ package org.dspace.checker;
* Component that receives BitstreamInfo results from a checker. * Component that receives BitstreamInfo results from a checker.
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public interface ChecksumResultsCollector public interface ChecksumResultsCollector
{ {

View File

@@ -8,6 +8,14 @@ import java.sql.Statement;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.storage.rdbms.DatabaseManager; import org.dspace.storage.rdbms.DatabaseManager;
/**
* Database Helper Class to cleanup database resources
*
* @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/
public class DAOSupport public class DAOSupport
{ {

View File

@@ -37,7 +37,10 @@ package org.dspace.checker;
* Value Object that holds bitstream information that will be used for dspace * Value Object that holds bitstream information that will be used for dspace
* bitstream. * bitstream.
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public final class DSpaceBitstreamInfo public final class DSpaceBitstreamInfo
{ {

View File

@@ -69,7 +69,10 @@ import org.dspace.core.ConfigurationManager;
* after the checksum checker has been run. * after the checksum checker has been run.
* </p> * </p>
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* *
*/ */
public class DailyReportEmailer public class DailyReportEmailer

View File

@@ -33,9 +33,6 @@
*/ */
package org.dspace.checker; package org.dspace.checker;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -51,21 +48,12 @@ import org.dspace.handle.HandleManager;
* item, collection or community referred to by Handle. * item, collection or community referred to by Handle.
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class HandleDispatcher implements BitstreamDispatcher public class HandleDispatcher implements BitstreamDispatcher
{ {
/** SQL query to retrieve bitstreams for a given item. */
private static final String ITEM_BITSTREAMS = "SELECT b2b.bitstream_id "
+ "FROM bundle2bitstream b2b, item2bundle i2b WHERE "
+ "b2b.bundle_id=i2b.bundle_id AND i2b.item_id=?";
/** SQL query to retrieve bitstreams for a given collection. */
private static final String COLLECTION_BITSTREAMS = "SELECT b2b.bitstream_id "
+ "FROM bundle2bitstream b2b, item2bundle i2b, collection2item c2i WHERE "
+ "b2b.bundle_id=i2b.bundle_id AND c2i.item_id=i2b.item_id AND c2i.collection_id=?";
/** SQL query to retrieve bitstreams for a given community. */
private static final String COMMUNITY_BITSTREAMS = "SELECT b2b.bitstream_id FROM bundle2bitstream b2b, item2bundle i2b, collection2item c2i, community2collection c2c WHERE b2b.bundle_id=i2b.bundle_id AND c2i.item_id=i2b.item_id AND c2c.collection_id=c2i.collection_id AND c2c.community_id=?";
/** Log 4j logger. */ /** Log 4j logger. */
private static final Logger LOG = Logger.getLogger(HandleDispatcher.class); private static final Logger LOG = Logger.getLogger(HandleDispatcher.class);
@@ -79,6 +67,11 @@ public class HandleDispatcher implements BitstreamDispatcher
/** the delegate to dispatch to. */ /** the delegate to dispatch to. */
ListDispatcher delegate = null; ListDispatcher delegate = null;
/**
* Database access for retrieving bitstreams
*/
BitstreamInfoDAO bitstreamInfoDAO;
/** /**
* Blanked off, no-op constructor. * Blanked off, no-op constructor.
*/ */
@@ -93,8 +86,9 @@ public class HandleDispatcher implements BitstreamDispatcher
* @param hdl * @param hdl
* the handle to get bitstreams from. * the handle to get bitstreams from.
*/ */
public HandleDispatcher(String hdl) public HandleDispatcher(BitstreamInfoDAO bitInfoDAO, String hdl)
{ {
bitstreamInfoDAO = bitInfoDAO;
handle = hdl; handle = hdl;
} }
@@ -104,41 +98,26 @@ public class HandleDispatcher implements BitstreamDispatcher
* @throws SQLException * @throws SQLException
* if database access fails. * if database access fails.
*/ */
private void init() throws SQLException private void init()
{ {
Context context = null; Context context = null;
int dsoType = -1;
int id = -1;
try try
{ {
context = new Context(); context = new Context();
DSpaceObject dso = HandleManager.resolveToObject(context, handle); DSpaceObject dso = HandleManager.resolveToObject(context, handle);
id = dso.getID();
dsoType = dso.getType();
context.abort(); context.abort();
List ids = new ArrayList(); }
catch (SQLException e)
{
LOG.error("init error " + e.getMessage(), e);
throw new RuntimeException("init error" + e.getMessage(), e);
switch (dso.getType())
{
case Constants.BITSTREAM:
ids.add(new Integer(dso.getID()));
break;
case Constants.ITEM:
ids = getItemIds(dso.getID());
break;
case Constants.COLLECTION:
ids = getCollectionIds(dso.getID());
break;
case Constants.COMMUNITY:
ids = getCommunityIds(dso.getID());
}
delegate = new ListDispatcher(ids);
init = Boolean.TRUE;
} }
finally finally
{ {
@@ -148,6 +127,30 @@ public class HandleDispatcher implements BitstreamDispatcher
context.abort(); context.abort();
} }
} }
List ids = new ArrayList();
switch (dsoType)
{
case Constants.BITSTREAM:
ids.add(new Integer(id));
break;
case Constants.ITEM:
ids = bitstreamInfoDAO.getItemBitstreams(id);
break;
case Constants.COLLECTION:
ids = bitstreamInfoDAO.getCollectionBitstreams(id);
break;
case Constants.COMMUNITY:
ids = bitstreamInfoDAO.getCommunityBitstreams(id);
break;
}
delegate = new ListDispatcher(ids);
init = Boolean.TRUE;
} }
/** /**
@@ -155,7 +158,7 @@ public class HandleDispatcher implements BitstreamDispatcher
* *
* @see org.dspace.checker.BitstreamDispatcher#next() * @see org.dspace.checker.BitstreamDispatcher#next()
*/ */
public int next() throws SQLException public int next()
{ {
synchronized (init) synchronized (init)
{ {
@@ -167,100 +170,4 @@ public class HandleDispatcher implements BitstreamDispatcher
return delegate.next(); return delegate.next();
} }
/**
* Utility query method to get item ids.
*
* @param id
* the item id
* @return a list of bitstream ids for items.
* @throws SQLException
* if database access fails
*/
private List getItemIds(int id) throws SQLException
{
return getIdList(id, ITEM_BITSTREAMS);
}
/**
* Utility query method.
*
* @param id
* Collection id
* @return a list of bitstream ids for collection
* @throws SQLException
* if database access error occurs.
*/
private List getCollectionIds(int id) throws SQLException
{
return getIdList(id, COLLECTION_BITSTREAMS);
}
/**
* Utility query method.
*
* @param id
* the community id
* @return the bitstream ids.
* @throws SQLException
* if a database access error occurs.
*/
private List getCommunityIds(int id) throws SQLException
{
return getIdList(id, COMMUNITY_BITSTREAMS);
}
/**
* Utility query method.
*
* @param arg
* community/collection/item id.
* @param query
* query to be excuted
* @return list of bitstream ids.
* @throws SQLException
* if database access occurs.
*/
private List getIdList(int arg, String query) throws SQLException
{
List ids = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Context ctx = new Context();
try
{
conn = ctx.getDBConnection();
ps = conn.prepareStatement(query);
ps.setInt(1, arg);
rs = ps.executeQuery();
while (rs.next())
{
ids.add(new Integer(rs.getInt(1)));
}
LOG.debug("Returned " + ids.size() + " ids for handle " + handle);
}
finally
{
if (rs != null)
{
rs.close();
}
if (ps != null)
{
ps.close();
}
ctx.complete();
}
return ids;
}
} }

View File

@@ -42,6 +42,9 @@ import org.dspace.core.PluginManager;
* dispatcher. * dispatcher.
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class LimitedCountDispatcher implements BitstreamDispatcher public class LimitedCountDispatcher implements BitstreamDispatcher
{ {
@@ -92,7 +95,7 @@ public class LimitedCountDispatcher implements BitstreamDispatcher
* @throws SQLException * @throws SQLException
* if database error occurs. * if database error occurs.
*/ */
public int next() throws SQLException public int next()
{ {
if (remaining > 0) if (remaining > 0)
{ {

View File

@@ -33,7 +33,6 @@
*/ */
package org.dspace.checker; package org.dspace.checker;
import java.sql.SQLException;
import java.util.Date; import java.util.Date;
/** /**
@@ -48,6 +47,9 @@ import java.util.Date;
* </p> * </p>
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class LimitedDurationDispatcher implements BitstreamDispatcher public class LimitedDurationDispatcher implements BitstreamDispatcher
{ {
@@ -90,7 +92,7 @@ public class LimitedDurationDispatcher implements BitstreamDispatcher
/** /**
* @see org.dspace.checker.BitstreamDispatcher#next() * @see org.dspace.checker.BitstreamDispatcher#next()
*/ */
public int next() throws SQLException public int next()
{ {
return (System.currentTimeMillis() > end) ? SENTINEL : delegate.next(); return (System.currentTimeMillis() > end) ? SENTINEL : delegate.next();
} }

View File

@@ -33,7 +33,6 @@
*/ */
package org.dspace.checker; package org.dspace.checker;
import java.sql.SQLException;
import java.util.Collections; import java.util.Collections;
import java.util.EmptyStackException; import java.util.EmptyStackException;
import java.util.List; import java.util.List;
@@ -43,6 +42,9 @@ import java.util.Stack;
* Really simple dispatcher that just iterates over a pre-defined list of ids. * Really simple dispatcher that just iterates over a pre-defined list of ids.
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class ListDispatcher implements BitstreamDispatcher public class ListDispatcher implements BitstreamDispatcher
{ {
@@ -74,7 +76,7 @@ public class ListDispatcher implements BitstreamDispatcher
/** /**
* @see org.dspace.checker.BitstreamDispatcher#next() * @see org.dspace.checker.BitstreamDispatcher#next()
*/ */
public synchronized int next() throws SQLException public synchronized int next()
{ {
try try
{ {

View File

@@ -47,7 +47,10 @@ import org.dspace.storage.rdbms.DatabaseManager;
/** /**
* This class will report information on the checksum checker process. * This class will report information on the checksum checker process.
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* *
*/ */
public class ReporterDAO extends DAOSupport public class ReporterDAO extends DAOSupport

View File

@@ -45,7 +45,10 @@ import org.dspace.core.I18N;
* </p> * </p>
* *
* *
* @author Jim Downing
* @author Grace Carpenter * @author Grace Carpenter
* @author Nathan Sarr
*
* *
*/ */
public class ResultsLogger implements ChecksumResultsCollector public class ResultsLogger implements ChecksumResultsCollector
@@ -131,7 +134,7 @@ public class ResultsLogger implements ChecksumResultsCollector
.info(msg("checksum-algorithm") + ": " .info(msg("checksum-algorithm") + ": "
+ info.getChecksumAlgorithm()); + info.getChecksumAlgorithm());
LOG.info(msg("previous-checksum") + ": " + info.getStoredChecksum()); LOG.info(msg("previous-checksum") + ": " + info.getStoredChecksum());
LOG.info(msg("previous-checksum-data") LOG.info(msg("previous-checksum-date")
+ ": " + ": "
+ ((info.getProcessEndDate() != null) ? DATE_FORMAT.format(info + ((info.getProcessEndDate() != null) ? DATE_FORMAT.format(info
.getProcessEndDate()) : "unknown")); .getProcessEndDate()) : "unknown"));

View File

@@ -57,6 +57,9 @@ import org.dspace.core.Utils;
* and can use a different configuration file if it is passed in. * and can use a different configuration file if it is passed in.
* *
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* *
*/ */
public final class ResultsPruner public final class ResultsPruner

View File

@@ -33,45 +33,19 @@
*/ */
package org.dspace.checker; package org.dspace.checker;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date; import java.util.Date;
import org.dspace.storage.rdbms.DatabaseManager;
/** /**
* An implementation of the selection strategy that selects bitstreams in the * An implementation of the selection strategy that selects bitstreams in the
* order that they were last checked, looping endlessly. * order that they were last checked, looping endlessly.
* *
* @author Nate Sarr
* @author Jim Downing * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public class SimpleDispatcher implements BitstreamDispatcher public class SimpleDispatcher implements BitstreamDispatcher
{ {
/**
* This selects the next bitstream that is to be processed, in order of last
* processing end date. The timestamp is truncated to milliseconds this is
* because the Date for java does not support nanoseconds and milliseconds
* were considered accurate enough
*/
public static final String FIND_BITSTREAMS_LOOP = "select bitstream_id "
+ "from most_recent_checksum " + "where to_be_processed = true "
+ "order by date_trunc('milliseconds', last_process_end_date), "
+ "bitstream_id " + "ASC LIMIT 1";
/**
* Selects the next bitstream in order of last processing end date, ensuring
* that no bitstream is checked more than once since the date parameter
* used.
*/
public static final String FIND_BITSTREAMS_NO_LOOP = "select bitstream_id "
+ "from most_recent_checksum "
+ "where to_be_processed = true "
+ "and last_process_start_date < ? "
+ "order by date_trunc('milliseconds', last_process_end_date), "
+ "bitstream_id " + "ASC LIMIT 1";
/** /**
* Should this dispatcher keep on dispatching around the collection? * Should this dispatcher keep on dispatching around the collection?
@@ -89,6 +63,11 @@ public class SimpleDispatcher implements BitstreamDispatcher
*/ */
private int bitstreamId = -1; private int bitstreamId = -1;
/**
* Access for bitstream information
*/
private BitstreamInfoDAO bitstreamInfoDAO;
/** /**
* Creates a new SimpleDispatcher. * Creates a new SimpleDispatcher.
* *
@@ -98,8 +77,10 @@ public class SimpleDispatcher implements BitstreamDispatcher
* indicates whether checker should loop infinitely through * indicates whether checker should loop infinitely through
* most_recent_checksum table * most_recent_checksum table
*/ */
public SimpleDispatcher(Date startTime, boolean looping) public SimpleDispatcher(BitstreamInfoDAO bitstreamInfoDAO, Date startTime,
boolean looping)
{ {
this.bitstreamInfoDAO = bitstreamInfoDAO;
this.processStartTime = startTime; this.processStartTime = startTime;
this.loopContinuously = looping; this.loopContinuously = looping;
} }
@@ -117,57 +98,19 @@ public class SimpleDispatcher implements BitstreamDispatcher
* *
* @see org.dspace.checker.BitstreamDispatcher#next() * @see org.dspace.checker.BitstreamDispatcher#next()
*/ */
public synchronized int next() throws SQLException public synchronized int next()
{ {
Connection conn = null; // should process loop infinitely through the
PreparedStatement prepStmt = null; // bitstreams in most_recent_checksum table?
ResultSet rs = null; if (!loopContinuously && (processStartTime != null))
try
{ {
// create the connection and execute the statement return bitstreamInfoDAO.getOldestBitstream(new java.sql.Timestamp(
conn = DatabaseManager.getConnection(); processStartTime.getTime()));
// should process loop infinitely through the
// bitstreams in most_recent_checksum table?
if (!loopContinuously && (processStartTime != null))
{
prepStmt = conn.prepareStatement(FIND_BITSTREAMS_NO_LOOP);
prepStmt.setTimestamp(1, new java.sql.Timestamp(
processStartTime.getTime()));
}
else
{
prepStmt = conn.prepareStatement(FIND_BITSTREAMS_LOOP);
}
rs = prepStmt.executeQuery();
if (rs.next())
{
return rs.getInt(1);
}
else
{
return SENTINEL;
}
} }
finally else
{ {
if (rs != null) return bitstreamInfoDAO.getOldestBitstream();
{
rs.close();
}
if (prepStmt != null)
{
prepStmt.close();
}
if (conn != null)
{
DatabaseManager.freeConnection(conn);
}
} }
} }
} }

View File

@@ -41,7 +41,10 @@ import java.util.Date;
* *
* Simple Reporting Class which can return several different reports. * Simple Reporting Class which can return several different reports.
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
*/ */
public interface SimpleReporter public interface SimpleReporter
{ {

View File

@@ -47,7 +47,10 @@ import org.dspace.core.I18N;
* *
* Simple Reporter implementation. * Simple Reporter implementation.
* *
* @author Nate Sarr * @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*
* @todo estimate string buffer sizes. * @todo estimate string buffer sizes.
*/ */
public class SimpleReporterImpl implements SimpleReporter public class SimpleReporterImpl implements SimpleReporter

View File

@@ -135,7 +135,9 @@ public class I18N {
* @return Localized message * @return Localized message
*/ */
public String getMessage(String msg, Class clazz) { public String getMessage(String msg, Class clazz) {
return getMessage(msg, clazz.getName()); String className = clazz.getName();
return messages.getString(new StringBuilder(50).append(className)
.append(".").append(msg).toString());
} }
/** /**