I'm exploring the option of subclassing the AbstractCouchbaseEventListener
to include custom document/entity lifecycle actions. I'm fairly new to Spring so I realize that this may be a sub-optimal way to do this (if it is, what would be a better or more common Spring way?).
Currently I'm looking at setting/removing reference documents for entities as they are saved / deleted. For current purposes by "reference document" I mean a document that maps a particular entity classes unique key value to the document that contains it: if User.username
is "billyTheKid" and User.id
is 12345 then the document User:by:username:12345
contains 12345 and so serves as a pointer to the User document.
My current approach is to have an interface ReferenceDocumentOwner
that can be implemented by any entity class that wants to store reference documents:
public interface ReferenceDocumentOwner<T, R> extends BasicDocument {
/*
Store the existing (stored) version of the entity. This is called in onBeforeSave()
to populate the about-to-be saved instance with its stored version. This previous
version can be used to determine the fields and values to populate the returns of
getDeleteRefDocMap() and getStoreRefDocMap().
*/
public void storePreviousRecord(T recorded);
public Class<R> getRepositoryClass();
/*
For values that used to be non-empty but are now empty. For example, if the
concrete implementation of this interface was User.class and this method returned:
electricServiceId => 12345,
garbageServiceId => AKIE3423
The reference documents {@code User:by:electricServiceId:12345} and
{@code User:by:garbageServiceId:AKIE3423} would be deleted in onAfterSave().
*/
public Map<String, Object> getDeleteRefDocMap ();
/*
For values that are non-empty. For example, if the concrete implementation of this
interface was User.class and this method returned:
email => someEmailValue,
garbageServiceId => AKIE3423,
username => billyTheKid
The reference documents {@code User:by:email:someEmailValue},
{@code User:by:garbageServiceId:AKIE3423}, and {@code User:by:username:billyTheKid}
would be stored pointing to the User instance's {@code id} in onAfterSave().
*/
public Map<String, Object> getStoreRefDocMap ();
}
(BasicDocument
here is just another simple interface defining getId()
and setId()
.)
And I have an ReferenceDocumentOwnerSaveDeleteEventListener extends AbstractCouchbaseEventListener<ReferenceDocumentOwner>
implementation that manages all that. I know there are potential race conditions between onBeforeSave() and onAfterSave() and for the purposes of this exploration I'm okay with that. The issue I'm running into is that once these reference documents are stored there's no simple way to delete them when their "owning" document is deleted. The onBeforeDelete() / onAfterDelete() methods only receive the CouchbaseDocument
, not the source object.
Question: why do these delete events not get passed the source object just as the other event handlers do?
Question: is there a recommended way / other way that people are implementing reference documents?
Edit:
One other wrinkle is that onBeforeDelete()
and onAfterDelete()
are being passed null
instead of the document being deleted, even though the repository.delete()
operation is successful.