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
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/TvkQWWs6)
# Features of modern Java

# Цели и задачи л/р:
На основе индивидуального задания произвести разработку бизнес-логики бэкэнда entriprise-системы.

В ходе реализации необходимо использовать возможности современных версий языка Java:
* Pattern matching для switch
* строковые шаблоны))))))))))))))
* Pattern matching для switch - ProjectService.getRoleDescription()
* расширенные возможности стандартной библиотеки Java
* sealed классы и record
* программирование в функциональном стиле
* preview как project Valhalla, structured concurrency...
* sealed классы и record - sealed interface ProjectRole, sealed class ProjectManagementException
* программирование в функциональном стиле - использование stream api / lambdas
* preview как project Valhalla, structured concurrency... - Использование structured concurrency в ProjectSummaryService
* и т.д.

# Обязательное условие:
Expand Down
23 changes: 22 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
plugins {
id("java")
id("application")
}

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

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

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

repositories {
mavenCentral()
}
Expand All @@ -13,8 +24,18 @@ dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation("com.google.guava:guava:33.5.0-jre")
}

tasks.withType<JavaCompile> {
options.compilerArgs.addAll(listOf("--enable-preview"))
}

tasks.withType<JavaExec> {
jvmArgs("--enable-preview")
}

tasks.test {
useJUnitPlatform()
}
jvmArgs("--enable-preview")
}
Empty file modified gradlew
100644 → 100755
Empty file.
176 changes: 176 additions & 0 deletions src/main/java/org/lab/Demo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package org.lab;

import java.time.LocalDate;
import java.util.concurrent.ExecutionException;

import org.lab.model.BugReport;
import org.lab.model.BugSeverity;
import org.lab.model.Milestone;
import org.lab.model.Project;
import org.lab.model.Ticket;
import org.lab.model.User;
import org.lab.service.BugReportService;
import org.lab.service.MilestoneService;
import org.lab.service.ProjectService;
import org.lab.service.ProjectSummaryService;
import org.lab.service.TicketService;
import org.lab.service.UserService;

public class Demo {

public static void main(String[] args) throws InterruptedException, ExecutionException {
var system = ProjectManagementSystem.withDefault();
new Demo().run(system);
}

public void run(ProjectManagementSystem system) throws InterruptedException, ExecutionException {
UserService userService = system.userService();
ProjectService projectService = system.projectService();
MilestoneService milestoneService = system.milestoneService();
TicketService ticketService = system.ticketService();
BugReportService bugReportService = system.bugReportService();
ProjectSummaryService summaryService = system.projectSummaryService();

System.out.println("=== Registering users ===");
User manager = userService.register("alice", "alice@company.com", "Alice Johnson");
User teamLead = userService.register("bob", "bob@company.com", "Bob Smith");
User dev1 = userService.register("charlie", "charlie@company.com", "Charlie Brown");
User dev2 = userService.register("diana", "diana@company.com", "Diana Prince");
User tester = userService.register("eve", "eve@company.com", "Eve Williams");

for (User user : userService.findAll()) {
System.out.println(user);
}

System.out.println("\n=== Creating project ===");
Project project = projectService.createProject(
"E-Commerce Platform",
"Modern e-commerce with microservices",
manager.id()
);
project = projectService.assignTeamLead(project.id(), manager.id(), teamLead.id());
project = projectService.addDeveloper(project.id(), manager.id(), dev1.id());
project = projectService.addDeveloper(project.id(), manager.id(), dev2.id());
project = projectService.addTester(project.id(), manager.id(), tester.id());
System.out.println(project);

System.out.println("\nProject team:");
for (var info : projectService.getProjectTeam(project.id())) {
System.out.println(STR." \{info.role().roleName()}: \{info.user().fullName()}, \{info.description()}");
}

System.out.println("\n=== Creating and activating milestone ===");
Milestone sprint = milestoneService.createMilestone(
project.id(), manager.id(),
"Sprint 1", "MVP features",
LocalDate.now(), LocalDate.now().plusWeeks(2)
);
sprint = milestoneService.activate(sprint.id(), manager.id());
System.out.println(STR."Milestone: \{sprint.name()} [\{sprint.status()}]");
System.out.println(STR."Period: \{sprint.startDate()} - \{sprint.endDate()}");

System.out.println("\n=== Creating and assigning tickets ===");
Ticket t1 = ticketService.createTicket(
project.id(),
sprint.id(),
teamLead.id(),
"Product Catalog API",
"REST endpoints for products"
);
Ticket t2 = ticketService.createTicket(
project.id(),
sprint.id(),
teamLead.id(),
"Shopping Cart",
"Cart functionality"
);
Ticket t3 = ticketService.createTicket(
project.id(),
sprint.id(),
teamLead.id(),
"User Auth",
"JWT authentication"
);

t1 = ticketService.assignDeveloper(t1.id(), teamLead.id(), dev1.id());
t2 = ticketService.assignDeveloper(t2.id(), teamLead.id(), dev2.id());
t3 = ticketService.assignDeveloper(t3.id(), teamLead.id(), dev1.id());

System.out.println(ticketService.getProjectStats(project.id()).summary());

System.out.println("=== Developing ===");
t1 = ticketService.acceptTicket(t1.id(), dev1.id());
t1 = ticketService.startProgress(t1.id(), dev1.id());
t1 = ticketService.completeTicket(t1.id(), dev1.id());
System.out.println(STR."\{dev1.fullName()} completed '\{t1.title()}'");

t2 = ticketService.acceptTicket(t2.id(), dev2.id());
t2 = ticketService.startProgress(t2.id(), dev2.id());
t2 = ticketService.completeTicket(t2.id(), dev2.id());
System.out.println(STR."\{dev2.fullName()} completed '\{t2.title()}'");

System.out.println("\n=== Code review ===");
var review1 = ticketService.reviewTicket(t1.id(), teamLead.id(), true);
System.out.println(STR."'\{t1.title()}': \{review1.message()}");

var review2 = ticketService.reviewTicket(t2.id(), teamLead.id(), false);
System.out.println(STR."'\{t2.title()}': \{review2.message()} -> status: \{review2.ticket().status()}");

t2 = ticketService.completeTicket(review2.ticket().id(), dev2.id());
review2 = ticketService.reviewTicket(t2.id(), teamLead.id(), true);
System.out.println(STR."'\{t2.title()}' after rework: \{review2.message()}");

System.out.println("\n=== Bug reports ===");
BugReport bug1 = bugReportService.createBugReport(
project.id(),
tester.id(),
"Cart calculation error",
"Discount not applied",
BugSeverity.CRITICAL
);
BugReport bug2 = bugReportService.createBugReport(
project.id(),
tester.id(),
"Image not loading",
"404 on thumbnails",
BugSeverity.MAJOR
);

System.out.println(bugReportService.getProjectStats(project.id()).summary());

System.out.println("=== Bug lifecycle ===");
bug1 = bugReportService.assignDeveloper(bug1.id(), teamLead.id(), dev2.id());
bug2 = bugReportService.assignDeveloper(bug2.id(), teamLead.id(), dev1.id());

bug1 = bugReportService.markAsFixed(bug1.id(), dev2.id());
bug2 = bugReportService.markAsFixed(bug2.id(), dev1.id());
System.out.println(STR."Bugs fixed: \{bug1.title()}, \{bug2.title()}");

bug1 = bugReportService.verifyFix(bug1.id(), tester.id(), true);
bug2 = bugReportService.verifyFix(bug2.id(), tester.id(), true);
System.out.println("Bugs verified by tester");

bugReportService.close(bug1.id(), manager.id());
bugReportService.close(bug2.id(), manager.id());

System.out.println(bugReportService.getProjectStats(project.id()).summary());

System.out.println("=== Completing sprint ===");
t3 = ticketService.acceptTicket(t3.id(), dev1.id());
t3 = ticketService.startProgress(t3.id(), dev1.id());
t3 = ticketService.completeTicket(t3.id(), dev1.id());
ticketService.reviewTicket(t3.id(), teamLead.id(), true);

System.out.println(milestoneService.getStats(sprint.id()).summary());

sprint = milestoneService.close(sprint.id(), manager.id());
System.out.println(STR."Milestone '\{sprint.name()}' closed: \{sprint.status()}");

var summary = summaryService.getProjectSummary(project.id());
System.out.println(summary.generateReport());

var activity = summaryService.getUserActivitySummary(dev1.id());
System.out.println(STR."Activity for \{dev1.fullName()}:");
System.out.println(activity.format());
}
}
10 changes: 7 additions & 3 deletions src/main/java/org/lab/Main.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
void main() {
IO.println("Hello and welcome!");
}
package org.lab;

public class Main {

public static void main(String[] args) {
ProjectManagementSystem system = ProjectManagementSystem.withDefault();
}
}
42 changes: 42 additions & 0 deletions src/main/java/org/lab/ProjectManagementSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.lab;

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

public record ProjectManagementSystem(
UserService userService,
ProjectService projectService,
MilestoneService milestoneService,
TicketService ticketService,
BugReportService bugReportService,
ProjectSummaryService projectSummaryService
) {
public static ProjectManagementSystem withDefault() {
var userRepository = new UserRepository();
var projectRepository = new ProjectRepository();
var milestoneRepository = new MilestoneRepository();
var ticketRepository = new TicketRepository();
var bugReportRepository = new BugReportRepository();

var userService = new UserService(userRepository);
var projectService = new ProjectService(projectRepository, userService);
var milestoneService = new MilestoneService(milestoneRepository, ticketRepository, projectService);
var ticketService = new TicketService(ticketRepository, milestoneRepository, projectService);
var bugReportService = new BugReportService(bugReportRepository, projectService);
var projectSummaryService = new ProjectSummaryService(
projectService,
ticketRepository,
bugReportRepository,
milestoneRepository
);

return new ProjectManagementSystem(
userService,
projectService,
milestoneService,
ticketService,
bugReportService,
projectSummaryService
);
}
}
73 changes: 73 additions & 0 deletions src/main/java/org/lab/exception/ProjectManagementException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.lab.exception;

import org.lab.model.role.Permission;

public sealed class ProjectManagementException extends RuntimeException permits
ProjectManagementException.EntityNotFoundException,
ProjectManagementException.AccessDeniedException,
ProjectManagementException.InvalidOperationException,
ProjectManagementException.DuplicateEntityException,
ProjectManagementException.ValidationException {

public ProjectManagementException(String message) {
super(message);
}

public static final class EntityNotFoundException extends ProjectManagementException {
private final String entityType;
private final String identifier;

public EntityNotFoundException(String entityType, String identifier) {
super("%s not found: %s".formatted(entityType, identifier));
this.entityType = entityType;
this.identifier = identifier;
}

public String getEntityType() {
return entityType;
}
public String getIdentifier() {
return identifier;
}
}

public static final class AccessDeniedException extends ProjectManagementException {
public AccessDeniedException(Permission requiredPermission) {
super("Access denied. Required permission: %s".formatted(requiredPermission));
}

public AccessDeniedException(String message) {
super(message);
}
}

public static final class InvalidOperationException extends ProjectManagementException {
public InvalidOperationException(String message) {
super(message);
}
}

public static final class DuplicateEntityException extends ProjectManagementException {
private final String entityType;
private final String field;

public DuplicateEntityException(String entityType, String field, String value) {
super("%s with %s='%s' already exists".formatted(entityType, field, value));
this.entityType = entityType;
this.field = field;
}

public String getEntityType() {
return entityType;
}
public String getField() {
return field;
}
}

public static final class ValidationException extends ProjectManagementException {
public ValidationException(String message) {
super(message);
}
}
}
Loading