
java.fedora.server.storage.replication.DefaultDOReplicator Maven / Gradle / Ivy
Show all versions of fcrepo-client Show documentation
/*
* -----------------------------------------------------------------------------
*
* License and Copyright: The contents of this file are subject to the
* Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of
* the License at
* http://www.fedora-commons.org/licenses.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The entire file consists of original code.
* Copyright © 2008 Fedora Commons, Inc.
*
Copyright © 2002-2007 The Rector and Visitors of the University of
* Virginia and Cornell University
* All rights reserved.
*
* -----------------------------------------------------------------------------
*/
package fedora.server.storage.replication;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import fedora.server.Module;
import fedora.server.Server;
import fedora.server.errors.ModuleInitializationException;
import fedora.server.errors.ReplicationException;
import fedora.server.errors.ServerException;
import fedora.server.errors.StorageDeviceException;
import fedora.server.storage.BDefReader;
import fedora.server.storage.BMechReader;
import fedora.server.storage.ConnectionPool;
import fedora.server.storage.ConnectionPoolManager;
import fedora.server.storage.DOReader;
import fedora.server.storage.types.BMechDSBindSpec;
import fedora.server.storage.types.DSBindingMapAugmented;
import fedora.server.storage.types.Datastream;
import fedora.server.storage.types.Disseminator;
import fedora.server.storage.types.MethodDef;
import fedora.server.storage.types.MethodDefOperationBind;
import fedora.server.storage.types.MethodParmDef;
import fedora.server.utilities.SQLUtility;
/**
*
* Title: DefaultDOReplicator.java
* Description: A Module that replicates digital object information
* to the dissemination database.
*
* Converts data read from the object reader interfaces and creates or
* updates the corresponding database rows in the dissemination database.
*
* @author Paul Charlton, [email protected]
* @version $Id: DefaultDOReplicator.java 5241 2006-11-27 08:14:31Z cwilper $
*/
public class DefaultDOReplicator
extends Module
implements DOReplicator {
/** Logger for this class. */
private static final Logger LOG = Logger.getLogger(
DefaultDOReplicator.class.getName());
private ConnectionPool m_pool;
private RowInsertion m_ri;
/**
* Server instance to work with in this module.
*/
private Server server;
/** Port number on which the Fedora server is running; determined from
* fedora.fcfg config file.
*/
private static String fedoraServerPort = null;
/** Hostname of the Fedora server determined from
* fedora.fcfg config file, or (fallback) by hostIP.getHostName()
*/
private static String fedoraServerHost = null;
/** SSL port number on which the Fedora server is running; determined from
* fedora.fcfg config file.
*/
private static String fedoraServerPortSSL = null;
/** The IP address of the local host; determined dynamically. */
private static InetAddress hostIP = null;
// Fedora URL LOCALIZATION Pattern:
// Pattern that is used as the internal replacement syntax for URLs that
// refer back to the local repository. This pattern virtualized the
// repository server address, so that if the host:port of the repository is
// changed, objects that have URLs that refer to the local repository won't break.
public static Pattern s_fedoraLocalPattern = Pattern.compile("http://local.fedora.server/");
// RELATIVE URL Patterns:
// Relative URL paths that are based at the local Fedora repository server.
public static Pattern s_relativePattern = Pattern.compile("fedora/");
public static Pattern s_relativeGetPattern = Pattern.compile("fedora/get/");
public static Pattern s_relativeSearchPattern = Pattern.compile("fedora/search/");
public static Pattern s_relativeGetPatternAsParm = Pattern.compile("=fedora/get/");
public static Pattern s_relativeSearchPatternAsParm = Pattern.compile("=fedora/search/");
// ABSOLUTE REPOSITORY URL Patterns:
// Patterns of how the protocol and repository server address may be encoded
// in a URL that points back to the local repository.
private static Pattern s_servernamePort; // "http://hostname:port/"
private static Pattern s_servername; // "http://hostname/"
private static Pattern s_localhostPort; // "http://localhost:port/"
private static Pattern s_localhost; // "http://localhost/"
private static Pattern s_servernamePortSSL; // "https://hostname:redirectport/"
private static Pattern s_servernameSSL; // "https://hostname/"
private static Pattern s_localhostPortSSL; // "https://localhost:redirectport/"
private static Pattern s_localhostSSL; // "https://localhost/"
// The actual host and port of the Fedora repository server
private static String s_hostInfo = null;
private static boolean m_serverOnPort80=false;
private static boolean m_serverOnRedirectPort443=false;
public DefaultDOReplicator(Map moduleParameters, Server server, String role)
throws ModuleInitializationException {
super(moduleParameters, server, role);
}
public void initModule() {
}
public void postInitModule()
throws ModuleInitializationException {
try {
ConnectionPoolManager mgr=(ConnectionPoolManager)
getServer().getModule(
"fedora.server.storage.ConnectionPoolManager");
m_pool=mgr.getPool();
// sdp: insert new
hostIP = null;
fedoraServerPort = getServer().getParameter("fedoraServerPort");
LOG.debug("fedoraServerPort: " + fedoraServerPort);
fedoraServerPortSSL = getServer().getParameter("fedoraRedirectPort");
LOG.debug("fedoraServerPortSSL: " + fedoraServerPortSSL);
hostIP = InetAddress.getLocalHost();
fedoraServerHost = getServer().getParameter("fedoraServerHost");
if (fedoraServerHost==null || fedoraServerHost.equals("")) {
fedoraServerHost=hostIP.getHostName();
}
LOG.debug("fedoraServerHost: " + fedoraServerHost);
if (fedoraServerPort.equals("80")) {
m_serverOnPort80=true;
}
if (fedoraServerPortSSL.equals("443")) {
m_serverOnRedirectPort443=true;
}
// set the currently configured host:port of the repository
s_hostInfo="http://" + fedoraServerHost;
if (!fedoraServerPort.equals("80") && !fedoraServerPort.equals("443")) {
s_hostInfo=s_hostInfo + ":" + fedoraServerPort;
}
s_hostInfo=s_hostInfo + "/";
// compile other patterns using the configured host and port
s_servernamePort = Pattern.compile("http://" + fedoraServerHost + ":" + fedoraServerPort + "/");
s_servername = Pattern.compile("http://" + fedoraServerHost + "/");
s_localhostPort = Pattern.compile("http://localhost:" + fedoraServerPort + "/");
s_localhost = Pattern.compile("http://localhost/");
s_servernamePortSSL = Pattern.compile("https://" + fedoraServerHost + ":" + fedoraServerPortSSL + "/");
s_servernameSSL = Pattern.compile("https://" + fedoraServerHost + "/");
s_localhostPortSSL = Pattern.compile("https://localhost:" + fedoraServerPortSSL + "/");
s_localhostSSL = Pattern.compile("https://localhost/");
} catch (ServerException se) {
throw new ModuleInitializationException(
"Error getting default pool: " + se.getMessage(),
getRole());
} catch (UnknownHostException se) {
throw new ModuleInitializationException(
"Error determining hostIP address: " + se.getMessage(),
getRole());
}
}
/**
* If the object has already been replicated, update the components
* and return true. Otherwise, return false.
*
* @ids=select doDbID from dobj where doPID='demo:5'
* if @ids.size=0, return false
* else:
* foreach $id in @ids
* ds=reader.getDatastream(id, null)
* update dsBind set dsLabel='mylabel', dsLocation='' where dsID='$id'
*
* // currentVersionId?
*
* @param reader a digital object reader.
* @return true is successful update; false oterhwise.
* @throws ReplicationException if replication fails for any reason.
*/
private boolean updateComponents(DOReader reader)
throws ReplicationException {
Connection connection=null;
Statement st=null;
ResultSet results=null;
boolean triedUpdate=false;
boolean failed=false;
LOG.debug("Entering updateComponents");
try {
connection=m_pool.getConnection();
st=connection.createStatement();
// Get db ID for the digital object
results=logAndExecuteQuery(st, "SELECT doDbID,doState,doLabel FROM dobj WHERE "
+ "doPID='" + reader.GetObjectPID() + "'");
if (!results.next()) {
LOG.debug("Object is "
+ "new; components dont need updating.");
return false;
}
int doDbID=results.getInt("doDbID");
String doState=results.getString("doState");
String doLabel=results.getString("doLabel");
results.close();
results=null;
ArrayList updates=new ArrayList();
// Check if state has changed for the digital object.
String objState = reader.GetObjectState();
if (!doState.equalsIgnoreCase(objState)) {
updates.add("UPDATE dobj SET doState='" + objState + "' WHERE doDbID=" + doDbID);
updates.add("UPDATE doRegistry SET objectState='" + objState + "' WHERE doPID='" + reader.GetObjectPID() + "'");
}
// Check if label has changed for the digital object.
String objLabel = reader.GetObjectLabel();
if (!doLabel.equalsIgnoreCase(objLabel)) {
updates.add("UPDATE dobj SET doLabel='" + SQLUtility.aposEscape(objLabel) + "' WHERE doDbID=" + doDbID);
updates.add("UPDATE doRegistry SET label='" + SQLUtility.aposEscape(objLabel) + "' WHERE doPID='" + reader.GetObjectPID() + "'");
}
// check if any mods to datastreams for this digital object
results=logAndExecuteQuery(st, "SELECT dsID, dsLabel, dsLocation, dsCurrentVersionID, dsState "
+ "FROM dsBind WHERE doDbID=" + doDbID);
while (results.next()) {
String dsID=results.getString("dsID");
String dsLabel=results.getString("dsLabel");
String dsCurrentVersionID=results.getString("dsCurrentVersionID");
String dsState=results.getString("dsState");
// sdp - local.fedora.server conversion
String dsLocation=makeAbsoluteURLs(results.getString("dsLocation"));
// compare the latest version of the datastream to what's in the db...
// if different, add to update list
Datastream ds=reader.GetDatastream(dsID, null);
if (!ds.DSLabel.equals(dsLabel)
|| !ds.DSLocation.equals(dsLocation)
|| !ds.DSVersionID.equals(dsCurrentVersionID)
|| !ds.DSState.equals(dsState)) {
updates.add("UPDATE dsBind SET dsLabel='"
+ SQLUtility.aposEscape(ds.DSLabel) + "', dsLocation='"
// sdp - local.fedora.server conversion
+ SQLUtility.aposEscape(makeFedoraLocalURLs(ds.DSLocation))
+ "', dsCurrentVersionID='" + ds.DSVersionID + "', "
+ "dsState='" + ds.DSState + "' "
+ " WHERE doDbID=" + doDbID + " AND dsID='" + dsID + "'");
}
}
results.close();
results=null;
// Do any required updates via a transaction.
if (updates.size()>0) {
connection.setAutoCommit(false);
triedUpdate=true;
for (int i=0; i dissDbIDs = new HashSet();
while (results.next()) {
dissDbIDs.add(results.getInt("dissDbID"));
}
if (dissDbIDs.size()==0 || reader.GetDisseminators(null, null).length!=dissDbIDs.size()) {
LOG.debug("Object "
+ "either has no disseminators or a new disseminator"
+ "has been added; components dont need updating.");
return false;
}
results.close();
results=null;
// Iterate over disseminators to check if any have been modified
Iterator dissIter = dissDbIDs.iterator();
while(dissIter.hasNext()) {
Integer dissDbID = (Integer) dissIter.next();
// Get disseminator info for this disseminator.
results=logAndExecuteQuery(st, "SELECT diss.bDefDbID, diss.bMechDbID, bMech.bMechPID, diss.dissID, diss.dissLabel, diss.dissState "
+ "FROM diss,bMech WHERE bMech.bMechDbID=diss.bMechDbID AND diss.dissDbID=" + dissDbID);
updates=new ArrayList();
int bDefDbID = 0;
int bMechDbID = 0;
String dissID=null;
String dissLabel=null;
String dissState=null;
String bMechPID=null;
while(results.next()) {
bDefDbID = results.getInt("bDefDbID");
bMechDbID = results.getInt("bMechDbID");
dissID=results.getString("dissID");
dissLabel=results.getString("dissLabel");
dissState=results.getString("dissState");
bMechPID=results.getString("bMechPID");
}
results.close();
results=null;
// Compare the latest version of the disseminator with what's in the db...
// Replace what's in db if they are different.
Disseminator diss=reader.GetDisseminator(dissID, null);
if (diss == null) {
// XML object has no disseminators
// so this must be a purgeComponents or a new object.
LOG.debug("XML object has no disseminators");
return false;
}
if (!diss.dissLabel.equals(dissLabel)
|| !diss.bMechID.equals(bMechPID)
|| !diss.dissState.equals(dissState)) {
if (!diss.dissLabel.equals(dissLabel))
LOG.debug("dissLabel changed from '" + dissLabel + "' to '"
+ diss.dissLabel + "'");
if (!diss.dissState.equals(dissState))
LOG.debug("dissState changed from '" + dissState + "' to '"
+ diss.dissState + "'");
// We might need to set the bMechDbID to the id for the new one,
// if the mechanism changed.
int newBMechDbID;
if (diss.bMechID.equals(bMechPID)) {
newBMechDbID=bMechDbID;
} else {
LOG.debug("bMechPID changed from '" + bMechPID + "' to '"
+ diss.bMechID + "'");
results=logAndExecuteQuery(st, "SELECT bMechDbID "
+ "FROM bMech "
+ "WHERE bMechPID='"
+ diss.bMechID + "'");
if (!results.next()) {
// shouldn't have gotten this far, but if so...
throw new ReplicationException("The behavior mechanism "
+ "changed to " + diss.bMechID + ", but there is no "
+ "record of that object in the dissemination db.");
}
newBMechDbID=results.getInt("bMechDbID");
results.close();
results=null;
}
// Update the diss/doDissAssoc tables as appropriate
if (newBMechDbID != bMechDbID) {
// The bMech changed, so for this disseminator,
// the object needs to use a different diss row.
// First, check if there's an appropriate diss row to latch on to.
int newDissDbID = getDissDbID(st, bDefDbID, newBMechDbID, diss.dissID, diss.dissState);
if (newDissDbID == -1) {
// None to latch on to, so create a new one
logAndExecuteUpdate(st,
"INSERT INTO diss (bDefDbID, bMechDbID, dissID, dissLabel, dissState) "
+ "VALUES (" + bDefDbID + ", "
+ newBMechDbID + ", "
+ "'" + diss.dissID + "', "
+ "'" + SQLUtility.aposEscape(diss.dissLabel) + "', "
+ "'" + diss.dissState + "')");
newDissDbID = getDissDbID(st, bDefDbID, newBMechDbID, diss.dissID, diss.dissState);
}
// Finally, modify the existing doDissAssoc row to point
// to the different diss row.
logAndExecuteUpdate(st,
"UPDATE doDissAssoc "
+ "SET dissDbID = " + newDissDbID + " "
+ "WHERE doDbID = " + doDbID + " "
+ "AND dissDbID = " + dissDbID);
} else {
// bMech did not change, so just update the appropriate diss row
logAndExecuteUpdate(st, "UPDATE diss SET dissLabel='"
+ SQLUtility.aposEscape(diss.dissLabel)
+ "', dissState='" + diss.dissState + "' "
+ " WHERE dissDbID=" + dissDbID);
}
}
// Compare the latest version of the disseminator's bindMap with what's in the db
// and replace what's in db if they are different.
results=logAndExecuteQuery(st, "SELECT DISTINCT dsBindMap.dsBindMapID,dsBindMap.dsBindMapDbID FROM dsBind,dsBindMap WHERE "
+ "dsBind.doDbID=" + doDbID + " AND dsBindMap.dsBindMapDbID=dsBind.dsBindMapDbID "
+ "AND dsBindMap.bMechDbID="+bMechDbID);
String origDSBindMapID=null;
int origDSBindMapDbID=0;
while (results.next()) {
origDSBindMapID=results.getString("dsBindMapID");
origDSBindMapDbID=results.getInt("dsBindMapDbID");
}
results.close();
results=null;
String newDSBindMapID=diss.dsBindMapID;
LOG.debug("newDSBindMapID: "
+ newDSBindMapID + " origDSBindMapID: " + origDSBindMapID);
// Is this a new bindingMap?
if (!newDSBindMapID.equals(origDSBindMapID)) {
// Yes, dsBindingMap was modified so remove original datastream bindings.
// The original dsBindingMap row will be left alone -- it will be cleaned
// up when the bmech is purged, if need be.
// Remove all datastreams for this binding map.
// If anything has changed, they will all be added back
// shortly from the current binding info the xml object.
String dsBindMapDBID = null;
dsBindMapDBID = lookupDataStreamBindingMapDBID(connection, (new Integer(bMechDbID)).toString(), origDSBindMapID);
int rowCount = logAndExecuteUpdate(st,"DELETE FROM dsBind WHERE doDbID=" + doDbID
+ " AND dsBindMapDbID="+dsBindMapDBID);
LOG.debug("Deleted " + rowCount + " rows from dsBind");
// Now add back new datastreams and dsBindMap associated with this disseminator
// using current info in xml object.
DSBindingMapAugmented[] allBindingMaps;
Disseminator disseminators[];
String bDefDBID;
String bindingMapDBID;
String bMechDBID;
String dissDBID;
String doDBID;
String doPID;
//String doLabel;
String dsBindingKeyDBID;
allBindingMaps = reader.GetDSBindingMaps(null);
LOG.debug("Bindings found: "+allBindingMaps.length);
for (int i=0; i newDisseminators = new HashSet();
int dissDBID = 0;
LOG.debug("Disseminators found: "
+ dissArray.length);
for (int j=0; j< dissArray.length; j++)
{
// Find disseminators that are NEW within an existing object
// (disseminator does not already exist in the database)
results=logAndExecuteQuery(st, "SELECT diss.dissDbID"
+ " FROM doDissAssoc, diss"
+ " WHERE doDissAssoc.doDbID=" + doDbID + " AND diss.dissID='" + dissArray[j].dissID + "'"
+ " AND doDissAssoc.dissDbID=diss.dissDbID");
dissDBID = 0;
while (results.next()) {
dissDBID = results.getInt("dissDbID");
}
if (dissDBID==0) {
// the disseminator does NOT exist in the database; it is NEW.
newDisseminators.add(dissArray[j]);
LOG.debug("Added new disseminator dissID: "+dissArray[j].dissID);
}
}
addDisseminators(doPID, (Disseminator[])newDisseminators.toArray(new Disseminator[0]), reader, connection);
connection.commit();
} catch (SQLException sqle) {
failed=true;
throw new ReplicationException("An error has occurred during "
+ "Replication. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage());
} catch (ServerException se) {
failed=true;
throw new ReplicationException("An error has occurred during "
+ "Replication. The error was \" " + se.getClass().getName()
+ " \". The cause was \" " + se.getMessage());
} catch (Exception e) {
e.printStackTrace();
} finally {
// TODO: make sure this makes sense here
if (connection!=null) {
try {
if (failed) connection.rollback();
} catch (Throwable th) {
LOG.warn("Error while rolling back", th);
} finally {
try {
if (results != null) results.close();
if (st!=null) st.close();
connection.setAutoCommit(true);
if (connection!=null) m_pool.free(connection);
} catch (SQLException sqle) {
LOG.warn("Error while cleaning up", sqle);
} finally {
results=null;
st=null;
}
}
}
}
LOG.debug("Exiting addNewComponents");
return true;
}
/**
* Removes components of a digital object from the database.
*
* @param reader an instance a DOReader.
* @return True if the removal was successfult; false otherwise.
* @throws ReplicationException If any type of error occurs during the removal.
*/
private boolean purgeComponents(DOReader reader)
throws ReplicationException {
Connection connection=null;
Statement st=null;
ResultSet results=null;
boolean failed=false;
LOG.debug("Entering purgeComponents");
try {
String doPID = reader.GetObjectPID();
connection=m_pool.getConnection();
connection.setAutoCommit(false);
st=connection.createStatement();
// get db ID for the digital object
results=logAndExecuteQuery(st, "SELECT doDbID FROM dobj WHERE "
+ "doPID='" + doPID + "'");
if (!results.next()) {
LOG.debug("Object is "
+ "new; components will be added as part of new object replication.");
return false;
}
int doDbID=results.getInt("doDbID");
results.close();
results=null;
// Get all disseminators that are in db for this object
HashSet dissDbIds = new HashSet();
results=logAndExecuteQuery(st, "SELECT dissDbID"
+ " FROM doDissAssoc"
+ " WHERE doDbID=" + doDbID);
while (results.next()) {
Integer id = new Integer(results.getInt("dissDbID"));
dissDbIds.add(id);
}
results.close();
results=null;
LOG.debug("Found " + dissDbIds.size() + "dissDbId(s). ");
// Get all binding maps that are in db for this object
HashSet dsBindMapIds = new HashSet();
results=logAndExecuteQuery(st, "SELECT DISTINCT dsBindMapDbID "
+ " FROM dsBind WHERE doDbID=" + doDbID);
while (results.next()) {
dsBindMapIds.add(results.getInt("dsBindMapDbID"));
}
results.close();
results=null;
LOG.debug("Found "
+ dsBindMapIds.size() + "dsBindMapDbId(s). ");
// Now get all existing disseminators that are in xml object for this object
Disseminator[] dissArray = reader.GetDisseminators(null, null);
HashSet existingDisseminators = new HashSet();
HashSet purgedDisseminators = new HashSet();
for (int j=0; j< dissArray.length; j++)
{
// Find disseminators that have been removed within an existing object
// (disseminator(s) still exist in the database)
results=logAndExecuteQuery(st, "SELECT diss.dissDbID"
+ " FROM doDissAssoc, diss"
+ " WHERE doDissAssoc.doDbID=" + doDbID + " AND diss.dissID='" + dissArray[j].dissID + "'"
+ " AND doDissAssoc.dissDbID=diss.dissDbID");
if (!results.next()) {
// No disseminator was found in db so it must be new one
// indicating an instance of AddNewComponents rather than purgeComponents
LOG.debug("Disseminator not found in db; Assuming this is case of AddNewComponents");
return false;
} else {
Integer id = new Integer(results.getInt("dissDbID"));
existingDisseminators.add(id);
LOG.debug("Adding "
+ " dissDbId: " + id + " to list of Existing dissDbId(s). ");
}
results.close();
results=null;
}
LOG.debug("Found "
+ existingDisseminators.size() + " existing dissDbId(s). ");
// Now get all existing dsbindmapids that are in xml object for this object
HashSet existingDsBindMapIds = new HashSet();
HashSet purgedDsBindMapIds = new HashSet();
for (int j=0; j< dissArray.length; j++)
{
// Find disseminators that have been removed within an existing object
// (disseminator(s) still exist in the database)
results=logAndExecuteQuery(st, "SELECT dsBindMapDbID, dsBindMapID"
+ " FROM dsBindMap,bMech,diss"
+ " WHERE dsBindMap.bMechDbID=bMech.bMechDbID AND bMech.bMechPID='" + dissArray[j].bMechID + "' "
+ " AND diss.dissID='" + dissArray[j].dissID + "' AND dsBindMapID='" + dissArray[j].dsBindMapID + "'");
if (!results.next()) {
// No disseminator was found in db so it must be new one
// indicating an instance of AddNewComponents rather than purgeComponents
LOG.debug("Disseminator not found in db; Assuming this is case of AddNewComponents");
return false;
} else {
Integer dsBindMapDbId = new Integer(results.getInt("dsBindMapDbID"));
existingDsBindMapIds.add(dsBindMapDbId);
LOG.debug("Adding "
+ " dsBindMapDbId: " + dsBindMapDbId + " to list of Existing dsBindMapDbId(s). ");
}
results.close();
results=null;
}
LOG.debug("Found "
+ existingDsBindMapIds.size() + " existing dsBindMapDbId(s). ");
// Compare what's in db with what's in xml object
Iterator dissDbIdIter = dissDbIds.iterator();
Iterator existingDissIter = existingDisseminators.iterator();
while (dissDbIdIter.hasNext()) {
Integer dissDbId = (Integer) dissDbIdIter.next();
if (existingDisseminators.contains(dissDbId)) {
// database disseminator exists in xml object
// so ignore
} else {
// database disseminator does not exist in xml object
// so remove it from database
purgedDisseminators.add(dissDbId);
LOG.debug("Adding "
+ " dissDbId: " + dissDbId + " to list of Purged dissDbId(s). ");
}
}
if (purgedDisseminators.isEmpty()) {
// no disseminators were removed so this must be an
// an instance of addComponent or updateComponent
LOG.debug("No disseminators have been removed from object;"
+ " Assuming this a case of UpdateComponents");
return false;
}
// Compare what's in db with what's in xml object
Iterator dsBindMapIdIter = dsBindMapIds.iterator();
Iterator existingDsBindMapIdIter = existingDsBindMapIds.iterator();
while (dsBindMapIdIter.hasNext()) {
Integer dsBindMapDbId = (Integer) dsBindMapIdIter.next();
if (existingDsBindMapIds.contains(dsBindMapDbId)) {
// database disseminator exists in xml object
// so ignore
} else {
// database disseminator does not exist in xml object
// so remove it from database
purgedDsBindMapIds.add(dsBindMapDbId);
LOG.debug("Adding "
+ " dsBindMapDbId: " + dsBindMapDbId + " to list of Purged dsBindMapDbId(s). ");
}
}
if (purgedDsBindMapIds.isEmpty()) {
// no disseminators were removed so this must be an
// an instance of addComponent or updateComponent
LOG.debug("No disseminators have been removed from object;"
+ " Assuming this a case of UpdateComponents");
return false;
}
purgeDisseminators(doPID, purgedDisseminators, purgedDsBindMapIds, reader, connection);
connection.commit();
} catch (SQLException sqle) {
failed=true;
throw new ReplicationException("An error has occurred during "
+ "Replication. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage());
} catch (ServerException se) {
failed=true;
throw new ReplicationException("An error has occurred during "
+ "Replication. The error was \" " + se.getClass().getName()
+ " \". The cause was \" " + se.getMessage());
} finally {
// TODO: make sure this makes sense here
if (connection!=null) {
try {
if (failed) connection.rollback();
} catch (Throwable th) {
LOG.warn("Error while rolling back", th);
} finally {
try {
if (results != null) results.close();
if (st!=null) st.close();
connection.setAutoCommit(true);
if (connection!=null) m_pool.free(connection);
} catch (SQLException sqle) {
LOG.warn("Error while cleaning up", sqle);
} finally {
results=null;
st=null;
}
}
}
}
LOG.debug("Exiting purgeComponents");
return true;
}
/**
* If the object has already been replicated, update the components
* and return true. Otherwise, return false.
*
* Currently bdef components cannot be updated, so this will
* simply return true if the bDef has already been replicated.
*
* @param reader a behavior definitionobject reader.
* @return true if bdef update successful; false otherwise.
* @throws ReplicationException if replication fails for any reason.
*/
private boolean updateComponents(BDefReader reader)
throws ReplicationException {
Connection connection=null;
Statement st=null;
ResultSet results=null;
boolean triedUpdate=false;
boolean failed=false;
LOG.debug("Entering updateComponents");
try {
connection=m_pool.getConnection();
st=connection.createStatement();
results=logAndExecuteQuery(st, "SELECT bDefDbID,bDefState FROM bDef WHERE "
+ "bDefPID='" + reader.GetObjectPID() + "'");
if (!results.next()) {
LOG.debug("Object is "
+ "new; components dont need updating.");
return false;
}
int bDefDbID=results.getInt("bDefDbID");
String bDefState=results.getString("bDefState");
results.close();
results=null;
ArrayList updates=new ArrayList();
// check if state has changed for the bdef object
String objState = reader.GetObjectState();
if (!bDefState.equalsIgnoreCase(objState)) {
updates.add("UPDATE bDef SET bDefState='"+objState+"' WHERE bDefDbID=" + bDefDbID);
updates.add("UPDATE doRegistry SET objectState='"+objState+"' WHERE doPID='" + reader.GetObjectPID() + "'");
}
// do any required updates via a transaction
if (updates.size()>0) {
connection.setAutoCommit(false);
triedUpdate=true;
for (int i=0; i updates=new ArrayList();
// check if state has changed for the bdef object
String objState = reader.GetObjectState();
if (!bMechState.equalsIgnoreCase(objState)) {
updates.add("UPDATE bMech SET bMechState='"+objState+"' WHERE bMechDbID=" + bMechDbID);
updates.add("UPDATE doRegistry SET objectState='"+objState+"' WHERE doPID='" + reader.GetObjectPID() + "'");
}
// do any required updates via a transaction
if (updates.size()>0) {
connection.setAutoCommit(false);
triedUpdate=true;
for (int i=0; i 0)
{
for (int k=0; k 0)
{
for (int k=0; kx=y1 or x=y2 or x=y3...etc, where x is the value from the
* column, and y1 is composed of the integer values from the given set.
*
* If the set doesn't contain any items, returns a condition that
* always evaluates to false, 1=2.
*
* @param column value of the column.
* @param integers set of integers.
* @return string suitable for SQL WHERE clause.
*/
private String inIntegerSetWhereConditionString(String column,
Set integers) {
StringBuffer out=new StringBuffer();
Iterator iter=integers.iterator();
int n=0;
while (iter.hasNext()) {
if (n>0) {
out.append(" OR ");
}
out.append(column);
out.append('=');
int i=((Integer) iter.next()).intValue();
out.append(i);
n++;
}
if (n>0) {
return out.toString();
} else {
return "1=2";
}
}
/**
* Deletes all rows pertinent to the given behavior definition object,
* if they exist.
*
* Pseudocode:
*
* $bDefDbID=SELECT bDefDbID FROM bDef WHERE bDefPID=$PID
* DELETE FROM bDef,method,parm
* WHERE bDefDbID=$bDefDbID
*
*
* @param connection a database connection.
* @param pid the idenitifer of a digital object.
* @throws SQLException If something totally unexpected happened.
*/
private void deleteBehaviorDefinition(Connection connection, String pid)
throws SQLException {
LOG.debug("Entered deleteBehaviorDefinition");
Statement st=null;
ResultSet results=null;
try {
st=connection.createStatement();
//
// READ
//
LOG.debug("Checking BehaviorDefinition table for " + pid + "...");
results=logAndExecuteQuery(st, "SELECT bDefDbID FROM "
+ "bDef WHERE bDefPID='" + pid + "'");
if (!results.next()) {
// must not be a bdef...exit early
LOG.debug(pid + " wasn't found in BehaviorDefinition table..."
+ "skipping deletion as such.");
return;
}
int dbid=results.getInt("bDefDbID");
LOG.debug(pid + " was found in BehaviorDefinition table (DBID="
+ dbid + ")");
//
// WRITE
//
int rowCount;
LOG.debug("Attempting row deletion from BehaviorDefinition "
+ "table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM bDef "
+ "WHERE bDefDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from method table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM method WHERE "
+ "bDefDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from parm table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM parm WHERE "
+ "bDefDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
} finally {
try {
if (results != null) results.close();
if (st!=null) st.close();
} catch (SQLException sqle) {
} finally {
results=null;
st=null;
LOG.debug("Exiting deleteBehaviorDefinition");
}
}
}
/**
* Deletes all rows pertinent to the given behavior mechanism object,
* if they exist.
*
* Pseudocode:
*
* $bMechDbID=SELECT bMechDbID
* FROM bMech WHERE bMechPID=$PID
* bMech
* @BKEYIDS=SELECT dsBindKeyDbID
* FROM dsBindSpec
* WHERE bMechDbID=$bMechDbID
* dsMIME WHERE dsBindKeyDbID in @BKEYIDS
* mechImpl
*
*
* @param connection a database connection.
* @param pid the identifier of a digital object.
* @throws SQLException If something totally unexpected happened.
*/
private void deleteBehaviorMechanism(Connection connection, String pid)
throws SQLException {
LOG.debug("Entering deleteBehaviorMechanism");
Statement st=null;
ResultSet results=null;
try {
st=connection.createStatement();
//
// READ
//
LOG.debug("Checking bMech table for " + pid + "...");
//results=logAndExecuteQuery(st, "SELECT bMechDbID, SMType_DBID "
results=logAndExecuteQuery(st, "SELECT bMechDbID "
+ "FROM bMech WHERE bMechPID='" + pid + "'");
if (!results.next()) {
// must not be a bmech...exit early
LOG.debug(pid + " wasn't found in bMech table..."
+ "skipping deletion as such.");
return;
}
int dbid=results.getInt("bMechDbID");
//int smtype_dbid=results.getInt("bMechDbID");
results.close();
results=null;
LOG.debug(pid + " was found in bMech table (DBID="
// + dbid + ", SMTYPE_DBID=" + smtype_dbid + ")");
+ dbid);
LOG.debug("Getting dsBindKeyDbID(s) from dsBindSpec "
+ "table...");
HashSet dsBindingKeyIds=new HashSet();
results=logAndExecuteQuery(st, "SELECT dsBindKeyDbID from "
+ "dsBindSpec WHERE bMechDbID=" + dbid);
while (results.next()) {
dsBindingKeyIds.add(results.getInt("dsBindKeyDbID"));
}
results.close();
results=null;
LOG.debug("Found " + dsBindingKeyIds.size()
+ " dsBindKeyDbID(s).");
//
// WRITE
//
int rowCount;
LOG.debug("Attempting row deletion from bMech table..");
rowCount=logAndExecuteUpdate(st, "DELETE FROM bMech "
+ "WHERE bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from dsBindSpec "
+ "table...");
LOG.debug("Attempting row deletion from dsBindSpec table..");
rowCount=logAndExecuteUpdate(st, "DELETE FROM "
+ "dsBindSpec WHERE bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from dsMIME table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM dsMIME WHERE "
+ inIntegerSetWhereConditionString("dsBindKeyDbID",
dsBindingKeyIds));
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from dsBindMap table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM dsBindMap WHERE "
+ "bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from diss table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM diss WHERE "
+ "bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from mechImpl table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM mechImpl WHERE "
+ "bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
LOG.debug("Attempting row deletion from mechDefParm table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM mechDefParm "
+ "WHERE bMechDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s).");
} finally {
try {
if (results != null) results.close();
if (st!=null)st.close();
} catch (SQLException sqle) {
} finally {
results=null;
st=null;
LOG.debug("Exiting deleteBehaviorMechanism");
}
}
}
/**
* Deletes all rows pertinent to the given digital object (treated as a
* data object) if they exist.
*
* Pseudocode:
*
* $doDbID=SELECT doDbID FROM dobj where doPID=$PID
* @DISSIDS=SELECT dissDbID
* FROM doDissAssoc WHERE doDbID=$doDbID
* @BMAPIDS=SELECT dsBindMapDbID
* FROM dsBind WHERE doDbID=$doDbID
* do
* doDissAssoc where $doDbID=doDbID
* dsBind WHERE $doDbID=doDbID
* diss WHERE dissDbID in @DISSIDS
* dsBindMap WHERE dsBindMapDbID in @BMAPIDS
*
*
* @param connection a databae connection.
* @param pid the identifier for a digital object.
* @throws SQLException If something totally unexpected happened.
*/
private void deleteDigitalObject(Connection connection, String pid)
throws SQLException {
LOG.debug("Entering deleteDigitalObject");
Statement st=null;
Statement st2=null;
Statement st3=null;
ResultSet results=null;
try {
st=connection.createStatement();
//
// READ
//
LOG.debug("Checking dobj table for " + pid + "...");
results=logAndExecuteQuery(st, "SELECT doDbID FROM "
+ "dobj WHERE doPID='" + pid + "'");
if (!results.next()) {
// must not be a digitalobject...exit early
LOG.debug(pid + " wasn't found in dobj table..."
+ "skipping deletion as such.");
return;
}
int dbid=results.getInt("doDbID");
results.close();
results=null;
LOG.debug(pid + " was found in dobj table (DBID=" + dbid + ")");
//
// WRITE
//
int rowCount;
LOG.debug("Attempting row deletion from dobj table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM dobj "
+ "WHERE doDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s) from do.");
LOG.debug("Attempting row deletion from doDissAssoc "
+ "table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM "
+ "doDissAssoc WHERE doDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s) from doDissAssoc.");
LOG.debug("Attempting row deletion from dsBind table..");
rowCount=logAndExecuteUpdate(st, "DELETE FROM dsBind "
+ "WHERE doDbID=" + dbid);
LOG.debug("Deleted " + rowCount + " row(s) from dsBind.");
// Leave any orphaned diss rows -- they'll be cleaned up if the bMech is removed
// Leave any orphaned dsBindMap rows -- they'll be cleaned up if the bMech is removed
} finally {
try {
if (results != null) results.close();
if (st!=null) st.close();
if (st2!=null) st2.close();
} catch (SQLException sqle) {
} finally {
results=null;
st=null;
st2=null;
LOG.debug("Exiting deleteDigitalObject");
}
}
}
/**
* Removes a digital object from the dissemination database.
*
* If the object is a behavior definition or mechanism, it's deleted
* as such, and then an attempt is made to delete it as a data object
* as well.
*
* Note that this does not do cascading check object dependencies at
* all. It is expected at this point that when this is called, any
* referencial integrity issues have been ironed out or checked as
* appropriate.
*
* All deletions happen in a transaction. If any database errors occur,
* the change is rolled back.
*
* @param pid The pid of the object to delete.
* @throws ReplicationException If the request couldn't be fulfilled for
* any reason.
*/
public void delete(String pid)
throws ReplicationException {
LOG.debug("Entering delete(" + pid + ")");
Connection connection=null;
try {
connection = m_pool.getConnection();
connection.setAutoCommit(false);
deleteBehaviorDefinition(connection, pid);
deleteBehaviorMechanism(connection, pid);
deleteDigitalObject(connection, pid);
connection.commit();
} catch (SQLException sqle) {
throw new ReplicationException("Error while replicator was trying "
+ "to delete " + pid + ". " + sqle.getMessage());
} finally {
if (connection!=null) {
try {
connection.rollback();
connection.setAutoCommit(true);
m_pool.free(connection);
} catch (SQLException sqle) {}
}
LOG.debug("Exiting delete");
}
}
/**
*
* Inserts a Behavior Definition row.
*
* @param connection JDBC DBMS connection
* @param bDefPID Behavior definition PID
* @param bDefLabel Behavior definition label
* @param bDefState State of behavior definition object.
*
* @exception SQLException JDBC, SQL error
*/
public void insertBehaviorDefinitionRow(Connection connection, String bDefPID, String bDefLabel, String bDefState) throws SQLException {
String insertionStatement = "INSERT INTO bDef (bDefPID, bDefLabel, bDefState) VALUES ('" + bDefPID + "', '" + SQLUtility.aposEscape(bDefLabel) + "', '" + bDefState + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a Behavior Mechanism row.
*
* @param connection JDBC DBMS connection
* @param bDefDbID Behavior definition DBID
* @param bMechPID Behavior mechanism DBID
* @param bMechLabel Behavior mechanism label
* @param bMechState Statye of behavior mechanism object.
*
* @throws SQLException JDBC, SQL error
*/
public void insertBehaviorMechanismRow(Connection connection, String bDefDbID, String bMechPID, String bMechLabel, String bMechState) throws SQLException {
String insertionStatement = "INSERT INTO bMech (bDefDbID, bMechPID, bMechLabel, bMechState) VALUES ('" + bDefDbID + "', '" + bMechPID + "', '" + SQLUtility.aposEscape(bMechLabel) + "', '" + bMechState + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a DataStreamBindingRow row.
*
* @param connection JDBC DBMS connection
* @param doDbID Digital object DBID
* @param dsBindKeyDbID Datastream binding key DBID
* @param dsBindMapDbID Binding map DBID
* @param dsBindKeySeq Datastream binding key sequence number
* @param dsID Datastream ID
* @param dsLabel Datastream label
* @param dsMIME Datastream mime type
* @param dsLocation Datastream location
* @param dsControlGroupType Datastream type
* @param dsCurrentVersionID Datastream current version ID
* @param policyDbID Policy DBID
* @param dsState State of datastream.
*
* @exception SQLException JDBC, SQL error
*/
public void insertDataStreamBindingRow(Connection connection, String doDbID, String dsBindKeyDbID, String dsBindMapDbID, String dsBindKeySeq, String dsID, String dsLabel, String dsMIME, String dsLocation, String dsControlGroupType, String dsCurrentVersionID, String policyDbID, String dsState) throws SQLException {
if (dsBindKeySeq == null || dsBindKeySeq.equals("")) dsBindKeySeq = "0";
String insertionStatement = "INSERT INTO dsBind (doDbID, dsBindKeyDbID, dsBindMapDbID, dsBindKeySeq, dsID, dsLabel, dsMIME, dsLocation, dsControlGroupType, dsCurrentVersionID, policyDbID, dsState) VALUES ('" + doDbID + "', '" + dsBindKeyDbID + "', '" + dsBindMapDbID + "', '" + dsBindKeySeq + "', '" + dsID + "', '" + SQLUtility.aposEscape(dsLabel) + "', '" + dsMIME + "', '" + SQLUtility.aposEscape(dsLocation) + "', '" + dsControlGroupType + "', '" + dsCurrentVersionID + "', '" + policyDbID + "', '" + dsState + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a dsBindMap row.
*
* @param connection JDBC DBMS connection
* @param bMechDbID Behavior mechanism DBID
* @param dsBindMapID Datastream binding map ID
* @param dsBindMapLabel Datastream binding map label
*
* @exception SQLException JDBC, SQL error
*/
public void insertDataStreamBindingMapRow(Connection connection, String bMechDbID, String dsBindMapID, String dsBindMapLabel) throws SQLException {
String insertionStatement = "INSERT INTO dsBindMap (bMechDbID, dsBindMapID, dsBindMapLabel) VALUES ('" + bMechDbID + "', '" + dsBindMapID + "', '" + SQLUtility.aposEscape(dsBindMapLabel) + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a dsBindSpec row.
*
* @param connection JDBC DBMS connection
* @param bMechDbID Behavior mechanism DBID
* @param dsBindSpecName Datastream binding spec name
* @param dsBindSpecOrdinality Datastream binding spec ordinality flag
* @param dsBindSpecCardinality Datastream binding cardinality
* @param dsBindSpecLabel Datastream binding spec lable
*
* @exception SQLException JDBC, SQL error
*/
public void insertDataStreamBindingSpecRow(Connection connection, String bMechDbID, String dsBindSpecName, String dsBindSpecOrdinality, String dsBindSpecCardinality, String dsBindSpecLabel) throws SQLException {
String insertionStatement = "INSERT INTO dsBindSpec (bMechDbID, dsBindSpecName, dsBindSpecOrdinality, dsBindSpecCardinality, dsBindSpecLabel) VALUES ('" + bMechDbID + "', '" + SQLUtility.aposEscape(dsBindSpecName) + "', '" + dsBindSpecOrdinality + "', '" + dsBindSpecCardinality + "', '" + SQLUtility.aposEscape(dsBindSpecLabel) + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a dsMIME row.
*
* @param connection JDBC DBMS connection
* @param dsBindKeyDbID Datastream binding key DBID
* @param dsMIMEName Datastream MIME type name
*
* @exception SQLException JDBC, SQL error
*/
public void insertDataStreamMIMERow(Connection connection, String dsBindKeyDbID, String dsMIMEName) throws SQLException {
String insertionStatement = "INSERT INTO dsMIME (dsBindKeyDbID, dsMIMEName) VALUES ('" + dsBindKeyDbID + "', '" + dsMIMEName + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a do row.
*
* @param connection JDBC DBMS connection
* @param doPID DigitalObject PID
* @param doLabel DigitalObject label
* @param doState State of digital object.
*
* @exception SQLException JDBC, SQL error
*/
public void insertDigitalObjectRow(Connection connection, String doPID, String doLabel, String doState) throws SQLException {
String insertionStatement = "INSERT INTO dobj (doPID, doLabel, doState) VALUES ('" + doPID + "', '" + SQLUtility.aposEscape(doLabel) + "', '" + doState + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a doDissAssoc row.
*
* @param connection JDBC DBMS connection
* @param doDbID DigitalObject DBID
* @param dissDbID Disseminator DBID
*
* @exception SQLException JDBC, SQL error
*/
public void insertDigitalObjectDissAssocRow(Connection connection, String doDbID, String dissDbID) throws SQLException {
String insertionStatement = "INSERT INTO doDissAssoc (doDbID, dissDbID) VALUES ('" + doDbID + "', '" + dissDbID + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a Disseminator row.
*
* @param connection JDBC DBMS connection
* @param bDefDbID Behavior definition DBID
* @param bMechDbID Behavior mechanism DBID
* @param dissID Disseminator ID
* @param dissLabel Disseminator label
* @param dissState State of disseminator.
*
* @exception SQLException JDBC, SQL error
*/
public void insertDisseminatorRow(Connection connection, String bDefDbID, String bMechDbID, String dissID, String dissLabel, String dissState) throws SQLException {
String insertionStatement = "INSERT INTO diss (bDefDbID, bMechDbID, dissID, dissLabel, dissState) VALUES ('" + bDefDbID + "', '" + bMechDbID + "', '" + dissID + "', '" + SQLUtility.aposEscape(dissLabel) + "', '" + dissState + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a mechImpl row.
*
* @param connection JDBC DBMS connection
* @param bMechDbID Behavior mechanism DBID
* @param bDefDbID Behavior definition DBID
* @param methodDbID Method DBID
* @param dsBindKeyDbID Datastream binding key DBID
* @param protocolType Mechanism implementation protocol type
* @param returnType Mechanism implementation return type
* @param addressLocation Mechanism implementation address location
* @param operationLocation Mechanism implementation operation location
* @param policyDbID Policy DBID
*
* @exception SQLException JDBC, SQL error
*/
public void insertMechanismImplRow(Connection connection, String bMechDbID, String bDefDbID, String methodDbID, String dsBindKeyDbID, String protocolType, String returnType, String addressLocation, String operationLocation, String policyDbID) throws SQLException {
String insertionStatement = "INSERT INTO mechImpl (bMechDbID, bDefDbID, methodDbID, dsBindKeyDbID, protocolType, returnType, addressLocation, operationLocation, policyDbID) VALUES ('" + bMechDbID + "', '" + bDefDbID + "', '" + methodDbID + "', '" + dsBindKeyDbID + "', '" + protocolType + "', '" + returnType + "', '" + addressLocation + "', '" + operationLocation + "', '" + policyDbID + "')";
insertGen(connection, insertionStatement);
}
/**
*
* Inserts a method row.
*
* @param connection JDBC DBMS connection
* @param bDefDbID Behavior definition DBID
* @param methodName Behavior definition label
* @param methodLabel Behavior definition label
*
* @exception SQLException JDBC, SQL error
*/
public void insertMethodRow(Connection connection, String bDefDbID, String methodName, String methodLabel) throws SQLException {
String insertionStatement = "INSERT INTO method (bDefDbID, methodName, methodLabel) VALUES ('" + bDefDbID + "', '" + SQLUtility.aposEscape(methodName) + "', '" + SQLUtility.aposEscape(methodLabel) + "')";
insertGen(connection, insertionStatement);
}
/**
*
* @param connection An SQL Connection.
* @param methDBID The method database ID.
* @param bdefDBID The behavior Definition object database ID.
* @param parmName the parameter name.
* @param parmDefaultValue A default value for the parameter.
* @param parmDomainValues A list of possible values for the parameter.
* @param parmRequiredFlag A boolean flag indicating whether the
* parameter is required or not.
* @param parmLabel The parameter label.
* @param parmType The parameter type.
* @throws SQLException JDBC, SQL error
*/
public void insertMethodParmRow(Connection connection, String methDBID,
String bdefDBID, String parmName, String parmDefaultValue,
String parmDomainValues, String parmRequiredFlag,
String parmLabel, String parmType)
throws SQLException {
String insertionStatement = "INSERT INTO parm "
+ "(methodDbID, bDefDbID, parmName, parmDefaultValue, "
+ "parmDomainValues, parmRequiredFlag, parmLabel, "
+ "parmType) VALUES ('"
+ methDBID + "', '" + bdefDBID + "', '"
+ SQLUtility.aposEscape(parmName) + "', '" + SQLUtility.aposEscape(parmDefaultValue) + "', '"
+ SQLUtility.aposEscape(parmDomainValues) + "', '"
+ parmRequiredFlag + "', '" + SQLUtility.aposEscape(parmLabel) + "', '"
+ parmType + "')";
insertGen(connection, insertionStatement);
}
/**
*
* @param connection An SQL Connection.
* @param methDBID The method database ID.
* @param bmechDBID The behavior Mechanism object database ID.
* @param parmName the parameter name.
* @param parmDefaultValue A default value for the parameter.
* @param parmRequiredFlag A boolean flag indicating whether the
* parameter is required or not.
* @param parmDomainValues A list of possible values for the parameter.
* @param parmLabel The parameter label.
* @param parmType The parameter type.
* @throws SQLException JDBC, SQL error
*/
public void insertMechDefaultMethodParmRow(Connection connection, String methDBID,
String bmechDBID, String parmName, String parmDefaultValue,
String parmDomainValues, String parmRequiredFlag,
String parmLabel, String parmType)
throws SQLException {
String insertionStatement = "INSERT INTO mechDefParm "
+ "(methodDbID, bMechDbID, defParmName, defParmDefaultValue, "
+ "defParmDomainValues, defParmRequiredFlag, defParmLabel, "
+ "defParmType) VALUES ('"
+ methDBID + "', '" + bmechDBID + "', '"
+ SQLUtility.aposEscape(parmName) + "', '" + SQLUtility.aposEscape(parmDefaultValue) + "', '"
+ SQLUtility.aposEscape(parmDomainValues) + "', '"
+ parmRequiredFlag + "', '" + SQLUtility.aposEscape(parmLabel) + "', '"
+ parmType + "')";
insertGen(connection, insertionStatement);
}
/**
*
* General JDBC row insertion method.
*
* @param connection JDBC DBMS connection
* @param insertionStatement SQL row insertion statement
*
* @exception SQLException JDBC, SQL error
*/
public void insertGen(Connection connection, String insertionStatement) throws SQLException {
int rowCount = 0;
Statement statement = null;
statement = connection.createStatement();
LOG.debug("Doing DB Insert: " + insertionStatement);
rowCount = statement.executeUpdate(insertionStatement);
statement.close();
statement=null;
}
/**
*
* Looks up a BehaviorDefinition DBID.
*
* @param connection JDBC DBMS connection
* @param bDefPID Behavior definition PID
*
* @return The DBID of the specified Behavior Definition row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupBehaviorDefinitionDBID(Connection connection, String bDefPID) throws StorageDeviceException {
return lookupDBID1(connection, "bDefDbID", "bDef", "bDefPID", bDefPID);
}
/**
*
* Looks up a BehaviorMechanism DBID.
*
* @param connection JDBC DBMS connection
* @param bMechPID Behavior mechanism PID
*
* @return The DBID of the specified Behavior Mechanism row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupBehaviorMechanismDBID(Connection connection, String bMechPID) throws StorageDeviceException {
return lookupDBID1(connection, "bMechDbID", "bMech", "bMechPID", bMechPID);
}
/**
*
* Looks up a dsBindMap DBID.
*
* @param connection JDBC DBMS connection
* @param bMechDBID Behavior mechanism DBID
* @param dsBindingMapID Data stream binding map ID
*
* @return The DBID of the specified dsBindMap row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDataStreamBindingMapDBID(Connection connection, String bMechDBID, String dsBindingMapID) throws StorageDeviceException {
return lookupDBID2FirstNum(connection, "dsBindMapDbID", "dsBindMap", "bMechDbID", bMechDBID, "dsBindMapID", dsBindingMapID);
}
public String lookupDataStreamBinding(Connection connection, String doDbID, String dsBindKeyDbID, String dsBindMapDbID, String dsBindKeySeq, String dsID, String dsLocation, String dsState) throws StorageDeviceException {
return lookupDBID4(connection, "dsID", "dsBind",
"doDbID", doDbID,
"dsBindKeyDbID", dsBindKeyDbID,
"dsBindMapDbID", dsBindMapDbID,
"dsBindKeySeq", dsBindKeySeq,
"dsID", dsID,
"dsLocation", dsLocation,
"dsState", dsState);
}
//public String lookupDsBindingMapDBID(Connection connection, String bMechDBID, String dsBindingMapID) throws StorageDeviceException {
// return lookupDBID2FirstNum(connection, "dsBindMapDbID", "dsBindMap", "bMechDbID", bMechDBID, "dsBindMapID", dsBindingMapID);
//}
/**
*
* Looks up a dsBindSpec DBID.
*
* @param connection JDBC DBMS connection
* @param bMechDBID Behavior mechanism DBID
* @param dsBindingSpecName Data stream binding spec name
*
* @return The DBID of the specified dsBindSpec row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDataStreamBindingSpecDBID(Connection connection, String bMechDBID, String dsBindingSpecName) throws StorageDeviceException {
return lookupDBID2FirstNum(connection, "dsBindKeyDbID", "dsBindSpec", "bMechDbID", bMechDBID, "dsBindSpecName", dsBindingSpecName);
}
/**
*
* Looks up a do DBID.
*
* @param connection JDBC DBMS connection
* @param doPID Data object PID
*
* @return The DBID of the specified DigitalObject row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDigitalObjectDBID(Connection connection, String doPID) throws StorageDeviceException {
return lookupDBID1(connection, "doDbID", "dobj", "doPID", doPID);
}
/**
*
* Looks up a Disseminator DBID.
*
* @param connection JDBC DBMS connection
* @param bDefDBID Behavior definition DBID
* @param bMechDBID Behavior mechanism DBID
* @param dissID Disseminator ID
*
* @return The DBID of the specified Disseminator row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDisseminatorDBID(Connection connection, String bDefDBID, String bMechDBID, String dissID) throws StorageDeviceException {
Statement statement = null;
ResultSet rs = null;
String query = null;
String ID = null;
try
{
query = "SELECT dissDbID FROM diss WHERE ";
query += "bDefDbID = " + bDefDBID + " AND ";
query += "bMechDbID = " + bMechDBID + " AND ";
query += "dissID = '" + dissID + "'";
LOG.debug("Doing Query: " + query);
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next())
ID = rs.getString(1);
} catch (Throwable th)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + th.getClass().getName()
+ " \". The cause was \" " + th.getMessage() + " \"");
} finally
{
try
{
if (rs != null) rs.close();
if (statement != null) statement.close();
} catch (SQLException sqle)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage() + " \"");
} finally {
rs=null;
statement=null;
}
}
return ID;
}
/**
*
* Looks up a method DBID.
*
* @param connection JDBC DBMS connection
* @param bDefDBID Behavior definition DBID
* @param methName Method name
*
* @return The DBID of the specified method row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupMethodDBID(Connection connection, String bDefDBID, String methName) throws StorageDeviceException {
return lookupDBID2FirstNum(connection, "methodDbID", "method", "bDefDbID", bDefDBID, "methodName", methName);
}
/**
*
* General JDBC lookup method with 1 lookup column value.
*
* @param connection JDBC DBMS connection
* @param DBIDName DBID column name
* @param tableName Table name
* @param lookupColumnName Lookup column name
* @param lookupColumnValue Lookup column value
*
* @return The DBID of the specified row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDBID1(Connection connection, String DBIDName, String tableName, String lookupColumnName, String lookupColumnValue) throws StorageDeviceException {
String query = null;
String ID = null;
Statement statement = null;
ResultSet rs = null;
try
{
query = "SELECT " + DBIDName + " FROM " + tableName + " WHERE ";
query += lookupColumnName + " = '" + lookupColumnValue + "'";
LOG.debug("Doing Query: " + query);
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next())
ID = rs.getString(1);
} catch (Throwable th)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + th.getClass().getName()
+ " \". The cause was \" " + th.getMessage() + " \"");
} finally
{
try
{
if (rs != null) rs.close();
if (statement != null) statement.close();
} catch (SQLException sqle)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage() + " \"");
} finally {
rs=null;
statement=null;
}
}
return ID;
}
/**
*
* General JDBC lookup method with 2 lookup column values.
*
* @param connection JDBC DBMS connection
* @param DBIDName DBID Column name
* @param tableName Table name
* @param lookupColumnName1 First lookup column name
* @param lookupColumnValue1 First lookup column value
* @param lookupColumnName2 Second lookup column name
* @param lookupColumnValue2 Second lookup column value
*
* @return The DBID of the specified row.
*
* @throws StorageDeviceException if db lookup fails for any reason.
*/
public String lookupDBID2(Connection connection, String DBIDName, String tableName, String lookupColumnName1, String lookupColumnValue1, String lookupColumnName2, String lookupColumnValue2) throws StorageDeviceException {
String query = null;
String ID = null;
Statement statement = null;
ResultSet rs = null;
try
{
query = "SELECT " + DBIDName + " FROM " + tableName + " WHERE ";
query += lookupColumnName1 + " = '" + lookupColumnValue1 + "' AND ";
query += lookupColumnName2 + " = '" + lookupColumnValue2 + "'";
LOG.debug("Doing Query: " + query);
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next())
ID = rs.getString(1);
} catch (Throwable th)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + th.getClass().getName()
+ " \". The cause was \" " + th.getMessage() + " \"");
} finally
{
try
{
if (rs != null) rs.close();
if (statement != null) statement.close();
} catch (SQLException sqle)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage() + " \"");
} finally {
rs=null;
statement=null;
}
}
return ID;
}
public String lookupDBID4(Connection connection, String DBIDName, String tableName,
String lookupColumnName1, String lookupColumnValue1,
String lookupColumnName2, String lookupColumnValue2,
String lookupColumnName3, String lookupColumnValue3,
String lookupColumnName4, String lookupColumnValue4,
String lookupColumnName5, String lookupColumnValue5,
String lookupColumnName6, String lookupColumnValue6,
String lookupColumnName7, String lookupColumnValue7) throws StorageDeviceException {
String query = null;
String ID = null;
Statement statement = null;
ResultSet rs = null;
try
{
query = "SELECT " + DBIDName + " FROM " + tableName + " WHERE ";
query += lookupColumnName1 + " =" + lookupColumnValue1 + " AND ";
query += lookupColumnName2 + " =" + lookupColumnValue2 + " AND ";
query += lookupColumnName3 + " =" + lookupColumnValue3 + " AND ";
query += lookupColumnName4 + " =" + lookupColumnValue4 + " AND ";
query += lookupColumnName5 + " ='" + lookupColumnValue5 + "' AND ";
query += lookupColumnName6 + " ='" + lookupColumnValue6 + "' AND ";
query += lookupColumnName7 + " ='" + lookupColumnValue7 + "'";
LOG.debug("Doing Query: " + query);
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next())
ID = rs.getString(1);
} catch (Throwable th)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + th.getClass().getName()
+ " \". The cause was \" " + th.getMessage() + " \"");
} finally
{
try
{
if (rs != null) rs.close();
if (statement != null) statement.close();
} catch (SQLException sqle)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage() + " \"");
} finally {
rs=null;
statement=null;
}
}
return ID;
}
public String lookupDBID2FirstNum(Connection connection, String DBIDName, String tableName, String lookupColumnName1, String lookupColumnValue1, String lookupColumnName2, String lookupColumnValue2) throws StorageDeviceException {
String query = null;
String ID = null;
Statement statement = null;
ResultSet rs = null;
try
{
query = "SELECT " + DBIDName + " FROM " + tableName + " WHERE ";
query += lookupColumnName1 + " =" + lookupColumnValue1 + " AND ";
query += lookupColumnName2 + " = '" + lookupColumnValue2 + "'";
LOG.debug("Doing Query: " + query);
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next())
ID = rs.getString(1);
} catch (Throwable th)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + th.getClass().getName()
+ " \". The cause was \" " + th.getMessage() + " \"");
} finally
{
try
{
if (rs != null) rs.close();
if (statement != null) statement.close();
} catch (SQLException sqle)
{
throw new StorageDeviceException("[DBIDLookup] An error has "
+ "occurred. The error was \" " + sqle.getClass().getName()
+ " \". The cause was \" " + sqle.getMessage() + " \"");
} finally {
rs=null;
statement=null;
}
}
return ID;
}
/**
* Make URLs that are relative to the local Fedora repository ABSOLUTE URLs.
* Look for all URLs that contain the special Fedora local URL syntax
* and replace instances of this string with the actual host:port configured for
* the repository. This ensures that all forms of relative repository URLs
* are converted to proper absolute URLs that reference the hostname:port of the
* local Fedora repository. Examples:
*
* "http://local.fedora.server/fedora/get/demo:1/DS1"
* is converted to
* "http://myrepo.com:8080/fedora/get/demo:1/DS1"
*
* "http://local.fedora.server/fedora/get/demo:1/bdef:1/getFoo?in="http://local.fedora.server/fedora/get/demo:2/DC"
* is converted to
* "http://myrepo.com:8080/fedora/get/demo:1/bdef:1/getFoo?in="http://myrepo.com:8080/fedora/get/demo:2/DC"
* @param input Input URL string to be converted.
* @return String with all relative repository URLs and Fedora local URLs
* converted to absolute URL syntax.
*/
private static String makeAbsoluteURLs(String input) {
String output=input;
// Make absolute URLs out of all instances of the Fedora local URL syntax ...
output=s_fedoraLocalPattern.matcher(output).replaceAll(s_hostInfo);
LOG.debug("makeAbsoluteURLs: input=" + input + ", output=" + output);
return output;
}
/**
* Detect all forms of URLs that point to the local Fedora repository and
* make sure they are encoded in the special Fedora local URL syntax
* (http://local.fedora.server/..."). Look for absolute URLs that have a
* host:port equal to the host:port currently configured for the Fedora
* repository and replace host:port with the special string. The special
* Fedora relative URL string provides a consistent unique string be easily
* searched for and either converted back to an absolute URL to the
* repository. Examples:
*
* "http://myrepo.com:8080/fedora/get/demo:1/DS1"
* is converted to
* "http://local.fedora.server/fedora/get/demo:1/DS1"
*
* "https://myrepo.com:8443/fedora/get/demo:1/bdef:1/getFoo?in="http://myrepo.com:8080/fedora/get/demo:2/DC"
* is converted to
* "http://local.fedora.server/fedora/get/demo:1/bdef:1/getFoo?in="http://local.fedora.server/fedora/get/demo:2/DC"
*
* "http://myrepo.com:8080/saxon..." (internal service in bMech WSDL)
* is converted to
* "http://local.fedora.server/saxon..."
* @param input Input URL string to be converted
* @return String with all forms of relative repository URLs converted to
* the Fedora local URL syntax.
*/
private static String makeFedoraLocalURLs(String input) {
String output=input;
// Detect any absolute URLs that reference the local
// repository and convert them to the Fedora LOCALIZATION URL syntax
// ("http://local.fedora.server/...")\
// convert URLs that begin with http along with host and port
// explicitly configured for the repository
output=s_servernamePort.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
output=s_localhostPort.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
// convert URLs that begin with https along with the host and port
// explicitly configured for the repository
output=s_servernamePortSSL.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
output=s_localhostPortSSL.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
if (m_serverOnPort80) {
// if the server is running on port 80, convert
// URLs that begin with "http://localhost/"
output=s_servername.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
output=s_localhost.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
}
if (m_serverOnRedirectPort443) {
// if the server is running on port 443, convert
// URLs that begin with "https://localhost/"
output=s_servernameSSL.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
output=s_localhostSSL.matcher(output).replaceAll(
s_fedoraLocalPattern.pattern());
}
LOG.debug("makeFedoraLocalURLs: input=" + input + ", output=" + output);
return output;
}
private void addDisseminators(String doPID, Disseminator[] disseminators, DOReader doReader, Connection connection)
throws ReplicationException, SQLException, ServerException
{
DSBindingMapAugmented[] allBindingMaps;
String bDefDBID;
String bindingMapDBID;
String bMechDBID;
String dissDBID;
String doDBID;
String doLabel;
String dsBindingKeyDBID;
int rc;
LOG.debug("Entering addDisseminators");
doDBID = lookupDigitalObjectDBID(connection, doPID);
for (int i=0; i Permanently removes a disseminator from the database incuding
* all associated datastream bindings and datastream binding maps.
* Associated entries are removed from the following db tables:
*
* - doDissAssoc - all entries matching pid of data object.
* - diss - all entries matching disseminator ID provided that no
* other objects depend on this disseminator.
* - dsBind - all entries matching pid of data object.
* - dsBindMap - all entries matching associated bMech object pid
* provided that no other objects depend on this binding map.
*
* @param pid Persistent identifier for the data object.
* @param dissIds Set of disseminator IDs to be removed.
* @param doReader An instance of DOReader.
* @param connection A database connection.
* @throws SQLException If something totally unexpected happened.
*/
private void purgeDisseminators(String pid, HashSet dissIds, HashSet bmapIds, DOReader doReader, Connection connection)
throws SQLException
{
LOG.debug("Entering purgeDisseminators");
Statement st=null;
Statement st2=null;
ResultSet results=null;
try {
st=connection.createStatement();
//
// READ
//
LOG.debug("Checking dobj table for " + pid + "...");
results=logAndExecuteQuery(st, "SELECT doDbID FROM "
+ "dobj WHERE doPID='" + pid + "'");
if (!results.next()) {
// must not be a digitalobject...exit early
LOG.debug(pid + " wasn't found in dobj table..."
+ "skipping deletion as such.");
return;
}
int dbid=results.getInt("doDbID");
results.close();
results=null;
LOG.debug(pid + " was found in dobj table (DBID="
+ dbid + ")");
//
// WRITE
//
int rowCount;
// In doDissAssoc table, we are removing rows specific to the
// doDbId, so remove all dissDbIds (both shared and nonShared).
LOG.debug("Attempting row deletion from doDissAssoc "
+ "table...");
rowCount=logAndExecuteUpdate(st, "DELETE FROM "
+ "doDissAssoc WHERE doDbID=" + dbid
+ " AND ( " + inIntegerSetWhereConditionString("dissDbID", dissIds) + " )");
LOG.debug("Deleted " + rowCount + " row(s). from doDissAssoc");
// In dsBind table, we are removing rows specific to the doDbID,
// so remove all dsBindMapIds (both shared and nonShared).
LOG.debug("Attempting row deletion from dsBind table..");
rowCount=logAndExecuteUpdate(st, "DELETE FROM dsBind "
+ "WHERE doDbID=" + dbid
+ " AND ( " + inIntegerSetWhereConditionString("dsBindMapDbID", bmapIds) + " )");
LOG.debug("Deleted " + rowCount + " row(s) from dsBind.");
// Leave any orphaned diss rows -- they'll be cleaned up if the bMech is removed
// Leave any orphaned dsBindMap rows -- they'll be cleaned up if the bMech is removed
} finally {
try {
if (results != null) results.close();
if (st!=null) st.close();
if (st2!=null) st2.close();
} catch (SQLException sqle) {
} finally {
results=null;
st=null;
st2=null;
LOG.debug("Exiting purgeDisseminators");
}
}
}
}