diff src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java @ 10:a50cf11e5178

Rewrite LGDataverse completely upgrading to dataverse4.0
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Tue, 08 Sep 2015 17:00:21 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java	Tue Sep 08 17:00:21 2015 +0200
@@ -0,0 +1,477 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package edu.harvard.iq.dataverse;
+
+import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
+import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
+import edu.harvard.iq.dataverse.authorization.users.User;
+import edu.harvard.iq.dataverse.dataaccess.ImageThumbConverter;
+import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.ejb.EJB;
+import javax.ejb.EJBException;
+import javax.ejb.Stateless;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.inject.Named;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.commons.lang.RandomStringUtils;
+
+/**
+ *
+ * @author skraffmiller
+ */
+@Stateless
+@Named
+public class DatasetServiceBean implements java.io.Serializable {
+
+    private static final Logger logger = Logger.getLogger(DatasetServiceBean.class.getCanonicalName());
+    @EJB
+    IndexServiceBean indexService;
+
+    @EJB
+    DOIEZIdServiceBean doiEZIdServiceBean;
+
+    @EJB
+    SettingsServiceBean settingsService;
+    
+    @EJB
+    DatasetVersionServiceBean versionService;
+    
+    @EJB
+    AuthenticationServiceBean authentication;
+    
+    @EJB
+    DataFileServiceBean fileService; 
+
+    @PersistenceContext(unitName = "VDCNet-ejbPU")
+    private EntityManager em;
+
+    public Dataset find(Object pk) {
+        return em.find(Dataset.class, pk);
+    }
+
+    public List<Dataset> findByOwnerId(Long ownerId) {
+        return findByOwnerId(ownerId, false);
+    }
+    
+    public List<Dataset> findPublishedByOwnerId(Long ownerId) {
+        return findByOwnerId(ownerId, true);
+    }    
+
+    private List<Dataset> findByOwnerId(Long ownerId, boolean onlyPublished) {
+        List<Dataset> retList = new ArrayList();
+        TypedQuery<Dataset>  query = em.createQuery("select object(o) from Dataset as o where o.owner.id =:ownerId order by o.id", Dataset.class);
+        query.setParameter("ownerId", ownerId);
+        if (!onlyPublished) {
+            return query.getResultList();
+        } else {
+            for (Dataset ds : query.getResultList()) {
+                if (ds.isReleased() && !ds.isDeaccessioned()) {
+                    retList.add(ds);
+                }
+            }
+            return retList;
+        }
+    }
+
+    public List<Dataset> findAll() {
+        return em.createQuery("select object(o) from Dataset as o order by o.id").getResultList();
+    }
+
+    /**
+     * For docs, see the equivalent method on the DataverseServiceBean.
+     * @see DataverseServiceBean#findAllOrSubset(long, long) 
+     */     
+    public List<Dataset> findAllOrSubset(long numPartitions, long partitionId, boolean skipIndexed) {
+        if (numPartitions < 1) {
+            long saneNumPartitions = 1;
+            numPartitions = saneNumPartitions;
+        }
+        String skipClause = skipIndexed ? "AND o.indexTime is null " : "";
+        TypedQuery<Dataset> typedQuery = em.createQuery("SELECT OBJECT(o) FROM Dataset AS o WHERE MOD( o.id, :numPartitions) = :partitionId " +
+                skipClause +
+                "ORDER BY o.id", Dataset.class);
+        typedQuery.setParameter("numPartitions", numPartitions);
+        typedQuery.setParameter("partitionId", partitionId);
+        return typedQuery.getResultList();
+    }
+
+    public Dataset findByGlobalId(String globalId) {
+
+        String protocol = "";
+        String authority = "";
+        String identifier = "";
+        int index1 = globalId.indexOf(':');
+        String nonNullDefaultIfKeyNotFound = ""; 
+        String separator = settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound);        
+        int index2 = globalId.indexOf(separator, index1 + 1);
+        int index3 = 0;
+        if (index1 == -1) {            
+            throw new EJBException("Error parsing identifier: " + globalId + ". ':' not found in string");
+        } else {
+            protocol = globalId.substring(0, index1);
+        }
+        if (index2 == -1 ) {
+            throw new EJBException("Error parsing identifier: " + globalId + ". Second separator not found in string");
+        } else {
+            if (index2 != -1) {
+                authority = globalId.substring(index1 + 1, index2);
+            }
+        }
+        if (protocol.equals("doi")) {
+
+            index3 = globalId.indexOf(separator, index2 + 1);
+            if (index3 == -1 ) {
+                identifier = globalId.substring(index2 + 1).toUpperCase();
+            } else {
+                if (index3 > -1) {
+                    authority = globalId.substring(index1 + 1, index3);
+                    identifier = globalId.substring(index3 + 1).toUpperCase();
+                }
+            }
+        } else {
+            identifier = globalId.substring(index2 + 1).toUpperCase();
+        }
+        String queryStr = "SELECT s from Dataset s where s.identifier = :identifier  and s.protocol= :protocol and s.authority= :authority";
+        Dataset foundDataset = null;
+        try {
+            Query query = em.createQuery(queryStr);
+            query.setParameter("identifier", identifier);
+            query.setParameter("protocol", protocol);
+            query.setParameter("authority", authority);
+            foundDataset = (Dataset) query.getSingleResult();
+        } catch (javax.persistence.NoResultException e) {
+            logger.info("no ds found: " + globalId);
+            // DO nothing, just return null.
+        }
+        return foundDataset;
+    }
+
+    public String generateIdentifierSequence(String protocol, String authority, String separator) {
+
+        String identifier = null;
+        do {
+            identifier = RandomStringUtils.randomAlphanumeric(6).toUpperCase();  
+        } while (!isUniqueIdentifier(identifier, protocol, authority, separator));
+
+        return identifier;
+    }
+
+    /**
+     * Check that a identifier entered by the user is unique (not currently used
+     * for any other study in this Dataverse Network) alos check for duplicate
+     * in EZID if needed
+     */
+    public boolean isUniqueIdentifier(String userIdentifier, String protocol, String authority, String separator) {
+        String query = "SELECT d FROM Dataset d WHERE d.identifier = '" + userIdentifier + "'";
+        query += " and d.protocol ='" + protocol + "'";
+        query += " and d.authority = '" + authority + "'";
+        boolean u = em.createQuery(query).getResultList().size() == 0;
+        String nonNullDefaultIfKeyNotFound = "";
+        String doiProvider = settingsService.getValueForKey(SettingsServiceBean.Key.DoiProvider, nonNullDefaultIfKeyNotFound);
+        if (doiProvider.equals("EZID")) {
+            if (!doiEZIdServiceBean.lookupMetadataFromIdentifier(protocol, authority, separator, userIdentifier).isEmpty()) {
+                u = false;
+            }
+        }
+        return u;
+    }
+
+    public String createCitationRIS(DatasetVersion version) {
+        return createCitationRIS(version, null);
+    } 
+    
+    public String createCitationRIS(DatasetVersion version, FileMetadata fileMetadata) {
+        String publisher = version.getRootDataverseNameforCitation();
+        List<DatasetAuthor> authorList = version.getDatasetAuthors();
+        String retString = "Provider: " + publisher + "\r\n";
+        retString += "Content: text/plain; charset=\"us-ascii\"" + "\r\n";
+        // Using type "DBASE" - "Online Database", for consistency with 
+        // EndNote (see the longer comment in the EndNote section below)> 
+        
+        retString += "TY  - DBASE" + "\r\n";
+        retString += "T1  - " + version.getTitle() + "\r\n";
+        for (DatasetAuthor author : authorList) {
+            retString += "AU  - " + author.getName().getDisplayValue() + "\r\n";
+        }
+        retString += "DO  - " + version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier() + "\r\n";
+        retString += "PY  - " + version.getVersionYear() + "\r\n";
+        retString += "UR  - " + version.getDataset().getPersistentURL() + "\r\n";
+        retString += "PB  - " + publisher + "\r\n";
+        
+        // a DataFile citation also includes filename und UNF, if applicable:
+        if (fileMetadata != null) { 
+            retString += "C1  - " + fileMetadata.getLabel() + "\r\n";
+            
+            if (fileMetadata.getDataFile().isTabularData()) {
+                if (fileMetadata.getDataFile().getUnf() != null) {
+                    retString += "C2  - " + fileMetadata.getDataFile().getUnf() + "\r\n";
+                }
+            }
+        }
+        
+        // closing element: 
+        retString += "ER  - \r\n";
+
+        return retString;
+    }
+
+    private XMLOutputFactory xmlOutputFactory = null;
+
+    public String createCitationXML(DatasetVersion datasetVersion, FileMetadata fileMetadata) {
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+        createEndNoteCitation(outStream, datasetVersion, fileMetadata);
+        String xml = outStream.toString();
+        return xml; 
+    } 
+    
+    public void createEndNoteCitation(OutputStream os, DatasetVersion datasetVersion, FileMetadata fileMetadata) {
+
+        xmlOutputFactory = javax.xml.stream.XMLOutputFactory.newInstance();
+        XMLStreamWriter xmlw = null;
+        try {
+            xmlw = xmlOutputFactory.createXMLStreamWriter(os);
+            xmlw.writeStartDocument();
+            createEndNoteXML(xmlw, datasetVersion, fileMetadata);
+            xmlw.writeEndDocument();
+        } catch (XMLStreamException ex) {
+            Logger.getLogger("global").log(Level.SEVERE, null, ex);
+            throw new EJBException("ERROR occurred during creating endnote xml.", ex);
+        } finally {
+            try {
+                if (xmlw != null) {
+                    xmlw.close();
+                }
+            } catch (XMLStreamException ex) {
+            }
+        }
+    }
+    
+    private void createEndNoteXML(XMLStreamWriter xmlw, DatasetVersion version, FileMetadata fileMetadata) throws XMLStreamException {
+
+        String title = version.getTitle();
+        String versionYear = version.getVersionYear();
+        String publisher = version.getRootDataverseNameforCitation();
+
+        List<DatasetAuthor> authorList = version.getDatasetAuthors();
+
+        xmlw.writeStartElement("xml");
+        xmlw.writeStartElement("records");
+
+        xmlw.writeStartElement("record");
+
+        // "Ref-type" indicates which of the (numerous!) available EndNote
+        // schemas this record will be interpreted as. 
+        // This is relatively important. Certain fields with generic 
+        // names like "custom1" and "custom2" become very specific things
+        // in specific schemas; for example, custom1 shows as "legal notice"
+        // in "Journal Article" (ref-type 84), or as "year published" in 
+        // "Government Document". 
+        // We don't want the UNF to show as a "legal notice"! 
+        // We have found a ref-type that works ok for our purposes - 
+        // "Online Database" (type 45). In this one, the fields Custom1 
+        // and Custom2 are not translated and just show as is. 
+        // And "Custom1" still beats "legal notice". 
+        // -- L.A. 12.12.2014 beta 10
+        
+        xmlw.writeStartElement("ref-type");
+        xmlw.writeAttribute("name", "Online Database");
+        xmlw.writeCharacters("45");
+        xmlw.writeEndElement(); // ref-type
+
+        xmlw.writeStartElement("contributors");
+        xmlw.writeStartElement("authors");
+        for (DatasetAuthor author : authorList) {
+            xmlw.writeStartElement("author");
+            xmlw.writeCharacters(author.getName().getDisplayValue());
+            xmlw.writeEndElement(); // author                    
+        }
+        xmlw.writeEndElement(); // authors 
+        xmlw.writeEndElement(); // contributors 
+
+        xmlw.writeStartElement("titles");
+        xmlw.writeStartElement("title");
+        xmlw.writeCharacters(title);
+        xmlw.writeEndElement(); // title
+        
+        xmlw.writeEndElement(); // titles
+
+        xmlw.writeStartElement("section");
+        String sectionString = "";
+        if (version.getDataset().isReleased()) {
+            sectionString = new SimpleDateFormat("yyyy-MM-dd").format(version.getDataset().getPublicationDate());
+        } else {
+            sectionString = new SimpleDateFormat("yyyy-MM-dd").format(version.getLastUpdateTime());
+        }
+
+        xmlw.writeCharacters(sectionString);
+        xmlw.writeEndElement(); // publisher
+
+        xmlw.writeStartElement("dates");
+        xmlw.writeStartElement("year");
+        xmlw.writeCharacters(versionYear);
+        xmlw.writeEndElement(); // year
+        xmlw.writeEndElement(); // dates
+
+        xmlw.writeStartElement("publisher");
+        xmlw.writeCharacters(publisher);
+        xmlw.writeEndElement(); // publisher
+
+        xmlw.writeStartElement("urls");
+        xmlw.writeStartElement("related-urls");
+        xmlw.writeStartElement("url");
+        xmlw.writeCharacters(version.getDataset().getPersistentURL());
+        xmlw.writeEndElement(); // url
+        xmlw.writeEndElement(); // related-urls
+        xmlw.writeEndElement(); // urls
+        
+        // a DataFile citation also includes the filename and (for Tabular
+        // files) the UNF signature, that we put into the custom1 and custom2 
+        // fields respectively:
+        
+        
+        if (fileMetadata != null) {
+            xmlw.writeStartElement("custom1");
+            xmlw.writeCharacters(fileMetadata.getLabel());
+            xmlw.writeEndElement(); // custom1
+            
+            if (fileMetadata.getDataFile().isTabularData()) {
+                if (fileMetadata.getDataFile().getUnf() != null) {
+                    xmlw.writeStartElement("custom2");
+                    xmlw.writeCharacters(fileMetadata.getDataFile().getUnf());
+                    xmlw.writeEndElement(); // custom2
+                }
+            }
+        }
+
+        xmlw.writeStartElement("electronic-resource-num");
+        String electResourceNum = version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier();
+        xmlw.writeCharacters(electResourceNum);
+        xmlw.writeEndElement();
+        //<electronic-resource-num>10.3886/ICPSR03259.v1</electronic-resource-num>                  
+        xmlw.writeEndElement(); // record
+
+        xmlw.writeEndElement(); // records
+        xmlw.writeEndElement(); // xml
+
+    }
+
+    public DatasetVersionUser getDatasetVersionUser(DatasetVersion version, User user) {
+
+        DatasetVersionUser ddu = null;
+        Query query = em.createQuery("select object(o) from DatasetVersionUser as o "
+                + "where o.datasetVersion.id =:versionId and o.authenticatedUser.id =:userId");
+        query.setParameter("versionId", version.getId());
+        String identifier = user.getIdentifier();
+        identifier = identifier.startsWith("@") ? identifier.substring(1) : identifier;
+        AuthenticatedUser au = authentication.getAuthenticatedUser(identifier);
+        query.setParameter("userId", au.getId());
+        try {
+            ddu = (DatasetVersionUser) query.getSingleResult();
+        } catch (javax.persistence.NoResultException e) {
+            // DO nothing, just return null.
+        }
+        return ddu;
+    }
+
+    public List<DatasetLock> getDatasetLocks() {
+        String query = "SELECT sl FROM DatasetLock sl";
+        return (List<DatasetLock>) em.createQuery(query).getResultList();
+    }
+
+    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+    public void addDatasetLock(Long datasetId, Long userId, String info) {
+
+        Dataset dataset = em.find(Dataset.class, datasetId);
+        DatasetLock lock = new DatasetLock();
+        lock.setDataset(dataset);
+        lock.setInfo(info);
+        lock.setStartTime(new Date());
+
+        if (userId != null) {
+            AuthenticatedUser user = em.find(AuthenticatedUser.class, userId);
+            lock.setUser(user);
+            if (user.getDatasetLocks() == null) {
+                user.setDatasetLocks(new ArrayList());
+            }
+            user.getDatasetLocks().add(lock);
+        }
+
+        dataset.setDatasetLock(lock);
+        em.persist(lock);
+    }
+
+    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+    public void removeDatasetLock(Long datasetId) {
+        Dataset dataset = em.find(Dataset.class, datasetId);
+        //em.refresh(dataset); (?)
+        DatasetLock lock = dataset.getDatasetLock();
+        if (lock != null) {
+            AuthenticatedUser user = lock.getUser();
+            dataset.setDatasetLock(null);
+            user.getDatasetLocks().remove(lock);
+            /* 
+             * TODO - ?
+             * throw an exception if for whatever reason we can't remove the lock?
+             try {
+             */
+            em.remove(lock);
+            /*
+             } catch (TransactionRequiredException te) {
+             ...
+             } catch (IllegalArgumentException iae) {
+             ...
+             }
+             */
+        }
+    }
+    
+    
+    public boolean isDatasetCardImageAvailable(DatasetVersion datasetVersion, User user) {        
+        if (datasetVersion == null) {
+            return false; 
+        }
+                
+        // First, check if this dataset has a designated thumbnail image: 
+        
+        if (datasetVersion.getDataset() != null) {
+            DataFile dataFile = datasetVersion.getDataset().getThumbnailFile();
+            if (dataFile != null) {
+                return ImageThumbConverter.isThumbnailAvailable(dataFile, 48);
+            }
+        }
+        
+        // If not, we'll try to use one of the files in this dataset version:
+        // (the first file with an available thumbnail, really)
+        
+        List<FileMetadata> fileMetadatas = datasetVersion.getFileMetadatas();
+
+        for (FileMetadata fileMetadata : fileMetadatas) {
+            DataFile dataFile = fileMetadata.getDataFile();
+            
+            if (fileService.isThumbnailAvailable(dataFile, user)) {
+                return true;
+            }
+ 
+        }
+        
+        return false;
+    }
+}