• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IQSS / dataverse / #23538

23 Oct 2024 04:54PM UTC coverage: 20.88% (+0.01%) from 20.87%
#23538

Pull #10790

github

web-flow
Merge 07e327ca6 into f970ab3f4
Pull Request #10790: fix: issues in exporters and citations for PermaLink/non-DOI PIDs

39 of 55 new or added lines in 7 files covered. (70.91%)

1 existing line in 1 file now uncovered.

17991 of 86162 relevant lines covered (20.88%)

0.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.35
/src/main/java/edu/harvard/iq/dataverse/DvObject.java
1
package edu.harvard.iq.dataverse;
2

3
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
4
import edu.harvard.iq.dataverse.pidproviders.PidUtil;
5
import edu.harvard.iq.dataverse.storageuse.StorageQuota;
6

7
import java.sql.Timestamp;
8
import java.text.SimpleDateFormat;
9
import java.util.Date;
10
import java.util.List;
11
import java.util.Objects;
12
import java.util.Set;
13
import java.util.logging.Logger;
14

15
import jakarta.persistence.*;
16

17
/**
18
 * Base of the object hierarchy for "anything that can be inside a dataverse".
19
 *
20
 * @author michael
21
 */
22
@NamedQueries({
23
    @NamedQuery(name = "DvObject.findAll",
24
            query = "SELECT o FROM DvObject o ORDER BY o.id"),
25
    @NamedQuery(name = "DvObject.findById",
26
            query = "SELECT o FROM DvObject o WHERE o.id=:id"),
27
    @NamedQuery(name = "DvObject.ownedObjectsById",
28
                        query="SELECT COUNT(obj) FROM DvObject obj WHERE obj.owner.id=:id"),
29
    @NamedQuery(name = "DvObject.findByGlobalId",
30
            query = "SELECT o FROM DvObject o WHERE o.identifier=:identifier and o.authority=:authority and o.protocol=:protocol and o.dtype=:dtype"),
31
    @NamedQuery(name = "DvObject.findIdByGlobalId",
32
            query = "SELECT o.id FROM DvObject o WHERE o.identifier=:identifier and o.authority=:authority and o.protocol=:protocol and o.dtype=:dtype"),
33

34
    @NamedQuery(name = "DvObject.findByAlternativeGlobalId",
35
            query = "SELECT o FROM DvObject o, AlternativePersistentIdentifier a  WHERE o.id = a.dvObject.id and a.identifier=:identifier and a.authority=:authority and a.protocol=:protocol and o.dtype=:dtype"),
36
    @NamedQuery(name = "DvObject.findIdByAlternativeGlobalId",
37
            query = "SELECT o.id FROM DvObject o, AlternativePersistentIdentifier a  WHERE o.id = a.dvObject.id and a.identifier=:identifier and a.authority=:authority and a.protocol=:protocol and o.dtype=:dtype"),
38

39
    @NamedQuery(name = "DvObject.findByProtocolIdentifierAuthority",
40
            query = "SELECT o FROM DvObject o WHERE o.identifier=:identifier and o.authority=:authority and o.protocol=:protocol"),
41
    @NamedQuery(name = "DvObject.findByOwnerId", 
42
                query = "SELECT o FROM DvObject o WHERE o.owner.id=:ownerId  order by o.dtype desc, o.id"),
43
    @NamedQuery(name = "DvObject.findByAuthenticatedUserId", 
44
                query = "SELECT o FROM DvObject o WHERE o.creator.id=:ownerId or o.releaseUser.id=:releaseUserId")
45
})
46
@Entity
47
// Inheritance strategy "JOINED" will create 4 db tables - 
48
// the top-level dvobject, with the common columns, and the 3 child classes - 
49
// dataverse, dataset and datafile. The ids from the main table will be reused
50
// in the child tables. (i.e., the id sequences will be "sparse" in the 3 
51
// child tables). Tested, appears to be working properly. -- L.A. Nov. 4 2014
52
@Inheritance(strategy=InheritanceType.JOINED)
53
@Table(indexes = {@Index(columnList="dtype")
54
                , @Index(columnList="owner_id")
55
                , @Index(columnList="creator_id")
56
                , @Index(columnList="releaseuser_id")},
57
                uniqueConstraints = {@UniqueConstraint(columnNames = {"authority,protocol,identifier"}),@UniqueConstraint(columnNames = {"owner_id,storageidentifier"})})
58
public abstract class DvObject extends DataverseEntity implements java.io.Serializable {
1✔
59
    
60
    private static final Logger logger = Logger.getLogger(DvObject.class.getCanonicalName());
1✔
61
    
62
    public enum DType {
×
63
        Dataverse("Dataverse"), Dataset("Dataset"),DataFile("DataFile");
×
64
       
65
        String dtype;
66
        DType(String dt) {
×
67
           dtype = dt;
×
68
        }
×
69
        public String getDType() {
70
           return dtype;
×
71
        } 
72
     }
73
    
74
    public static final Visitor<String> NamePrinter = new Visitor<String>(){
1✔
75

76
        @Override
77
        public String visit(Dataverse dv) {
78
            return dv.getName();
×
79
        }
80

81
        @Override
82
        public String visit(Dataset ds) {
83
            return ds.getLatestVersion().getTitle();
×
84
        }
85

86
        @Override
87
        public String visit(DataFile df) {
88
            return df.getFileMetadata().getLabel();
×
89
        }
90
    };
91
    public static final Visitor<String> NameIdPrinter = new Visitor<String>(){
1✔
92

93
        @Override
94
        public String visit(Dataverse dv) {
95
            return "[" + dv.getId() + " " + dv.getName() + "]";
×
96
        }
97

98
        @Override
99
        public String visit(Dataset ds) {
100
            return "[" + ds.getId() + (ds.getLatestVersion() != null ? " " + ds.getLatestVersion().getTitle() : "") + "]";
×
101
        }
102

103
        @Override
104
        public String visit(DataFile df) {
105
            return "[" + df.getId() + (df.getFileMetadata() != null ? " " + df.getFileMetadata().getLabel() : "") + "]";
×
106
        }
107
    };
108
    
109
    @Id
110
    @GeneratedValue(strategy = GenerationType.IDENTITY)
111
    private Long id;
112

113
    @ManyToOne
114
    private DvObject owner;
115

116
    private Timestamp publicationDate;
117

118
    /** The user that released this dataverse */
119
    @ManyToOne
120
    private AuthenticatedUser releaseUser;
121
    
122
    @Column( nullable = false )
123
    private Timestamp createDate;
124

125
    @Column(nullable = false)
126
    private Timestamp modificationTime;
127

128
    /**
129
     * @todo Rename this to contentIndexTime (or something) to differentiate it
130
     * from permissionIndexTime. Content Solr docs vs. permission Solr docs.
131
     */
132
    private Timestamp indexTime;
133

134
    @Column(nullable = true)
135
    private Timestamp permissionModificationTime;
136

137
    private Timestamp permissionIndexTime;
138
    
139
    @Column
140
    private String storageIdentifier;
141
    
142
    @Column(insertable = false, updatable = false) private String dtype;
143
    
144
    /*
145
    * Add PID related fields
146
    */
147
   
148
    private String protocol;
149
    private String authority;
150

151
    private String separator;
152

153
    @Temporal(value = TemporalType.TIMESTAMP)
154
    private Date globalIdCreateTime;
155

156
    private String identifier;
157
    
158
    private boolean identifierRegistered;
159
        
160
    private transient GlobalId globalId = null;
1✔
161
    
162
    @OneToMany(mappedBy = "dvObject", cascade = CascadeType.ALL, orphanRemoval = true)
163
    private Set<AlternativePersistentIdentifier> alternativePersistentIndentifiers;
164

165
    public Set<AlternativePersistentIdentifier> getAlternativePersistentIndentifiers() {
166
        return alternativePersistentIndentifiers;
1✔
167
    }
168

169
    public void setAlternativePersistentIndentifiers(Set<AlternativePersistentIdentifier> alternativePersistentIndentifiers) {
170
        this.alternativePersistentIndentifiers = alternativePersistentIndentifiers;
×
171
    }
×
172
        
173
    
174
    /**
175
     * previewImageAvailable could also be thought of as "thumbnail has been
176
     * generated. However, were all three thumbnails generated? We might need a
177
     * boolean per thumbnail size.
178
     */
179
    private boolean previewImageAvailable;
180
    
181
    @OneToOne(mappedBy = "definitionPoint",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
182
    private StorageQuota storageQuota;
183
    
184
    public boolean isPreviewImageAvailable() {
185
        return previewImageAvailable;
×
186
    }
187
    
188
    public void setPreviewImageAvailable(boolean status) {
189
        this.previewImageAvailable = status;
1✔
190
    }
1✔
191
    
192
    /**
193
     * Indicates whether a previous attempt to generate a preview image has failed,
194
     * regardless of size. This could be due to the file not being accessible, or a
195
     * real failure in generating the thumbnail. In both cases, we won't want to try
196
     * again every time the preview/thumbnail is requested for a view.
197
     */
198
    private boolean previewImageFail;
199

200
    public boolean isPreviewImageFail() {
201
        return previewImageFail;
1✔
202
    }
203

204
    public void setPreviewImageFail(boolean previewImageFail) {
205
        this.previewImageFail = previewImageFail;
1✔
206
    }
1✔
207
    
208
    public Timestamp getModificationTime() {
209
        return modificationTime;
1✔
210
    }
211

212
    /**
213
     * modificationTime is used for comparison with indexTime so we know if the
214
     * Solr index is stale.
215
     * @param modificationTime
216
     */
217
    public void setModificationTime(Timestamp modificationTime) {
218
        this.modificationTime = modificationTime;
1✔
219
    }
1✔
220

221
    public Timestamp getIndexTime() {
222
        return indexTime;
×
223
    }
224

225
    /**
226
     * indexTime is used for comparison with modificationTime so we know if the
227
     * Solr index is stale.
228
     * @param indexTime
229
     */
230
    public void setIndexTime(Timestamp indexTime) {
231
        this.indexTime = indexTime;
×
232
    }
×
233

234
    @ManyToOne
235
    private AuthenticatedUser creator;
236

237
    public interface Visitor<T> {
238
        public T visit(Dataverse dv);
239
        public T visit(Dataset   ds);
240
        public T visit(DataFile  df);
241
    }
242

243
    /**
244
     * Sets the owner of the object. This is {@code protected} rather than
245
     * {@code public}, since different sub-classes have different possible owner
246
     * types: a {@link DataFile} can only have a {@link Dataset}, for example.
247
     *
248
     * @param newOwner
249
     */
250
    protected void setOwner(DvObjectContainer newOwner) {
251
        owner = newOwner;
1✔
252
    }
1✔
253

254
    public DvObjectContainer getOwner() {
255
        return (DvObjectContainer)owner;
1✔
256
    }
257

258
    public Long getId() {
259
        return id;
1✔
260
    }
261

262
    public void setId(Long id) {
263
        this.id = id;
1✔
264
    }
1✔
265
    
266
    /**
267
     * @return Whether {@code this} takes no permissions from roles assigned on its parents.
268
     */
269
    public abstract boolean isEffectivelyPermissionRoot();
270

271
    public Timestamp getPublicationDate() {
272
        return publicationDate;
1✔
273
    }
274

275
    public void setPublicationDate(Timestamp publicationDate) {
276
        this.publicationDate = publicationDate;
1✔
277
    }
1✔
278

279
    public AuthenticatedUser getReleaseUser() {
280
        return releaseUser;
×
281
    }
282
    
283
    public void setReleaseUser(AuthenticatedUser releaseUser) {
284
        this.releaseUser = releaseUser;
×
285
    }
×
286

287
    public boolean isReleased() {
288
        return publicationDate != null;
1✔
289
    }
290

291
    public Timestamp getCreateDate() {
292
        return createDate;
1✔
293
    }
294

295
    public void setCreateDate(Timestamp createDate) {
296
        this.createDate = createDate;
1✔
297
    }
1✔
298

299
    public AuthenticatedUser getCreator() {
300
        return creator;
1✔
301
    }
302

303
    public void setCreator(AuthenticatedUser creator) {
304
        this.creator = creator;
1✔
305
    }
1✔
306
    
307
     public String getProtocol() {
308
        return protocol;
1✔
309
    }
310

311
    public void setProtocol(String protocol) {
312
        this.protocol = protocol;
1✔
313
        //Remove cached value
314
        globalId=null;
1✔
315
    }
1✔
316

317
    public String getAuthority() {
318
        return authority;
1✔
319
    }
320

321
    public void setAuthority(String authority) {
322
        this.authority = authority;
1✔
323
        //Remove cached value
324
        globalId=null;
1✔
325
    }
1✔
326

327
    public String getSeparator() {
NEW
328
        return separator;
×
329
    }
330

331
    public void setSeparator(String separator) {
332
        this.separator = separator;
1✔
333
        //Remove cached value
334
        globalId=null;
1✔
335
    }
1✔
336

337
    public Date getGlobalIdCreateTime() {
338
        return globalIdCreateTime;
×
339
    }
340

341
    public void setGlobalIdCreateTime(Date globalIdCreateTime) {
342
        this.globalIdCreateTime = globalIdCreateTime;
×
343
    }
×
344

345
    public String getIdentifier() {
346
        return identifier;
1✔
347
    }
348

349
    public void setIdentifier(String identifier) {
350
        this.identifier = identifier;
1✔
351
        //Remove cached value
352
        globalId=null;
1✔
353
    }
1✔
354

355
    public boolean isIdentifierRegistered() {
356
        return identifierRegistered;
×
357
    } 
358

359
    public void setIdentifierRegistered(boolean identifierRegistered) {
360
        this.identifierRegistered = identifierRegistered;
×
361
    }  
×
362
    
363
    public void setGlobalId( GlobalId pid ) {
364
        if ( pid == null ) {
1✔
365
            setProtocol(null);
×
366
            setAuthority(null);
×
NEW
367
            setSeparator(null);
×
UNCOV
368
            setIdentifier(null);
×
369
        } else {
370
            //These reset globalId=null
371
            setProtocol(pid.getProtocol());
1✔
372
            setAuthority(pid.getAuthority());
1✔
373
            setSeparator(pid.getSeparator());
1✔
374
            setIdentifier(pid.getIdentifier());
1✔
375
        }
376
    }
1✔
377
    
378
    public GlobalId getGlobalId() {
379
        // Cache this
380
        if ((globalId == null) && !(getProtocol() == null || getAuthority() == null || getIdentifier() == null)) {
1✔
381
            globalId = PidUtil.parseAsGlobalID(getProtocol(), getAuthority(), getIdentifier());
1✔
382
        }
383
        return globalId;
1✔
384
    }
385
    
386
    public abstract <T> T accept(Visitor<T> v);
387

388
    @Override
389
    public int hashCode() {
390
        return Objects.hash(getId());
1✔
391
    }
392

393
    @Override
394
    public abstract boolean equals(Object o);
395

396
    @Override
397
    public String toString() {
398
        String classNameComps[] = getClass().getName().split("\\.");
1✔
399
        return String.format("[%s id:%d %s]", classNameComps[classNameComps.length - 1],
1✔
400
                getId(), toStringExtras());
1✔
401
    }
402

403
    /**
404
     * Convenience method to add data to the default toString output.
405
     *
406
     * @return
407
     */
408
    protected String toStringExtras() {
409
        return "";
1✔
410
    }
411
    
412
    public abstract String getDisplayName();
413
    
414
    public abstract String getCurrentName();
415
    
416
    // helper method used to mimic instanceof on JSF pge
417
    public boolean isInstanceofDataverse() {
418
        return this instanceof Dataverse;
1✔
419
    }        
420

421
    public boolean isInstanceofDataset() {
422
        return this instanceof Dataset;
1✔
423
    }
424
    
425
    public boolean isInstanceofDataFile() {
426
        return this instanceof DataFile;
1✔
427
    }
428

429
    public Timestamp getPermissionModificationTime() {
430
        return permissionModificationTime;
×
431
    }
432

433
    public void setPermissionModificationTime(Timestamp permissionModificationTime) {
434
        this.permissionModificationTime = permissionModificationTime;
1✔
435
    }
1✔
436

437
    public Timestamp getPermissionIndexTime() {
438
        return permissionIndexTime;
×
439
    }
440

441
    public void setPermissionIndexTime(Timestamp permissionIndexTime) {
442
        this.permissionIndexTime = permissionIndexTime;
×
443
    }
×
444

445
    public Dataverse getDataverseContext() {
446
        if (this instanceof Dataverse) {
1✔
447
            return (Dataverse) this;
1✔
448
        } else if (this.getOwner() != null){
1✔
449
            return this.getOwner().getDataverseContext();
1✔
450
        }
451
        
452
        return null;
×
453
    }
454
    
455
    public String getAuthorString(){
456
        if (this instanceof Dataverse){
×
457
            throw new UnsupportedOperationException("Not supported yet.");
×
458
        }
459
        if (this instanceof Dataset){
×
460
            Dataset dataset = (Dataset) this;
×
461
            return dataset.getLatestVersion().getAuthorsStr();
×
462
        }
463
        if (this instanceof DataFile){
×
464
            Dataset dataset = (Dataset) this.getOwner();
×
465
            return dataset.getLatestVersion().getAuthorsStr();
×
466
        }
467
        throw new UnsupportedOperationException("Not supported yet. New DVObject Instance?");
×
468
    }
469
    
470
    public String getTargetUrl(){
471
        throw new UnsupportedOperationException("Not supported yet. New DVObject Instance?");
×
472
    }
473
    
474
    public String getYearPublishedCreated(){
475
        //if published get the year if draft get when created
476
        if (this.isReleased()){
×
477
            return new SimpleDateFormat("yyyy").format(this.getPublicationDate());
×
478
        } else if (this.getCreateDate() != null) {
×
479
           return  new SimpleDateFormat("yyyy").format(this.getCreateDate());
×
480
        } else {
481
            return new SimpleDateFormat("yyyy").format(new Date());
×
482
        }
483
    }
484
    
485
    public String getStorageIdentifier() {
486
        return storageIdentifier;
1✔
487
    }
488
    
489
    public void setStorageIdentifier(String storageIdentifier) {
490
        this.storageIdentifier = storageIdentifier;
1✔
491
    }
1✔
492
    
493
    public StorageQuota getStorageQuota() {
494
        return storageQuota;
×
495
    }
496
    
497
    public void setStorageQuota(StorageQuota storageQuota) {
498
        this.storageQuota = storageQuota;
×
499
    }
×
500

501
    /**
502
     * 
503
     * @param other 
504
     * @return {@code true} iff {@code other} is {@code this} or below {@code this} in the containment hierarchy.
505
     */
506
    public abstract boolean isAncestorOf( DvObject other );
507
    
508

509
    @OneToMany(mappedBy = "definitionPoint",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
510
    List<RoleAssignment> roleAssignments;
511
    
512
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc