package pl.edu.icm.saos.persistence.model;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.util.ObjectUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import pl.edu.icm.saos.common.visitor.Visitor;
import pl.edu.icm.saos.persistence.common.IndexableObject;
import pl.edu.icm.saos.persistence.model.Judge.JudgeRole;
/**
*
* pl. Orzeczenie
*
* @author Łukasz Dumiszewski
*/
@Entity
@Table(
indexes={@Index(columnList="judgmentDate, id"), @Index(columnList="sourceCode, sourceJudgmentId")},
uniqueConstraints={@UniqueConstraint(name="source_id_judgment_id_unique", columnNames={"sourceCode", "sourceJudgmentId"})})
@Inheritance(strategy = InheritanceType.JOINED)
@Cacheable(false)
@SequenceGenerator(name = "seq_judgment", allocationSize = 1, sequenceName = "seq_judgment")
public abstract class Judgment extends IndexableObject {
/** pl. rodzaj wyroku */
public enum JudgmentType {
/** pl. postanowienie */
DECISION,
/** pl. uchwała */
RESOLUTION,
/** pl. wyrok */
SENTENCE,
/** pl. zarządzenie */
REGULATION,
/** pl. uzasadnienie,
* the common court judgment data provider sometimes gives the judgment and reasons as
two separate entities. */
REASONS
}
private JudgmentSourceInfo sourceInfo = new JudgmentSourceInfo();
private LocalDate receiptDate;
private LocalDate judgmentDate;
private List<CourtCase> courtCases = Lists.newArrayList();
private List<Judge> judges = Lists.newArrayList();
private List<String> courtReporters = Lists.newArrayList();
private String decision;
private String summary;
private JudgmentTextContent textContent = new JudgmentTextContent();
private List<String> legalBases = Lists.newArrayList();
private List<JudgmentReferencedRegulation> referencedRegulations = Lists.newArrayList();
private List<JudgmentKeyword> keywords = Lists.newArrayList();
private JudgmentType judgmentType;
private DateTime modificationDate = new DateTime();
private List<ReferencedCourtCase> referencedCourtCases = Lists.newArrayList();
private MeansOfAppeal meansOfAppeal;
private JudgmentResult judgmentResult;
private List<String> lowerCourtJudgments = Lists.newArrayList();
private MoneyAmount maxMoneyAmount;
//------------------------ GETTERS --------------------------
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_judgment")
@Override
public long getId() {
return id;
}
@Embedded
public JudgmentSourceInfo getSourceInfo() {
return sourceInfo;
}
/**
* Receipt date [of suit/file] / pl. data wpływu [pozwu/sprawy]
*/
@Type(type="pl.edu.icm.saos.persistence.mapper.SaosPersistentLocalDate")
public LocalDate getReceiptDate() {
return receiptDate;
}
/** pl. data orzeczenia */
@Type(type="pl.edu.icm.saos.persistence.mapper.SaosPersistentLocalDate")
public LocalDate getJudgmentDate() {
return judgmentDate;
}
@OneToMany(mappedBy="judgment", orphanRemoval=true, cascade=CascadeType.ALL)
@OrderBy("name")
private List<Judge> getJudges_() {
return judges;
}
@Transient
public List<Judge> getJudges() {
return ImmutableList.copyOf(getJudges_());
}
/** pl. protokolanci */
@ElementCollection
@CollectionTable(name="judgment_court_reporter", uniqueConstraints={@UniqueConstraint(name="judgment_court_reporter_unique", columnNames={"fk_judgment", "court_reporter"})})
@Column(name="court_reporter")
@OrderBy("court_reporter")
private List<String> getCourtReporters_() {
return courtReporters;
}
@Transient
public List<String> getCourtReporters() {
return ImmutableList.copyOf(getCourtReporters_());
}
/** pl. rozstrzygnięcie */
public String getDecision() {
return decision;
}
/** ruling summary, pl. teza */
public String getSummary() {
return summary;
}
/** pl. podstawy prawne */
@ElementCollection
@CollectionTable(name="judgment_legal_bases", uniqueConstraints={@UniqueConstraint(name="judgment_legal_base_unique", columnNames={"fk_judgment", "legal_base"})})
@Column(name="legal_base")
@OrderBy("legal_base")
private List<String> getLegalBases_() {
return legalBases;
}
@Transient
public List<String> getLegalBases() {
return ImmutableList.copyOf(getLegalBases_());
}
/**
* Referenced law journal entries
* pl. powołane przepisy
* for hibernate
*/
@OneToMany(mappedBy="judgment", orphanRemoval=true, cascade=CascadeType.ALL)
@OrderBy
private List<JudgmentReferencedRegulation> getReferencedRegulations_() {
return referencedRegulations;
}
@Transient
public List<JudgmentReferencedRegulation> getReferencedRegulations() {
return ImmutableList.copyOf(getReferencedRegulations_());
}
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "assigned_judgment_keyword",
indexes = {@Index(name = "assigned_keyword_fk_judgment_index", columnList = "fk_judgment")},
joinColumns = {@JoinColumn(name = "fk_judgment", nullable = false, updatable = false) },
inverseJoinColumns = {@JoinColumn(name = "fk_keyword", nullable = false, updatable = false) })
@OrderBy("phrase")
private List<JudgmentKeyword> getKeywords_() {
return keywords;
}
@Transient
public List<JudgmentKeyword> getKeywords() {
return ImmutableList.copyOf(getKeywords_());
}
@Enumerated(EnumType.STRING)
public JudgmentType getJudgmentType() {
return judgmentType;
}
/**
* A full raw text content of the judgment
*/
@Transient
public String getRawTextContent() {
return textContent.getRawTextContent();
}
@OneToOne(mappedBy="judgment", cascade=CascadeType.ALL, fetch=FetchType.LAZY, optional=false)
public JudgmentTextContent getTextContent() {
return textContent;
}
@OneToMany(mappedBy="judgment", orphanRemoval=true, cascade=CascadeType.ALL)
@OrderBy("caseNumber")
private List<CourtCase> getCourtCases_() {
return courtCases;
}
@Transient
public List<String> getCaseNumbers() {
return ImmutableList.copyOf(getCourtCases_().stream().map(CourtCase::getCaseNumber).collect(Collectors.toList()));
}
@Transient
public List<CourtCase> getCourtCases() {
return ImmutableList.copyOf(getCourtCases_());
}
@Transient
public abstract CourtType getCourtType();
/**
* @return Judgment's last modification date.
* <br/>
* Modification means any change
* made to judgment entity or judgment dependent entities
* (i.e. authors, keywords, ...)
*/
public DateTime getModificationDate() {
return modificationDate;
}
/**
* Court cases that are referred in {@link #getRawTextContent()}
*/
@Transient
public List<ReferencedCourtCase> getReferencedCourtCases() {
return referencedCourtCases;
}
/**
* {@link MeansOfAppeal} which was the cause of this judgment
*/
@ManyToOne
public MeansOfAppeal getMeansOfAppeal() {
return meansOfAppeal;
}
@ManyToOne
public JudgmentResult getJudgmentResult() {
return judgmentResult;
}
@ElementCollection
@CollectionTable(name="judgment_lower_court_judgments", uniqueConstraints={@UniqueConstraint(name="judgment_lower_court_judgment_unique", columnNames={"fk_judgment", "lower_court_judgment"})})
@Column(name="lower_court_judgment")
@OrderBy("lower_court_judgment")
private List<String> getLowerCourtJudgments_() {
return lowerCourtJudgments;
}
/**
* Lower court judgments in text form, e.g. pl. Wyrok Sądu Najwyższego z dn. 20.02.2009 o nr XXX1123
*/
@Transient
public List<String> getLowerCourtJudgments() {
return ImmutableList.copyOf(lowerCourtJudgments);
}
/**
* Maximal amount of money referenced in judgment content
*/
@Transient
public MoneyAmount getMaxMoneyAmount() {
return maxMoneyAmount;
}
//------------------------ LOGIC --------------------------
//--- court cases ---
@Transient
public boolean isSingleCourtCase() {
return getCourtCases_().size() == 1;
}
public void addCourtCase(CourtCase courtCase) {
Preconditions.checkNotNull(courtCase);
Preconditions.checkArgument(!StringUtils.isBlank(courtCase.getCaseNumber()));
Preconditions.checkArgument(!containsCourtCase(courtCase.getCaseNumber()));
courtCase.setJudgment(this);
this.courtCases.add(courtCase);
}
public CourtCase getCourtCase(String caseNumber) {
for (CourtCase courtCase : this.courtCases) {
if (courtCase.getCaseNumber().equals(caseNumber)) {
return courtCase;
}
}
return null;
}
public boolean containsCourtCase(String caseNumber) {
return getCourtCase(caseNumber) != null;
}
public void removeCourtCase(CourtCase courtCase) {
courtCases.remove(courtCase);
}
public void removeAllCourtCases() {
courtCases.clear();
}
//--- judges ---
public void addJudge(Judge judge) {
Preconditions.checkArgument(!this.containsJudge(judge.getName()));
this.judges.add(judge);
judge.setJudgment(this);
}
/**
* Returns {@link Judge}s that have the given role. If the role == null then returns judges that
* have no special role assigned. See {@link Judge#getSpecialRoles()}.
*/
@Transient
public List<Judge> getJudges(JudgeRole role) {
List<Judge> roleJudges = Lists.newArrayList();
for (Judge judge : getJudges()) {
if (role != null && judge.hasAnySpecialRole()) {
if (judge.getSpecialRoles().contains(role)) {
roleJudges.add(judge);
}
}
else if (role == null && !judge.hasAnySpecialRole()) {
roleJudges.add(judge);
}
}
return roleJudges;
}
public boolean containsJudge(String judgeName) {
return getJudge(judgeName) != null;
}
public Judge getJudge(String judgeName) {
for (Judge existingJudge : judges) {
if (StringUtils.equalsIgnoreCase(existingJudge.getName(), judgeName)) {
return existingJudge;
}
}
return null;
}
public void removeAllJudges() {
judges.clear();
}
public void removeJudge(Judge judge) {
judges.remove(judge);
}
//--- legal bases ---
public void addLegalBase(String legalBase) {
Preconditions.checkArgument(!containsLegalBase(legalBase));
this.legalBases.add(legalBase);
}
public boolean containsLegalBase(String legalBase) {
return this.legalBases.contains(legalBase);
}
public void removeLegalBase(String legalBase) {
this.legalBases.remove(legalBase);
}
//--- court reporters ---
public void addCourtReporter(String courtReporter) {
Preconditions.checkArgument(!StringUtils.isBlank(courtReporter));
Preconditions.checkArgument(!containsCourtReporter(courtReporter));
this.courtReporters.add(courtReporter);
}
public boolean containsCourtReporter(String courtReporter) {
return this.courtReporters.contains(courtReporter);
}
public void removeCourtReporter(String courtReporter) {
this.courtReporters.remove(courtReporter);
}
//--- referenced regulations ---
public void addReferencedRegulation(JudgmentReferencedRegulation regulation) {
Preconditions.checkArgument(!this.containsReferencedRegulation(regulation));
this.referencedRegulations.add(regulation);
regulation.setJudgment(this);
}
public void removeAllReferencedRegulations() {
referencedRegulations.clear();
}
public void removeReferencedRegulation(JudgmentReferencedRegulation regulation) {
referencedRegulations.remove(regulation);
}
public boolean containsReferencedRegulation(JudgmentReferencedRegulation regulation) {
Preconditions.checkNotNull(regulation);
for (JudgmentReferencedRegulation referencedRegulation : getReferencedRegulations_()) {
if (regulation.getRawText().equals(referencedRegulation.getRawText()) &&
ObjectUtils.nullSafeEquals(regulation.getLawJournalEntry(), referencedRegulation.getLawJournalEntry())) {
return true;
}
}
return false;
}
//--- keywords ---
public void addKeyword(JudgmentKeyword keyword) {
Preconditions.checkArgument(!containsKeyword(keyword));
Preconditions.checkArgument(keyword.getCourtType().equals(getCourtType()));
this.keywords.add(keyword);
}
public void removeAllKeywords() {
this.keywords.clear();
}
public void removeKeyword(JudgmentKeyword keyword) {
this.keywords.remove(keyword);
}
@Transient
public JudgmentKeyword getKeyword(String phrase) {
for (JudgmentKeyword keyword : this.keywords) {
if (keyword.getPhrase().equalsIgnoreCase(phrase)) {
return keyword;
}
}
return null;
}
public boolean containsKeyword(String phrase) {
return getKeyword(phrase) != null;
}
public boolean containsKeyword(JudgmentKeyword keyword) {
return keywords.contains(keyword);
}
//--- referenced court cases ---
public boolean containsReferencedCourtCase(ReferencedCourtCase referencedCourtCase) {
return this.referencedCourtCases.contains(referencedCourtCase);
}
public boolean addReferencedCourtCase(ReferencedCourtCase referencedCourtCase) {
Preconditions.checkNotNull(referencedCourtCase);
Preconditions.checkArgument(!containsReferencedCourtCase(referencedCourtCase), "judgmentId="+this.id);
return this.referencedCourtCases.add(referencedCourtCase);
}
public void removeReferencedCourtCase(ReferencedCourtCase referencedCourtCase) {
referencedCourtCases.remove(referencedCourtCase);
}
//--- lower court judgments ---
public void addLowerCourtJudgment(String lowerCourtJudgment) {
Preconditions.checkArgument(!containsLowerCourtJudgment(lowerCourtJudgment));
this.lowerCourtJudgments.add(lowerCourtJudgment);
}
public boolean containsLowerCourtJudgment(String lowerCourtJudgment) {
return this.lowerCourtJudgments.contains(lowerCourtJudgment);
}
public void removeLowerCourtJudgment(String lowerCourtJudgment) {
this.lowerCourtJudgments.remove(lowerCourtJudgment);
}
//--- other ---
@Override
public void passVisitorDown(Visitor visitor) {
for (Judge judge : getJudges()) {
judge.accept(visitor);
}
for (CourtCase courtCase : getCourtCases_()) {
courtCase.accept(visitor);
}
for (JudgmentReferencedRegulation regulation : getReferencedRegulations()) {
regulation.accept(visitor);
}
}
/**
* Sets the modification date to the current time.
* <br/>
* This method is used in persistence repository classes,
* so that saving the object updates the modification date.
* You should not use it in other classes.
*/
public void updateModificationDate() {
this.modificationDate = new DateTime();
}
//------------------------ SETTERS --------------------------
public void setReceiptDate(LocalDate receiptDate) {
this.receiptDate = receiptDate;
}
public void setJudgmentDate(LocalDate judgmentDate) {
this.judgmentDate = judgmentDate;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setJudges_(List<Judge> judges) {
this.judges = judges;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setCourtReporters_(List<String> courtReporters) {
this.courtReporters = courtReporters;
}
public void setDecision(String decision) {
this.decision = decision;
}
public void setSummary(String summary) {
this.summary = summary;
}
@SuppressWarnings("unused") /** for hibernate */
private void setLegalBases_(List<String> legalBases) {
this.legalBases = legalBases;
}
@SuppressWarnings("unused") /** for hibernate */
private void setKeywords_(List<JudgmentKeyword> keywords) {
this.keywords = keywords;
}
public void setJudgmentType(JudgmentType judgmentType) {
this.judgmentType = judgmentType;
}
public void setTextContent(JudgmentTextContent textContent) {
if (textContent != null) {
textContent.setJudgment(this);
}
this.textContent = textContent;
}
// public void setRawTextContent(String rawTextContent) {
// if (this.textContent == null) {
// this.textContent = new JudgmentTextContent();
// }
// this.textContent.setRawTextContent(rawTextContent);
// }
public void setSourceInfo(JudgmentSourceInfo sourceInfo) {
this.sourceInfo = sourceInfo;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setCourtCases_(List<CourtCase> courtCases) {
this.courtCases = courtCases;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setReferencedRegulations_(List<JudgmentReferencedRegulation> referencedRegulations) {
this.referencedRegulations = referencedRegulations;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setModificationDate(DateTime modificationDate) {
this.modificationDate = modificationDate;
}
public void setMeansOfAppeal(MeansOfAppeal meansOfAppeal) {
this.meansOfAppeal = meansOfAppeal;
}
@SuppressWarnings("unused") /** for hibernate only */
private void setLowerCourtJudgments_(List<String> lowerCourtJudgments) {
this.lowerCourtJudgments = lowerCourtJudgments;
}
public void setJudgmentResult(JudgmentResult judgmentResult) {
this.judgmentResult = judgmentResult;
}
public void setMaxMoneyAmount(MoneyAmount maxMoneyAmount) {
this.maxMoneyAmount = maxMoneyAmount;
}
//------------------------ HashCode & Equals --------------------------
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((sourceInfo == null) ? 0 : sourceInfo.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Judgment other = (Judgment) obj;
if (sourceInfo == null) {
if (other.sourceInfo != null)
return false;
} else if (!sourceInfo.equals(other.sourceInfo))
return false;
return true;
}
//------------------------ toString --------------------------
@Override
public String toString() {
return "Judgment [sourceInfo=" + sourceInfo + ", judgmentDate="
+ judgmentDate + ", courtCases=" + courtCases + ", judges="
+ judges + ", courtReporters=" + courtReporters
+ ", legalBases=" + legalBases + ", referencedRegulations="
+ referencedRegulations + ", judgmentType=" + judgmentType
+ "]";
}
}