/* 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 fedora.server.journal.readerwriter.multicast.rmi;
import java.io.BufferedWriter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Date;
import java.util.Map;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javanet.staxutils.IndentingXMLEventWriter;
import fedora.server.journal.JournalException;
import fedora.server.journal.readerwriter.multicast.Transport;
import fedora.server.journal.readerwriter.multicast.TransportParent;
/**
* <p>
* RmiTransport.java
* </p>
* <p>
* Writes Journal files to an {@link RmiJournalReceiver}, either locally or on
* another machine. Requires parameters for the names of the receiving host and
* the receiving RMI service. Also accepts optional parameters for the RMI port
* number and the internal message buffer size.
* </p>
*
* @author jblake
* @version $Id: RmiTransport.java,v 1.3 2007/06/01 17:21:32 jblake Exp $
*/
public class RmiTransport
extends Transport {
public static final String PARAMETER_HOST_NAME = "hostName";
public static final String PARAMETER_PORT_NUMBER = "port";
public static final String PARAMETER_SERVICE_NAME = "service";
public static final String PARAMETER_BUFFER_SIZE = "bufferSize";
public static final int DEFAULT_PORT_NUMBER = 1099;
public static final int DEFAULT_BUFFER_SIZE = 100000;
private final int bufferSize;
private final RmiJournalReceiverInterface receiver;
private RmiTransportWriter writer;
private XMLEventWriter xmlWriter;
public RmiTransport(Map<String, String> parameters,
boolean crucial,
TransportParent parent)
throws JournalException {
super(parameters, crucial, parent);
String host = parseHost(parameters);
String port = parsePort(parameters);
String serviceName = parseServiceName(parameters);
bufferSize = parseBufferSize(parameters);
String serverName = "//" + host + ":" + port;
String nameString = serverName + "/" + serviceName;
try {
receiver = (RmiJournalReceiverInterface) Naming.lookup(nameString);
} catch (MalformedURLException e) {
throw new JournalException("Problem finding RMI registry", e);
} catch (RemoteException e) {
throw new JournalException("Problem contacting RMI registry", e);
} catch (NotBoundException e) {
throw new JournalException("'" + serviceName
+ "' not registered at '" + serverName + "'", e);
}
}
private String parseHost(Map<String, String> parameters)
throws JournalException {
String host = getRequiredParameter(parameters, PARAMETER_HOST_NAME);
try {
InetAddress.getByName(host);
} catch (UnknownHostException e) {
throw new JournalException("Invalid '" + PARAMETER_HOST_NAME
+ "' parameter: " + host, e);
}
return host;
}
private String parsePort(Map<String, String> parameters)
throws JournalException {
if (parameters.containsKey(PARAMETER_PORT_NUMBER)) {
String port = parameters.get(PARAMETER_PORT_NUMBER);
try {
Integer.parseInt(port);
return port;
} catch (NumberFormatException e) {
throw new JournalException("Invalid '" + PARAMETER_PORT_NUMBER
+ "' parameter: " + port, e);
}
} else {
return String.valueOf(DEFAULT_PORT_NUMBER);
}
}
private String parseServiceName(Map<String, String> parameters)
throws JournalException {
return getRequiredParameter(parameters, PARAMETER_SERVICE_NAME);
}
private int parseBufferSize(Map<String, String> parameters)
throws JournalException {
if (parameters.containsKey(PARAMETER_BUFFER_SIZE)) {
String size = parameters.get(PARAMETER_BUFFER_SIZE);
try {
return Integer.parseInt(size);
} catch (NumberFormatException e) {
throw new JournalException("Invalid '" + PARAMETER_BUFFER_SIZE
+ "' parameter: " + size, e);
}
} else {
return DEFAULT_BUFFER_SIZE;
}
}
private String getRequiredParameter(Map<String, String> parameters,
String parameter)
throws JournalException {
if (!parameters.containsKey(parameter)) {
throw new JournalException("RmiTransport requires '" + parameter
+ "' parameter.");
}
return parameters.get(parameter);
}
/**
* check state, send the open request, open a very special writer, write the
* file opening, set state
*/
@Override
public void openFile(String repositoryHash,
String filename,
Date currentDate) throws JournalException {
try {
super.testStateChange(State.FILE_OPEN);
writer = new RmiTransportWriter(receiver, repositoryHash, filename);
xmlWriter =
new IndentingXMLEventWriter(XMLOutputFactory
.newInstance()
.createXMLEventWriter(new BufferedWriter(writer,
bufferSize)));
parent.writeDocumentHeader(xmlWriter, repositoryHash, currentDate);
super.setState(State.FILE_OPEN);
} catch (XMLStreamException e) {
throw new JournalException(e);
} catch (FactoryConfigurationError e) {
throw new JournalException(e);
}
}
/**
* check state, hand over to the writer
*/
@Override
public XMLEventWriter getWriter() throws JournalException {
super.testWriterState();
return xmlWriter;
}
/**
* check state, write the file closing, close/flush the writer, send the
* close request, set state.
*/
@Override
public void closeFile() throws JournalException {
try {
super.testStateChange(State.FILE_CLOSED);
parent.writeDocumentTrailer(xmlWriter);
xmlWriter.close();
super.setState(State.FILE_CLOSED);
} catch (XMLStreamException e) {
throw new JournalException(e);
}
}
/**
* check state, set state. a redundant call is not an error, but requires no
* action.
*/
@Override
public void shutdown() throws JournalException {
super.testStateChange(State.SHUTDOWN);
if (super.getState() != State.SHUTDOWN) {
super.setState(State.SHUTDOWN);
}
}
}