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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Rozwój kodu

Kod będzie rozwijać się wraz z cotygodniową narracją szkoleniową.
Zarówno pojawiać się w nim będą kolejne poprawki jak i odziedziczone po firmach partnerskich nowe moduły ;-) Jak to w prawdziwym legacy.

# Przeglądanie kodu

Poszczególne kroki refaktoryzacyjne najlepiej przeglądać używająć tagów. Każdy krok szkoleniowy, który opisany jest w odcinku Legacy Fighter posiada na końcu planszę z nazwą odpowiedniego taga. Porównać zmiany można robiąc diffa w stosunku do poprzedniego taga z narracji.
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-spring-boot-starter</artifactId>
<version>2.6.1.Final</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -43,6 +48,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-junit5</artifactId>
<version>2.6.1.Final</version>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.legacyfighter.cabs.contracts.application.acme.dynamic;

import io.legacyfighter.cabs.contracts.model.ContentId;
import io.legacyfighter.cabs.contracts.model.content.DocumentNumber;

import java.util.List;
import java.util.Map;

public class DocumentOperationResult {

public enum Result{
SUCCESS, ERROR
}

private Result result;
private String stateName;
private ContentId contentId;

private Long documentHeaderId;
private DocumentNumber documentNumber;

private Map<String, List<String>> possibleTransitionsAndRules;
private boolean contentChangePossible;
private String contentChangePredicate;


public DocumentOperationResult(Result result, Long documentHeaderId, DocumentNumber documentNumber, String stateName, ContentId contentId, Map<String, List<String>> possibleTransitionsAndRules, boolean contentChangePossible, String contentChangePredicate) {
this.result = result;
this.documentHeaderId = documentHeaderId;
this.documentNumber = documentNumber;
this.stateName = stateName;
this.contentId = contentId;
this.possibleTransitionsAndRules = possibleTransitionsAndRules;
this.contentChangePossible = contentChangePossible;
this.contentChangePredicate = contentChangePredicate;
}

public Map<String, List<String>> getPossibleTransitionsAndRules() {
return possibleTransitionsAndRules;
}

public String getContentChangePredicate() {
return contentChangePredicate;
}

public boolean isContentChangePossible() {
return contentChangePossible;
}

public Result getResult() {
return result;
}

public String getStateName() {
return stateName;
}

public DocumentNumber getDocumentNumber() {
return documentNumber;
}

public Long getDocumentHeaderId() {
return documentHeaderId;
}

public ContentId getContentId() {
return contentId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package io.legacyfighter.cabs.contracts.application.acme.dynamic;

import io.legacyfighter.cabs.contracts.legacy.User;
import io.legacyfighter.cabs.contracts.legacy.UserRepository;
import io.legacyfighter.cabs.contracts.model.ContentId;
import io.legacyfighter.cabs.contracts.model.DocumentHeader;
import io.legacyfighter.cabs.contracts.model.DocumentHeaderRepository;
import io.legacyfighter.cabs.contracts.model.content.DocumentNumber;
import io.legacyfighter.cabs.contracts.model.state.dynamic.ChangeCommand;
import io.legacyfighter.cabs.contracts.model.state.dynamic.State;
import io.legacyfighter.cabs.contracts.model.state.dynamic.StateConfig;
import io.legacyfighter.cabs.contracts.model.state.dynamic.acme.AcmeContractStateAssembler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.BiFunction;

@Service
@Transactional
public class DocumentResourceManager {

@Autowired
private DocumentHeaderRepository documentHeaderRepository;

@Autowired
private AcmeContractStateAssembler assembler;

@Autowired
private UserRepository userRepository;

public void changeContent(){

}

public DocumentOperationResult createDocument(Long authorId){
User author = userRepository.getOne(authorId);

DocumentNumber number = generateNumber();
DocumentHeader documentHeader = new DocumentHeader(author.getId(), number);

StateConfig stateConfig = assembler.assemble();
State state = stateConfig.begin(documentHeader);

documentHeaderRepository.save(documentHeader);

return generateDocumentOperationResult(DocumentOperationResult.Result.SUCCESS, state);
}

public DocumentOperationResult changeState(Long documentId, String desiredState, Map<String, Object> params){
DocumentHeader documentHeader = documentHeaderRepository.getOne(documentId);
StateConfig stateConfig = assembler.assemble();
State state = stateConfig.recreate(documentHeader);

state = state.changeState(new ChangeCommand(desiredState, params));

documentHeaderRepository.save(documentHeader);

return generateDocumentOperationResult(DocumentOperationResult.Result.SUCCESS, state);
}

public DocumentOperationResult changeContent(Long headerId, ContentId contentVersion) {
DocumentHeader documentHeader = documentHeaderRepository.getOne(headerId);
StateConfig stateConfig = assembler.assemble();
State state = stateConfig.recreate(documentHeader);
state = state.changeContent(contentVersion);

documentHeaderRepository.save(documentHeader);
return generateDocumentOperationResult(DocumentOperationResult.Result.SUCCESS, state);
}

private DocumentOperationResult generateDocumentOperationResult(DocumentOperationResult.Result result, State state) {
return new DocumentOperationResult(result, state.getDocumentHeader().getId(),
state.getDocumentHeader().getDocumentNumber(), state.getStateDescriptor(), state.getDocumentHeader().getContentId(),
extractPossibleTransitionsAndRules(state),
state.isContentEditable(),
extractContentChangePredicate(state));
}

private String extractContentChangePredicate(State state) {
if (state.isContentEditable())
return state.getContentChangePredicate().getClass().getTypeName();
return null;
}


private Map<String, List<String>> extractPossibleTransitionsAndRules(State state) {
Map<String, List<String>> transitionsAndRules = new HashMap<>();

Map<State, List<BiFunction<State, ChangeCommand, Boolean>>> stateChangePredicates = state.getStateChangePredicates();
for (State s : stateChangePredicates.keySet()){
//transition to self is not important
if (s.equals(state))
continue;

List<BiFunction<State, ChangeCommand, Boolean>> predicates = stateChangePredicates.get(s);
List<String> ruleNames = new ArrayList<>();
for (BiFunction<State, ChangeCommand, Boolean> predicate : predicates){
ruleNames.add(predicate.getClass().getTypeName());
}
transitionsAndRules.put(s.getStateDescriptor(), ruleNames);
}

return transitionsAndRules;
}

private DocumentNumber generateNumber() {
return new DocumentNumber("nr: " + new Random().nextInt()); //TODO integrate with doc number generator
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.legacyfighter.cabs.contracts.application.acme.straigthforward;

import io.legacyfighter.cabs.contracts.legacy.User;
import io.legacyfighter.cabs.contracts.legacy.UserRepository;
import io.legacyfighter.cabs.contracts.model.ContentId;
import io.legacyfighter.cabs.contracts.model.DocumentHeader;
import io.legacyfighter.cabs.contracts.model.DocumentHeaderRepository;
import io.legacyfighter.cabs.contracts.model.content.DocumentNumber;
import io.legacyfighter.cabs.contracts.model.state.straightforward.BaseState;
import io.legacyfighter.cabs.contracts.model.state.straightforward.acme.VerifiedState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Random;

@Service
@Transactional
public class AcmeContractProcessBasedOnStraightforwardDocumentModel {
@Autowired
private UserRepository userRepository;

@Autowired
private DocumentHeaderRepository documentHeaderRepository;

@Autowired
private AcmeStateFactory stateFactory;

public ContractResult createContract(Long authorId){
User author = userRepository.getOne(authorId);

DocumentNumber number = generateNumber();
DocumentHeader header = new DocumentHeader(author.getId(), number);

documentHeaderRepository.save(header);

return new ContractResult(ContractResult.Result.SUCCESS, header.getId(), number, header.getStateDescriptor());
}


public ContractResult verify(Long headerId, Long verifierId) {
User verifier = userRepository.getOne(verifierId);
//TODO user authorization

DocumentHeader header = documentHeaderRepository.getOne(headerId);

BaseState state = stateFactory.create(header);
state = state.changeState(new VerifiedState(verifierId));

documentHeaderRepository.save(header);
return new ContractResult(ContractResult.Result.SUCCESS, headerId, header.getDocumentNumber(), header.getStateDescriptor());
}

public ContractResult changeContent(Long headerId, ContentId contentVersion) {
DocumentHeader header = documentHeaderRepository.getOne(headerId);

BaseState state = stateFactory.create(header);
state = state.changeContent(contentVersion);

documentHeaderRepository.save(header);
return new ContractResult(ContractResult.Result.SUCCESS, headerId, header.getDocumentNumber(), header.getStateDescriptor());
}

private DocumentNumber generateNumber() {
return new DocumentNumber("nr: " + new Random().nextInt()); //TODO integrate with doc number generator
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.legacyfighter.cabs.contracts.application.acme.straigthforward;

import io.legacyfighter.cabs.contracts.model.DocumentHeader;
import io.legacyfighter.cabs.contracts.model.state.straightforward.BaseState;
import io.legacyfighter.cabs.contracts.model.state.straightforward.acme.DraftState;
import org.springframework.stereotype.Component;

@Component
class AcmeStateFactory {
public BaseState create(DocumentHeader header){
//sample impl is based on class names
//other possibilities: names Dependency Injection Containers, states persisted via ORM Discriminator mechanism, mapper
String className = header.getStateDescriptor();

if (className == null) {
DraftState state = new DraftState();
state.init(header);
return state;
}

try {
Class<? extends BaseState> clazz = (Class<? extends BaseState>) Class.forName(className);
BaseState state = clazz.getConstructor().newInstance();
state.init(header);
return state;
}
catch (Exception e){
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.legacyfighter.cabs.contracts.application.acme.straigthforward;

import io.legacyfighter.cabs.contracts.model.content.DocumentNumber;

public class ContractResult {

public enum Result{
FAILURE, SUCCESS
}

private Result result;
private Long documentHeaderId;
private DocumentNumber documentNumber;
private String stateDescriptor;

public ContractResult(Result result, Long documentHeaderId, DocumentNumber documentNumber, String stateDescriptor) {
this.result = result;
this.documentHeaderId = documentHeaderId;
this.documentNumber = documentNumber;
this.stateDescriptor = stateDescriptor;
}

public Result getResult() {
return result;
}

public DocumentNumber getDocumentNumber() {
return documentNumber;
}

public Long getDocumentHeaderId() {
return documentHeaderId;
}

public String getStateDescriptor() {
return stateDescriptor;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.legacyfighter.cabs.contracts.application.editor;

import java.util.UUID;

public class CommitResult {


public enum Result{
FAILURE, SUCCESS
}

private UUID contentId;
private Result result;
private String message;

public CommitResult(UUID contentId, Result result, String message) {
this.contentId = contentId;
this.result = result;
this.message = message;
}

public CommitResult(UUID documentId, Result result) {
this(documentId, result, null);
}

public Result getResult() {
return result;
}

public UUID getContentId() {
return contentId;
}
}
Loading