Java tutorial
///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.business.task; import java.math.BigDecimal; import java.util.Date; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; import org.hibernate.search.annotations.Analyze; import org.hibernate.search.annotations.ClassBridge; import org.hibernate.search.annotations.DateBridge; import org.hibernate.search.annotations.EncodingType; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.FieldBridge; import org.hibernate.search.annotations.Index; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.IndexedEmbedded; import org.hibernate.search.annotations.Resolution; import org.hibernate.search.annotations.Store; import org.hibernate.search.bridge.builtin.IntegerBridge; import org.projectforge.business.gantt.GanttObjectType; import org.projectforge.business.gantt.GanttRelationType; import org.projectforge.common.StringHelper; import org.projectforge.common.i18n.Priority; import org.projectforge.common.task.TaskStatus; import org.projectforge.common.task.TimesheetBookingStatus; import org.projectforge.framework.persistence.api.ShortDisplayNameCapable; import org.projectforge.framework.persistence.entities.DefaultBaseDO; import org.projectforge.framework.persistence.user.entities.PFUserDO; import de.micromata.genome.db.jpa.xmldump.api.JpaXmlPersist; /** * * @author Kai Reinhard (k.reinhard@micromata.de) * */ @Entity @Indexed @ClassBridge(name = "taskpath", index = Index.YES /* TOKENIZED */, store = Store.NO, impl = HibernateSearchTaskPathBridge.class) @Table(name = "T_TASK", uniqueConstraints = { @UniqueConstraint(columnNames = { "parent_task_id", "title" }) }, indexes = { @javax.persistence.Index(name = "idx_fk_t_task_gantt_predecessor_fk", columnList = "gantt_predecessor_fk"), @javax.persistence.Index(name = "idx_fk_t_task_parent_task_id", columnList = "parent_task_id"), @javax.persistence.Index(name = "idx_fk_t_task_responsible_user_id", columnList = "responsible_user_id"), @javax.persistence.Index(name = "idx_fk_t_task_tenant_id", columnList = "tenant_id") }) @JpaXmlPersist(beforePersistListener = TaskXmlBeforePersistListener.class) public class TaskDO extends DefaultBaseDO implements ShortDisplayNameCapable, Cloneable// , GanttObject { public static final String KOST2_SEPARATOR_CHARS = ",; "; public static final int TITLE_LENGTH = 40; public static final int DESCRIPTION_LENGTH = 4000; public static final int SHORT_DESCRIPTION_LENGTH = 255; public static final int REFERENCE_LENGTH = 1000; public static final int PRIORITY_LENGTH = 7; public static final int STATUS_LENGTH = 1; private static final long serialVersionUID = -9167354530511386533L; private TaskDO parentTask = null; @Field(index = Index.YES /* TOKENIZED */, store = Store.NO) private String title; private TaskStatus status = TaskStatus.N; private Priority priority; @Field(index = Index.YES /* TOKENIZED */, store = Store.NO) private String shortDescription; @Field(index = Index.YES /* TOKENIZED */, store = Store.NO) private String description; /** -> Gantt */ @Deprecated @Field(index = Index.YES, analyze = Analyze.NO /* UN_TOKENIZED */, store = Store.NO, bridge = @FieldBridge(impl = IntegerBridge.class)) private Integer progress; @Field(index = Index.YES, analyze = Analyze.NO /* UN_TOKENIZED */, store = Store.NO, bridge = @FieldBridge(impl = IntegerBridge.class)) private Integer maxHours; /** -> Gantt */ @Deprecated @Field(index = Index.YES, analyze = Analyze.NO /* UN_TOKENIZED */) @DateBridge(resolution = Resolution.DAY, encoding = EncodingType.STRING) private Date startDate; /** -> Gantt */ @Deprecated @Field(index = Index.YES, analyze = Analyze.NO /* UN_TOKENIZED */) @DateBridge(resolution = Resolution.DAY, encoding = EncodingType.STRING) private Date endDate; /** -> Gantt */ @Deprecated private BigDecimal duration; @Field(index = Index.YES, analyze = Analyze.NO /* UN_TOKENIZED */) @DateBridge(resolution = Resolution.DAY, encoding = EncodingType.STRING) private Date protectTimesheetsUntil; @IndexedEmbedded(depth = 1) private PFUserDO responsibleUser; @Field(index = Index.YES /* TOKENIZED */, store = Store.NO) private String reference; private TimesheetBookingStatus timesheetBookingStatus = TimesheetBookingStatus.DEFAULT; private String kost2BlackWhiteList; private boolean kost2IsBlackList; private boolean protectionOfPrivacy; @Deprecated private Integer oldKost2Id; /** -> Gantt */ @Deprecated @Field(index = Index.YES /* TOKENIZED */, store = Store.NO) private String workpackageCode; /** -> Gantt */ @Deprecated private Integer ganttPredecessorOffset; /** -> Gantt */ @Deprecated private GanttRelationType ganttRelationType; /** -> Gantt */ @Deprecated private GanttObjectType ganttObjectType; /** -> Gantt */ @Deprecated private TaskDO ganttPredecessor; @Column(name = "description", length = DESCRIPTION_LENGTH) public String getDescription() { return description; } public TaskDO setDescription(final String longDescription) { this.description = longDescription; return this; } @Column(name = "max_hours") public Integer getMaxHours() { return maxHours; } public TaskDO setMaxHours(final Integer maxHours) { this.maxHours = maxHours; return this; } /** -> Gantt */ @Deprecated @Column public Integer getProgress() { return progress; } /** -> Gantt */ @Deprecated public TaskDO setProgress(final Integer progress) { this.progress = progress; return this; } @Column(length = TITLE_LENGTH, nullable = false) public String getTitle() { return title; } public TaskDO setTitle(final String title) { this.title = title; return this; } /** * Please use getTitle() instead. getName() should only be used in Groovy scripts. * * @return The title. */ @Deprecated @Transient public String getName() { return title; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_task_id") public TaskDO getParentTask() { return parentTask; } @Transient public Integer getParentTaskId() { if (this.parentTask == null) { return null; } return this.parentTask.getId(); } public TaskDO setParentTask(final TaskDO parentTask) { this.parentTask = parentTask; return this; } @Enumerated(EnumType.STRING) @Column(length = PRIORITY_LENGTH) public Priority getPriority() { return priority; } public TaskDO setPriority(final Priority priority) { this.priority = priority; return this; } /** * Zu diesem Task knnen keine Zeitberichte mehr eingegeben werden, die vor diesem Datum liegen (z. B. weil bis zu * diesem Datum die Zeitberichte bereits berechnet wurden. Nur die Buchhaltung (PF_Finance) kann noch nderungen * vornehmen. Auch knnen diese Zeitberichte nicht mehr in der Dauer gendert oder gelscht bzw. auerhalb des Tasks * verschoben werden. * * @return */ @Column(name = "protect_timesheets_until") public Date getProtectTimesheetsUntil() { return protectTimesheetsUntil; } public TaskDO setProtectTimesheetsUntil(final Date protectTimesheetsUntil) { this.protectTimesheetsUntil = protectTimesheetsUntil; return this; } @Column(name = "short_description", length = SHORT_DESCRIPTION_LENGTH) public String getShortDescription() { return shortDescription; } public TaskDO setShortDescription(final String shortDescription) { this.shortDescription = shortDescription; return this; } @Enumerated(EnumType.STRING) @Column(length = STATUS_LENGTH) public TaskStatus getStatus() { return status; } public TaskDO setStatus(final TaskStatus status) { this.status = status; return this; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "responsible_user_id") public PFUserDO getResponsibleUser() { return responsibleUser; } public TaskDO setResponsibleUser(final PFUserDO responsibleUser) { this.responsibleUser = responsibleUser; return this; } @Transient public Integer getResponsibleUserId() { if (this.responsibleUser == null) { return null; } return responsibleUser.getId(); } /** * Reference is a free use-able field, which will be inherited to all sibling tasks. The reference is exported e. g. * in the time sheet MS Excel export. */ @Column(length = REFERENCE_LENGTH) public String getReference() { return reference; } public TaskDO setReference(final String reference) { this.reference = reference; return this; } @Enumerated(EnumType.STRING) @Column(name = "timesheet_booking_status", length = 20, nullable = false) public TimesheetBookingStatus getTimesheetBookingStatus() { if (timesheetBookingStatus == null) { return TimesheetBookingStatus.DEFAULT; } else { return timesheetBookingStatus; } } public TaskDO setTimesheetBookingStatus(final TimesheetBookingStatus timesheetBookingStatus) { if (timesheetBookingStatus != null) { this.timesheetBookingStatus = timesheetBookingStatus; } else { this.timesheetBookingStatus = TimesheetBookingStatus.DEFAULT; } return this; } /** * Whether this list is a black or a white list depends on isBlackList() value. Rules: * <ul> * <li>General * <ul> * <li>Multiple entries should be separated by comma, semicolon and/or spaces.</li> * <li>A Kost2 matches if it ends with at least one entry of the list. * </ul> * </li> * <li>Examples * <ul> * <li>"02" matches 5.123.76.02</li> * <li>"76.02" matches 5.123.76.02</li> * <li>"7602" does not match 5.123.76.02</li> * <li>"123.76.02" does not match 5.123.76.02</li> * <li>"5.123.76.02" does not match 5.123.76.02</li> * </ul> * </li> * <li>Black list * <ul> * <li>Has only an effect if a project is assigned to the task.</li> * <li>"*" means, that no cost entry matches.</li> * <li>Every kost2 entry which matches at list one entry will be removed from the kost2 list.</li> * </ul> * </li> * <li>White list * <ul> * <li>If Kost2 entries are assigned (project is given), the only such entries will match, which ends with at least * one entry of the list.</li> * <li>"*" or empty string means, that all cost entry matches.</li> * </ul> * </li> * </ul> */ @Column(name = "kost2_black_white_list", length = 1024) public String getKost2BlackWhiteList() { return kost2BlackWhiteList; } public TaskDO setKost2BlackWhiteList(final String kost2BlackWhiteList) { this.kost2BlackWhiteList = kost2BlackWhiteList; return this; } /** * Get the items of the kost2 black white list as string array. * * @return The items as string array or null, if black white list is null. * @see StringHelper#splitAndTrim(String, String) */ @Transient public String[] getKost2BlackWhiteItems() { return getKost2BlackWhiteItems(getKost2BlackWhiteList()); } /** * Get the items of the kost2 black white list as string array. * * @return The items as string array or null, if black white list is null. * @see StringHelper#splitAndTrim(String, String) */ @Transient public static String[] getKost2BlackWhiteItems(final String kost2BlackWhiteList) { return StringHelper.splitAndTrim(kost2BlackWhiteList, KOST2_SEPARATOR_CHARS); } /** * @return True if the black-white-list should be interpreted as black list, otherwise false (default). */ @Column(name = "kost2_is_black_list", nullable = false) public boolean isKost2IsBlackList() { return kost2IsBlackList; } public TaskDO setKost2IsBlackList(final boolean kost2IsBlackList) { this.kost2IsBlackList = kost2IsBlackList; return this; } @Deprecated @Column(name = "old_kost2_id") public Integer getOldKost2Id() { return oldKost2Id; } @Deprecated public void setOldKost2Id(final Integer oldKost2Id) { this.oldKost2Id = oldKost2Id; } /** * If set then normal user are not allowed to select (read) the time sheets of other users of this task and all sub * tasks. This is important e. g. for hiding the days of illness of an employee. * * @return True if the flag is set. */ @Column(name = "protectionOfPrivacy", nullable = false, columnDefinition = "BOOLEAN DEFAULT 'false'") public boolean isProtectionOfPrivacy() { return protectionOfPrivacy; } /** * @param protectionOfPrivacy * @return This for chaining. */ public TaskDO setProtectionOfPrivacy(final boolean protectionOfPrivacy) { this.protectionOfPrivacy = protectionOfPrivacy; return this; } /** * @see org.projectforge.business.gantt.GanttTask#getStartDate() */ /** -> Gantt */ @Deprecated @Column(name = "start_date") public Date getStartDate() { return startDate; } public TaskDO setStartDate(final Date startDate) { this.startDate = startDate; return this; } /** * @see org.projectforge.business.gantt.GanttTask#getEndDate() */ /** -> Gantt */ @Deprecated @Column(name = "end_date") public Date getEndDate() { return endDate; } /** -> Gantt */ @Deprecated public TaskDO setEndDate(final Date endDate) { this.endDate = endDate; return this; } /** * Duration in days. * * @see org.projectforge.business.gantt.GanttTask#getDuration() */ /** -> Gantt */ @Deprecated @Column(name = "duration", scale = 2, precision = 10) public BigDecimal getDuration() { return duration; } /** -> Gantt */ @Deprecated public TaskDO setDuration(final BigDecimal duration) { this.duration = duration; return this; } /** -> Gantt */ @Column(name = "workpackage_code", length = 100) @Deprecated public String getWorkpackageCode() { return workpackageCode; } @Deprecated public TaskDO setWorkpackageCode(final String workpackageCode) { this.workpackageCode = workpackageCode; return this; } /** -> Gantt */ @Deprecated @Enumerated(EnumType.STRING) @Column(name = "gantt_type", length = 10) public GanttObjectType getGanttObjectType() { return ganttObjectType; } /** -> Gantt */ @Deprecated public TaskDO setGanttObjectType(final GanttObjectType ganttObjectType) { this.ganttObjectType = ganttObjectType; return this; } /** -> Gantt */ @Deprecated @Enumerated(EnumType.STRING) @Column(name = "gantt_rel_type", length = 15) public GanttRelationType getGanttRelationType() { return ganttRelationType; } /** -> Gantt */ @Deprecated public TaskDO setGanttRelationType(final GanttRelationType ganttRelationType) { this.ganttRelationType = ganttRelationType; return this; } /** * In days. */ /** -> Gantt */ @Deprecated @Column(name = "gantt_predecessor_offset") public Integer getGanttPredecessorOffset() { return ganttPredecessorOffset; } /** -> Gantt */ @Deprecated public TaskDO setGanttPredecessorOffset(final Integer ganttPredecessorOffset) { this.ganttPredecessorOffset = ganttPredecessorOffset; return this; } /** * Please note: if you use TaskTree as cache then note, that the depend-on-task can be out-dated! Get the id of the * depend-on-task and get the every-time up-to-date task from the task tree by this id. */ /** -> Gantt */ @Deprecated @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, targetEntity = TaskDO.class) @JoinColumn(name = "gantt_predecessor_fk") public TaskDO getGanttPredecessor() { return ganttPredecessor; } /** -> Gantt */ @Deprecated public TaskDO setGanttPredecessor(final TaskDO ganttPredecessor) { this.ganttPredecessor = ganttPredecessor; return this; } /** -> Gantt */ @Deprecated @Transient public Integer getGanttPredecessorId() { if (this.ganttPredecessor == null) { return null; } else { return this.ganttPredecessor.getId(); } } @Override public boolean equals(final Object o) { if (o instanceof TaskDO) { final TaskDO other = (TaskDO) o; return ObjectUtils.equals(this.getParentTaskId(), other.getParentTaskId()) == true && ObjectUtils.equals(this.getTitle(), other.getTitle()) == true; } return false; } @Override public int hashCode() { final HashCodeBuilder hcb = new HashCodeBuilder(); hcb.append(this.getParentTaskId()).append(this.getTitle()); return hcb.toHashCode(); } @Override public String toString() { final ToStringBuilder builder = new ToStringBuilder(this); builder.append("id", getId()); builder.append("parentTaskId", getParentTaskId()); builder.append("title", getTitle()); builder.append("status", getStatus()); builder.append("priority", getPriority()); builder.append("progress", getProgress()); builder.append("shortDescription", getShortDescription()); builder.append("description", getDescription()); builder.append("maxHours", getMaxHours()); builder.append("startDate", getStartDate()); builder.append("endDate", getEndDate()); builder.append("responsibleUserId", getResponsibleUserId()); if (this.kost2IsBlackList == true) { builder.append("kost2BlackWhiteList", isKost2IsBlackList()); } if (StringUtils.isNotBlank(kost2BlackWhiteList) == true) { builder.append("kost2BlackWhiteList", getKost2BlackWhiteList()); } builder.append("timesheetBookingStatus", getTimesheetBookingStatus()); return builder.toString(); } @Override @Transient public String getShortDisplayName() { return this.getTitle() + " (#" + this.getId() + ")"; } /** * Used for building read-only clone in ScriptingTaskNode. * * @see java.lang.Object#clone() */ @Override protected Object clone() throws CloneNotSupportedException { final TaskDO clone = (TaskDO) super.clone(); if (this.startDate != null) { clone.startDate = (Date) this.startDate.clone(); } if (this.endDate != null) { clone.endDate = (Date) this.endDate.clone(); } if (this.ganttPredecessor != null) { clone.ganttPredecessor = new TaskDO(); clone.ganttPredecessor.setId(this.getGanttPredecessorId()); } if (this.parentTask != null) { clone.parentTask = new TaskDO(); clone.parentTask.setId(this.getParentTaskId()); } if (this.protectTimesheetsUntil != null) { clone.protectTimesheetsUntil = (Date) this.protectTimesheetsUntil.clone(); } if (this.responsibleUser != null) { clone.responsibleUser = new PFUserDO(); clone.responsibleUser.setId(getResponsibleUserId()); } return clone; } }