-
Notifications
You must be signed in to change notification settings - Fork 192
DATACOUCH-955 - Add support for reactive auditing and ReactiveEntityCallbacks. #1102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DATACOUCH-955 - Add support for reactive auditing and ReactiveEntityCallbacks. #1102
Conversation
57ce457
to
4c91e66
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the net result is that instead of CouchbaseTemplateSupport methods being called, now the corresponding ReactiveCouchbaseTemplateSupport methods are being called, resulting in the auditing configured as ReactiveAuditing being called instead of the the (nonReactive)auditing being called. And CouchbaseTemplateSupport is no longer used.
@@ -53,7 +53,7 @@ public ExecutableFindByAnalyticsOperationSupport(final CouchbaseTemplate templat | |||
this.domainType = domainType; | |||
this.query = query; | |||
this.reactiveSupport = new ReactiveFindByAnalyticsSupport<>(template.reactive(), domainType, query, | |||
scanConsistency); | |||
scanConsistency, new NonReactiveSupportWrapper(template.support())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this NonReactiveSupportWrapper object the same as template.reactive().support() ?
Then this extra argument to the ReactiveSupport constructors is not necessary.
And the ReactiveTemplateSupport support object in the ReactiveSupport objects is not necessary - they can just use template.support().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @mikereiche
In my opinion and following the implementations of other spring-data projects such as spring-data-mongo, I believe that in blocked stack we should launch EntityCallback
and from the reactive stack we should launch ReactiveEntityCallback
.
To have that differentiation, there needs to be one path for blocking (CouchbaseTemplateSupport
) and another path for reactive (ReactiveCouchbaseTemplateSupport
).
Also, I think that, additionally, the blocking audit event should be linked to AuditingEntityCallback
instead of AuditingEventListener
(this is not in the PR but you could add it).
How do you see it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thanks for the explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This point
Also, I think that, additionally, the blocking audit event should be linked to AuditingEntityCallback instead of AuditingEventListener (this is not in the PR but you could add it).
Do you want me to add it to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}); | ||
.insert(converted.getId(), converted.export(), buildInsertOptions(converted)).flatMap(result -> | ||
support.applyUpdatedId(object, converted.getId()) | ||
.map(updatedObject -> support.applyUpdatedCas(updatedObject, result.cas()))); | ||
}).onErrorMap(throwable -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had test failures here with. src/test/resources/integration.properties, cluster.type=unmanaged
mvn integration-test
I think this code needs to be as follows (similar to ReactiveUpsertByIdOperationSupport.one()
public Mono<T> one(T object) {
return (Mono<T>)Mono.just(object).flatMap(template.support()::encodeEntity).flatMap(converted ->
template.getCollection(collection).reactive()
.insert(converted.getId(), converted.export(), buildInsertOptions(converted)).flatMap(result ->
template.support().applyUpdatedId(object, converted.getId())
.flatMap( updatedObject -> template.support().applyUpdatedCas(updatedObject, result.cas())))
).onErrorMap(throwable -> {
if (throwable instanceof RuntimeException) {
return template.potentiallyConvertRuntimeException((RuntimeException) throwable);
} else {
return throwable;
}
});
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @mikereiche
This test fails because if you enable auditing, field annoted with @createdby, @CreatedDate, @LastModifiedBy and @LastModifiedDate are injected.
IMHO, the test is not entirely correct as the assertion should be between the User obtained from userRepository.save(user).block()
and the User obtained from userRepository.findById(user.getId()).blockOptional().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please set src/test/resources/integration.properties, cluster.type=unmanaged
and run mvn integration-test. It gives ClassCastExceptions. If you remove the cast to (Mono<T>) your IDE should tell you that you are returning a <Mono<Mono> instead of a <Mono. The issues is the .map() on line 78 should be a .flatMap().
The code in ReactiveUpsertByIdOperationSupport is correct, just cut-and-paste and change the upsert and buildUpsertOptions to insert and buildInsertOptions.
Yes, it should be comparing the entities from save and find, but that's not causing the ClassCast error.
[ERROR] Errors:
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.existsById:251 ClassCast reactor.cor...
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.insertById:231 ClassCast reactor.cor...
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.insertByIdwithDurability:240 ClassCast
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.saveAndFindImmutableById:266 ClassCast
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.withDurability:115 ClassCast reactor...
[ERROR] CouchbaseTemplateKeyValueIntegrationTests.withExpiryAndExpiryAnnotation:157 ClassCast
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are four fixes in comments, then I will approve and merge it.
It can be manually tested by adding the @EnableReactiveCouchbaseAuditing annotation to ReactiveCouchbaseRepositoryKeyValueIntegrationTests.Config
And the @EnableCouchbaseAuditing annotation to CouchbaseRepositoryKeyValueIntegrationTests.Config
then changing src/test/resources/integration.properties
cluster.type=unmanaged
|
||
protected <T> Mono<T> maybeCallAfterConvert(T object, CouchbaseDocument document, String collection) { | ||
if (null != reactiveEntityCallbacks) { | ||
return reactiveEntityCallbacks.callback(AfterConvertCallback.class, object, document, collection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should use ReactiveAfterConvertCallback.class, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* @author Jorge Rodríguez Martín | ||
* @since 4.2 | ||
*/ | ||
public class ReactiveAuditingEntityCallback implements ReactiveBeforeConvertCallback<Object>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this also implement ReactiveAfterConvertCallback. Add onAfterConvert(Object, CouchbaseDocument, String)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is not correct to add ReactiveAfterConvertCallback
. Audit event should only be associated to a single event (ReactiveBeforeConvertCallback).
If we also add the ReactiveAfterConvertCallback
, in each conversion the information of the fields annotated with @createdby, @CreatedDate, @LastModifiedBy and @LastModifiedDate will be modified 2 times and the returned object will have different values for the date type fields than the saved CouchbaseDocument.
* @param collection name of the collection. | ||
* @return a {@link Publisher} emitting the domain object to be persisted. | ||
*/ | ||
Publisher<T> onAfterConvert(T entity, Document document, String collection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be CouchbaseDocument (org.springframework.data.couchbase.core.mapping.Document is an annotation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Closes spring-projects#1105. Co-authored-by: mikereiche <[email protected]>
It was present on non-Reactive, but missing from reactive. Closes spring-projects#1096. Original pull request spring-projects#1108. Co-authored-by: mikereiche <[email protected]>
Add QueryCriteria arrayContaining which maps to n1ql array_containing. Closes spring-projects#1073. Original pull request spring-projects#1109. Co-authored-by: mikereiche <[email protected]>
Support enum in AbstractCouchbaseConverter.convertForWriteIfNeeded() and also call that from MappingCouchbaseConverter.getPotentiallyConvertedSimpleWrite() Closes spring-projects#1069. Original pull request spring-projects#1112. Co-authored-by: mikereiche <[email protected]>
* Add QueryCriteria arrayContaining. Add QueryCriteria arrayContaining which maps to n1ql array_containing. Closes spring-projects#1073. Original pull request spring-projects#1109. * Support enum parameters to repository queries. Support enums in AbstractCouchbaseConverter.convertForWriteIfNeeded(). Closes spring-projects#1069. Original pull request spring-projects#1110. Co-authored-by: mikereiche <[email protected]>
e569e59
to
09b1503
Compare
Couple little things - they changed the format for Title/Description. The no longer want the DATACOUCH-955 in the title, it should just be "Add support for reactive auditing and ReactiveEntityCallbacks" Closes #955. I'll have one of my colleagues review it as well before merging. |
Can you add a test in ReactiveCouchbaseRepositoryQueryIntegrationTests? And an analogous test in CouchbaseRepositoryIntegrationTests to check for regression. Add createdBy to Airport
add
Updated the Config class in ReactiveCouchbaseRepositoryQueryIntegrationTests. NaiveAuditorAware and AuditingDateTimeProvider already exist.
|
09b1503
to
8db28c9
Compare
…allbacks. Also, adapt CouchbaseAuditingRegistrar for support AuditingEntityCallback. Co-authored-by: Carlos Espinado <carlosemart>
8db28c9
to
b0dd3d9
Compare
@mikereiche I have added the tests you asked for |
ef9c5f4
to
d16bbff
Compare
Add support for reactive auditing and ReactiveEntityCallbacks. Also, adapt CouchbaseAuditingRegistrar for support AuditingEntityCallback. Closes #955. Original pull request: #1102. Co-authored-by: Carlos Espinado <carlosemart> Co-authored-by: mikereiche <[email protected]>
Add support for reactive auditing and ReactiveEntityCallbacks. Also, adapt CouchbaseAuditingRegistrar for support AuditingEntityCallback. Closes #955. Original pull request: #1102. Co-authored-by: Carlos Espinado <carlosemart> Co-authored-by: mikereiche <[email protected]>
@@ -84,7 +86,7 @@ protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandle | |||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry)); | |||
|
|||
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(), | |||
AuditingEventListener.class.getName(), registry); | |||
AuditingEntityCallback.class.getName(), registry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this just changes the name used in registering? On line 84, the rootBeanDefinitions is still AuditingEventListener.class - and after this change, the AuditEventListener is still the listener class is being used. And it already had an onApplicationEvent() that calls markedAudit(). The changed line above can even be changed to as below and it still works. So I don't think this particular change is needed - and I don't think the AuditingEventCallback class is needed.
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
/*AuditingEntityCallback.class.getName()*/ "My_Friend_Dave", registry);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok - I just looked at the ReactiveCouchbaseAuditingRegistrar - and it appears that the intention is to use the new AuditEntityCallback.class - both when creating the listenerBeanDefinitionBuilder and when registering. And to no longer use the AuditEventListener.
Closes #955.
Original pull request: #1111.