package edu.harvard.iq.dataverse;
import edu.harvard.iq.dataverse.authorization.Permission;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.datasetutility.TwoRavensHelper;
import edu.harvard.iq.dataverse.datasetutility.WorldMapPermissionHelper;
import edu.harvard.iq.dataverse.engine.command.Command;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.impl.CreateGuestbookResponseCommand;
import edu.harvard.iq.dataverse.engine.command.impl.RequestAccessCommand;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.primefaces.context.RequestContext;
/**
*
* @author skraffmi
* Handles All File Download processes
* including Guestbook responses
*/
@Stateless
@Named
public class FileDownloadServiceBean implements java.io.Serializable {
@PersistenceContext(unitName = "VDCNet-ejbPU")
private EntityManager em;
@EJB
GuestbookResponseServiceBean guestbookResponseService;
@EJB
DatasetServiceBean datasetService;
@EJB
DatasetVersionServiceBean datasetVersionService;
@EJB
DataFileServiceBean datafileService;
@EJB
PermissionServiceBean permissionService;
@EJB
DataverseServiceBean dataverseService;
@EJB
UserNotificationServiceBean userNotificationService;
@Inject
DataverseSession session;
@EJB
EjbDataverseEngine commandEngine;
@Inject
DataverseRequestServiceBean dvRequestService;
@Inject TwoRavensHelper twoRavensHelper;
@Inject WorldMapPermissionHelper worldMapPermissionHelper;
private static final Logger logger = Logger.getLogger(FileDownloadServiceBean.class.getCanonicalName());
public void writeGuestbookAndStartDownload(GuestbookResponse guestbookResponse){
if (guestbookResponse != null && guestbookResponse.getDataFile() != null ){
writeGuestbookResponseRecord(guestbookResponse);
callDownloadServlet(guestbookResponse.getFileFormat(), guestbookResponse.getDataFile().getId(), guestbookResponse.isWriteResponse());
}
if (guestbookResponse != null && guestbookResponse.getSelectedFileIds() != null ){
List<String> list = new ArrayList<>(Arrays.asList(guestbookResponse.getSelectedFileIds().split(",")));
for (String idAsString : list) {
DataFile df = datafileService.findCheapAndEasy(new Long(idAsString)) ;
if (df != null) {
guestbookResponse.setDataFile(df);
writeGuestbookResponseRecord(guestbookResponse);
}
}
callDownloadServlet(guestbookResponse.getSelectedFileIds(), true);
}
}
public void writeGuestbookResponseRecord(GuestbookResponse guestbookResponse) {
try {
Command cmd = new CreateGuestbookResponseCommand(dvRequestService.getDataverseRequest(), guestbookResponse, guestbookResponse.getDataset());
commandEngine.submit(cmd);
} catch (CommandException e) {
//if an error occurs here then download won't happen no need for response recs...
}
}
public void callDownloadServlet(String multiFileString, Boolean gbRecordsWritten){
String fileDownloadUrl = "/api/access/datafiles/" + multiFileString;
if (gbRecordsWritten){
fileDownloadUrl += "?gbrecs=true";
}
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(fileDownloadUrl);
} catch (IOException ex) {
logger.info("Failed to issue a redirect to file download url.");
}
//return fileDownloadUrl;
}
//private String callDownloadServlet( String downloadType, Long fileId){
public void callDownloadServlet( String downloadType, Long fileId, Boolean gbRecordsWritten){
String fileDownloadUrl = "/api/access/datafile/" + fileId;
if (downloadType != null && downloadType.equals("bundle")){
fileDownloadUrl = "/api/access/datafile/bundle/" + fileId;
}
if (downloadType != null && downloadType.equals("original")){
fileDownloadUrl = "/api/access/datafile/" + fileId + "?format=original";
}
if (downloadType != null && downloadType.equals("RData")){
fileDownloadUrl = "/api/access/datafile/" + fileId + "?format=RData";
}
if (downloadType != null && downloadType.equals("var")){
fileDownloadUrl = "/api/meta/datafile/" + fileId;
}
if (downloadType != null && downloadType.equals("tab")){
fileDownloadUrl = "/api/access/datafile/" + fileId+ "?format=tab";
}
if (gbRecordsWritten){
if(downloadType != null && ( downloadType.equals("original") || downloadType.equals("RData") || downloadType.equals("tab")) ){
fileDownloadUrl += "&gbrecs=true";
} else {
fileDownloadUrl += "?gbrecs=true";
}
}
logger.fine("Returning file download url: " + fileDownloadUrl);
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(fileDownloadUrl);
} catch (IOException ex) {
logger.info("Failed to issue a redirect to file download url.");
}
//return fileDownloadUrl;
}
//public String startFileDownload(FileMetadata fileMetadata, String format) {
public void startFileDownload(GuestbookResponse guestbookResponse, FileMetadata fileMetadata, String format) {
boolean recordsWritten = false;
if(!fileMetadata.getDatasetVersion().isDraft()){
guestbookResponse = guestbookResponseService.modifyDatafileAndFormat(guestbookResponse, fileMetadata, format);
writeGuestbookResponseRecord(guestbookResponse);
recordsWritten = true;
}
callDownloadServlet(format, fileMetadata.getDataFile().getId(), recordsWritten);
logger.fine("issued file download redirect for filemetadata "+fileMetadata.getId()+", datafile "+fileMetadata.getDataFile().getId());
}
public String startExploreDownloadLink(GuestbookResponse guestbookResponse, FileMetadata fmd){
if (guestbookResponse != null && guestbookResponse.isWriteResponse()
&& (( fmd != null && fmd.getDataFile() != null) || guestbookResponse.getDataFile() != null)){
if(guestbookResponse.getDataFile() == null && fmd != null){
guestbookResponse.setDataFile(fmd.getDataFile());
}
if (fmd == null || !fmd.getDatasetVersion().isDraft()){
writeGuestbookResponseRecord(guestbookResponse);
}
}
Long datafileId;
if (fmd == null && guestbookResponse != null && guestbookResponse.getDataFile() != null){
datafileId = guestbookResponse.getDataFile().getId();
} else {
datafileId = fmd.getDataFile().getId();
}
String retVal = twoRavensHelper.getDataExploreURLComplete(datafileId);
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(retVal);
return retVal;
} catch (IOException ex) {
logger.info("Failed to issue a redirect to file download url.");
}
return retVal;
}
public String startWorldMapDownloadLink(GuestbookResponse guestbookResponse, FileMetadata fmd){
if (guestbookResponse != null && guestbookResponse.isWriteResponse() && ((fmd != null && fmd.getDataFile() != null) || guestbookResponse.getDataFile() != null)){
if(guestbookResponse.getDataFile() == null && fmd != null){
guestbookResponse.setDataFile(fmd.getDataFile());
}
if (fmd == null || !fmd.getDatasetVersion().isDraft()){
writeGuestbookResponseRecord(guestbookResponse);
}
}
DataFile file = null;
if (fmd != null){
file = fmd.getDataFile();
}
if (guestbookResponse != null && guestbookResponse.getDataFile() != null){
file = guestbookResponse.getDataFile();
}
String retVal = worldMapPermissionHelper.getMapLayerMetadata(file).getLayerLink();
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(retVal);
return retVal;
} catch (IOException ex) {
logger.info("Failed to issue a redirect to file download url.");
}
return retVal;
}
public boolean isDownloadPopupRequired(DatasetVersion datasetVersion) {
// Each of these conditions is sufficient reason to have to
// present the user with the popup:
if (datasetVersion == null){
return false;
}
//0. if version is draft then Popup "not required"
if (!datasetVersion.isReleased()){
return false;
}
// 1. License and Terms of Use:
if (datasetVersion.getTermsOfUseAndAccess() != null) {
if (!TermsOfUseAndAccess.License.CC0.equals(datasetVersion.getTermsOfUseAndAccess().getLicense())
&& !(datasetVersion.getTermsOfUseAndAccess().getTermsOfUse() == null
|| datasetVersion.getTermsOfUseAndAccess().getTermsOfUse().equals(""))) {
return true;
}
// 2. Terms of Access:
if (!(datasetVersion.getTermsOfUseAndAccess().getTermsOfAccess() == null) && !datasetVersion.getTermsOfUseAndAccess().getTermsOfAccess().equals("")) {
return true;
}
}
// 3. Guest Book:
if (datasetVersion.getDataset().getGuestbook() != null && datasetVersion.getDataset().getGuestbook().isEnabled() && datasetVersion.getDataset().getGuestbook().getDataverse() != null ) {
return true;
}
return false;
}
public Boolean canSeeTwoRavensExploreButton(){
return false;
}
public Boolean canUserSeeExploreWorldMapButton(){
return false;
}
public void downloadDatasetCitationXML(Dataset dataset) {
downloadCitationXML(null, dataset);
}
public void downloadDatafileCitationXML(FileMetadata fileMetadata) {
downloadCitationXML(fileMetadata, null);
}
public void downloadCitationXML(FileMetadata fileMetadata, Dataset dataset) {
DatasetVersion workingVersion;
if (dataset != null){
workingVersion = dataset.getLatestVersion();
} else {
workingVersion = fileMetadata.getDatasetVersion();
}
String xml = datasetService.createCitationXML(workingVersion, fileMetadata);
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
response.setContentType("text/xml");
String fileNameString = "";
if (fileMetadata == null || fileMetadata.getLabel() == null) {
// Dataset-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + ".xml";
} else {
// Datafile-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + "-" + fileMetadata.getLabel().replaceAll("\\.tab$", "-endnote.xml");
}
response.setHeader("Content-Disposition", fileNameString);
try {
ServletOutputStream out = response.getOutputStream();
out.write(xml.getBytes());
out.flush();
ctx.responseComplete();
} catch (Exception e) {
}
}
public void downloadDatasetCitationRIS(Dataset dataset) {
downloadCitationRIS(null, dataset);
}
public void downloadDatafileCitationRIS(FileMetadata fileMetadata) {
downloadCitationRIS(fileMetadata, null);
}
public void downloadCitationRIS(FileMetadata fileMetadata, Dataset dataset) {
DatasetVersion workingVersion;
if (dataset != null){
workingVersion = dataset.getLatestVersion();
} else {
workingVersion = fileMetadata.getDatasetVersion();
}
String risFormatDowload = datasetService.createCitationRIS(workingVersion, fileMetadata);
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
response.setContentType("application/download");
String fileNameString = "";
if (fileMetadata == null || fileMetadata.getLabel() == null) {
// Dataset-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + ".ris";
} else {
// Datafile-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + "-" + fileMetadata.getLabel().replaceAll("\\.tab$", ".ris");
}
response.setHeader("Content-Disposition", fileNameString);
try {
ServletOutputStream out = response.getOutputStream();
out.write(risFormatDowload.getBytes());
out.flush();
ctx.responseComplete();
} catch (Exception e) {
}
}
private String getFileNameDOI(DatasetVersion workingVersion) {
Dataset ds = workingVersion.getDataset();
return "DOI:" + ds.getAuthority() + "_" + ds.getIdentifier().toString();
}
public void downloadDatasetCitationBibtex(Dataset dataset) {
downloadCitationBibtex(null, dataset);
}
public void downloadDatafileCitationBibtex(FileMetadata fileMetadata) {
downloadCitationBibtex(fileMetadata, null);
}
public void downloadCitationBibtex(FileMetadata fileMetadata, Dataset dataset) {
DatasetVersion workingVersion;
if (dataset != null){
workingVersion = dataset.getLatestVersion();
} else {
workingVersion = fileMetadata.getDatasetVersion();
}
String bibFormatDowload = new BibtexCitation(workingVersion).toString();
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
response.setContentType("application/download");
String fileNameString = "";
if (fileMetadata == null || fileMetadata.getLabel() == null) {
// Dataset-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + ".bib";
} else {
// Datafile-level citation:
fileNameString = "attachment;filename=" + getFileNameDOI(workingVersion) + "-" + fileMetadata.getLabel().replaceAll("\\.tab$", ".bib");
}
response.setHeader("Content-Disposition", fileNameString);
try {
ServletOutputStream out = response.getOutputStream();
out.write(bibFormatDowload.getBytes());
out.flush();
ctx.responseComplete();
} catch (Exception e) {
}
}
public void requestAccess(DataFile file) {
if (requestAccess(file.getId())) {
// update the local file object so that the page properly updates
file.getFileAccessRequesters().add((AuthenticatedUser) session.getUser());
// create notifications
sendRequestFileAccessNotification(file.getOwner(), file.getId());
}
}
public boolean requestAccess(Long fileId) {
DataFile file = datafileService.find(fileId);
if (!file.getFileAccessRequesters().contains((AuthenticatedUser) session.getUser())) {
try {
commandEngine.submit(new RequestAccessCommand(dvRequestService.getDataverseRequest(), file));
return true;
} catch (CommandException ex) {
logger.info("Unable to request access for file id " + fileId + ". Exception: " + ex);
}
}
return false;
}
public void sendRequestFileAccessNotification(Dataset dataset, Long fileId) {
permissionService.getUsersWithPermissionOn(Permission.ManageDatasetPermissions, dataset).stream().forEach((au) -> {
userNotificationService.sendNotification(au, new Timestamp(new Date().getTime()), UserNotification.Type.REQUESTFILEACCESS, fileId);
});
}
}