package ca.intelliware.ihtsdo.mlds.domain; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.DiscriminatorColumn; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import org.hibernate.search.annotations.ContainedIn; import org.hibernate.search.annotations.IndexedEmbedded; import org.joda.time.Instant; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="application_type") // Note that concrete subclass MUST set @Where and @SQLDelete for soft-delete functionality @Where(clause = "inactive_at IS NULL") @SQLDelete(sql="UPDATE application SET inactive_at = now() WHERE application_id = ?") @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="applicationType") @JsonSubTypes({ @Type(value=PrimaryApplication.class, name="PRIMARY"), @Type(value=ExtensionApplication.class, name="EXTENSION"), @Type(value=ImportApplication.class, name="IMPORT") }) public abstract class Application extends BaseEntity { public static enum ApplicationType { PRIMARY, EXTENSION, IMPORT } @Id @GeneratedValue @Column(name="application_id") Long applicationId; // the parent @JsonIgnoreProperties({"application", "applications"}) @ManyToOne @JoinColumn(name="affiliate_id") @ContainedIn Affiliate affiliate; String username; @OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="affiliate_details_id") @IndexedEmbedded(prefix="") AffiliateDetails affiliateDetails; @Column(name="notes_internal") String notesInternal; @Column(name="created_at") private Instant createdAt = Instant.now(); @JsonIgnore @Column(name="inactive_at") Instant inactiveAt; // Timestamp last submitted by the applicant @Column(name="submitted_at") Instant submittedAt; // Timestamp when application was completed by staff, into either the ACCEPTED or REJECTED state @Column(name="completed_at") Instant completedAt; @Enumerated(EnumType.STRING) @Column(name="approval_state") ApprovalState approvalState = ApprovalState.NOT_SUBMITTED; @ManyToOne @JoinColumn(name="member_id") Member member; @Column(name="application_type", insertable=false, updatable=false) String applicationTypeValue; public Application() { } // For tests public Application(Long applicationId) { this.applicationId = applicationId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getNotesInternal() { return notesInternal; } public void setNotesInternal(String notesInternal) { this.notesInternal = notesInternal; } public Instant getSubmittedAt() { return submittedAt; } public void setSubmittedAt(Instant submittedAt) { this.submittedAt = submittedAt; } public Instant getCompletedAt() { return completedAt; } public void setCompletedAt(Instant completedAt) { this.completedAt = completedAt; } public ApprovalState getApprovalState() { return approvalState; } public void setApprovalState(ApprovalState approvalState) { this.approvalState = approvalState; } public Long getApplicationId() { return applicationId; } @Override protected Object getPK() { return applicationId; } public AffiliateDetails getAffiliateDetails() { return affiliateDetails; } public void setAffiliateDetails(AffiliateDetails affiliateDetails) { this.affiliateDetails = affiliateDetails; } public Affiliate getAffiliate() { return affiliate; } public void setAffiliate(Affiliate affiliate) { affiliate.addApplication(this); } public Member getMember() { return member; } public void setMember(Member member) { this.member = member; } public static Application create(ApplicationType applicationType) { switch (applicationType) { case PRIMARY: return new PrimaryApplication(); case EXTENSION: return new ExtensionApplication(); case IMPORT: return new ImportApplication(); default: throw new RuntimeException("Unsupported applicationType " + applicationType); } } public Instant getCreatedAt() { return createdAt; } @JsonIgnore public abstract ApplicationType getApplicationType(); @JsonIgnore public String getApplicationTypeValue() { return applicationTypeValue; } public Instant getInactiveAt() { return inactiveAt; } public void setInactiveAt(Instant inactiveAt) { this.inactiveAt = inactiveAt; }; }