diff --git a/README.md b/README.md index 4a80115..19aec56 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/TvkQWWs6) # Features of modern Java # Цели и задачи л/р: diff --git a/build.gradle.kts b/build.gradle.kts index 79bf52a..e4d3ceb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,12 @@ plugins { group = "org.lab" version = "1.0-SNAPSHOT" +java { + toolchain { + languageVersion = JavaLanguageVersion.of(26) + } +} + repositories { mavenCentral() } @@ -17,4 +23,19 @@ dependencies { tasks.test { useJUnitPlatform() +} + +// 2. Включаем preview-фичи для компиляции +tasks.withType().configureEach { + options.compilerArgs.add("--enable-preview") +} + +// 3. Включаем preview-фичи для запуска тестов +tasks.withType().configureEach { + jvmArgs("--enable-preview") +} + +// 4. Включаем preview-фичи для запуска приложения через run +tasks.withType().configureEach { + jvmArgs("--enable-preview") } \ No newline at end of file diff --git a/src/main/java/org/lab/Main.java b/src/main/java/org/lab/Main.java index 22028ef..183bc87 100644 --- a/src/main/java/org/lab/Main.java +++ b/src/main/java/org/lab/Main.java @@ -1,4 +1,40 @@ +import org.lab.model.bug.Bug; +import org.lab.model.bug.BugStatus; +import org.lab.model.milestone.MilestoneStatus; +import org.lab.model.users.Developer; +import org.lab.model.users.Manager; + +import java.util.Date; + void main() { - IO.println("Hello and welcome!"); + Manager manager = new Manager("Manager"); + var project = manager.createProject("Lab 4"); + IO.println("Manager " + manager.getName() + " create project " + project.getName()); + + var developer = new Developer("Backend"); + manager.addDeveloper(project, developer); + + var milestone = manager.createMilestone("MVP", new Date(), project); + manager.setMilestoneStatus(milestone, MilestoneStatus.ACTIVE); + + var _ = manager.createTicket("Do backend", project, milestone, developer); + + var bug = developer.createBug(project, "can't start backend"); + var newBug = new Bug("can't start backend", project, BugStatus.NEW); + IO.println(bug == newBug); + + Bug[] bugs = new Bug[2]; + bugs[0] = bug; + bugs[1] = newBug; + + var fixedBug = developer.resolveBug(); + IO.println(bug == fixedBug); + IO.println(developer.getFirstBug() == fixedBug); + IO.println(developer.getFirstBug() == bug); + + Object[] closedBugs = Arrays.stream(bugs).map(Bug::withFixed).map(Bug::withTested).map(Bug::withClosed).toArray(); + IO.println(closedBugs[0] == closedBugs[1]); + + var _ = new Developer("python backend"); } diff --git a/src/main/java/org/lab/Point.java b/src/main/java/org/lab/Point.java new file mode 100644 index 0000000..8c457fe --- /dev/null +++ b/src/main/java/org/lab/Point.java @@ -0,0 +1,22 @@ +package org.lab; + +public value class Point { + private final double x; + private final double y; + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + + public double x() { return x; } + public double y() { return y; } + + public Point withX(double newX) { + return new Point(newX, this.y); + } + + public Point withY(double newY) { + return new Point(this.x, newY); + } +} diff --git a/src/main/java/org/lab/model/bug/Bug.java b/src/main/java/org/lab/model/bug/Bug.java new file mode 100644 index 0000000..12e8c0b --- /dev/null +++ b/src/main/java/org/lab/model/bug/Bug.java @@ -0,0 +1,25 @@ +package org.lab.model.bug; + +import org.lab.model.project.Project; + +public value record Bug(String name, Project project, BugStatus status) { + public Bug(String name, Project project) { + this(name, project, BugStatus.NEW); + } + + public Bug withProject(Project project) { + return new Bug(this.name, project, this.status); + } + + public Bug withFixed() { + return new Bug(this.name, this.project, BugStatus.FIXED); + } + + public Bug withTested() { + return new Bug(this.name, this.project, BugStatus.FIXED); + } + + public Bug withClosed() { + return new Bug(this.name, this.project, BugStatus.CLOSED); + } +} \ No newline at end of file diff --git a/src/main/java/org/lab/model/bug/BugStatus.java b/src/main/java/org/lab/model/bug/BugStatus.java new file mode 100644 index 0000000..9983871 --- /dev/null +++ b/src/main/java/org/lab/model/bug/BugStatus.java @@ -0,0 +1,8 @@ +package org.lab.model.bug; + +public enum BugStatus { + NEW, + FIXED, + TESTED, + CLOSED, +} diff --git a/src/main/java/org/lab/model/milestone/Milestone.java b/src/main/java/org/lab/model/milestone/Milestone.java new file mode 100644 index 0000000..b9361a9 --- /dev/null +++ b/src/main/java/org/lab/model/milestone/Milestone.java @@ -0,0 +1,50 @@ +package org.lab.model.milestone; + +import org.lab.model.project.Project; +import org.lab.model.ticket.Ticket; + +import java.util.ArrayList; +import java.util.Date; +import java.util.SequencedCollection; + +public class Milestone { + private final String name; + private final Date date; + private final Project project; + private final SequencedCollection tickets = new ArrayList<>(); + private MilestoneStatus status = MilestoneStatus.OPEN; + + public Milestone(String name, Date date, Project project) { + this.name = name; + this.date = date; + this.project = project; + } + + public void setStatus(MilestoneStatus status) { + this.status = status; + } + + public void addTicket(Ticket ticket) { + this.tickets.addFirst(ticket); + } + + public SequencedCollection getTickets() { + return this.tickets; + } + + public Date getDate() { + return date; + } + + public Project getProject() { + return project; + } + + public MilestoneStatus getStatus() { + return status; + } + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/org/lab/model/milestone/MilestoneStatus.java b/src/main/java/org/lab/model/milestone/MilestoneStatus.java new file mode 100644 index 0000000..fa936cc --- /dev/null +++ b/src/main/java/org/lab/model/milestone/MilestoneStatus.java @@ -0,0 +1,7 @@ +package org.lab.model.milestone; + +public enum MilestoneStatus { + OPEN, + ACTIVE, + CLOSED, +} diff --git a/src/main/java/org/lab/model/project/Project.java b/src/main/java/org/lab/model/project/Project.java new file mode 100644 index 0000000..f28e32e --- /dev/null +++ b/src/main/java/org/lab/model/project/Project.java @@ -0,0 +1,114 @@ +package org.lab.model.project; + +import org.lab.model.bug.Bug; +import org.lab.model.milestone.Milestone; +import org.lab.model.users.*; + +import java.util.*; + +public class Project { + String name; + Leader leader; + Manager manager; + List developers = new ArrayList<>(); + List testers = new ArrayList<>(); + + List milestones = new ArrayList<>(); + SequencedCollection bugs = new ArrayList<>(); + + public Project(String name) { + this.name = name; + } + + public void addManager(Manager manager) { + if (this.manager != null) { + this.removeUser(manager); + } + this.manager = manager; + manager.addProject(this); + } + + public void removeUser(User user) { + StringBuilder sb = new StringBuilder(); + sb.append("Remove "); + switch (user) { + case Developer developer -> { + this.developers.remove(developer); + developer.removeProject(this); + sb.append("developer ").append(developer.getName()); + } + case Tester tester -> { + this.testers.remove(tester); + tester.removeProject(this); + sb.append("tester ").append(tester.getName()); + } + case Manager manager -> { + this.manager = null; + manager.removeProject(this); + sb.append("manager ").append(manager.getName()); + } + case Leader leader -> { + this.leader = null; + leader.removeProject(this); + sb.append("leader ").append(leader.getName()); + } + default -> throw new IllegalStateException("Unexpected value: " + user); + } + sb.append(" from project ").append(this.getName()); + String result = sb.toString(); + System.out.println(result); + } + + public void addUser(User user) { + StringBuilder sb = new StringBuilder(); + sb.append("Add "); + switch (user) { + case Developer developer -> { + this.developers.add(developer); + developer.addProject(this); + sb.append("developer ").append(developer.getName()); + } + case Tester tester -> { + this.testers.add(tester); + tester.addProject(this); + sb.append("tester ").append(tester.getName()); + } + case Manager manager -> { + if (this.manager != null) { + this.removeUser(manager); + } + this.manager = manager; + manager.addProject(this); + sb.append("manager ").append(manager.getName()); + } + case Leader leader -> { + if (this.leader != null) { + this.removeUser(this.leader); + } + this.leader = leader; + leader.addProject(this); + sb.append("leader ").append(leader.getName()); + } + default -> throw new IllegalStateException("Unexpected value: " + user); + } + sb.append(" to project ").append(this.getName()); + String result = sb.toString(); + System.out.println(result); + } + + public void addMilestone(Milestone milestone) { + this.milestones.add(milestone); + } + + public void addBug(Bug bug) { + this.bugs.addLast(bug); + } + + public boolean isManager(Manager manager) { + return this.manager == manager; + } + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/org/lab/model/ticket/Ticket.java b/src/main/java/org/lab/model/ticket/Ticket.java new file mode 100644 index 0000000..1b0b194 --- /dev/null +++ b/src/main/java/org/lab/model/ticket/Ticket.java @@ -0,0 +1,11 @@ +package org.lab.model.ticket; + +import org.lab.model.milestone.Milestone; +import org.lab.model.project.Project; +import org.lab.model.users.Developer; + +public record Ticket(String name, Project project, Developer developer, Milestone milestone, TicketStatus status) { + public Ticket(String name, Project project, Developer developer, Milestone milestone) { + this(name, project, developer, milestone, TicketStatus.NEW); + } +} \ No newline at end of file diff --git a/src/main/java/org/lab/model/ticket/TicketStatus.java b/src/main/java/org/lab/model/ticket/TicketStatus.java new file mode 100644 index 0000000..00cd6d6 --- /dev/null +++ b/src/main/java/org/lab/model/ticket/TicketStatus.java @@ -0,0 +1,8 @@ +package org.lab.model.ticket; + +public enum TicketStatus { + NEW, + ACCEPTED, + IN_PROGRESS, + COMPLETED, +} diff --git a/src/main/java/org/lab/model/users/Developer.java b/src/main/java/org/lab/model/users/Developer.java new file mode 100644 index 0000000..96bf1b2 --- /dev/null +++ b/src/main/java/org/lab/model/users/Developer.java @@ -0,0 +1,26 @@ +package org.lab.model.users; + +import org.lab.model.bug.Bug; +import org.lab.model.project.Project; + +public final class Developer extends User { + public Developer(String name) { + if (name.contains("python")) throw new IllegalArgumentException("we can't create python developers"); + super(name); + } + + public Bug createBug(Project project, String name) { + var bug = new Bug(name, project); + project.addBug(bug); + this.bugs.addLast(bug); + return bug; + } + + public Bug resolveBug() { + var bug = this.bugs.getFirst(); + bug = bug.withFixed(); + this.bugs.removeFirst(); + this.bugs.addFirst(bug); + return bug; + } +} diff --git a/src/main/java/org/lab/model/users/Leader.java b/src/main/java/org/lab/model/users/Leader.java new file mode 100644 index 0000000..6c8438f --- /dev/null +++ b/src/main/java/org/lab/model/users/Leader.java @@ -0,0 +1,7 @@ +package org.lab.model.users; + +public final class Leader extends User { + public Leader(String name) { + super(name); + } +} diff --git a/src/main/java/org/lab/model/users/Manager.java b/src/main/java/org/lab/model/users/Manager.java new file mode 100644 index 0000000..a96b5b8 --- /dev/null +++ b/src/main/java/org/lab/model/users/Manager.java @@ -0,0 +1,68 @@ +package org.lab.model.users; + +import org.lab.model.milestone.Milestone; +import org.lab.model.milestone.MilestoneStatus; +import org.lab.model.project.Project; +import org.lab.model.ticket.Ticket; +import org.lab.model.ticket.TicketStatus; + +import java.util.Date; + +public final class Manager extends User { + public Manager(String name) { + super(name); + } + + public void addLeader(Project project, Leader leader) { + if (project.isManager(this)) { + return; + } + project.addUser(leader); + leader.addProject(project); + } + + public void addDeveloper(Project project, Developer developer) { + if (project.isManager(this)) { + return; + } + project.addUser(developer); + developer.addProject(project); + } + + public void addTester(Project project, Tester tester) { + if (project.isManager(this)) { + return; + } + project.addUser(tester); + tester.addProject(project); + } + + public Milestone createMilestone(String name, Date date, Project project) { + var milestone = new Milestone(name, date, project); + IO.println("Manager " + this.getName() + " create milestone " + milestone.getName()); + return milestone; + } + + public void setMilestoneStatus(Milestone milestone, MilestoneStatus status) { + StringBuilder sb = new StringBuilder(); + sb.append("Manager ").append(this.getName()); + sb.append(" milestone ").append(milestone.getName()); + sb.append(" switch status from ").append(milestone.getStatus()); + milestone.setStatus(status); + sb.append(" to ").append(milestone.getStatus()); + String result = sb.toString(); + System.out.println(result); + } + + public Ticket createTicket(String name, Project project, Milestone milestone, Developer developer) { + var ticket = new Ticket(name, project, developer, milestone); + developer.addTicket(ticket); + milestone.addTicket(ticket); + IO.println("Manager " + this.getName() + " create ticket " + ticket.name()); + return ticket; + } + + public boolean checkTicketSuccess(Ticket ticket) { + return ticket.status() == TicketStatus.COMPLETED; + } +} diff --git a/src/main/java/org/lab/model/users/Tester.java b/src/main/java/org/lab/model/users/Tester.java new file mode 100644 index 0000000..8fdc442 --- /dev/null +++ b/src/main/java/org/lab/model/users/Tester.java @@ -0,0 +1,7 @@ +package org.lab.model.users; + +public final class Tester extends User{ + public Tester(String name) { + super(name); + } +} diff --git a/src/main/java/org/lab/model/users/User.java b/src/main/java/org/lab/model/users/User.java new file mode 100644 index 0000000..40d5658 --- /dev/null +++ b/src/main/java/org/lab/model/users/User.java @@ -0,0 +1,64 @@ +package org.lab.model.users; + +import org.lab.model.bug.Bug; +import org.lab.model.project.Project; +import org.lab.model.ticket.Ticket; + +import java.util.*; + +public sealed class User permits Developer, Tester, Manager, Leader { + protected final String name; + protected final Set projects = new HashSet<>(); + protected final SequencedCollection tickets = new ArrayList<>(); + protected final SequencedCollection bugs = new ArrayList<>(); + + public User(String name) { + this.name = name; + } + + public Project createProject(String name) { + var project = new Project(name); + this.projects.add(project); + return project; + } + + public void removeProject(Project project) { + this.projects.remove(project); + } + + public void addProject(Project project) { + this.projects.add(project); + } + + public List getAllProjects() { + return this.projects.stream().toList(); + } + + public void addTicket(Ticket ticket) { + this.tickets.addLast(ticket); + } + + public Ticket getFirstTicket() { + return this.tickets.getFirst(); + } + + public List getAllTickets() { + return this.tickets.stream().toList(); + } + + public void addBug(Bug bug) { + this.bugs.addLast(bug); + } + + public Bug getFirstBug() { + return this.bugs.getFirst(); + } + + public List getAllBugs() { + return this.bugs.stream().toList(); + } + + public String getName() { + return this.name; + } +}