Mercurial > hg > LGDataverses
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 9:5926d6419569 | 10:a50cf11e5178 |
|---|---|
| 1 /* | |
| 2 * To change this license header, choose License Headers in Project Properties. | |
| 3 * To change this template file, choose Tools | Templates | |
| 4 * and open the template in the editor. | |
| 5 */ | |
| 6 package edu.harvard.iq.dataverse; | |
| 7 | |
| 8 import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; | |
| 9 import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; | |
| 10 import edu.harvard.iq.dataverse.authorization.users.User; | |
| 11 import edu.harvard.iq.dataverse.dataaccess.ImageThumbConverter; | |
| 12 import edu.harvard.iq.dataverse.settings.SettingsServiceBean; | |
| 13 import java.io.ByteArrayOutputStream; | |
| 14 import java.io.OutputStream; | |
| 15 import java.text.SimpleDateFormat; | |
| 16 import java.util.ArrayList; | |
| 17 import java.util.Date; | |
| 18 import java.util.List; | |
| 19 import java.util.logging.Level; | |
| 20 import java.util.logging.Logger; | |
| 21 import javax.ejb.EJB; | |
| 22 import javax.ejb.EJBException; | |
| 23 import javax.ejb.Stateless; | |
| 24 import javax.ejb.TransactionAttribute; | |
| 25 import javax.ejb.TransactionAttributeType; | |
| 26 import javax.inject.Named; | |
| 27 import javax.persistence.EntityManager; | |
| 28 import javax.persistence.PersistenceContext; | |
| 29 import javax.persistence.Query; | |
| 30 import javax.persistence.TypedQuery; | |
| 31 import javax.xml.stream.XMLOutputFactory; | |
| 32 import javax.xml.stream.XMLStreamException; | |
| 33 import javax.xml.stream.XMLStreamWriter; | |
| 34 import org.apache.commons.lang.RandomStringUtils; | |
| 35 | |
| 36 /** | |
| 37 * | |
| 38 * @author skraffmiller | |
| 39 */ | |
| 40 @Stateless | |
| 41 @Named | |
| 42 public class DatasetServiceBean implements java.io.Serializable { | |
| 43 | |
| 44 private static final Logger logger = Logger.getLogger(DatasetServiceBean.class.getCanonicalName()); | |
| 45 @EJB | |
| 46 IndexServiceBean indexService; | |
| 47 | |
| 48 @EJB | |
| 49 DOIEZIdServiceBean doiEZIdServiceBean; | |
| 50 | |
| 51 @EJB | |
| 52 SettingsServiceBean settingsService; | |
| 53 | |
| 54 @EJB | |
| 55 DatasetVersionServiceBean versionService; | |
| 56 | |
| 57 @EJB | |
| 58 AuthenticationServiceBean authentication; | |
| 59 | |
| 60 @EJB | |
| 61 DataFileServiceBean fileService; | |
| 62 | |
| 63 @PersistenceContext(unitName = "VDCNet-ejbPU") | |
| 64 private EntityManager em; | |
| 65 | |
| 66 public Dataset find(Object pk) { | |
| 67 return em.find(Dataset.class, pk); | |
| 68 } | |
| 69 | |
| 70 public List<Dataset> findByOwnerId(Long ownerId) { | |
| 71 return findByOwnerId(ownerId, false); | |
| 72 } | |
| 73 | |
| 74 public List<Dataset> findPublishedByOwnerId(Long ownerId) { | |
| 75 return findByOwnerId(ownerId, true); | |
| 76 } | |
| 77 | |
| 78 private List<Dataset> findByOwnerId(Long ownerId, boolean onlyPublished) { | |
| 79 List<Dataset> retList = new ArrayList(); | |
| 80 TypedQuery<Dataset> query = em.createQuery("select object(o) from Dataset as o where o.owner.id =:ownerId order by o.id", Dataset.class); | |
| 81 query.setParameter("ownerId", ownerId); | |
| 82 if (!onlyPublished) { | |
| 83 return query.getResultList(); | |
| 84 } else { | |
| 85 for (Dataset ds : query.getResultList()) { | |
| 86 if (ds.isReleased() && !ds.isDeaccessioned()) { | |
| 87 retList.add(ds); | |
| 88 } | |
| 89 } | |
| 90 return retList; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 public List<Dataset> findAll() { | |
| 95 return em.createQuery("select object(o) from Dataset as o order by o.id").getResultList(); | |
| 96 } | |
| 97 | |
| 98 /** | |
| 99 * For docs, see the equivalent method on the DataverseServiceBean. | |
| 100 * @see DataverseServiceBean#findAllOrSubset(long, long) | |
| 101 */ | |
| 102 public List<Dataset> findAllOrSubset(long numPartitions, long partitionId, boolean skipIndexed) { | |
| 103 if (numPartitions < 1) { | |
| 104 long saneNumPartitions = 1; | |
| 105 numPartitions = saneNumPartitions; | |
| 106 } | |
| 107 String skipClause = skipIndexed ? "AND o.indexTime is null " : ""; | |
| 108 TypedQuery<Dataset> typedQuery = em.createQuery("SELECT OBJECT(o) FROM Dataset AS o WHERE MOD( o.id, :numPartitions) = :partitionId " + | |
| 109 skipClause + | |
| 110 "ORDER BY o.id", Dataset.class); | |
| 111 typedQuery.setParameter("numPartitions", numPartitions); | |
| 112 typedQuery.setParameter("partitionId", partitionId); | |
| 113 return typedQuery.getResultList(); | |
| 114 } | |
| 115 | |
| 116 public Dataset findByGlobalId(String globalId) { | |
| 117 | |
| 118 String protocol = ""; | |
| 119 String authority = ""; | |
| 120 String identifier = ""; | |
| 121 int index1 = globalId.indexOf(':'); | |
| 122 String nonNullDefaultIfKeyNotFound = ""; | |
| 123 String separator = settingsService.getValueForKey(SettingsServiceBean.Key.DoiSeparator, nonNullDefaultIfKeyNotFound); | |
| 124 int index2 = globalId.indexOf(separator, index1 + 1); | |
| 125 int index3 = 0; | |
| 126 if (index1 == -1) { | |
| 127 throw new EJBException("Error parsing identifier: " + globalId + ". ':' not found in string"); | |
| 128 } else { | |
| 129 protocol = globalId.substring(0, index1); | |
| 130 } | |
| 131 if (index2 == -1 ) { | |
| 132 throw new EJBException("Error parsing identifier: " + globalId + ". Second separator not found in string"); | |
| 133 } else { | |
| 134 if (index2 != -1) { | |
| 135 authority = globalId.substring(index1 + 1, index2); | |
| 136 } | |
| 137 } | |
| 138 if (protocol.equals("doi")) { | |
| 139 | |
| 140 index3 = globalId.indexOf(separator, index2 + 1); | |
| 141 if (index3 == -1 ) { | |
| 142 identifier = globalId.substring(index2 + 1).toUpperCase(); | |
| 143 } else { | |
| 144 if (index3 > -1) { | |
| 145 authority = globalId.substring(index1 + 1, index3); | |
| 146 identifier = globalId.substring(index3 + 1).toUpperCase(); | |
| 147 } | |
| 148 } | |
| 149 } else { | |
| 150 identifier = globalId.substring(index2 + 1).toUpperCase(); | |
| 151 } | |
| 152 String queryStr = "SELECT s from Dataset s where s.identifier = :identifier and s.protocol= :protocol and s.authority= :authority"; | |
| 153 Dataset foundDataset = null; | |
| 154 try { | |
| 155 Query query = em.createQuery(queryStr); | |
| 156 query.setParameter("identifier", identifier); | |
| 157 query.setParameter("protocol", protocol); | |
| 158 query.setParameter("authority", authority); | |
| 159 foundDataset = (Dataset) query.getSingleResult(); | |
| 160 } catch (javax.persistence.NoResultException e) { | |
| 161 logger.info("no ds found: " + globalId); | |
| 162 // DO nothing, just return null. | |
| 163 } | |
| 164 return foundDataset; | |
| 165 } | |
| 166 | |
| 167 public String generateIdentifierSequence(String protocol, String authority, String separator) { | |
| 168 | |
| 169 String identifier = null; | |
| 170 do { | |
| 171 identifier = RandomStringUtils.randomAlphanumeric(6).toUpperCase(); | |
| 172 } while (!isUniqueIdentifier(identifier, protocol, authority, separator)); | |
| 173 | |
| 174 return identifier; | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * Check that a identifier entered by the user is unique (not currently used | |
| 179 * for any other study in this Dataverse Network) alos check for duplicate | |
| 180 * in EZID if needed | |
| 181 */ | |
| 182 public boolean isUniqueIdentifier(String userIdentifier, String protocol, String authority, String separator) { | |
| 183 String query = "SELECT d FROM Dataset d WHERE d.identifier = '" + userIdentifier + "'"; | |
| 184 query += " and d.protocol ='" + protocol + "'"; | |
| 185 query += " and d.authority = '" + authority + "'"; | |
| 186 boolean u = em.createQuery(query).getResultList().size() == 0; | |
| 187 String nonNullDefaultIfKeyNotFound = ""; | |
| 188 String doiProvider = settingsService.getValueForKey(SettingsServiceBean.Key.DoiProvider, nonNullDefaultIfKeyNotFound); | |
| 189 if (doiProvider.equals("EZID")) { | |
| 190 if (!doiEZIdServiceBean.lookupMetadataFromIdentifier(protocol, authority, separator, userIdentifier).isEmpty()) { | |
| 191 u = false; | |
| 192 } | |
| 193 } | |
| 194 return u; | |
| 195 } | |
| 196 | |
| 197 public String createCitationRIS(DatasetVersion version) { | |
| 198 return createCitationRIS(version, null); | |
| 199 } | |
| 200 | |
| 201 public String createCitationRIS(DatasetVersion version, FileMetadata fileMetadata) { | |
| 202 String publisher = version.getRootDataverseNameforCitation(); | |
| 203 List<DatasetAuthor> authorList = version.getDatasetAuthors(); | |
| 204 String retString = "Provider: " + publisher + "\r\n"; | |
| 205 retString += "Content: text/plain; charset=\"us-ascii\"" + "\r\n"; | |
| 206 // Using type "DBASE" - "Online Database", for consistency with | |
| 207 // EndNote (see the longer comment in the EndNote section below)> | |
| 208 | |
| 209 retString += "TY - DBASE" + "\r\n"; | |
| 210 retString += "T1 - " + version.getTitle() + "\r\n"; | |
| 211 for (DatasetAuthor author : authorList) { | |
| 212 retString += "AU - " + author.getName().getDisplayValue() + "\r\n"; | |
| 213 } | |
| 214 retString += "DO - " + version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier() + "\r\n"; | |
| 215 retString += "PY - " + version.getVersionYear() + "\r\n"; | |
| 216 retString += "UR - " + version.getDataset().getPersistentURL() + "\r\n"; | |
| 217 retString += "PB - " + publisher + "\r\n"; | |
| 218 | |
| 219 // a DataFile citation also includes filename und UNF, if applicable: | |
| 220 if (fileMetadata != null) { | |
| 221 retString += "C1 - " + fileMetadata.getLabel() + "\r\n"; | |
| 222 | |
| 223 if (fileMetadata.getDataFile().isTabularData()) { | |
| 224 if (fileMetadata.getDataFile().getUnf() != null) { | |
| 225 retString += "C2 - " + fileMetadata.getDataFile().getUnf() + "\r\n"; | |
| 226 } | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 // closing element: | |
| 231 retString += "ER - \r\n"; | |
| 232 | |
| 233 return retString; | |
| 234 } | |
| 235 | |
| 236 private XMLOutputFactory xmlOutputFactory = null; | |
| 237 | |
| 238 public String createCitationXML(DatasetVersion datasetVersion, FileMetadata fileMetadata) { | |
| 239 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); | |
| 240 createEndNoteCitation(outStream, datasetVersion, fileMetadata); | |
| 241 String xml = outStream.toString(); | |
| 242 return xml; | |
| 243 } | |
| 244 | |
| 245 public void createEndNoteCitation(OutputStream os, DatasetVersion datasetVersion, FileMetadata fileMetadata) { | |
| 246 | |
| 247 xmlOutputFactory = javax.xml.stream.XMLOutputFactory.newInstance(); | |
| 248 XMLStreamWriter xmlw = null; | |
| 249 try { | |
| 250 xmlw = xmlOutputFactory.createXMLStreamWriter(os); | |
| 251 xmlw.writeStartDocument(); | |
| 252 createEndNoteXML(xmlw, datasetVersion, fileMetadata); | |
| 253 xmlw.writeEndDocument(); | |
| 254 } catch (XMLStreamException ex) { | |
| 255 Logger.getLogger("global").log(Level.SEVERE, null, ex); | |
| 256 throw new EJBException("ERROR occurred during creating endnote xml.", ex); | |
| 257 } finally { | |
| 258 try { | |
| 259 if (xmlw != null) { | |
| 260 xmlw.close(); | |
| 261 } | |
| 262 } catch (XMLStreamException ex) { | |
| 263 } | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 private void createEndNoteXML(XMLStreamWriter xmlw, DatasetVersion version, FileMetadata fileMetadata) throws XMLStreamException { | |
| 268 | |
| 269 String title = version.getTitle(); | |
| 270 String versionYear = version.getVersionYear(); | |
| 271 String publisher = version.getRootDataverseNameforCitation(); | |
| 272 | |
| 273 List<DatasetAuthor> authorList = version.getDatasetAuthors(); | |
| 274 | |
| 275 xmlw.writeStartElement("xml"); | |
| 276 xmlw.writeStartElement("records"); | |
| 277 | |
| 278 xmlw.writeStartElement("record"); | |
| 279 | |
| 280 // "Ref-type" indicates which of the (numerous!) available EndNote | |
| 281 // schemas this record will be interpreted as. | |
| 282 // This is relatively important. Certain fields with generic | |
| 283 // names like "custom1" and "custom2" become very specific things | |
| 284 // in specific schemas; for example, custom1 shows as "legal notice" | |
| 285 // in "Journal Article" (ref-type 84), or as "year published" in | |
| 286 // "Government Document". | |
| 287 // We don't want the UNF to show as a "legal notice"! | |
| 288 // We have found a ref-type that works ok for our purposes - | |
| 289 // "Online Database" (type 45). In this one, the fields Custom1 | |
| 290 // and Custom2 are not translated and just show as is. | |
| 291 // And "Custom1" still beats "legal notice". | |
| 292 // -- L.A. 12.12.2014 beta 10 | |
| 293 | |
| 294 xmlw.writeStartElement("ref-type"); | |
| 295 xmlw.writeAttribute("name", "Online Database"); | |
| 296 xmlw.writeCharacters("45"); | |
| 297 xmlw.writeEndElement(); // ref-type | |
| 298 | |
| 299 xmlw.writeStartElement("contributors"); | |
| 300 xmlw.writeStartElement("authors"); | |
| 301 for (DatasetAuthor author : authorList) { | |
| 302 xmlw.writeStartElement("author"); | |
| 303 xmlw.writeCharacters(author.getName().getDisplayValue()); | |
| 304 xmlw.writeEndElement(); // author | |
| 305 } | |
| 306 xmlw.writeEndElement(); // authors | |
| 307 xmlw.writeEndElement(); // contributors | |
| 308 | |
| 309 xmlw.writeStartElement("titles"); | |
| 310 xmlw.writeStartElement("title"); | |
| 311 xmlw.writeCharacters(title); | |
| 312 xmlw.writeEndElement(); // title | |
| 313 | |
| 314 xmlw.writeEndElement(); // titles | |
| 315 | |
| 316 xmlw.writeStartElement("section"); | |
| 317 String sectionString = ""; | |
| 318 if (version.getDataset().isReleased()) { | |
| 319 sectionString = new SimpleDateFormat("yyyy-MM-dd").format(version.getDataset().getPublicationDate()); | |
| 320 } else { | |
| 321 sectionString = new SimpleDateFormat("yyyy-MM-dd").format(version.getLastUpdateTime()); | |
| 322 } | |
| 323 | |
| 324 xmlw.writeCharacters(sectionString); | |
| 325 xmlw.writeEndElement(); // publisher | |
| 326 | |
| 327 xmlw.writeStartElement("dates"); | |
| 328 xmlw.writeStartElement("year"); | |
| 329 xmlw.writeCharacters(versionYear); | |
| 330 xmlw.writeEndElement(); // year | |
| 331 xmlw.writeEndElement(); // dates | |
| 332 | |
| 333 xmlw.writeStartElement("publisher"); | |
| 334 xmlw.writeCharacters(publisher); | |
| 335 xmlw.writeEndElement(); // publisher | |
| 336 | |
| 337 xmlw.writeStartElement("urls"); | |
| 338 xmlw.writeStartElement("related-urls"); | |
| 339 xmlw.writeStartElement("url"); | |
| 340 xmlw.writeCharacters(version.getDataset().getPersistentURL()); | |
| 341 xmlw.writeEndElement(); // url | |
| 342 xmlw.writeEndElement(); // related-urls | |
| 343 xmlw.writeEndElement(); // urls | |
| 344 | |
| 345 // a DataFile citation also includes the filename and (for Tabular | |
| 346 // files) the UNF signature, that we put into the custom1 and custom2 | |
| 347 // fields respectively: | |
| 348 | |
| 349 | |
| 350 if (fileMetadata != null) { | |
| 351 xmlw.writeStartElement("custom1"); | |
| 352 xmlw.writeCharacters(fileMetadata.getLabel()); | |
| 353 xmlw.writeEndElement(); // custom1 | |
| 354 | |
| 355 if (fileMetadata.getDataFile().isTabularData()) { | |
| 356 if (fileMetadata.getDataFile().getUnf() != null) { | |
| 357 xmlw.writeStartElement("custom2"); | |
| 358 xmlw.writeCharacters(fileMetadata.getDataFile().getUnf()); | |
| 359 xmlw.writeEndElement(); // custom2 | |
| 360 } | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 xmlw.writeStartElement("electronic-resource-num"); | |
| 365 String electResourceNum = version.getDataset().getProtocol() + "/" + version.getDataset().getAuthority() + version.getDataset().getDoiSeparator() + version.getDataset().getIdentifier(); | |
| 366 xmlw.writeCharacters(electResourceNum); | |
| 367 xmlw.writeEndElement(); | |
| 368 //<electronic-resource-num>10.3886/ICPSR03259.v1</electronic-resource-num> | |
| 369 xmlw.writeEndElement(); // record | |
| 370 | |
| 371 xmlw.writeEndElement(); // records | |
| 372 xmlw.writeEndElement(); // xml | |
| 373 | |
| 374 } | |
| 375 | |
| 376 public DatasetVersionUser getDatasetVersionUser(DatasetVersion version, User user) { | |
| 377 | |
| 378 DatasetVersionUser ddu = null; | |
| 379 Query query = em.createQuery("select object(o) from DatasetVersionUser as o " | |
| 380 + "where o.datasetVersion.id =:versionId and o.authenticatedUser.id =:userId"); | |
| 381 query.setParameter("versionId", version.getId()); | |
| 382 String identifier = user.getIdentifier(); | |
| 383 identifier = identifier.startsWith("@") ? identifier.substring(1) : identifier; | |
| 384 AuthenticatedUser au = authentication.getAuthenticatedUser(identifier); | |
| 385 query.setParameter("userId", au.getId()); | |
| 386 try { | |
| 387 ddu = (DatasetVersionUser) query.getSingleResult(); | |
| 388 } catch (javax.persistence.NoResultException e) { | |
| 389 // DO nothing, just return null. | |
| 390 } | |
| 391 return ddu; | |
| 392 } | |
| 393 | |
| 394 public List<DatasetLock> getDatasetLocks() { | |
| 395 String query = "SELECT sl FROM DatasetLock sl"; | |
| 396 return (List<DatasetLock>) em.createQuery(query).getResultList(); | |
| 397 } | |
| 398 | |
| 399 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) | |
| 400 public void addDatasetLock(Long datasetId, Long userId, String info) { | |
| 401 | |
| 402 Dataset dataset = em.find(Dataset.class, datasetId); | |
| 403 DatasetLock lock = new DatasetLock(); | |
| 404 lock.setDataset(dataset); | |
| 405 lock.setInfo(info); | |
| 406 lock.setStartTime(new Date()); | |
| 407 | |
| 408 if (userId != null) { | |
| 409 AuthenticatedUser user = em.find(AuthenticatedUser.class, userId); | |
| 410 lock.setUser(user); | |
| 411 if (user.getDatasetLocks() == null) { | |
| 412 user.setDatasetLocks(new ArrayList()); | |
| 413 } | |
| 414 user.getDatasetLocks().add(lock); | |
| 415 } | |
| 416 | |
| 417 dataset.setDatasetLock(lock); | |
| 418 em.persist(lock); | |
| 419 } | |
| 420 | |
| 421 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) | |
| 422 public void removeDatasetLock(Long datasetId) { | |
| 423 Dataset dataset = em.find(Dataset.class, datasetId); | |
| 424 //em.refresh(dataset); (?) | |
| 425 DatasetLock lock = dataset.getDatasetLock(); | |
| 426 if (lock != null) { | |
| 427 AuthenticatedUser user = lock.getUser(); | |
| 428 dataset.setDatasetLock(null); | |
| 429 user.getDatasetLocks().remove(lock); | |
| 430 /* | |
| 431 * TODO - ? | |
| 432 * throw an exception if for whatever reason we can't remove the lock? | |
| 433 try { | |
| 434 */ | |
| 435 em.remove(lock); | |
| 436 /* | |
| 437 } catch (TransactionRequiredException te) { | |
| 438 ... | |
| 439 } catch (IllegalArgumentException iae) { | |
| 440 ... | |
| 441 } | |
| 442 */ | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 | |
| 447 public boolean isDatasetCardImageAvailable(DatasetVersion datasetVersion, User user) { | |
| 448 if (datasetVersion == null) { | |
| 449 return false; | |
| 450 } | |
| 451 | |
| 452 // First, check if this dataset has a designated thumbnail image: | |
| 453 | |
| 454 if (datasetVersion.getDataset() != null) { | |
| 455 DataFile dataFile = datasetVersion.getDataset().getThumbnailFile(); | |
| 456 if (dataFile != null) { | |
| 457 return ImageThumbConverter.isThumbnailAvailable(dataFile, 48); | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 // If not, we'll try to use one of the files in this dataset version: | |
| 462 // (the first file with an available thumbnail, really) | |
| 463 | |
| 464 List<FileMetadata> fileMetadatas = datasetVersion.getFileMetadatas(); | |
| 465 | |
| 466 for (FileMetadata fileMetadata : fileMetadatas) { | |
| 467 DataFile dataFile = fileMetadata.getDataFile(); | |
| 468 | |
| 469 if (fileService.isThumbnailAvailable(dataFile, user)) { | |
| 470 return true; | |
| 471 } | |
| 472 | |
| 473 } | |
| 474 | |
| 475 return false; | |
| 476 } | |
| 477 } |
