/* 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;
import java.io.File;
import java.io.StringWriter;
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.entry.CreatorJournalEntry;
import fedora.server.journal.entry.JournalEntry;
/**
* <p>
* <b>Title:</b> JournalEntrySizeEstimator.java
* </p>
* <p>
* <b>Description:</b> The easiest, simplest, most maintainable way to estimate
* the size of a formatted JournalEntry is to just have the JournalWriter format
* it. We save some work and avoid memory overflow issues by removing any data
* files from the entry before formatting: we know how big the files will be
* when encoded.
* </p>
*
* @author jblake
* @version $Id: JournalEntrySizeEstimator.java,v 1.3 2007/06/01 17:21:31 jblake
* Exp $
*/
public class JournalEntrySizeEstimator {
private final MulticastJournalWriter journalWriter;
public JournalEntrySizeEstimator(MulticastJournalWriter journalWriter) {
this.journalWriter = journalWriter;
}
/**
* Create a modified entry, minus any file arguments, and ask the
* JournalWriter to format it so we can check the size. The size of the
* file(s) can be determined separately.
*
* @throws JournalException
*/
public long estimateSize(JournalEntry journalEntry) throws JournalException {
try {
long totalFileSizes = 0;
// Initialize the copy of the JournalEntry
CreatorJournalEntry copyEntry =
new CreatorJournalEntry(journalEntry.getMethodName(),
journalEntry.getContext());
// Add arguments to the copy of the JournalEntry, except for File
// arguments. Calculate any file sizes here.
Map<String, Object> argumentsMap = journalEntry.getArgumentsMap();
for (String name : argumentsMap.keySet()) {
Object value = argumentsMap.get(name);
if (value instanceof File) {
totalFileSizes += estimateFileSize((File) value);
copyEntry.addArgument(name, (File) null);
} else {
copyEntry.addArgument(name, value);
}
}
// Create an XMLEventWriter on a StringBuffer, and ask the
// JournalWriter to write the copy of the JournalEntry to it.
StringWriter stringWriter = new StringWriter();
XMLEventWriter xmlEventWriter = createXmlEventWriter(stringWriter);
journalWriter.writeJournalEntry(copyEntry, xmlEventWriter);
// Add the size of the formatted string to the size of the encoded
// files.
return totalFileSizes + stringWriter.getBuffer().length();
} catch (FactoryConfigurationError e) {
throw new JournalException("can't estimate the size of a JournalEntry",
e);
} catch (XMLStreamException e) {
throw new JournalException("can't estimate the size of a JournalEntry",
e);
}
}
/**
* When a file is Base64-encoded, it takes 4 bytes to encode 3 bytes of
* content, plus we throw in a newline after encoding 57 characters or so.
*/
private long estimateFileSize(File file) {
if (file == null) {
return 0;
} else {
return file.length() * 4 / 3 + file.length() / 57;
}
}
/**
* Wrap an XMLEventWriter around that StringWriter.
*/
private XMLEventWriter createXmlEventWriter(StringWriter stringWriter)
throws FactoryConfigurationError, XMLStreamException {
return new IndentingXMLEventWriter(XMLOutputFactory.newInstance()
.createXMLEventWriter(stringWriter));
}
}