0

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.

Paddy
  • 1,195
  • 9
  • 16
atani
  • 53
  • 6

1 Answers1

0

Answering my own question (until someone else can better clarify):

Digging further into the couchbase event code, it looks like the delete related event objects will never have a CouchbaseDocument since they are created with the source object but call their superclass CouchbaseMappingEvent constructor with a null document argument. I've posted a pull request that fixes this.

atani
  • 53
  • 6