Parent-Child Association Created Event - Alfresco Content Services - 23.4 - 23.4 - Ready - Alfresco - external

Alfresco Content Services

Platform
Alfresco
Product
Alfresco Content Services
Release
23.4
License

This event is fired whenever a secondary parent -> child association is created, such as via the the POST nodes/{parentId}/secondary-children. For more information, see Create an Association for a Node that Exists.

ReST API. The full name of this event is org.alfresco.event.assoc.child.Created.

Note:

This event will not be generated when a file is created or a folder is created. In this case the primary parent -> child association (i.e. cm:contains) is created but an event for this association is not triggered. You will have to listen to the org.alfresco.event.node.Created event instead, and from the data for this event you can get to the primary parent -> child association.

Here is an example payload for this event type:

{
  "specversion": "1.0",
  "type": "org.alfresco.event.assoc.child.Created",
  "id": "4014bcb2-f1e6-447f-8caa-3a6219bc94ad",
  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",
  "time": "2021-01-28T13:42:34.329162Z",
  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/childAssocCreated",
  "datacontenttype": "application/json",
  "data": {
    "eventGroupId": "78da21cc-fa5a-47d1-afcb-03005229efa9",
    "resource": {
      "@type": "ChildAssociationResource",
      "assocType": "fdk:images",
      "parent": {
        "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"
      },
      "child": {
        "id": "ceb3c804-8b32-4050-b2da-b55c47f01666"    
      }
    }
  }
}

Using the Node Browser (see Using the Node Browser) the following NodeRefs were resolved as follows:

  "parent": {
    "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"  /app:company_home/cm:My_x0020_Gadgets/cm:My_x0020_Gadget  
  },
  "child": {
    "id": "ceb3c804-8b32-4050-b2da-b55c47f01666"  /app:company_home/cm:My_x0020_Gadgets/cm:gadget-picture.png

The event payload is telling us that a secondary parent-child association of type fdk:images (i.e. data.resource.assocType) was set up between a gadget file My Gadget (i.e. data.resource.parent) and a gadget image gadget-picture.png (i.e. data.resource.child).

When subscribing to the org.alfresco.event.assoc.child.Created event it’s possible to filter out anything that is of no interest. So for example, if you are only interested in associations of type fdk:images it would be easy to configure this.

SDK5 - Plain Java

The following code shows how this can be done with SDK 5 and plain Java event handlers:

package org.alfresco.tutorial.events;

import org.alfresco.event.sdk.handling.filter.AssocTypeFilter;
import org.alfresco.event.sdk.handling.filter.EventFilter;
import org.alfresco.event.sdk.handling.handler.OnChildAssocCreatedEventHandler;
import org.alfresco.event.sdk.model.v1.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
* Sample event handler to demonstrate reacting to a parent-child assoc being created.
*/
@Component
public class ParentChildAssocCreatedEventHandler implements OnChildAssocCreatedEventHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(ParentChildAssocCreatedEventHandler.class);

    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {
        ChildAssociationResource resource = (ChildAssociationResource) repoEvent.getData().getResource();
        LOGGER.info("A secondary Parent-Child association was created: {} -> {}", resource.getParent().getId(), 
                resource.getChild().getId());
    }

    public EventFilter getEventFilter() {
        return AssocTypeFilter.of("fdk:images"); // Make sure the Parent-Child association is of type FDK Images
    }
}

This code uses the org.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Parent-Child association we are interested in.

For more information about how to extract all the properties from the message payload see the ChildAssociationResource information in Software Development Kits (SDK).

To create an SDK event handler project that uses plain Java event handlers follow the instructions on pure Java event handlers in Software Development Kits (SDK).

SDK5 - Spring Integration

The following code shows how this can be done with SDK 5 and Spring Integration event handlers:

package org.alfresco.tutorial.events;

import org.alfresco.event.sdk.handling.filter.AssocTypeFilter;
import org.alfresco.event.sdk.handling.filter.EventTypeFilter;
import org.alfresco.event.sdk.integration.EventChannels;
import org.alfresco.event.sdk.integration.filter.IntegrationEventFilter;
import org.alfresco.event.sdk.model.v1.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.dsl.IntegrationFlowAdapter;
import org.springframework.integration.dsl.IntegrationFlowDefinition;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

/**
 * Spring Integration based event handler that will execute code when a secondary parent-child assoc is being created.
 */
@Component
public class ParentChildAssocCreatedFlow extends IntegrationFlowAdapter {
    private static final Logger LOGGER = LoggerFactory.getLogger(ParentChildAssocCreatedFlow.class);

    // Use builder to create an integration flow based on alfresco.events.main.channel event channel
    @Override
    protected IntegrationFlowDefinition<?> buildFlow() {
        return from(EventChannels.MAIN) // Listen to events coming from the Alfresco events channel
                .filter(IntegrationEventFilter.of(EventTypeFilter.CHILD_ASSOC_CREATED)) // Filter events and select only Parent-Child assoc created events
                .filter(IntegrationEventFilter.of(AssocTypeFilter.of("fdk:images"))) // Make sure the Parent-Child association is of type FDK Images
                .handle(t -> handleEvent(t)); // Handle event with a bit of logging
    }

    private void handleEvent(Message message) {
        RepoEvent<DataAttributes<Resource>> repoEvent = (RepoEvent<DataAttributes<Resource>>)message.getPayload();
        ChildAssociationResource resource = (ChildAssociationResource) repoEvent.getData().getResource();
        LOGGER.info("A secondary Parent-Child association was created: {} -> {}", resource.getParent().getId(),
                resource.getChild().getId());
    }
}

This code uses the org.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Parent-Child association we are interested in.

For more information about how to extract all the properties from the message payload see the ChildAssociationResource information in Software Development Kits (SDK).

To create an SDK event handler project that uses plain Java event handlers follow the instructions on pure Java event handlers in Software Development Kits (SDK).

Apache Camel

The following code snippet shows how this could be done with an Apache Camel route configuration:

public class SimpleRoute extends RouteBuilder {

    @Override
    public void configure() {
        from("amqpConnection:topic:alfresco.repo.event2")
            .id("ParentChildAssocCreatedRoute")
            .log("${body}") // Log all incoming events on this topic, even those that we are not interested in
            .choice()
            .when() // When the following is true:
            // The event type is parent-child assoc created
            .jsonpath("$[?(@.type=='org.alfresco.event.assoc.child.Created' && " +
                    // and the association type is fdk:images
                    "@.data.resource.assocType=='fdk:images')]" )
            // Unpack the data into JSON format
            .unmarshal("publicDataFormat")
            // Call a Spring Bean with the event data
            .bean("parentChildAssocCreatedEventHandlerImpl", "onReceive(*, COPY)")
            .end();
    }
}

The jsonpath expression uses several of the event data properties to filter out exactly the events we are interested in.

In this case a Spring Bean with ID parentChildAssocCreatedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.