Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ build/
!**/src/test/**/build/

### IntelliJ IDEA ###
.idea
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
Expand Down Expand Up @@ -38,5 +39,7 @@ bin/
### VS Code ###
.vscode/

.java-version

### Mac OS ###
.DS_Store
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

# Цели и задачи л/р:
Expand Down
30 changes: 25 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
plugins {
id("java")
java
application
}

group = "org.lab"
version = "1.0-SNAPSHOT"

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}

repositories {
mavenCentral()
}

application {
mainClass.set("org.lab.Main")
}

dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")

testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.test {
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("--enable-preview")
}

tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
jvmArgs("--enable-preview")
}

tasks.withType<JavaExec>().configureEach {
jvmArgs("--enable-preview")
}
Empty file modified gradlew
100644 → 100755
Empty file.
84 changes: 81 additions & 3 deletions src/main/java/org/lab/Main.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,82 @@
void main() {
IO.println("Hello and welcome!");
}
package org.lab;

import org.lab.model.*;
import org.lab.repository.*;
import org.lab.service.*;
import org.lab.workflow.*;

import java.time.LocalDate;

public class Main {
public static void main() {

UserRepository userRepo = new UserRepository();
ProjectRepository projectRepo = new ProjectRepository();
MilestoneRepository milestoneRepo = new MilestoneRepository();
TicketRepository ticketRepo = new TicketRepository();
BugReportRepository bugRepo = new BugReportRepository();

RoleValidationService roleValidator = new RoleValidationService();

UserService userService = new UserService(userRepo, projectRepo, ticketRepo, bugRepo);
ProjectService projectService = new ProjectService(projectRepo, roleValidator);
MilestoneService milestoneService = new MilestoneService(milestoneRepo, ticketRepo, roleValidator);
TicketService ticketService = new TicketService(ticketRepo, roleValidator);
BugReportService bugService = new BugReportService(bugRepo, roleValidator);

WorkflowService workflow = new WorkflowService(ticketService, bugService);

User manager = userService.register("Alice (Manager)");
User dev = userService.register("Bob (Developer)");
User tester = userService.register("Eve (Tester)");

Project project = projectService.createProject(manager, "Enterprise Project");
project = projectService.addMember(project, manager, dev, Role.DEVELOPER);
project = projectService.addMember(project, manager, tester, Role.TESTER);

Milestone milestone = milestoneService.createMilestone(manager, project, "Milestone 1",
LocalDate.now(), LocalDate.now().plusDays(14));

Ticket ticket = workflow.apply(manager, project, milestone,
new CreateTicket("Implement Auth", "JWT-based login/logout"));

ticket = workflow.apply(manager, project, ticket,
new AssignDeveloper(dev.id()));

ticket = workflow.apply(dev, project, ticket, new StartWork());
ticket = workflow.apply(dev, project, ticket, new CompleteWork());

System.out.println("Ticket status after completion: " + ticket.status());

BugReport bug = workflow.apply(tester, project, null,
new ReportBug("Login fails on empty password"));

bug = workflow.apply(dev, project, bug, new FixBug());
bug = workflow.apply(tester, project, bug, new TestBug());
bug = workflow.apply(tester, project, bug, new CloseBug());

System.out.println("Bug status after closure: " + bug.status());

milestone = milestoneService.closeMilestone(manager, project, milestone);

String report = """
===== PROJECT REPORT =====
Project: %s
Milestone: %s
Milestone status: %s
Ticket: %s
Ticket status: %s
Bug status: %s
=========================
""".formatted(
project.name(),
milestone.name(),
milestone.status(),
ticket.title(),
ticket.status(),
bug.status()
);

System.out.println(report);
}
}
36 changes: 36 additions & 0 deletions src/main/java/org/lab/model/BugReport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.lab.model;

import java.util.UUID;

public record BugReport(
UUID id,
UUID projectId,
String description,
BugStatus status,
UUID assignedDeveloperId
) {

public BugReport assignDeveloper(UUID developerId) {
return new BugReport(
id,
projectId,
description,
status,
developerId
);
}

public BugReport changeStatus(BugStatus newStatus) {
return new BugReport(
id,
projectId,
description,
newStatus,
assignedDeveloperId
);
}

public boolean isOpen() {
return status != BugStatus.CLOSED;
}
}
8 changes: 8 additions & 0 deletions src/main/java/org/lab/model/BugStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.lab.model;

public enum BugStatus {
NEW,
FIXED,
TESTED,
CLOSED
}
53 changes: 53 additions & 0 deletions src/main/java/org/lab/model/Milestone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.lab.model;

import java.time.LocalDate;
import java.util.List;
import java.util.UUID;

public record Milestone(
UUID id,
UUID projectId,
String name,
LocalDate startDate,
LocalDate endDate,
MilestoneStatus status,
List<UUID> ticketIds
) {

public Milestone addTicket(UUID ticketId) {
var updated = new java.util.ArrayList<>(ticketIds);
updated.add(ticketId);

return new Milestone(
id,
projectId,
name,
startDate,
endDate,
status,
List.copyOf(updated)
);
}

public boolean canBeClosed(List<Ticket> tickets) {
return tickets.stream()
.filter(t -> ticketIds.contains(t.id()))
.allMatch(Ticket::isCompleted);
}

public Milestone changeStatus(MilestoneStatus newStatus) {
return new Milestone(
id,
projectId,
name,
startDate,
endDate,
newStatus,
ticketIds
);
}

public boolean isActive() {
return status == MilestoneStatus.ACTIVE;
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/lab/model/MilestoneStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.lab.model;

public enum MilestoneStatus {
OPEN, ACTIVE, CLOSED
}
32 changes: 32 additions & 0 deletions src/main/java/org/lab/model/Project.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.lab.model;

import java.util.*;

public record Project(
UUID id,
String name,
List<ProjectMembership> memberships,
List<Milestone> milestones,
List<BugReport> bugReports
) {

public Project addMember(UUID userId, Role role) {
var updated = new ArrayList<>(memberships);
updated.add(new ProjectMembership(userId, role));

return new Project(
id,
name,
List.copyOf(updated),
milestones,
bugReports
);
}

public Optional<Role> getUserRole(UUID userId) {
return memberships.stream()
.filter(m -> m.userId().equals(userId))
.map(ProjectMembership::role)
.findFirst();
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/lab/model/ProjectMembership.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.lab.model;

import java.util.UUID;

public record ProjectMembership(UUID userId, Role role) {}
8 changes: 8 additions & 0 deletions src/main/java/org/lab/model/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.lab.model;

public enum Role {
MANAGER,
TEAM_LEAD,
DEVELOPER,
TESTER
}
42 changes: 42 additions & 0 deletions src/main/java/org/lab/model/Ticket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.lab.model;

import java.util.UUID;

public record Ticket(
UUID id,
UUID projectId,
UUID milestoneId,
String title,
String description,
TicketStatus status,
UUID assignedDeveloperId
) {

public Ticket assignDeveloper(UUID developerId) {
return new Ticket(
id,
projectId,
milestoneId,
title,
description,
status,
developerId
);
}

public Ticket changeStatus(TicketStatus newStatus) {
return new Ticket(
id,
projectId,
milestoneId,
title,
description,
newStatus,
assignedDeveloperId
);
}

public boolean isCompleted() {
return status == TicketStatus.DONE;
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/lab/model/TicketStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.lab.model;

public enum TicketStatus {
NEW, ACCEPTED, IN_PROGRESS, DONE
}
5 changes: 5 additions & 0 deletions src/main/java/org/lab/model/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.lab.model;

import java.util.UUID;

public record User(UUID id, String name) {}
26 changes: 26 additions & 0 deletions src/main/java/org/lab/repository/BugReportRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.lab.repository;

import org.lab.model.BugReport;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class BugReportRepository {

private final Map<UUID, BugReport> storage = new ConcurrentHashMap<>();

public BugReport save(BugReport bug) {
storage.put(bug.id(), bug);
return bug;
}

public List<BugReport> findAll() {
return List.copyOf(storage.values());
}

public List<BugReport> findByProject(UUID projectId) {
return storage.values().stream()
.filter(b -> b.projectId().equals(projectId))
.toList();
}
}
Loading