Skip to content

Commit

Permalink
Corrected List<Epic> conversion check issue PredefinedTasksSerializer…
Browse files Browse the repository at this point in the history
…; Corrected PredefinedTasksDeserializer output; Fixed issue with infinite logged time calculation; Corrected randomized epics saving issue; Additional code corrections and optimization
  • Loading branch information
MarkoDojkic committed Aug 21, 2024
1 parent 37d3e64 commit 2f5cc94
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ public List<UserStory> assignUserStoriesAndPrepareTechnicalTasks(Message<Epic> e

new Thread(() -> inProgressEpic.send(epicMessage)).start();

if(getTotalEpicsCount() != -1) {
if(getEpicsForSaving() != null) {
addEpicForSaving(epic);
setTotalEpicsCount(getTotalEpicsCount() - 1);
if(getTotalEpicsCount() == 0) saveEpics();
if(getEpicsForSaving().size() == getTotalEpicsCount()) saveEpics();
}

return epic.getUserStories();
Expand Down Expand Up @@ -170,10 +169,14 @@ private boolean markUserStoryAsDone(UserStory userStory){
}

private int calculateTotalLoggedTimeInHours(Developer reporter, Developer assignee, Priority taskPriority){
double reporterExpertise = reporter.getExperienceCoefficient() * reporter.getDeveloperType().getSeniorityCoefficient();
double assigneeExpertise = assignee.getExperienceCoefficient() * assignee.getDeveloperType().getSeniorityCoefficient();
double averageExpertise = (reporterExpertise + assigneeExpertise) / 2.0;

return (int) Math.round(Math.clamp(1.0, 240.0 * (taskPriority.getResolutionTimeCoefficient() / averageExpertise) * (1.0 / (1 + taskPriority.getUrgency())), 240.0));
try {
double reporterExpertise = reporter.getExperienceCoefficient() * reporter.getDeveloperType().getSeniorityCoefficient();
double assigneeExpertise = assignee.getExperienceCoefficient() * assignee.getDeveloperType().getSeniorityCoefficient();
double averageExpertise = (reporterExpertise + assigneeExpertise) / 2.0;

return (int) Math.round(Math.clamp(1.0, 240.0 * (taskPriority.getResolutionTimeCoefficient() / averageExpertise) * (1.0 / (1 + taskPriority.getUrgency())), 240.0));
} catch (Exception e){
return 240;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package dev.markodojkic.softwaredevelopmentsimulation.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.common.reflect.TypeToken;
import dev.markodojkic.softwaredevelopmentsimulation.model.Epic;
import dev.markodojkic.softwaredevelopmentsimulation.util.EpicNotDoneException;
import dev.markodojkic.softwaredevelopmentsimulation.util.PredefinedTasksDeserializer;
Expand All @@ -26,14 +30,17 @@
import org.springframework.messaging.MessageChannel;
import org.springframework.retry.support.RetryTemplateBuilder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.UUID;

@Configuration
@EnableIntegration
@IntegrationComponentScan(basePackages = "dev.markodojkic.softwaredevelopmentsimulation")
@SuppressWarnings("unchecked")
public class MiscellaneousConfig {
private static final String CLIENT_ID = "be-client-" + UUID.randomUUID();

Expand Down Expand Up @@ -103,7 +110,34 @@ public ObjectMapper objectMapper() {
SimpleModule module = new SimpleModule();

//Add mappings for predefined tasks
module.addSerializer(Epic.class, new PredefinedTasksSerializer());
module.addSerializer(new JsonSerializer<List<?>>() {
@Override
public void serialize(List<?> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value.isEmpty()) {
gen.writeStartArray();
gen.writeEndArray();
return;
}

// Check if the list is of type List<Epic>
if (value.getFirst() instanceof Epic) { //Unchecked cast is checked here
new PredefinedTasksSerializer().serialize((List<Epic>) value, gen, serializers);
} else {
// Handle other list types with default serialization
gen.writeStartArray();
for (Object item : value) {
gen.writeObject(item);
}
gen.writeEndArray();
}
}

@Override
public Class<List<?>> handledType() {
TypeToken<List<?>> typeToken = new TypeToken<>() {};
return (Class<List<?>>) typeToken.getRawType();
}
});
module.addDeserializer(Epic.class, new PredefinedTasksDeserializer());

objectMapper.registerModule(module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
public class DataProvider {
@Getter
@Setter
static Developer technicalManager;
private static Developer technicalManager;

@Getter
static List<List<Developer>> currentDevelopmentTeamsSetup = Collections.emptyList();
private static List<List<Developer>> currentDevelopmentTeamsSetup = Collections.emptyList();
@Getter
static LinkedList<Integer> availableDevelopmentTeamIds = new LinkedList<>();
private static final LinkedList<Integer> availableDevelopmentTeamIds = new LinkedList<>();

static final String PLACE_OF_BIRTH_MAPS_DEFAULT_VALUE = "Unknown";
static NavigableMap<Integer, String> countryMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Epic deserialize(JsonParser jsonParser, DeserializationContext deserializ
.id(epicId)
.name(epicName)
.priority(Priority.valueOf(epicPriority))
.reporter(currentDevelopmentTeam.get(epicReporterIndex))
.reporter(epicReporterIndex == -1 ? DataProvider.getTechnicalManager() : currentDevelopmentTeam.get(epicReporterIndex))
.assignee(currentDevelopmentTeam.get(epicAssigneeIndex))
.createdOn(ZonedDateTime.of(LocalDateTime.parse(epicCreatedOn, Utilities.DATE_TIME_FORMATTER), ZoneId.systemDefault()))
.description(epicDescription)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,66 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.google.common.reflect.TypeToken;
import dev.markodojkic.softwaredevelopmentsimulation.enums.DeveloperType;
import dev.markodojkic.softwaredevelopmentsimulation.model.*;

import java.io.IOException;
import java.util.List;

//Below class was generated by ChatGPT :)
public class PredefinedTasksSerializer extends JsonSerializer<Epic> {
public class PredefinedTasksSerializer extends JsonSerializer<List<Epic>> {

public static final String SELECTED_EPIC_DEVELOPMENT_TEAM = "selectedEpicDevelopmentTeam";

@Override
public void serialize(Epic epic, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
public void serialize(List<Epic> epics, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStartArray();

List<Developer> currentDevelopmentTeam = DataProvider.getCurrentDevelopmentTeamsSetup().stream().filter(team -> team.contains(epic.getAssignee())).findFirst().orElse(DataProvider.getCurrentDevelopmentTeamsSetup().getFirst());
for (int i = 0; i < epics.size(); i++) {
jsonGenerator.writeStartObject();
Epic epic = epics.get(i);

jsonGenerator.writeStringField("epicId", epic.getId());
jsonGenerator.writeStringField("epicName", epic.getName());
jsonGenerator.writeStringField("epicPriority", epic.getPriority().name());
jsonGenerator.writeNumberField("epicReporter", getDeveloperIndex(currentDevelopmentTeam, epic.getReporter()));
jsonGenerator.writeNumberField("epicAssignee", getDeveloperIndex(currentDevelopmentTeam, epic.getAssignee()));
jsonGenerator.writeStringField("epicCreatedOn", epic.getCreatedOn().format(Utilities.DATE_TIME_FORMATTER));
jsonGenerator.writeStringField("epicDescription", epic.getDescription());
jsonGenerator.writeStringField(SELECTED_EPIC_DEVELOPMENT_TEAM, String.valueOf(DataProvider.getCurrentDevelopmentTeamsSetup().indexOf(currentDevelopmentTeam)));
List<Developer> currentDevelopmentTeam = DataProvider.getCurrentDevelopmentTeamsSetup().stream().filter(team -> team.contains(epic.getAssignee())).findFirst().orElse(DataProvider.getCurrentDevelopmentTeamsSetup().getFirst());

serializeUserStories(currentDevelopmentTeam, String.valueOf(DataProvider.getCurrentDevelopmentTeamsSetup().indexOf(currentDevelopmentTeam)), epic.getUserStories(), jsonGenerator);
jsonGenerator.writeStringField("epicId", epic.getId());
jsonGenerator.writeStringField("epicName", epic.getName());
jsonGenerator.writeStringField("epicPriority", epic.getPriority().name());
jsonGenerator.writeNumberField("epicReporter", getDeveloperIndex(currentDevelopmentTeam, epic.getReporter()));
jsonGenerator.writeNumberField("epicAssignee", getDeveloperIndex(currentDevelopmentTeam, epic.getAssignee()));
jsonGenerator.writeStringField("epicCreatedOn", epic.getCreatedOn().format(Utilities.DATE_TIME_FORMATTER));
jsonGenerator.writeStringField("epicDescription", epic.getDescription());
jsonGenerator.writeStringField(SELECTED_EPIC_DEVELOPMENT_TEAM, String.valueOf(DataProvider.getCurrentDevelopmentTeamsSetup().indexOf(currentDevelopmentTeam)));

jsonGenerator.writeEndObject();
serializeUserStories(i, currentDevelopmentTeam, String.valueOf(DataProvider.getCurrentDevelopmentTeamsSetup().indexOf(currentDevelopmentTeam)), epic.getUserStories(), jsonGenerator);

jsonGenerator.writeEndObject();
}

jsonGenerator.writeEndArray();
}

@Override
public Class<Epic> handledType() {
return Epic.class;
public Class<List<Epic>> handledType() {
TypeToken<List<Epic>> typeToken = new TypeToken<>() {
};
return (Class<List<Epic>>) typeToken.getRawType();
}

private void serializeUserStories(List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, List<UserStory> userStories, JsonGenerator jsonGenerator)
private void serializeUserStories(int epicIndex, List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, List<UserStory> userStories, JsonGenerator jsonGenerator)
throws IOException {
jsonGenerator.writeFieldName("userStories");
jsonGenerator.writeStartArray();

for (UserStory userStory : userStories) {
serializeUserStory(currentDevelopmentTeam, selectedEpicDevelopmentTeam, userStory, jsonGenerator);
for (int i = 0; i < userStories.size(); i++) {
serializeUserStory(epicIndex, i, currentDevelopmentTeam, selectedEpicDevelopmentTeam, userStories.get(i), jsonGenerator);
}

jsonGenerator.writeEndArray();
}

private void serializeUserStory(List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, UserStory userStory, JsonGenerator jsonGenerator)
private void serializeUserStory(int epicIndex, int userStoryIndex, List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, UserStory userStory, JsonGenerator jsonGenerator)
throws IOException {
jsonGenerator.writeStartObject();

Expand All @@ -63,25 +74,26 @@ private void serializeUserStory(List<Developer> currentDevelopmentTeam, String s
jsonGenerator.writeStringField("userStoryCreatedOn", userStory.getCreatedOn().format(Utilities.DATE_TIME_FORMATTER));
jsonGenerator.writeStringField("userStoryDescription", userStory.getDescription());
jsonGenerator.writeStringField(SELECTED_EPIC_DEVELOPMENT_TEAM, selectedEpicDevelopmentTeam);
jsonGenerator.writeStringField("selectedEpicIndex", String.valueOf(epicIndex));

serializeTechnicalTasks(currentDevelopmentTeam, selectedEpicDevelopmentTeam, userStory.getTechnicalTasks(), jsonGenerator);
serializeTechnicalTasks(epicIndex, userStoryIndex, currentDevelopmentTeam, selectedEpicDevelopmentTeam, userStory.getTechnicalTasks(), jsonGenerator);

jsonGenerator.writeEndObject();
}

private void serializeTechnicalTasks(List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, List<TechnicalTask> technicalTasks, JsonGenerator jsonGenerator)
private void serializeTechnicalTasks(int epicIndex, int userStoryIndex, List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, List<TechnicalTask> technicalTasks, JsonGenerator jsonGenerator)
throws IOException {
jsonGenerator.writeFieldName("technicalTasks");
jsonGenerator.writeStartArray();

for (TechnicalTask technicalTask : technicalTasks) {
serializeTechnicalTask(currentDevelopmentTeam, selectedEpicDevelopmentTeam, technicalTask, jsonGenerator);
serializeTechnicalTask(epicIndex, userStoryIndex, currentDevelopmentTeam, selectedEpicDevelopmentTeam, technicalTask, jsonGenerator);
}

jsonGenerator.writeEndArray();
}

private void serializeTechnicalTask(List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, TechnicalTask technicalTask, JsonGenerator jsonGenerator)
private void serializeTechnicalTask(int epicIndex, int userStoryIndex, List<Developer> currentDevelopmentTeam, String selectedEpicDevelopmentTeam, TechnicalTask technicalTask, JsonGenerator jsonGenerator)
throws IOException {
jsonGenerator.writeStartObject();

Expand All @@ -93,11 +105,13 @@ private void serializeTechnicalTask(List<Developer> currentDevelopmentTeam, Stri
jsonGenerator.writeStringField("technicalTaskCreatedOn", technicalTask.getCreatedOn().format(Utilities.DATE_TIME_FORMATTER));
jsonGenerator.writeStringField("technicalTaskDescription", technicalTask.getDescription());
jsonGenerator.writeStringField(SELECTED_EPIC_DEVELOPMENT_TEAM, selectedEpicDevelopmentTeam);
jsonGenerator.writeStringField("selectedEpicIndex", String.valueOf(epicIndex));
jsonGenerator.writeStringField("selectedUserStoryIndex", String.valueOf(userStoryIndex));

jsonGenerator.writeEndObject();
}

private int getDeveloperIndex(List<Developer> currentDevelopmentTeam, Developer developer) {
return currentDevelopmentTeam.indexOf(developer);
return developer.getDeveloperType().equals(DeveloperType.TECHNICAL_MANAGER) ? -1 : currentDevelopmentTeam.indexOf(developer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
import com.thedeanda.lorem.LoremIpsum;
import dev.markodojkic.softwaredevelopmentsimulation.enums.Priority;
import dev.markodojkic.softwaredevelopmentsimulation.interfaces.IGateways;
import dev.markodojkic.softwaredevelopmentsimulation.model.Epic;
import dev.markodojkic.softwaredevelopmentsimulation.model.TechnicalTask;
import dev.markodojkic.softwaredevelopmentsimulation.model.UserStory;
import dev.markodojkic.softwaredevelopmentsimulation.model.*;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.UtilityClass;
Expand Down Expand Up @@ -38,7 +36,7 @@
@UtilityClass
public class Utilities {
private static final Logger logger = Logger.getLogger(Utilities.class.getName());
public static final String STRING_FORMAT = "%s-%s";
private static final String STRING_FORMAT = "%s-%s";
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy. HH:mm:ss");
public static final String ASSIGNED_DEVELOPMENT_TEAM_POSITION_NUMBER = "assignedDevelopmentTeamPositionNumber";
public static final SecureRandom SECURE_RANDOM = new SecureRandom();
Expand All @@ -59,7 +57,8 @@ public class Utilities {
@Setter
private static int totalEpicsCount;
@Getter
private static final List<Epic> epicsForSaving = new ArrayList<>();
@Setter
private static List<Epic> epicsForSaving;
@Getter
@Setter
private static ObjectMapper objectMapper;
Expand All @@ -73,18 +72,18 @@ public class Utilities {

public static void loadPredefinedTasks(List<Epic> predefinedEpics){
AtomicReference<String> jiraEpicCreatedOutput = new AtomicReference<>(Strings.EMPTY);
availableDevelopmentTeamIds.clear();
getAvailableDevelopmentTeamIds().clear();
predefinedEpics.forEach(epic -> {
int epicDevelopmentTeamId = IntStream.range(0, currentDevelopmentTeamsSetup.size())
.filter(i -> currentDevelopmentTeamsSetup.get(i).stream()
.anyMatch(d -> Objects.equals(d.getId(), epic.getReporter().getId())))
int epicDevelopmentTeamId = IntStream.range(0, getCurrentDevelopmentTeamsSetup().size())
.filter(i -> getCurrentDevelopmentTeamsSetup().get(i).stream()
.anyMatch(d -> Objects.equals(d.getId(), epic.getAssignee().getId())))
.findFirst().orElse(0);
if(!availableDevelopmentTeamIds.contains(epicDevelopmentTeamId)) availableDevelopmentTeamIds.push(epicDevelopmentTeamId);
if(!getAvailableDevelopmentTeamIds().contains(epicDevelopmentTeamId)) getAvailableDevelopmentTeamIds().push(epicDevelopmentTeamId);
jiraEpicCreatedOutput.set(String.format("\033[1m%s\033[21m\033[24m created EPIC: \033[3m\033[1m%s\033[21m\033[24m - %s\033[23m ◴ %s$",
epic.getReporter().getDisplayName(), epic.getId(), epic.getName(), epic.getCreatedOn().format(DATE_TIME_FORMATTER)).concat(jiraEpicCreatedOutput.get()));
});

totalDevelopmentTeamsPresent = availableDevelopmentTeamIds.size();
totalDevelopmentTeamsPresent = getAvailableDevelopmentTeamIds().size();

iGateways.sendToInfo("""
All epics are created. Total developerTeams available: {0}
Expand All @@ -102,8 +101,8 @@ public static void generateRandomEpics(boolean save, int epicCountDownLimit, int
AtomicReference<String> jiraEpicCreatedOutput = new AtomicReference<>(Strings.EMPTY);
totalEpicsCount = SECURE_RANDOM.nextInt(epicCountDownLimit,epicCountUpperLimit);

availableDevelopmentTeamIds.addAll(IntStream.rangeClosed(0, currentDevelopmentTeamsSetup.size() - 1).boxed().collect(Collectors.toCollection(ArrayList::new)));
totalDevelopmentTeamsPresent = currentDevelopmentTeamsSetup.size();
getAvailableDevelopmentTeamIds().addAll(IntStream.rangeClosed(0, getCurrentDevelopmentTeamsSetup().size() - 1).boxed().collect(Collectors.toCollection(ArrayList::new)));
totalDevelopmentTeamsPresent = getCurrentDevelopmentTeamsSetup().size();

for (var i = 0; i < totalEpicsCount; i++) {
int finalI = i;
Expand Down Expand Up @@ -137,9 +136,9 @@ public static void generateRandomEpics(boolean save, int epicCountDownLimit, int

iGateways.sendToJiraActivityStream(jiraEpicCreatedOutput.get().replaceFirst(".$", ""));

totalEpicsCount = save ? totalEpicsCount : -1;
epicsForSaving = save ? new ArrayList<>() : null;

Collections.shuffle(availableDevelopmentTeamIds);
Collections.shuffle(getAvailableDevelopmentTeamIds());
epicList.forEach(epic -> iGateways.generateEpic(epic));
}

Expand All @@ -155,7 +154,7 @@ private List<UserStory> generateUserStories(String epicId, String boardName, int
.description(LOREM.getWords(2, 4))
.priority(Priority.values()[SECURE_RANDOM.nextInt(Priority.values().length)])
.epicId(epicId)
.createdOn(ZonedDateTime.now())
.createdOn(ZonedDateTime.now().plusSeconds(1))
.technicalTasks(new ArrayList<>())
.build();
int totalTechnicalTasks = SECURE_RANDOM.nextInt(userStory.getPriority().getUrgency() + 3, userStory.getPriority().getUrgency() + 8);
Expand Down Expand Up @@ -184,7 +183,7 @@ private List<TechnicalTask> generateTechnicalTasks(String userStoryId, String bo
.priority(Priority.values()[SECURE_RANDOM.nextInt(Priority.values().length)])
.userStoryId(userStoryId)
.id(String.format(STRING_FORMAT, boardName, Long.parseLong(userStoryId.split(boardName.concat("-"))[1]+1)+i))
.createdOn(ZonedDateTime.now())
.createdOn(ZonedDateTime.now().plusSeconds(2))
.build());
logger.log(Level.INFO, () -> colorize(String.format("\t\t+ Generated TECHNICAL TASK #%d", finalI), Attribute.TEXT_COLOR(118), Attribute.BACK_COLOR(244)));
}
Expand All @@ -198,7 +197,6 @@ public static void addEpicForSaving(Epic epic) {

public static void saveEpics(){
try {
setTotalEpicsCount(0);
String folderName = ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"));
Path parentDirectory = Utilities.getCurrentApplicationDataPath().resolve(PREDEFINED_DATA);

Expand Down
Loading

0 comments on commit 2f5cc94

Please sign in to comment.