package edu.harvard.iq.dataverse.export; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.export.spi.Exporter; import edu.harvard.iq.dataverse.util.SystemConfig; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.jsonAsDatasetDto; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import javax.ejb.EJB; import javax.ejb.TransactionAttribute; import static javax.ejb.TransactionAttributeType.REQUIRES_NEW; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; /** * * @author skraffmi */ public class ExportService { private static ExportService service; private ServiceLoader<Exporter> loader; private ExportService() { loader = ServiceLoader.load(Exporter.class); } public static synchronized ExportService getInstance() { if (service == null) { service = new ExportService(); } else{ service.loader.reload(); } return service; } public List< String[]> getExportersLabels() { List<String[]> retList = new ArrayList(); Iterator<Exporter> exporters = ExportService.getInstance().loader.iterator(); while (exporters.hasNext()) { Exporter e = exporters.next(); String[] temp = new String[2]; temp[0] = e.getDisplayName(); temp[1] = e.getProviderName(); retList.add(temp); } return retList; } public InputStream getExport(Dataset dataset, String formatName) throws ExportException { // first we will try to locate an already existing, cached export // for this format: InputStream exportInputStream = getCachedExportFormat(dataset, formatName); if (exportInputStream != null) { return exportInputStream; } // if it doesn't exist, we'll try to run the export: exportFormat(dataset, formatName); // and then try again: exportInputStream = getCachedExportFormat(dataset, formatName); if (exportInputStream != null) { return exportInputStream; } // if there is no cached export still - we have to give up and throw // an exception! throw new ExportException("Failed to export the dataset as "+formatName); } public String getExportAsString(Dataset dataset, String formatName) { try { InputStream inputStream = getExport(dataset, formatName); if (inputStream != null) { BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF8")); StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null) { sb.append(line); sb.append('\n'); } br.close(); return sb.toString(); } } catch (Exception ex) { //ex.printStackTrace(); return null; } return null; } // This method goes through all the Exporters and calls // the "chacheExport()" method that will save the produced output // in a file in the dataset directory, on each Exporter available. public void exportAllFormats (Dataset dataset) throws ExportException { clearAllCachedFormats(dataset); try { DatasetVersion releasedVersion = dataset.getReleasedVersion(); if (releasedVersion == null) { throw new ExportException("No released version for dataset "+dataset.getGlobalId()); } final JsonObjectBuilder datasetAsJsonBuilder = jsonAsDatasetDto(releasedVersion); JsonObject datasetAsJson = datasetAsJsonBuilder.build(); Iterator<Exporter> exporters = loader.iterator(); while ( exporters.hasNext()) { Exporter e = exporters.next(); String formatName = e.getProviderName(); cacheExport(releasedVersion, formatName, datasetAsJson, e); } } catch (ServiceConfigurationError serviceError) { throw new ExportException("Service configuration error during export. "+serviceError.getMessage()); } // Finally, if we have been able to successfully export in all available // formats, we'll increment the "last exported" time stamp: dataset.setLastExportTime(new Timestamp(new Date().getTime())); } public void clearAllCachedFormats(Dataset dataset) { Iterator<Exporter> exporters = loader.iterator(); while (exporters.hasNext()) { Exporter e = exporters.next(); String formatName = e.getProviderName(); clearCachedExport(dataset, formatName); } dataset.setLastExportTime(null); } // This method finds the exporter for the format requested, // then produces the dataset metadata as a JsonObject, then calls // the "chacheExport()" method that will save the produced output // in a file in the dataset directory. public void exportFormat(Dataset dataset, String formatName) throws ExportException { try { Iterator<Exporter> exporters = loader.iterator(); while (exporters.hasNext()) { Exporter e = exporters.next(); if (e.getProviderName().equals(formatName)) { DatasetVersion releasedVersion = dataset.getReleasedVersion(); if (releasedVersion == null) { throw new IllegalStateException("No Released Version"); } final JsonObjectBuilder datasetAsJsonBuilder = jsonAsDatasetDto(releasedVersion); cacheExport(releasedVersion, formatName, datasetAsJsonBuilder.build(), e); } } } catch (ServiceConfigurationError serviceError) { throw new ExportException("Service configuration error during export. " + serviceError.getMessage()); } catch (IllegalStateException e) { throw new ExportException("No published version found during export. " + dataset.getGlobalId()); } } public Exporter getExporter(String formatName) throws ExportException { try { Iterator<Exporter> exporters = loader.iterator(); while (exporters.hasNext()) { Exporter e = exporters.next(); if (e.getProviderName().equals(formatName)) { return e; } } } catch (ServiceConfigurationError serviceError) { throw new ExportException("Service configuration error during export. " + serviceError.getMessage()); } catch (Exception ex) { throw new ExportException("Could not find Exporter \""+formatName+"\", unknown exception"); } throw new ExportException("No such Exporter: "+formatName); } // This method runs the selected metadata exporter, caching the output // in a file in the dataset dirctory: private void cacheExport(DatasetVersion version, String format, JsonObject datasetAsJson, Exporter exporter) throws ExportException { try { if (version.getDataset().getFileSystemDirectory() != null && !Files.exists(version.getDataset().getFileSystemDirectory())) { /* Note that "createDirectories()" must be used - not * "createDirectory()", to make sure all the parent * directories that may not yet exist are created as well. */ Files.createDirectories(version.getDataset().getFileSystemDirectory()); } Path cachedMetadataFilePath = Paths.get(version.getDataset().getFileSystemDirectory().toString(), "export_" + format + ".cached"); FileOutputStream cachedExportOutputStream = new FileOutputStream(cachedMetadataFilePath.toFile()); exporter.exportDataset(version, datasetAsJson, cachedExportOutputStream); cachedExportOutputStream.flush(); cachedExportOutputStream.close(); } catch (IOException ioex) { throw new ExportException("IO Exception thrown exporting as " + format); } } private void clearCachedExport(Dataset dataset, String format) { if (dataset != null && dataset.getFileSystemDirectory() != null && Files.exists(dataset.getFileSystemDirectory())) { Path cachedMetadataFilePath = Paths.get(dataset.getFileSystemDirectory().toString(), "export_" + format + ".cached"); try { Files.delete(cachedMetadataFilePath); } catch (IOException ioex) { } } } // This method checks if the metadata has already been exported in this // format and cached on disk. If it has, it'll open the file and retun // the file input stream. If not, it'll return null. private InputStream getCachedExportFormat(Dataset dataset, String formatName) { try { if (dataset.getFileSystemDirectory() != null) { Path cachedMetadataFilePath = Paths.get(dataset.getFileSystemDirectory().toString(), "export_" + formatName + ".cached"); if (Files.exists(cachedMetadataFilePath)) { FileInputStream cachedExportInputStream = new FileInputStream(cachedMetadataFilePath.toFile()); return cachedExportInputStream; } } } catch (IOException ioex) { // don't do anything - we'll just return null } return null; } public Long getCachedExportSize(Dataset dataset, String formatName) { try { if (dataset.getFileSystemDirectory() != null) { Path cachedMetadataFilePath = Paths.get(dataset.getFileSystemDirectory().toString(), "export_" + formatName + ".cached"); if (Files.exists(cachedMetadataFilePath)) { return cachedMetadataFilePath.toFile().length(); } } } catch (Exception ioex) { // don't do anything - we'll just return null } return null; } public Boolean isXMLFormat(String provider){ try { Iterator<Exporter> exporters = loader.iterator(); while (exporters.hasNext()) { Exporter e = exporters.next(); if (e.getProviderName().equals(provider)) { return e.isXMLFormat(); } } } catch (ServiceConfigurationError serviceError) { serviceError.printStackTrace(); } return null; } }