comparison src/main/java/edu/harvard/iq/dataverse/DataFile.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 package edu.harvard.iq.dataverse;
2
3 import edu.harvard.iq.dataverse.DatasetVersion.VersionState;
4 import edu.harvard.iq.dataverse.api.WorldMapRelatedData;
5 import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
6 import edu.harvard.iq.dataverse.dataaccess.DataAccess;
7 import edu.harvard.iq.dataverse.dataaccess.DataAccessObject;
8 import edu.harvard.iq.dataverse.ingest.IngestReport;
9 import edu.harvard.iq.dataverse.ingest.IngestRequest;
10 import edu.harvard.iq.dataverse.util.FileUtil;
11 import edu.harvard.iq.dataverse.util.ShapefileHandler;
12 import java.io.IOException;
13 import java.util.List;
14 import java.util.ArrayList;
15 import java.util.Objects;
16 import java.nio.file.Path;
17 import java.nio.file.Paths;
18 import java.nio.file.Files;
19 import javax.persistence.Entity;
20 import javax.persistence.OneToMany;
21 import javax.persistence.OneToOne;
22 import javax.persistence.CascadeType;
23 import javax.persistence.Column;
24 import javax.persistence.JoinColumn;
25 import javax.persistence.JoinTable;
26 import javax.persistence.ManyToMany;
27 import javax.persistence.NamedQueries;
28 import javax.persistence.NamedQuery;
29 import javax.validation.constraints.Pattern;
30 import org.hibernate.validator.constraints.NotBlank;
31
32 /**
33 *
34 * @author gdurand
35 */
36 @NamedQueries({
37 @NamedQuery( name="DataFile.removeFromDatasetVersion",
38 query="DELETE FROM FileMetadata f WHERE f.datasetVersion.id=:versionId and f.dataFile.id=:fileId")
39 })
40 @Entity
41 public class DataFile extends DvObject {
42 private static final long serialVersionUID = 1L;
43
44 public static final char INGEST_STATUS_NONE = 65;
45 public static final char INGEST_STATUS_SCHEDULED = 66;
46 public static final char INGEST_STATUS_INPROGRESS = 67;
47 public static final char INGEST_STATUS_ERROR = 68;
48
49 private String name;
50
51 @NotBlank
52 @Column( nullable = false )
53 @Pattern(regexp = "^.*/.*$", message = "Content-Type must contain a slash")
54 private String contentType;
55
56 @Column( nullable = false )
57 private String fileSystemName;
58
59 @Column( nullable = false )
60 private String md5;
61
62 @Column(nullable=true)
63 private Long filesize; // Number of bytes in file. Allows 0 and null, negative numbers not permitted
64
65 private boolean restricted;
66
67 /*
68 Tabular (formerly "subsettable") data files have DataTable objects
69 associated with them:
70 */
71
72 @OneToMany(mappedBy = "dataFile", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
73 private List<DataTable> dataTables;
74
75 @OneToMany(mappedBy = "dataFile", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
76 private List<IngestReport> ingestReports;
77
78 @OneToOne(mappedBy = "dataFile", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
79 private IngestRequest ingestRequest;
80
81 @OneToMany(mappedBy = "dataFile", orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
82 private List<DataFileTag> dataFileTags;
83
84 @OneToMany(mappedBy="dataFile", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
85 private List<FileMetadata> fileMetadatas;
86
87 @OneToMany(mappedBy="dataFile", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST})
88 private List<GuestbookResponse> guestbookResponses;
89
90 public List<GuestbookResponse> getGuestbookResponses() {
91 return guestbookResponses;
92 }
93
94 public void setGuestbookResponses(List<GuestbookResponse> guestbookResponses) {
95 this.guestbookResponses = guestbookResponses;
96 }
97
98 private char ingestStatus = INGEST_STATUS_NONE;
99
100 @OneToOne(mappedBy = "thumbnailFile")
101 private Dataset thumbnailForDataset;
102
103
104 public DataFile() {
105 this.fileMetadatas = new ArrayList<>();
106 }
107
108 public DataFile(String contentType) {
109 this.contentType = contentType;
110 this.fileMetadatas = new ArrayList<>();
111 }
112
113 // The dvObject field "name" should not be used in
114 // datafile objects.
115 // The file name must be stored in the file metadata.
116 @Deprecated
117 public DataFile(String name, String contentType) {
118 this.name = name;
119 this.contentType = contentType;
120 this.fileMetadatas = new ArrayList<>();
121 }
122
123 @Override
124 public boolean isEffectivelyPermissionRoot() {
125 return false;
126 }
127
128 public List<DataTable> getDataTables() {
129 return dataTables;
130 }
131
132 public void setDataTables(List<DataTable> dataTables) {
133 this.dataTables = dataTables;
134 }
135
136 public DataTable getDataTable() {
137 if ( getDataTables() != null && getDataTables().size() > 0 ) {
138 return getDataTables().get(0);
139 } else {
140 return null;
141 }
142 }
143
144 public void setDataTable(DataTable dt) {
145 if (this.getDataTables() == null) {
146 this.setDataTables( new ArrayList() );
147 } else {
148 this.getDataTables().clear();
149 }
150
151 this.getDataTables().add(dt);
152 }
153
154 public List<DataFileTag> getTags() {
155 return dataFileTags;
156 }
157
158 public void setTags(List<DataFileTag> dataFileTags) {
159 this.dataFileTags = dataFileTags;
160 }
161
162 public void addTag(DataFileTag tag) {
163 if (dataFileTags == null) {
164 dataFileTags = new ArrayList<>();
165 }
166
167 dataFileTags.add(tag);
168 }
169
170 public List<FileMetadata> getFileMetadatas() {
171 return fileMetadatas;
172 }
173
174 public void setFileMetadatas(List<FileMetadata> fileMetadatas) {
175 this.fileMetadatas = fileMetadatas;
176 }
177
178 public IngestReport getIngestReport() {
179 if ( ingestReports != null && ingestReports.size() > 0 ) {
180 return ingestReports.get(0);
181 } else {
182 return null;
183 }
184 }
185
186 public void setIngestReport(IngestReport report) {
187 if (ingestReports == null) {
188 ingestReports = new ArrayList();
189 } else {
190 ingestReports.clear();
191 }
192
193 ingestReports.add(report);
194 }
195
196 public IngestRequest getIngestRequest() {
197 return ingestRequest;
198 }
199
200 public void setIngestRequest(IngestRequest ingestRequest) {
201 this.ingestRequest = ingestRequest;
202 }
203
204 public String getIngestReportMessage() {
205 if ( ingestReports != null && ingestReports.size() > 0 ) {
206 if (ingestReports.get(0).getReport() != null && !"".equals(ingestReports.get(0).getReport())) {
207 return ingestReports.get(0).getReport();
208 }
209 }
210 return "Ingest failed. No further information is available.";
211 }
212 public boolean isTabularData() {
213 return getDataTables() != null && getDataTables().size() > 0;
214 }
215
216 public String getOriginalFileFormat() {
217 if (isTabularData()) {
218 DataTable dataTable = getDataTable();
219 if (dataTable != null) {
220 return dataTable.getOriginalFileFormat();
221 }
222 }
223 return null;
224 }
225
226 /*
227 * A user-friendly version of the "original format":
228 */
229 public String getOriginalFormatLabel() {
230 return FileUtil.getUserFriendlyOriginalType(this);
231 }
232
233 // The dvObject field "name" should not be used in
234 // datafile objects.
235 // The file name must be stored in the file metadata.
236 @Deprecated
237 public String getName() {
238 return name;
239 }
240
241 @Deprecated
242 public void setName(String name) {
243 this.name = name;
244 }
245
246 public String getContentType() {
247 return contentType;
248 }
249
250 public void setContentType(String contentType) {
251 this.contentType = contentType;
252 }
253
254 public String getFriendlyType() {
255 return FileUtil.getUserFriendlyFileType(this);
256 }
257
258 @Override
259 public Dataset getOwner() {
260 return (Dataset) super.getOwner();
261 }
262
263 public void setOwner(Dataset dataset) {
264 super.setOwner(dataset);
265 }
266
267 public String getFileSystemName() {
268 return this.fileSystemName;
269 }
270
271 public void setFileSystemName(String fileSystemName) {
272 this.fileSystemName = fileSystemName;
273 }
274
275 public String getDescription() {
276 FileMetadata fmd = getLatestFileMetadata();
277
278 if (fmd == null) {
279 return null;
280 }
281 return fmd.getDescription();
282 }
283
284 public void setDescription(String description) {
285 FileMetadata fmd = getLatestFileMetadata();
286
287 if (fmd != null) {
288 fmd.setDescription(description);
289 }
290 }
291
292 public FileMetadata getFileMetadata() {
293 return getLatestFileMetadata();
294 }
295
296 private FileMetadata getLatestFileMetadata() {
297 FileMetadata fmd = null;
298
299 // for newly added or harvested, just return the one fmd
300 if (fileMetadatas.size() == 1) {
301 return fileMetadatas.get(0);
302 }
303
304 for (FileMetadata fileMetadata : fileMetadatas) {
305 // if it finds a draft, return it
306 if (fileMetadata.getDatasetVersion().getVersionState().equals(VersionState.DRAFT)) {
307 return fileMetadata;
308 }
309
310 // otherwise return the one with the latest version number
311 if (fmd == null || fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber() ) > 0 ) {
312 fmd = fileMetadata;
313 } else if ((fileMetadata.getDatasetVersion().getVersionNumber().compareTo( fmd.getDatasetVersion().getVersionNumber())==0 )&&
314 ( fileMetadata.getDatasetVersion().getMinorVersionNumber().compareTo( fmd.getDatasetVersion().getMinorVersionNumber()) > 0 ) )
315 fmd = fileMetadata;
316 }
317 return fmd;
318 }
319
320 /**
321 * Get property filesize, number of bytes
322 * @return value of property filesize.
323 */
324 public long getFilesize() {
325 if (this.filesize == null) {
326 // -1 means "unknown"
327 return -1;
328 }
329 return this.filesize;
330 }
331
332 /**
333 * Set property filesize in bytes
334 *
335 * Allow nulls, but not negative numbers.
336 *
337 * @param filesize new value of property filesize.
338 */
339 public void setFilesize(long filesize) {
340 if (filesize < 0){
341 return;
342 }
343 this.filesize = filesize;
344 }
345
346 /**
347 * Converts the stored size of the file in bytes to
348 * a user-friendly value in KB, MB or GB.
349 */
350 public String getFriendlySize() {
351 return FileUtil.getFriendlySize(filesize);
352 }
353
354 public boolean isRestricted() {
355 return restricted;
356 }
357
358 public void setRestricted(boolean restricted) {
359 this.restricted = restricted;
360 }
361
362
363 public String getmd5() {
364 return this.md5;
365 }
366
367 public void setmd5(String md5) {
368 this.md5 = md5;
369 }
370
371 public Path getFileSystemLocation() {
372 // TEMPORARY HACK!
373 // (only used in batch ingest testing -- L.A. 4.0 beta)
374 if (this.fileSystemName != null && this.fileSystemName.startsWith("/")) {
375 return Paths.get(this.fileSystemName);
376 }
377
378 Path studyDirectoryPath = this.getOwner().getFileSystemDirectory();
379 if (studyDirectoryPath == null) {
380 return null;
381 }
382 String studyDirectory = studyDirectoryPath.toString();
383
384 return Paths.get(studyDirectory, this.fileSystemName);
385 }
386
387 public DataAccessObject getAccessObject() throws IOException {
388 DataAccessObject dataAccess = DataAccess.createDataAccessObject(this);
389
390 if (dataAccess == null) {
391 throw new IOException("Failed to create access object for datafile.");
392 }
393
394 return dataAccess;
395 }
396
397 public Path getSavedOriginalFile() {
398
399 if (!this.isTabularData() || this.fileSystemName == null) {
400 return null;
401 }
402
403 Path studyDirectoryPath = this.getOwner().getFileSystemDirectory();
404 if (studyDirectoryPath == null) {
405 return null;
406 }
407 String studyDirectory = studyDirectoryPath.toString();
408
409 Path savedOriginal = Paths.get(studyDirectory, "_" + this.fileSystemName);
410 if (Files.exists(savedOriginal)) {
411 return savedOriginal;
412 }
413 return null;
414 }
415
416 public String getFilename() {
417 String studyDirectory = this.getOwner().getFileSystemDirectory().toString();
418
419 if (studyDirectory == null || this.fileSystemName == null || this.fileSystemName.equals("")) {
420 return null;
421 }
422 String fileSystemPath = studyDirectory + "/" + this.fileSystemName;
423 return fileSystemPath.replaceAll("/", "%2F");
424 }
425
426 /*
427 Does the contentType indicate a shapefile?
428 */
429 public boolean isShapefileType(){
430 if (this.contentType==null){
431 return false;
432 }
433 return ShapefileHandler.SHAPEFILE_FILE_TYPE.equalsIgnoreCase(this.contentType);
434 }
435
436 public boolean isImage() {
437 // Some browsers (Chrome?) seem to identify FITS files as mime
438 // type "image/fits" on upload; this is both incorrect (the official
439 // mime type for FITS is "application/fits", and problematic: then
440 // the file is identified as an image, and the page will attempt to
441 // generate a preview - which of course is going to fail...
442 if ("image/fits".equalsIgnoreCase(contentType)) {
443 return false;
444 }
445 // a pdf file is an "image" for practical purposes (we will attempt to
446 // generate thumbnails and previews for them)
447 return (contentType != null && (contentType.startsWith("image/") || contentType.equalsIgnoreCase("application/pdf")));
448 }
449
450 public boolean isIngestScheduled() {
451 return (ingestStatus == INGEST_STATUS_SCHEDULED);
452 }
453
454 public boolean isIngestInProgress() {
455 return ((ingestStatus == INGEST_STATUS_SCHEDULED) || (ingestStatus == INGEST_STATUS_INPROGRESS));
456 }
457
458 public boolean isIngestProblem() {
459 return (ingestStatus == INGEST_STATUS_ERROR);
460 }
461
462 public void SetIngestScheduled() {
463 ingestStatus = INGEST_STATUS_SCHEDULED;
464 }
465
466 public void SetIngestInProgress() {
467 ingestStatus = INGEST_STATUS_INPROGRESS;
468 }
469
470 public void SetIngestProblem() {
471 ingestStatus = INGEST_STATUS_ERROR;
472 }
473
474 public void setIngestDone() {
475 ingestStatus = INGEST_STATUS_NONE;
476 }
477
478 public int getIngestStatus() {
479 return ingestStatus;
480 }
481
482 public Dataset getThumbnailForDataset() {
483 return thumbnailForDataset;
484 }
485
486 public void setAsThumbnailForDataset(Dataset dataset) {
487 thumbnailForDataset = dataset;
488 }
489
490 /**
491 * URL to use with the WorldMapRelatedData API
492 * Used within dataset.xhtml
493 *
494 * @param dataverseUserID
495 * @return URL for "Map It" functionality
496 */
497 public String getMapItURL(Long dataverseUserID){
498 if (dataverseUserID==null){
499 return null;
500 }
501 return WorldMapRelatedData.getMapItURL(this.getId(), dataverseUserID);
502 }
503
504 /*
505 8/10/2014 - Using the current "open access" url
506 */
507 public String getMapItFileDownloadURL(String serverName){
508 if ((this.getId() == null)||(serverName == null)){
509 return null;
510 }
511 return serverName + "/api/access/datafile/" + this.getId();
512 }
513
514 /*
515 * If this is tabular data, the corresponding dataTable may have a UNF -
516 * "numeric fingerprint" signature - generated:
517 */
518
519 public String getUnf() {
520 if (this.isTabularData()) {
521 // (isTabularData() method above verifies that that this file
522 // has a datDatable associated with it, so the line below is
523 // safe, in terms of a NullPointerException:
524 return this.getDataTable().getUnf();
525 }
526 return null;
527 }
528
529
530 @ManyToMany
531 @JoinTable(name = "fileaccessrequests",
532 joinColumns = @JoinColumn(name = "datafile_id"),
533 inverseJoinColumns = @JoinColumn(name = "authenticated_user_id"))
534 private List<AuthenticatedUser> fileAccessRequesters;
535
536 public List<AuthenticatedUser> getFileAccessRequesters() {
537 return fileAccessRequesters;
538 }
539
540 public void setFileAccessRequesters(List<AuthenticatedUser> fileAccessRequesters) {
541 this.fileAccessRequesters = fileAccessRequesters;
542 }
543
544
545 public boolean isHarvested() {
546 // TODO:
547 // alternatively, we can determine whether this is a harvested file
548 // by looking at the storage identifier of the physical file;
549 // if it's something that's not a filesystem path (URL, etc.) -
550 // then it's a harvested object.
551 // -- L.A. 4.0
552 Dataset ownerDataset = this.getOwner();
553 if (ownerDataset != null) {
554 return ownerDataset.isHarvested();
555 }
556 return false;
557 }
558
559 public String getRemoteArchiveURL() {
560 if (isHarvested()) {
561 Dataset ownerDataset = this.getOwner();
562 return ownerDataset.getRemoteArchiveURL();
563 }
564
565 return null;
566 }
567
568 public String getHarvestingDescription() {
569 if (isHarvested()) {
570 Dataset ownerDataset = this.getOwner();
571 return ownerDataset.getHarvestingDescription();
572 }
573
574 return null;
575 }
576
577 @Override
578 public boolean equals(Object object) {
579 if (!(object instanceof DataFile)) {
580 return false;
581 }
582 DataFile other = (DataFile) object;
583 return Objects.equals(getId(), other.getId());
584 }
585
586 @Override
587 public int hashCode() {
588 return super.hashCode();
589 }
590
591 @Override
592 protected String toStringExtras() {
593 return "name:" + getName();
594 }
595
596 @Override
597 public <T> T accept( Visitor<T> v ) {
598 return v.visit(this);
599 }
600
601 public String getDisplayName() {
602 // @todo should we show the published version label instead?
603 // currently this method is not being used
604 return getLatestFileMetadata().getLabel();
605 }
606 }