Skip to content

Commit d515a68

Browse files
authored
Merge pull request #910 from qbicsoftware/development
Prepare smaller 1.6.1 release with minor improvements
2 parents f04fa41 + 9466cd4 commit d515a68

File tree

70 files changed

+499
-335
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+499
-335
lines changed

application-commons/src/main/java/life/qbic/application/commons/ApplicationException.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
public class ApplicationException extends RuntimeException {
1818

1919
private final ErrorCode errorCode;
20-
private final ErrorParameters errorParameters;
20+
private final transient ErrorParameters errorParameters;
2121

2222
public ApplicationException() {
2323
this(ErrorCode.GENERAL, ErrorParameters.empty());

broadcasting/src/main/java/life/qbic/broadcasting/Exchange.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public void subscribe(MessageSubscriber subscriber, String topic) {
169169
*/
170170
static class Topic {
171171

172-
private final String topic;
172+
private final String value;
173173

174174
private final Set<MessageSubscriber> subscribers;
175175

@@ -185,7 +185,7 @@ static Topic create(String topic) {
185185

186186
protected Topic(String topic) {
187187
super();
188-
this.topic = topic;
188+
this.value = topic;
189189
subscribers = new HashSet<>();
190190
}
191191

@@ -198,11 +198,11 @@ synchronized void removeSubscriber(MessageSubscriber subscriber) {
198198
}
199199

200200
boolean matchesTopic(String topic) {
201-
return this.topic.equalsIgnoreCase(topic);
201+
return this.value.equalsIgnoreCase(topic);
202202
}
203203

204204
synchronized void informAllSubscribers(String message, MessageParameters messageParameters) {
205-
if (messageParameters.messageType.equalsIgnoreCase(topic)) {
205+
if (messageParameters.messageType.equalsIgnoreCase(value)) {
206206
informSubscribers(message, messageParameters);
207207
}
208208
}

docs/processes/Sample_registration_process.svg

+2-1
Loading

domain-concept/src/test/groovy/life/qbic/domain/concepts/TestEvent.groovy

-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
package life.qbic.domain.concepts
2-
3-
4-
import java.time.Instant
5-
62
/**
73
* <b><class short description - 1 Line!></b>
84
*

email-service-provider/src/main/java/life/qbic/infrastructure/email/identity/IdentityEmailServiceProvider.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ public IdentityEmailServiceProvider(EmailServiceProvider emailServiceProvider) {
3333
@Override
3434
public void send(Subject subject, Recipient recipient, Content content)
3535
throws CommunicationException {
36-
Optional.ofNullable(subject)
36+
subject = Optional.ofNullable(subject)
3737
.orElseThrow(() -> new CommunicationException("No subject provided."));
38-
Optional.ofNullable(recipient)
38+
recipient = Optional.ofNullable(recipient)
3939
.orElseThrow(() -> new CommunicationException("No recipient provided."));
40-
Optional.ofNullable(content)
40+
content = Optional.ofNullable(content)
4141
.orElseThrow(() -> new CommunicationException("No content provided."));
4242

4343
try {

identity/src/main/java/life/qbic/identity/application/user/IdentityService.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public ApplicationResponse registerUser(final String fullName, String userName,
6464

6565
var userDomainService = DomainRegistry.instance().userDomainService();
6666
if (userDomainService.isEmpty()) {
67-
throw new RuntimeException("User registration failed.");
67+
throw new ApplicationException("User registration failed.");
6868
}
6969

7070
var userEmail = EmailAddress.from(email);
@@ -98,7 +98,7 @@ public ApplicationResponse registerOpenIdUser(String fullName, String userName,
9898

9999
var userDomainService = DomainRegistry.instance().userDomainService();
100100
if (userDomainService.isEmpty()) {
101-
throw new RuntimeException("User registration failed.");
101+
throw new ApplicationException("User registration failed.");
102102
}
103103

104104
var userEmail = EmailAddress.from(email);
@@ -301,6 +301,7 @@ public static class UserNameNotAvailableException extends ApplicationException {
301301
private static final long serialVersionUID = 4409722243047442583L;
302302

303303
public UserNameNotAvailableException() {
304+
super();
304305
}
305306
}
306307

identity/src/main/java/life/qbic/identity/application/user/policy/EmailConfirmationLinkSupplier.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.net.MalformedURLException;
44
import java.net.URL;
5+
import life.qbic.application.commons.ApplicationException;
56
import org.springframework.beans.factory.annotation.Value;
67
import org.springframework.stereotype.Service;
78

@@ -46,7 +47,7 @@ public String emailConfirmationUrl(String userId) {
4647
URL url = new URL(protocol, host, port, pathWithQuery);
4748
return url.toExternalForm();
4849
} catch (MalformedURLException e) {
49-
throw new RuntimeException("Link creation failed.", e);
50+
throw new ApplicationException("Link creation failed.", e);
5051
}
5152

5253
}

project-management/src/main/java/life/qbic/projectmanagement/application/AddExperimentToProjectService.java

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ public Result<ExperimentId, RuntimeException> addExperimentToProject(ProjectId p
6161
String specimenIconLabel) {
6262
requireNonNull(projectId, "project id must not be null during experiment creation");
6363
if (experimentName.isBlank()) {
64-
//ToDo Add Iterator for multiple experiments?
6564
experimentName = "Unnamed Experiment";
6665
}
6766
if (CollectionUtils.isEmpty(species)) {

project-management/src/main/java/life/qbic/projectmanagement/application/CollaboratorUserInfosConverter.java

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package life.qbic.projectmanagement.application;
22

33
import static java.util.Objects.isNull;
4-
import static life.qbic.logging.service.LoggerFactory.logger;
54

65
import com.fasterxml.jackson.core.JsonProcessingException;
76
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -11,7 +10,7 @@
1110
import java.io.IOException;
1211
import java.util.ArrayList;
1312
import java.util.List;
14-
import life.qbic.logging.api.Logger;
13+
import life.qbic.application.commons.ApplicationException;
1514
import life.qbic.projectmanagement.application.ProjectOverview.UserInfo;
1615

1716
/**
@@ -24,8 +23,6 @@
2423
public class CollaboratorUserInfosConverter implements
2524
AttributeConverter<List<UserInfo>, String> {
2625

27-
private static final Logger log = logger(CollaboratorUserInfosConverter.class);
28-
2926
private final ObjectMapper objectMapper = new ObjectMapper();
3027

3128
@Override
@@ -41,7 +38,7 @@ public String convertToDatabaseColumn(List<UserInfo> attribute) {
4138
return outputStream.toString();
4239
} catch (IOException e) {
4340
// we need to throw to prevent data loss
44-
throw new RuntimeException(
41+
throw new ApplicationException(
4542
"Unexpected problems writing project collaborators to the database", e);
4643
}
4744
}
@@ -58,7 +55,7 @@ public List<UserInfo> convertToEntityAttribute(String dbData) {
5855
);
5956
} catch (JsonProcessingException e) {
6057
// we need to throw to prevent data loss
61-
throw new RuntimeException("Unexpected failure parsing project collaborators from database",
58+
throw new ApplicationException("Unexpected failure parsing project collaborators from database",
6259
e);
6360
}
6461

project-management/src/main/java/life/qbic/projectmanagement/application/ContactRepository.java

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ public class ContactRepository {
1111

1212
@PostFilter("hasAnyAuthority('ROLE_ADMIN')")
1313
public List<Contact> findAll() {
14-
//TODO implement
1514
return dummyContacts();
1615
}
1716

project-management/src/main/java/life/qbic/projectmanagement/application/DeletionService.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package life.qbic.projectmanagement.application;
22

33
import static java.util.Objects.requireNonNull;
4-
import static life.qbic.logging.service.LoggerFactory.logger;
54

65
import java.util.Collection;
76
import life.qbic.application.commons.ApplicationException;
87
import life.qbic.application.commons.Result;
9-
import life.qbic.logging.api.Logger;
108
import life.qbic.projectmanagement.application.experiment.ExperimentInformationService;
119
import life.qbic.projectmanagement.application.sample.SampleInformationService;
1210
import life.qbic.projectmanagement.domain.model.batch.BatchId;
@@ -17,6 +15,7 @@
1715
import life.qbic.projectmanagement.domain.service.BatchDomainService;
1816
import life.qbic.projectmanagement.domain.service.SampleDomainService;
1917
import org.springframework.beans.factory.annotation.Autowired;
18+
import org.springframework.context.ApplicationContext;
2019
import org.springframework.stereotype.Service;
2120
import org.springframework.transaction.annotation.Transactional;
2221

@@ -30,7 +29,8 @@
3029
@Service
3130
public class DeletionService {
3231

33-
private static final Logger log = logger(DeletionService.class);
32+
private ApplicationContext context;
33+
3434
private final ProjectInformationService projectInformationService;
3535
private final ExperimentInformationService experimentInformationService;
3636
private final SampleInformationService sampleInformationService;
@@ -41,7 +41,7 @@ public class DeletionService {
4141
public DeletionService(ProjectInformationService projectInformationService,
4242
ExperimentInformationService experimentInformationService,
4343
SampleInformationService sampleInformationService, BatchDomainService batchDomainService,
44-
SampleDomainService sampleDomainService) {
44+
SampleDomainService sampleDomainService, ApplicationContext context) {
4545
this.projectInformationService = requireNonNull(projectInformationService,
4646
"experimentInformationService must not be null");
4747
this.experimentInformationService = requireNonNull(experimentInformationService,
@@ -86,7 +86,9 @@ public BatchId deleteBatch(ProjectId projectId, BatchId batchId) {
8686
deletedBatchId.onError(error -> {
8787
throw new ApplicationException("Could not delete batch " + batchId);
8888
});
89-
deleteSamples(projectId, batchId, samples);
89+
// We need to get the proxy Spring has wrapped around the service, otherwise calling
90+
// the @transaction annotated method has no effect
91+
context.getBean(DeletionService.class).deleteSamples(projectId, batchId, samples);
9092
return deletedBatchId.getValue();
9193
}
9294

project-management/src/main/java/life/qbic/projectmanagement/application/batch/BatchRegistrationService.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package life.qbic.projectmanagement.application.batch;
22

33

4+
import java.security.SecureRandom;
45
import java.util.Collection;
56
import java.util.Objects;
67
import java.util.Random;
@@ -45,6 +46,7 @@ public class BatchRegistrationService {
4546
private final SampleInformationService sampleInformationService;
4647
private final SampleRegistrationService sampleRegistrationService;
4748
private final DeletionService deletionService;
49+
private static final Random RANDOM = new SecureRandom();
4850

4951
@Autowired
5052
public BatchRegistrationService(BatchRepository batchRepository,
@@ -105,7 +107,6 @@ public Result<BatchId, ResponseCode> addSamplesToBatch(Collection<SampleId> samp
105107
}
106108

107109
public Result<BatchId, ResponseCode> addSampleToBatch(SampleId sampleId, BatchId batchId) {
108-
var random = new Random();
109110
while (true) {
110111
try {
111112
return tryToUpdateBatch(sampleId, batchId);
@@ -115,9 +116,14 @@ public Result<BatchId, ResponseCode> addSampleToBatch(SampleId sampleId, BatchId
115116
batchId.value()));
116117
}
117118
try {
118-
Thread.sleep(random.nextInt(500));
119+
Thread.sleep(RANDOM.nextInt(500));
119120
} catch (InterruptedException e) {
120-
throw new RuntimeException(e);
121+
log.error("Batch update interrupted", e);
122+
// Try to update one last time
123+
var result = tryToUpdateBatch(sampleId, batchId);
124+
result.onValue(id -> log.info("Updating batch %s was successful.".formatted(batchId.value())));
125+
result.onError(responseCode -> log.error("Updating batch failed. Response code was: %s".formatted(responseCode)));
126+
Thread.currentThread().interrupt();
121127
}
122128
}
123129
}

project-management/src/main/java/life/qbic/projectmanagement/application/policy/directive/AddSampleToBatch.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package life.qbic.projectmanagement.application.policy.directive;
22

3-
import static life.qbic.logging.service.LoggerFactory.logger;
4-
53
import life.qbic.domain.concepts.DomainEvent;
64
import life.qbic.domain.concepts.DomainEventSubscriber;
7-
import life.qbic.logging.api.Logger;
85
import life.qbic.projectmanagement.application.batch.BatchRegistrationService;
96
import life.qbic.projectmanagement.domain.model.batch.BatchId;
107
import life.qbic.projectmanagement.domain.model.sample.SampleId;
@@ -23,7 +20,6 @@
2320
@Component
2421
public class AddSampleToBatch implements DomainEventSubscriber<SampleRegistered> {
2522

26-
private static final Logger log = logger(AddSampleToBatch.class);
2723
private final BatchRegistrationService batchRegistrationService;
2824

2925
private final JobScheduler jobScheduler;
@@ -45,9 +41,9 @@ public void handleEvent(SampleRegistered event) {
4541
}
4642

4743
@Job(name = "Add sample %0 to batch %1")
48-
public void addSampleToBatch(SampleId sample, BatchId batch) throws RuntimeException {
44+
public void addSampleToBatch(SampleId sample, BatchId batch) throws DirectiveExecutionException {
4945
batchRegistrationService.addSampleToBatch(sample, batch).onError(responseCode -> {
50-
throw new RuntimeException(
46+
throw new DirectiveExecutionException(
5147
String.format("Adding sample %s to batch %s failed, response code was %s ", sample, batch,
5248
responseCode));
5349
});

project-management/src/main/java/life/qbic/projectmanagement/application/policy/directive/CreateNewSampleStatisticsEntry.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package life.qbic.projectmanagement.application.policy.directive;
22

33
import static java.util.Objects.requireNonNull;
4-
import static life.qbic.logging.service.LoggerFactory.logger;
54

65
import java.util.Optional;
76
import life.qbic.domain.concepts.DomainEvent;
87
import life.qbic.domain.concepts.DomainEventSubscriber;
9-
import life.qbic.logging.api.Logger;
108
import life.qbic.projectmanagement.application.api.SampleCodeService;
119
import life.qbic.projectmanagement.domain.model.project.Project;
1210
import life.qbic.projectmanagement.domain.model.project.ProjectId;
@@ -27,8 +25,6 @@
2725
public class CreateNewSampleStatisticsEntry implements
2826
DomainEventSubscriber<ProjectRegisteredEvent> {
2927

30-
private static final Logger log = logger(CreateNewSampleStatisticsEntry.class);
31-
3228
private final SampleCodeService sampleCodeService;
3329

3430
private final ProjectRepository projectRepository;
@@ -52,13 +48,13 @@ public void handleEvent(ProjectRegisteredEvent event) {
5248
}
5349

5450
@Job(name = "Create sample statistics entry for project %0")
55-
public void createSampleStatisticsEntry(String projectId) throws RuntimeException {
51+
public void createSampleStatisticsEntry(String projectId) throws DirectiveExecutionException {
5652
var id = ProjectId.parse(projectId);
5753
if (sampleStatisticsEntryMissing(id)) {
5854
Optional<Project> searchResult = projectRepository.find(id).stream()
5955
.findFirst();
6056
if (searchResult.isEmpty()) {
61-
throw new RuntimeException("Project with id " + projectId
57+
throw new DirectiveExecutionException("Project with id " + projectId
6258
+ " not found. Domain event processing failed for directive "
6359
+ getClass().getSimpleName());
6460
}

project-management/src/main/java/life/qbic/projectmanagement/application/policy/directive/DeleteSampleFromBatch.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ public void handleEvent(SampleDeleted event) {
4747
}
4848

4949
@Job(name = "Delete sample %0 from batch %1")
50-
public void deleteSampleFromBatch(SampleId sample, BatchId batch) throws RuntimeException {
50+
public void deleteSampleFromBatch(SampleId sample, BatchId batch) throws DirectiveExecutionException {
5151
batchRegistrationService.deleteSampleFromBatch(sample, batch).onError(responseCode -> {
5252
if (Objects.requireNonNull(responseCode) == ResponseCode.UNKNOWN_BATCH) {
5353
// This accounts for a batch that might have already been deleted, so nothing is to be done
5454
log.warn("Cannot delete sample from unknown batch: %s".formatted(batch.value()));
5555
} else {
56-
throw new RuntimeException(
56+
throw new DirectiveExecutionException(
5757
String.format("Deletion of sample %s from batch %s failed, response code was %s ",
5858
sample,
5959
batch,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package life.qbic.projectmanagement.application.policy.directive;
2+
3+
/**
4+
* <b>Policy Execution Exception </b>
5+
*
6+
* <p>Should be used to indicate an exception during the execution of a policy directive.</p>
7+
*
8+
* @since 1.7.0
9+
*/
10+
public class DirectiveExecutionException extends RuntimeException {
11+
public DirectiveExecutionException(String message) {
12+
super(message);
13+
}
14+
15+
}

project-management/src/main/java/life/qbic/projectmanagement/application/policy/directive/InformUserAboutGrantedAccess.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void handleEvent(ProjectAccessGranted event) {
6666

6767
@Job(name = "Notify user %0 about granted access to project %1")
6868
public void notifyUser(String userId, String projectId, String projectTitle)
69-
throws RuntimeException {
69+
throws DirectiveExecutionException {
7070
var recipient = userInformationService.findById(userId).orElseThrow();
7171
var projectUrl = appContextProvider.urlToProject(projectId);
7272
var message = Messages.projectAccessToUser(recipient.fullName(), projectTitle, projectUrl);

0 commit comments

Comments
 (0)