package edu.harvard.iq.dataverse.harvest.server.xoai; import com.lyncode.xoai.model.oaipmh.Header; import com.lyncode.xoai.model.oaipmh.Record; import com.lyncode.xoai.xml.XmlWriter; import static com.lyncode.xoai.xml.XmlWriter.defaultContext; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.export.ExportException; import edu.harvard.iq.dataverse.export.ExportService; import static edu.harvard.iq.dataverse.util.SystemConfig.FQDN; import static edu.harvard.iq.dataverse.util.SystemConfig.SITE_URL; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.UnknownHostException; /** * * @author Leonid Andreev * * This is the Dataverse extension of XOAI Record, * optimized to directly output a pre-exported metadata record to the * output stream, thus by-passing expensive parsing and writing by * an XML writer, as in the original XOAI implementation. */ public class Xrecord extends Record { private static final String METADATA_FIELD = "metadata"; private static final String METADATA_START_ELEMENT = "<"+METADATA_FIELD+">"; private static final String METADATA_END_ELEMENT = "</"+METADATA_FIELD+">"; private static final String HEADER_FIELD = "header"; private static final String STATUS_ATTRIBUTE = "status"; private static final String IDENTIFIER_FIELD = "identifier"; private static final String DATESTAMP_FIELD = "datestamp"; private static final String SETSPEC_FIELD = "setSpec"; private static final String DATAVERSE_EXTENDED_METADATA_FORMAT = "dataverse_json"; private static final String DATAVERSE_EXTENDED_METADATA_API = "/api/datasets/export"; protected Dataset dataset; protected String formatName; public Dataset getDataset() { return dataset; } public Xrecord withDataset(Dataset dataset) { this.dataset = dataset; return this; } public String getFormatName() { return formatName; } public Xrecord withFormatName(String formatName) { this.formatName = formatName; return this; } public void writeToStream(OutputStream outputStream) throws IOException { outputStream.flush(); String headerString = itemHeaderToString(this.header); if (headerString == null) { throw new IOException("Xrecord: failed to stream item header."); } outputStream.write(headerString.getBytes()); if (!isExtendedDataverseMetadataMode(formatName)) { outputStream.write(METADATA_START_ELEMENT.getBytes()); outputStream.flush(); if (dataset != null && formatName != null) { InputStream inputStream = null; try { inputStream = ExportService.getInstance().getExport(dataset, formatName); } catch (ExportException ex) { inputStream = null; } if (inputStream == null) { throw new IOException("Xrecord: failed to open metadata stream."); } writeMetadataStream(inputStream, outputStream); } outputStream.write(METADATA_END_ELEMENT.getBytes()); } else { outputStream.write(customMetadataExtensionRef(this.dataset.getGlobalId()).getBytes()); } outputStream.flush(); } private String itemHeaderToString(Header header) { try { ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); XmlWriter writer = new XmlWriter(byteOutputStream, defaultContext()); writer.writeStartElement(HEADER_FIELD); if (header.getStatus() != null) { writer.writeAttribute(STATUS_ATTRIBUTE, header.getStatus().value()); } writer.writeElement(IDENTIFIER_FIELD, header.getIdentifier()); writer.writeElement(DATESTAMP_FIELD, header.getDatestamp()); for (String setSpec : header.getSetSpecs()) { writer.writeElement(SETSPEC_FIELD, setSpec); } writer.writeEndElement(); // header writer.flush(); writer.close(); String ret = byteOutputStream.toString(); return ret; } catch (Exception ex) { return null; } } private void writeMetadataStream(InputStream inputStream, OutputStream outputStream) throws IOException { int bufsize; byte[] buffer = new byte[4 * 8192]; while ((bufsize = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bufsize); outputStream.flush(); } inputStream.close(); } private String customMetadataExtensionRef(String identifier) { String ret = "<" + METADATA_FIELD + " directApiCall=\"" + getDataverseSiteUrl() + DATAVERSE_EXTENDED_METADATA_API + "?exporter=" + DATAVERSE_EXTENDED_METADATA_FORMAT + "&persistentId=" + identifier + "\"" + "/>"; return ret; } private boolean isExtendedDataverseMetadataMode(String formatName) { return DATAVERSE_EXTENDED_METADATA_FORMAT.equals(formatName); } private String getDataverseSiteUrl() { String hostUrl = System.getProperty(SITE_URL); if (hostUrl != null && !"".equals(hostUrl)) { return hostUrl; } String hostName = System.getProperty(FQDN); if (hostName == null) { try { hostName = InetAddress.getLocalHost().getCanonicalHostName(); } catch (UnknownHostException e) { return null; } } hostUrl = "https://" + hostName; return hostUrl; } }