/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server.journal;
import org.fcrepo.server.Context;
import org.fcrepo.server.errors.InvalidStateException;
import org.fcrepo.server.errors.ModuleInitializationException;
import org.fcrepo.server.errors.ModuleShutdownException;
import org.fcrepo.server.errors.ServerException;
import org.fcrepo.server.journal.recoverylog.JournalRecoveryLog;
import org.fcrepo.server.management.ManagementDelegate;
import org.fcrepo.server.messaging.PName;
import org.fcrepo.server.storage.types.Datastream;
import org.fcrepo.server.storage.types.RelationshipTuple;
import org.fcrepo.server.storage.types.Validation;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import javax.ws.rs.core.StreamingOutput;
/**
* The JournalWorker class to use in recovery mode or in* following mode.
* <p>
* Create a <code>JournalConsumerThread</code> to process the journal. If any
* calls to Management methods come in from outside, reject them.
* </p>
*
* @author Jim Blake
*/
public class JournalConsumer
implements JournalWorker {
private final String role;
private final JournalConsumerThread consumerThread;
private final JournalReader reader;
private final JournalRecoveryLog recoveryLog;
private ManagementDelegate delegate;
/**
* Get the appropriate JournalReader and JournalRecoveryLog, based on the
* server parameters, and create a JournalConsumerThread that will process
* the journal entries, using that reader and that logger.
*/
public JournalConsumer(Map<String, String> parameters,
String role,
ServerInterface server)
throws ModuleInitializationException {
this.role = role;
recoveryLog = JournalRecoveryLog.getInstance(parameters, role, server);
reader =
JournalReader
.getInstance(parameters, role, recoveryLog, server);
consumerThread =
new JournalConsumerThread(parameters,
role,
server,
reader,
recoveryLog);
}
/**
* Get the ManagementDelegate module and pass it to the
* JournalConsumerThread, so it can start working.
*/
public void setManagementDelegate(ManagementDelegate delegate) {
this.delegate = delegate;
consumerThread.setManagementDelegate(delegate);
}
/**
* Tell the thread, the reader and the log to shut down.
*/
public void shutdown() throws ModuleShutdownException {
try {
consumerThread.shutdown();
reader.shutdown();
recoveryLog.shutdown("Server is shutting down.");
} catch (JournalException e) {
throw new ModuleShutdownException("Error closing journal reader.",
role,
e);
}
}
//
// -------------------------------------------------------------------------
//
// Reject outside calls to Management API methods that modify the
// repository.
//
// -------------------------------------------------------------------------
//
/**
* Reject API calls from outside while we are in recovery mode.
*/
public String ingest(Context context,
InputStream serialization,
String logMessage,
String format,
String encoding,
String pid) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date modifyObject(Context context,
String pid,
String state,
String label,
String ownerId,
String logMessage,
Date lastModifiedDate) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date purgeObject(Context context,
String pid,
String logMessage) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public String addDatastream(Context context,
String pid,
String dsID,
String[] altIDs,
String dsLabel,
boolean versionable,
String MIMEType,
String formatURI,
String location,
String controlGroup,
String dsState,
String checksumType,
String checksum,
String logMessage) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date modifyDatastreamByReference(Context context,
String pid,
String datastreamID,
String[] altIDs,
String dsLabel,
String mimeType,
String formatURI,
String dsLocation,
String checksumType,
String checksum,
String logMessage,
Date lastModifiedDate)
throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date modifyDatastreamByValue(Context context,
String pid,
String datastreamID,
String[] altIDs,
String dsLabel,
String mimeType,
String formatURI,
InputStream dsContent,
String checksumType,
String checksum,
String logMessage,
Date lastModifiedDate) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date[] purgeDatastream(Context context,
String pid,
String datastreamID,
Date startDT,
Date endDT,
String logMessage) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public String putTempStream(Context context, InputStream in)
throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date setDatastreamState(Context context,
String pid,
String dsID,
String dsState,
String logMessage) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date setDatastreamVersionable(Context context,
String pid,
String dsID,
boolean versionable,
String logMessage)
throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Date setDisseminatorState(Context context,
String pid,
String dsID,
String dsState,
String logMessage) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public String[] getNextPID(Context context, int numPIDs, String namespace)
throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public boolean addRelationship(Context context,
String pid,
String relationship,
String objURI,
boolean isLiteral,
String datatype) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public boolean purgeRelationship(Context context,
String pid,
String relationship,
String objURI,
boolean isLiteral,
String datatype) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
/**
* Reject API calls from outside while we are in recovery mode.
*/
public Validation validate(@PName("context") Context context, @PName("pid") String pid,
@PName("asOfDateTime") Date asOfDateTime) throws ServerException {
throw rejectCallsFromOutsideWhileInRecoveryMode();
}
//
// -------------------------------------------------------------------------
//
// Permit outside calls to Management API methods that do not modify the
// repository.
//
// -------------------------------------------------------------------------
//
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public String compareDatastreamChecksum(Context context,
String pid,
String dsID,
Date versionDate)
throws ServerException {
return delegate.compareDatastreamChecksum(context,
pid,
dsID,
versionDate);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public InputStream export(Context context,
String pid,
String format,
String exportContext,
String encoding) throws ServerException {
return delegate.export(context, pid, format, exportContext, encoding);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public StreamingOutput stream(Context context,
String pid,
String format,
String exportContext,
String encoding) throws ServerException {
return delegate.stream(context, pid, format, exportContext, encoding);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public InputStream getObjectXML(Context context, String pid, String encoding)
throws ServerException {
return delegate.getObjectXML(context, pid, encoding);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public Datastream getDatastream(Context context,
String pid,
String datastreamID,
Date asOfDateTime) throws ServerException {
return delegate.getDatastream(context, pid, datastreamID, asOfDateTime);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public Datastream[] getDatastreams(Context context,
String pid,
Date asOfDateTime,
String dsState) throws ServerException {
return delegate.getDatastreams(context, pid, asOfDateTime, dsState);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public Datastream[] getDatastreamHistory(Context context,
String pid,
String datastreamID)
throws ServerException {
return delegate.getDatastreamHistory(context, pid, datastreamID);
}
/**
* Read-only method: pass the call to the {@link ManagementDelegate}.
*/
public RelationshipTuple[] getRelationships(Context context,
String pid,
String relationship)
throws ServerException {
return delegate.getRelationships(context, pid, relationship);
}
/**
* Delegate to the ManagementDelegate. Note: Unlike other methods of the
* Management interface, this method is not exposed at the service level.
* Therefore, it is safe to forward the call to the delegate. It is also
* necessary because, in the course of fulfilling API-M requests that
* involve uploaded content, this method is invoked by internal server code.
*/
public InputStream getTempStream(String id) throws ServerException {
return delegate.getTempStream(id);
}
/**
* While the server is reading a Journal to recover its state, block any
* attempt to use the Management API.
*
* @throws ServerException
*/
private ServerException rejectCallsFromOutsideWhileInRecoveryMode() {
return new InvalidStateException("Server is in Journal Recovery mode.");
}
}