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

IQSS / dataverse / #24468

05 Feb 2025 03:21PM CUT coverage: 22.788% (+0.04%) from 22.752%
#24468

Pull #10790

github

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

51 of 69 new or added lines in 7 files covered. (73.91%)

1 existing line in 1 file now uncovered.

19949 of 87542 relevant lines covered (22.79%)

0.23 hits per line

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

57.14
/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 UPPER(o.identifier)=UPPER(: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 UPPER(o.identifier)=UPPER(: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 UPPER(o.identifier)=UPPER(: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
        , @Index(columnList="authority,protocol, UPPER(identifier)", name="INDEX_DVOBJECT_authority_protocol_upper_identifier")},
58
                uniqueConstraints = {@UniqueConstraint(columnNames = {"authority,protocol,identifier"}),@UniqueConstraint(columnNames = {"owner_id,storageidentifier"})})
59
public abstract class DvObject extends DataverseEntity implements java.io.Serializable {
1✔
60
    
61
    private static final Logger logger = Logger.getLogger(DvObject.class.getCanonicalName());
1✔
62
    
63
    public enum DType {
×
64
        Dataverse("Dataverse"), Dataset("Dataset"),DataFile("DataFile");
×
65
       
66
        String dtype;
67
        DType(String dt) {
×
68
           dtype = dt;
×
69
        }
×
70
        public String getDType() {
71
           return dtype;
×
72
        } 
73
     }
74
    
75
    public static final Visitor<String> NamePrinter = new Visitor<String>(){
1✔
76

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

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

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

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

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

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

114
    @ManyToOne
115
    private DvObject owner;
116

117
    private Timestamp publicationDate;
118

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

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

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

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

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

152
    private String separator;
153

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

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

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

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

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

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

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

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

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

235
    @ManyToOne
236
    private AuthenticatedUser creator;
237

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

328
    public String getSeparator() {
329
        return separator;
1✔
330
    }
331

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

510
    @OneToMany(mappedBy = "definitionPoint",cascade={ CascadeType.REMOVE, CascadeType.MERGE,CascadeType.PERSIST}, orphanRemoval=true)
511
    List<RoleAssignment> roleAssignments;
512
    
513
}
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