models.Milestone.java Source code

Java tutorial

Introduction

Here is the source code for models.Milestone.java

Source

/**
 * Yobi, Project Hosting SW
 *
 * Copyright 2012 NAVER Corp.
 * http://yobi.io
 *
 * @Author Tae
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package models;

import models.enumeration.*;
import models.resource.Resource;
import models.resource.ResourceConvertible;
import models.support.*;

import org.apache.commons.lang3.time.DateUtils;
import play.data.format.*;
import play.data.validation.*;
import play.db.ebean.*;
import play.i18n.Messages;
import utils.JodaDateUtil;

import javax.persistence.*;
import java.text.*;
import java.util.*;

@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "project_id", "title" }))
public class Milestone extends Model implements ResourceConvertible {

    private static final long serialVersionUID = 1L;
    public static final Finder<Long, Milestone> find = new Finder<>(Long.class, Milestone.class);

    public static final String DEFAULT_SORTER = "dueDate";

    public static final Long NULL_MILESTONE_ID = -1l;

    @Id
    public Long id;

    @Constraints.Required
    public String title;

    @Formats.DateTime(pattern = "yyyy-MM-dd")
    public Date dueDate;

    @Constraints.Required
    @Lob
    public String contents;

    @Constraints.Required
    public State state;

    @ManyToOne
    public Project project;

    @OneToMany(mappedBy = "milestone")
    public Set<Issue> issues;

    public void delete() {
        // Set all issues' milestone to null.
        // I don't know why Ebean does not do this by itself.
        for (Issue issue : issues) {
            issue.milestone = null;
            issue.update();
        }

        super.delete();
    }

    public static void create(Milestone milestone) {
        milestone.save();
    }

    public int getNumClosedIssues() {
        return Issue.finder.where().eq("milestone", this).eq("state", State.CLOSED).findRowCount();
    }

    public int getNumOpenIssues() {
        return Issue.finder.where().eq("milestone", this).eq("state", State.OPEN).findRowCount();
    }

    public List<Issue> sortedByNumberOfIssue() {
        List<Issue> sortedIssues = new ArrayList<>(this.issues);
        Collections.sort(sortedIssues, new Comparator<Issue>() {
            @Override
            public int compare(Issue a, Issue b) {
                return b.getNumber().compareTo(a.getNumber());
            }
        });
        return sortedIssues;
    }

    public List<Issue> sortedByNumberOfOpenIssue() {
        List<Issue> openedIssues = new ArrayList<>();
        for (Issue issue : sortedByNumberOfIssue()) {
            if (issue.isOpen()) {
                openedIssues.add(issue);
            }
        }
        return openedIssues;
    }

    public List<Issue> sortedByNumberOfClosedIssue() {
        List<Issue> closedIssues = new ArrayList<>();
        for (Issue issue : sortedByNumberOfIssue()) {
            if (issue.isClosed()) {
                closedIssues.add(issue);
            }
        }
        return closedIssues;
    }

    public int getNumTotalIssues() {
        return issues.size();
    }

    public int getCompletionRate() {
        return (int) (((double) getNumClosedIssues() / (double) getNumTotalIssues()) * 100);
    }

    public static Milestone findById(Long id) {
        return find.byId(id);
    }

    public static List<Milestone> findByProjectId(Long projectId) {
        return Milestone.findMilestones(projectId, State.ALL);
    }

    public static List<Milestone> findClosedMilestones(Long projectId) {
        return Milestone.findMilestones(projectId, State.CLOSED);
    }

    public static List<Milestone> findOpenMilestones(Long projectId) {
        return Milestone.findMilestones(projectId, State.OPEN);
    }

    /**
     * convert mildestone due date string into yyyy-MM-dd format
     *
     * @return
     */
    public String getDueDateString() {
        if (dueDate == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(this.dueDate);
    }

    /**
     * Sort milestone list by direction. 
     * If there is no direction, then sort with DEFAULT_SORTER.
     *
     * @param projectId
     * @param state
     * @return
     */
    public static List<Milestone> findMilestones(Long projectId, State state) {
        return findMilestones(projectId, state, DEFAULT_SORTER, Direction.ASC);
    }

    /**
     * find milestone with OrderParam (string for sorting)
     *
     * @param projectId
     * @param state
     * @param sort
     * @param direction
     * @return
     */
    public static List<Milestone> findMilestones(Long projectId, State state, String sort,
            final Direction direction) {

        OrderParams orderParams = new OrderParams();

        if (!"completionRate".equals(sort)) {
            orderParams.add(sort, direction);
        }

        SearchParams searchParams = new SearchParams().add("project.id", projectId, Matching.EQUALS);
        if (state != null && state != State.ALL) {
            searchParams.add("state", state, Matching.EQUALS);
        }

        List<Milestone> milestones = FinderTemplate.findBy(orderParams, searchParams, find);

        if ("completionRate".equals(sort)) {
            Collections.sort(milestones, new Comparator<Milestone>() {
                @Override
                public int compare(Milestone o1, Milestone o2) {
                    int o1CompletionRate = o1.getCompletionRate();
                    int o2CompletionRate = o2.getCompletionRate();

                    if (direction == Direction.ASC) {
                        return (o1CompletionRate < o2CompletionRate ? -1
                                : (o1CompletionRate == o2CompletionRate ? 0 : 1));
                    } else {
                        return (o1CompletionRate < o2CompletionRate ? 1
                                : (o1CompletionRate == o2CompletionRate ? 0 : -1));
                    }
                }
            });
        }

        return milestones;
    }

    public void updateWith(Milestone newMilestone) {
        this.contents = newMilestone.contents;
        this.title = newMilestone.title;
        this.dueDate = newMilestone.dueDate;
        this.state = newMilestone.state;
        save();
    }

    /**
     * get milestone list by hashmap.
     * key: milestone id
     * value: milestone title
     *
     * @return linkedHashMap
     */
    public static Map<String, String> options(Long projectId) {
        LinkedHashMap<String, String> options = new LinkedHashMap<>();
        for (Milestone milestone : findMilestones(projectId, State.ALL, "title", Direction.ASC)) {
            options.put(milestone.id.toString(), milestone.title);
        }
        return options;
    }

    public static boolean isUniqueProjectIdAndTitle(Long projectId, String title) {
        int count = find.where().eq("project.id", projectId).eq("title", title).findRowCount();
        return (count == 0);
    }

    public String until() {
        if (dueDate == null) {
            return null;
        }

        Date now = JodaDateUtil.now();

        if (DateUtils.isSameDay(now, dueDate)) {
            return Messages.get("common.time.today");
        } else if (isOverDueDate()) {
            return Messages.get("common.time.overday", JodaDateUtil.localDaysBetween(dueDate, now));
        } else {
            return Messages.get("common.time.leftday", JodaDateUtil.localDaysBetween(now, dueDate));
        }
    }

    public Boolean isOverDueDate() {
        return (JodaDateUtil.ago(dueDate).getMillis() > 0);
    }

    @Override
    public Resource asResource() {
        return new Resource() {
            @Override
            public String getId() {
                return id.toString();
            }

            @Override
            public Project getProject() {
                return project;
            }

            @Override
            public ResourceType getType() {
                return ResourceType.MILESTONE;
            }
        };
    }

    public void open() {
        this.state = State.OPEN;
        update();
    }

    public void close() {
        this.state = State.CLOSED;
        update();
    }

    public boolean isNullMilestone() {
        return this.id.equals(NULL_MILESTONE_ID);
    }

    public static int countOpened(Project project) {
        return find.where().eq("project", project).eq("state", State.OPEN).findRowCount();
    }
}