Movatterモバイル変換


[0]ホーム

URL:


In: content-servicesIn: All docs
Close
Alfresco Content Services

Events Extension Point

When implementing business logic an out-of-process model should be used. For example, if some processing should be doneevery time a PDF is uploaded to a specific folder, then there is an event that can be subscribed to and the business logic can be implemented in an external process separate from the Content Services server process.

The following diagram gives an overview of the Event System and the event types:

acs_70_event_system_overview

Architecture Information:Platform Architecture

Event Model

The event model in Content Services is a library packaged as a JAR file, which is part of the repository (i.e.alfresco.war). The library contains the event model and the databind helpers used to help the clients to marshall and unmarshall the events.

The event model is based on theCloudEvents specification.CloudEvents is a specification for describing event data in common formats to provide interoperability across services, platforms and systems. For more information seeCloudEvents Primer.

The Content Services event payload (i.e. the part of transmitted data that is the actual intended message) consistof two parts. The CloudEvent attributes and the Content Services event attributes.

{  CloudEvent standard attributes...  "data": {    Content Services custom event attributes...   }}

Basic configuration of the event system is in therepository.propertiesfile:

### Repository events2## Type and aspect filters which should be excluded.# Note: System folder node types are added by default.repo.event2.filter.nodeTypes=sys:*, fm:*, cm:thumbnail, cm:failedThumbnail, cm:rating, rma:rmsite include_subtypesrepo.event2.filter.nodeAspects=sys:*repo.event2.filter.childAssocTypes=rn:rendition## Comma separated list of users which should be excluded# Note: username's case-sensitivity depends on the {user.name.caseSensitive} settingrepo.event2.filter.users=System, null## Topic namerepo.event2.topic.endpoint=amqp:topic:alfresco.repo.event2

Any custom configuration, to for example the default event filtering, can be done inalfresco-global.properties.

CloudEvent attributes

Standard CloudEvent attributes in the context of Content Services events:

PropertyTypeDescription
typeStringTheAlfresco event type. (1.0 spec#type)
specversionStringThe CloudEvents specification version. Value should be1.0. (1.0 spec#specversion)
idStringEvent ID, a UUID generated by the producer (1.0 spec#id)
sourceURI-referenceThe instance of a repository that produced the event, .i.e. repository cluster node identifier (1.0 spec#source)
timeTimestampThe producer’s timestamp of when the event occurred. (1.0 spec#time)
dataschemaURI-referenceIdentifies the schema that data adheres to.
datacontenttypeStringThe content type of the data attribute. Value should beapplication/json. (1.0 spec#datacontenttype)
dataJSONThe domain-specificdata of the event. (1.0 spec#data)

Content Services event data attributes

Content Services event data payload/attributes:

PropertyTypeDescription
data.eventGroupIdStringOptional unique identifier for events group, i.e. a transaction ID. Multiple nodes can be created in the same transaction.
data.resourceObject (varies)The object representing the resource affected. Here the resource represents a node in the Alfresco Repository.
data.resource.@typeStringThe type of resource object (NodeResource,ChildAssociationResource).
data.resource.idStringThe Alfresco Repository Node Id for the resource (e.g. node such as folder or file) that the data represent.
data.resource.primaryHierarchyArrayOptional primary hierarchy of ancestors of the resource affected, i.e. folder path for the node. Note that the first element is the immediate parent.
data.resource.nameStringThe name of the resource. This is the name of the node, e.g. the name of a folder or a file.
data.resource.nodeTypeStringA content model type, such ascm:content for a file orcm:folder for a folder. Seecontent modelling
data.resource.createdByUserObjectThe id (String) and display name (String) of the user that created the node.
data.resource.createdAtStringThe time a node was created.
data.resource.modifiedByUserObjectThe id (String) and display name (String) of the user that modified/updated the node.
data.resource.modifiedAtStringThe time a node was modified/updated.
data.resource.contentObjectIf the node is of content typecm:content (i.e. a file), then this object contains information about the file, such as MIME-type and size.
data.resource.propertiesObjectContent model properties corresponding to thedata.resource.nodeType.
data.resource.aspectNamesArrayContent model aspects that have been applied to the node.
data.resource.isFolderBooleantrue if this node is of typecm:folder.
data.resource.isFileBooleantrue if this node is of typecm:content.
data.resource.resourceReaderAuthoritiesArray(Enterprise Only) The authority IDs, such asGROUP_EVERYONE, that have READ access to the resource affected by the event.Note: this property will not be present in the event whenauthorities generation is disabled.
data.resource.resourceDeniedAuthoritiesArray(Enterprise Only) The authority IDs, such asGROUP_EVERYONE, that are denied READ access to the resource affected by the event.Note: this property will not be present in the event whenauthorities generation is disabled.
data.resource.resourceReaderSecurityControlsArray(Enterprise Only) The Governance security controls that have been placed on the resource affected by the event.Note: this property is only available for AGS. Also, it will not be present in the event response whenauthorities generation is disabled or when the AGS module is not installed.
data.resourceBeforeObject (varies)The object representing the old values of the changed resource’s attributes. Note, this object is only available on theorg.alfresco.event.node.Updated event type.

For a detailed view of the event data refer toRepo Event JSON schema.

Content Services event types

The following are the different types of events that can be subscribed to:

NameDescription
org.alfresco.event.node.CreatedOccurs when a node is created.
org.alfresco.event.node.UpdatedOccurs when a node is updated or moved. Currently only node’s name, type, properties, aspects, and content are supported.
org.alfresco.event.node.DeletedOccurs when a node is deleted.
org.alfresco.event.assoc.child.CreatedOccurs when a secondary child association is created.

Note. This event is not triggered forcm:contains primary parent-child associations. I.e. when a file or folder is created.
org.alfresco.event.assoc.child.DeletedOccurs when a secondary child association is deleted.

Note. This event is not triggered forcm:contains primary parent-child associations. I.e. when a file or folder is deleted.
org.alfresco.event.assoc.peer.CreatedOccurs when a peer association is created.
org.alfresco.event.assoc.peer.DeletedOccurs when a peer association is deleted.
org.alfresco.event.permission.UpdatedOccurs when permissions for a node is updated

=== Event descriptions ===

Let’s have a look at each event and see what we can use it for when implementing business logic for a particular content domain.

Content Services events are published on theJMS Topic calledalfresco.repo.event2. See (search) default configuration in therepository.properties file.So a Camel Route could for example be configured to pick up events fromamqpConnection:topic:alfresco.repo.event2. TheamqpConnection to theActive MQ endpoint in the Content Services server would then be configured to connect toamqp://localhost:5672.

Node created event

This event is fired whenever a node, such as a folder or file, is created in the repository. The full name of this event isorg.alfresco.event.node.Created.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.node.Created",  "id": "368818d9-dddd-4b8b-8eab-e050253d7f61",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-01-21T11:14:16.42372Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/nodeCreated",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "4004ca99-9d2a-400d-9d80-8f840e223581",    "resource": {      "@type": "NodeResource",      "id": "d71dd823-82c7-477c-8490-04cb0e826e65",      "primaryHierarchy": [        "5f355d16-f824-4173-bf4b-b1ec37ef5549",        "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",        "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",        "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"       ],      "name": "purchase-order-scan.pdf",      "nodeType": "cm:content",      "createdByUser": {        "id": "admin",        "displayName": "Administrator"      },      "createdAt": "2021-01-21T11:14:15.695Z",      "modifiedByUser": {        "id": "admin",        "displayName": "Administrator"      },      "modifiedAt": "2021-01-21T11:14:15.695Z",      "content": {        "mimeType": "application/pdf",        "sizeInBytes": 531152,        "encoding": "UTF-8"      },      "properties": {        "cm:autoVersion": true,        "cm:versionType": "MAJOR",        "cm:autoVersionOnUpdateProps": false,        "cm:versionLabel": "1.0",        "cm:initialVersion": true      },      "aspectNames": [        "cm:versionable",        "cm:auditable"      ],      "isFolder": false,      "isFile": true    },    "resourceReaderAuthorities": [      "GROUP_EVERYONE"    ],    "resourceDeniedAuthorities": []  }}

Using theNode Browser the followingNodeRefs were resolved as follows:

  "id": "d71dd823-82c7-477c-8490-04cb0e826e65",   /app:company_home/cm:Testing/cm:Inbound/cm:purchase-order-scan.pdf (cm:content)  "primaryHierarchy": [    "5f355d16-f824-4173-bf4b-b1ec37ef5549",       /app:company_home/cm:Testing/cm:Inbound  (cm:folder)    "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",       /app:company_home/cm:Testing             (cm:folder)    "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",       /app:company_home                        (cm:folder)    "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"        Store root                               (sys:store_root)

The event payload is telling us that a file calledpurchase-order-scan.pdf (i.e.data.resource.name) of typecm:content (i.e.data.resource.nodeType) was created by the useradmin (i.e.data.resource.createdByUser.id) in the/Company Home/Testing/Inbound folder (i.e.data.resource.primaryHierarchy[0]). The new node has a Node IDd71dd823-82c7-477c-8490-04cb0e826e65 (i.e.data.resource.id).

To find out the display name for a folder or file via its Node ID use the ReST API toget metadata. This call can also be used to get other properties for the created node as not all are returned in the event data (i.e.data.resource.properties).

When subscribing to theorg.alfresco.event.node.Created event it’s possible to filter out anything that isof no interest. So for example, if you are interested in files with content typecm:content uploaded to a folder called/Company Home/Testing/Inbound (e.g. Node ID5f355d16-f824-4173-bf4b-b1ec37ef5549) 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:

    import org.alfresco.event.sdk.handling.filter.EventFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.handling.handler.OnNodeCreatedEventHandler;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;/** * Sample event handler to demonstrate reacting to a document/file being uploaded to the repository. */@Componentpublic class ContentUploadedEventHandler implements OnNodeCreatedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(ContentUploadedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        NodeResource nodeResource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("A file was uploaded to the repository: {}, {}, {}", nodeResource.getId(), nodeResource.getNodeType(),               nodeResource.getName());    }    public EventFilter getEventFilter() {        return IsFileFilter.get() // Make sure it's a file                .and(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549")); // Located in the /Company Home/Testing/Inbound folder    }}

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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.EventTypeFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.integration.EventChannels;import org.alfresco.event.sdk.integration.filter.IntegrationEventFilter;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;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 file is uploaded */@Componentpublic class NewContentFlow extends IntegrationFlowAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(NewContentFlow.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.NODE_CREATED)) // Filter events and select only node created events                .filter(IntegrationEventFilter.of(IsFileFilter.get())) // Filter node and make sure it is a file node                .filter(IntegrationEventFilter.of(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549"))) // Filter node and make sure we got correct parent folder ID                .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();        NodeResource resource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("File uploaded: {}", resource);    }}

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("CreatedFileRoute")            .log("${body}")             .choice()             .when() // When the following is true:                // The event type is node created                .jsonpath("$[?(@.type=='org.alfresco.event.node.Created' && " +                   // The node that was created is a file                "@.data.resource.nodeType=='cm:content' && " +                            // The file is located in the /Company Home/Testing/Inbound folder                "'5f355d16-f824-4173-bf4b-b1ec37ef5549' in @.data.resource.primaryHierarchy[:1])]")            // Unpack the data into JSON format              .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data             .bean("eventHandlerImpl", "onReceive(*, COPY)")             .end();    }}

    Thejsonpath 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 IDeventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Node updated event

This event is fired whenever a node, such as a folder or file, is updated or moved in the repository. The full name of this event isorg.alfresco.event.node.Updated. The event is fired when the node’s name, type, properties, aspects, or content is updated.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.node.Updated",  "id": "ae5dac3c-25d0-438d-b148-2084d1ab05a6",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-01-26T10:29:42.99524Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/nodeUpdated",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "b5b1ebfe-45fc-4f86-b71b-421996482881",    "resource": {      "@type": "NodeResource",      "id": "d71dd823-82c7-477c-8490-04cb0e826e65",      "primaryHierarchy": [        "5f355d16-f824-4173-bf4b-b1ec37ef5549",        "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",        "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",        "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"      ],      "name": "purchase-order-scan.pdf",      "nodeType": "cm:content",      "createdByUser": {        "id": "admin",        "displayName": "Administrator"      },      "createdAt": "2021-01-21T11:14:15.695Z",      "modifiedByUser": {        "id": "admin",        "displayName": "Administrator"      },      "modifiedAt": "2021-01-26T10:29:42.529Z",      "content": {        "mimeType": "application/pdf",        "sizeInBytes": 531152,        "encoding": "UTF-8"      },      "properties": {        "cm:autoVersion": true,        "cm:title": "Purchase Order",        "cm:versionType": "MAJOR",        "cm:versionLabel": "1.0",        "cm:autoVersionOnUpdateProps": false,        "cm:lastThumbnailModification": [          "doclib:1611227666770"        ],        "cm:description": "",        "cm:taggable": null,        "cm:initialVersion": true      },      "aspectNames": [        "cm:versionable",        "cm:author",        "cm:thumbnailModification",        "cm:titled",        "rn:renditioned",        "cm:auditable",        "cm:taggable"      ],      "isFolder": false,      "isFile": true    },    "resourceBefore": {      "@type": "NodeResource",      "modifiedAt": "2021-01-21T11:14:25.223Z",      "properties": {        "cm:title": null,        "cm:taggable": null,        "cm:description": null      },      "aspectNames": [        "cm:versionable",        "cm:author",        "cm:thumbnailModification",        "cm:titled",        "rn:renditioned",        "cm:auditable"      ]    },    "resourceReaderAuthorities": [      "GROUP_EVERYONE"    ],    "resourceDeniedAuthorities": []  }}

The event data payload looks very similar to the data for a created node. There is just one extra object calledresourceBefore that contains the property values before the update. In this case we can see that thecm:title propertyof thecm:titled aspect has been filled in (i.e.data.resource.properties.cm:title: "Purchase Order").

Using theNode Browser the followingNodeRefs were resolved as follows:

  "id": "d71dd823-82c7-477c-8490-04cb0e826e65",   /app:company_home/cm:Testing/cm:Inbound/cm:purchase-order-scan.pdf (cm:content)  "primaryHierarchy": [    "5f355d16-f824-4173-bf4b-b1ec37ef5549",       /app:company_home/cm:Testing/cm:Inbound  (cm:folder)    "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",       /app:company_home/cm:Testing             (cm:folder)    "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",       /app:company_home                        (cm:folder)    "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"        Store root                               (sys:store_root)

The event payload is telling us that a file calledpurchase-order-scan.pdf (i.e.data.resource.name) of typecm:content (i.e.data.resource.nodeType) was updated by the useradmin (i.e.data.resource.createdByUser.id) in the/Company Home/Testing/Inbound folder (i.e.data.resource.primaryHierarchy[0]). The updated node has a Node IDd71dd823-82c7-477c-8490-04cb0e826e65 (i.e.data.resource.id).

To find out the display name for a folder or file via its Node ID use the ReST API toget metadata. This call can also be used to get other properties for the created node as not all are returned in the event data (i.e.data.resource.properties).

When subscribing to theorg.alfresco.event.node.Updated event it’s possible to filter out anything that isof no interest. So for example, if you are interested in files with content typecm:content updated in the folder called/Company Home/Testing/Inbound (e.g. Node ID5f355d16-f824-4173-bf4b-b1ec37ef5549) 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.EventFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.handling.handler.OnNodeUpdatedEventHandler;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;/** * Sample event handler to demonstrate reacting to a document/file being updated. */@Componentpublic class ContentUpdatedEventHandler implements OnNodeUpdatedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(ContentUploadedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        NodeResource beforeUpdateResource = (NodeResource) repoEvent.getData().getResourceBefore();        NodeResource afterUpdateResource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("A file was updated in the repository: {}, {}, {}", afterUpdateResource.getId(),                 afterUpdateResource.getNodeType(), afterUpdateResource.getName());    }    public EventFilter getEventFilter() {        return IsFileFilter.get() // Make sure it's a file                .and(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549")); // Located in the /Company Home/Testing/Inbound folder    }}

    Note that you can get to the property values before the update via therepoEvent.getData().getResourceBefore() call.You can compare those to the values retreived viarepoEvent.getData().getResource() and see what’s changed.

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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.EventTypeFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.integration.EventChannels;import org.alfresco.event.sdk.integration.filter.IntegrationEventFilter;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;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 file is updated */@Componentpublic class UpdatedContentFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(UpdatedContentFlow.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.NODE_UPDATED)) // Filter events and select only node updated events                .filter(IntegrationEventFilter.of(IsFileFilter.get())) // Filter node and make sure it is a file node                .filter(IntegrationEventFilter.of(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549"))) // Filter node and make sure we got correct parent folder ID (/Company Home/Testing/Inbound)                .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();        NodeResource beforeUpdateResource = (NodeResource) repoEvent.getData().getResourceBefore();        NodeResource afterUpdateResource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("File updated: Before update {}, after update {}", beforeUpdateResource.toString(),                afterUpdateResource.toString());    }}

    Note that you can get to the property values before the update via therepoEvent.getData().getResourceBefore() call.You can compare those to the values retreived viarepoEvent.getData().getResource() and see what’s changed.

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("UpdatedFileRoute")            .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 node updated                .jsonpath("$[?(@.type=='org.alfresco.event.node.Updated' && " +                // and the node that was updated is a file                "@.data.resource.nodeType=='cm:content' && " +                // and the file is located in the /Company Home/Testing/Inbound folder                "'5f355d16-f824-4173-bf4b-b1ec37ef5549' in @.data.resource.primaryHierarchy[:1])]")            // Unpack the data into JSON format            .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data            .bean("updatedEventHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDupdatedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Node deleted event

This event is fired whenever a node, such as a folder or file, is deleted in the repository. The full name of this event isorg.alfresco.event.node.Deleted.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.node.Deleted",  "id": "df329995-d744-427c-bafb-4a31ba7d50e3",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-01-27T10:57:02.586606Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/nodeDeleted",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "acb8e25f-a340-48b5-8de8-249ae5bac670",    "resource": {      "@type": "NodeResource",      "id": "d71dd823-82c7-477c-8490-04cb0e826e65",      "primaryHierarchy": [        "5f355d16-f824-4173-bf4b-b1ec37ef5549",        "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",        "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",        "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"      ],      "name": "purchase-order-scan.pdf",      "nodeType": "cm:content",      "createdByUser": {        "id": "admin",        "displayName": "Administrator"      },      "createdAt": "2021-01-21T11:14:15.695Z",      "modifiedByUser": {        "id": "admin",        "displayName": "Administrator"      },      "modifiedAt": "2021-01-26T10:29:42.529Z",      "content": {        "mimeType": "application/pdf",        "sizeInBytes": 531152,        "encoding": "UTF-8"      },      "properties": {        "cm:autoVersion": true,        "cm:title": "Purchase Order",        "cm:versionType": "MAJOR",        "cm:versionLabel": "1.0",        "cm:autoVersionOnUpdateProps": false,        "cm:lastThumbnailModification": [          "doclib:1611227666770"        ],        "cm:description": "",        "cm:taggable": null,        "cm:initialVersion": true      },      "aspectNames": [        "cm:versionable",        "cm:author",        "cm:thumbnailModification",        "cm:titled",        "rn:renditioned",        "cm:auditable",        "cm:taggable"      ],      "isFolder": false,      "isFile": true    },    "resourceReaderAuthorities": [],    "resourceDeniedAuthorities": []  }}

The event data payload looks very similar to the data for a created node. Using theNode Browser the followingNodeRefs were resolved as follows:

  "id": "d71dd823-82c7-477c-8490-04cb0e826e65",   /app:company_home/cm:Testing/cm:Inbound/cm:purchase-order-scan.pdf (cm:content)  "primaryHierarchy": [    "5f355d16-f824-4173-bf4b-b1ec37ef5549",       /app:company_home/cm:Testing/cm:Inbound  (cm:folder)    "93f7edf5-e4d8-4749-9b4c-e45097e2e19d",       /app:company_home/cm:Testing             (cm:folder)    "c388532e-8da6-4d50-a6d2-4f3f3ac36ff7",       /app:company_home                        (cm:folder)    "2fa2cde5-9d83-4460-a38c-cfe4ec9cca08"        Store root                               (sys:store_root)

The event payload is telling us that a file calledpurchase-order-scan.pdf (i.e.data.resource.name) of typecm:content (i.e.data.resource.nodeType) was deleted by the useradmin (i.e.data.resource.createdByUser.id) in the/Company Home/Testing/Inbound folder (i.e.data.resource.primaryHierarchy[0]). The deleted node had a Node IDd71dd823-82c7-477c-8490-04cb0e826e65 (i.e.data.resource.id). Note that the deleted node is soft deleted and is nowavailable in the trash can.

When subscribing to theorg.alfresco.event.node.Deleted event it’s possible to filter out anything that isof no interest. So for example, if you are interested in files with content typecm:content deleted in the folder called/Company Home/Testing/Inbound (e.g. Node ID5f355d16-f824-4173-bf4b-b1ec37ef5549) 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.EventFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.handling.handler.OnNodeDeletedEventHandler;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;/** * Sample event handler to demonstrate reacting to a document/file being deleted. */@Componentpublic class ContentDeletedEventHandler implements OnNodeDeletedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(ContentDeletedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        NodeResource resource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("A file was deleted: {}, {}, {}", resource.getId(), resource.getNodeType(),             resource.getName());    }    public EventFilter getEventFilter() {        return IsFileFilter.get() // Make sure it's a file                .and(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549")); // Located in the /Company Home/Testing/Inbound folder    }}

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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.EventTypeFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.integration.EventChannels;import org.alfresco.event.sdk.integration.filter.IntegrationEventFilter;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;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 file is deleted */@Componentpublic class DeletedContentFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(DeletedContentFlow.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.NODE_DELETED)) // Filter events and select only node deleted events                .filter(IntegrationEventFilter.of(IsFileFilter.get())) // Filter node and make sure it is a file node                .filter(IntegrationEventFilter.of(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549"))) // Filter node and make sure we got correct parent folder ID (/Company Home/Testing/Inbound)                .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();        NodeResource resource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("File deleted: {}", resource.toString());    }}

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("DeletedFileRoute")            .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 node deleted            .jsonpath("$[?(@.type=='org.alfresco.event.node.Deleted' && " +                    // and the node that was deleted is a file                    "@.data.resource.nodeType=='cm:content' && " +                    // and the file is located in the /Company Home/Testing/Inbound folder                    "'5f355d16-f824-4173-bf4b-b1ec37ef5549' in @.data.resource.primaryHierarchy[:1])]")            // Unpack the data into JSON format            .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data            .bean("deletedEventHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDdeletedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Parent-Child association created event

This event is fired whenever asecondary parent -> child association is created, such as via the thePOST nodes/{parentId}/secondary-children
ReST API. The full name of this event isorg.alfresco.event.assoc.child.Created.

Note that this event will not be generated when a file is created or a folder is created. In this case theprimary parent -> child association (i.e.cm:contains) is created but an event for this association is not triggered. You will have to listen to theorg.alfresco.event.node.Created event instead, and from the data for this event you can get to theprimary 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 theNode Browser the followingNodeRefs 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 typefdk:images (i.e.data.resource.assocType) was set up between a gadget fileMy Gadget (i.e.data.resource.parent) and a gadget imagegadget-picture.png (i.e.data.resource.child).

When subscribing to theorg.alfresco.event.assoc.child.Created event it’s possible to filter out anything that isof no interest. So for example, if you are only interested in associations of typefdk: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.*/@Componentpublic 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 theorg.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 seeChildAssociationResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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. */@Componentpublic 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 theorg.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 seeChildAssociationResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

  • Apache Camel
  • The following code snippet shows how this could be done with anApache 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();    }}

    Thejsonpath 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 IDparentChildAssocCreatedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Parent-Child association deleted event

This event is fired whenever asecondary parent -> child association is deleted, such as via the theDELETE nodes/{parentId}/secondary-children
ReST API. The full name of this event isorg.alfresco.event.assoc.child.Deleted.

Note that this event will not be generated when a file is deleted or a folder is deleted. In this case theprimary parent -> child association (i.e.cm:contains) is deleted but an event for this association is not triggered. You will have to listen to theorg.alfresco.event.node.Deleted event instead, and from the data for this event you can get data for the deletedprimary parent -> child association.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.assoc.child.Deleted",  "id": "80a8b1db-9bac-4f20-8273-025bc555ba61",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-02-01T16:39:56.583965Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/childAssocDeleted",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "3c53ff93-9a7c-4275-ac17-7bb2b7413f53",    "resource": {      "@type": "ChildAssociationResource",      "assocType": "fdk:images",      "parent": {        "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"      },      "child": {        "id": "ceb3c804-8b32-4050-b2da-b55c47f01666"      }    }  }}

Using theNode Browser the followingNodeRefs 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"  /sys:archivedItem/gadget-picture.png

The event payload is telling us that a secondary parent-child association of typefdk:images (i.e.data.resource.assocType) was deleted between a gadget fileMy Gadget (i.e.data.resource.parent) and a gadget reviewgadget-picture.png (i.e.data.resource.child).

Note. when you use the Node Browser to look for the deletedgadget-picture.png file (i.e. with ID ceb3c804-8b32-4050-b2da-b55c47f01666) you have to search in thearchive://SpacesStore store to find it. This store contains soft deleted files.

When subscribing to theorg.alfresco.event.assoc.child.Deleted event it’s possible to filter out anything that isof no interest. So for example, if you are only interested in associations of typefdk: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.OnChildAssocDeletedEventHandler;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 deleted.*/@Componentpublic class ParentChildAssocDeletedEventHandler implements OnChildAssocDeletedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(ParentChildAssocDeletedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        ChildAssociationResource resource = (ChildAssociationResource) repoEvent.getData().getResource();        LOGGER.info("A secondary Parent-Child association was deleted: {} -> {}", 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 theorg.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 seeChildAssociationResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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 deleted. */@Componentpublic class ParentChildAssocDeletedFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(ParentChildAssocDeletedFlow.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_DELETED)) // Filter events and select only Parent-Child assoc deleted 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 deleted: {} -> {}", resource.getParent().getId(),                resource.getChild().getId());    }}

    This code uses theorg.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 seeChildAssociationResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("ParentChildAssocDeletedRoute")            .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 deleted            .jsonpath("$[?(@.type=='org.alfresco.event.assoc.child.Deleted' && " +                    // 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("parentChildAssocDeletedEventHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDparentChildAssocDeletedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Peer association created event

This event is fired whenever a peer association is created, such as via the thePOST nodes/{sourceId}/targets
ReST API. The full name of this event isorg.alfresco.event.assoc.peer.Created.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.assoc.peer.Created",  "id": "8a8113a2-fa67-4914-9ecb-2ec47c456159",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-01-28T13:42:34.352956Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/peerAssocCreated",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "78da21cc-fa5a-47d1-afcb-03005229efa9",    "resource": {      "@type": "PeerAssociationResource",      "assocType": "fdk:reviews",      "source": {        "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"      },      "target": {        "id": "f826ac49-0262-48af-8f63-f87eb7007078"      }    }  }}

Using theNode Browser the followingNodeRefs were resolved as follows:

  "source": {    "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"  /app:company_home/cm:My_x0020_Gadgets/cm:My_x0020_Gadget  },  "target": {    "id": "f826ac49-0262-48af-8f63-f87eb7007078"  /app:company_home/cm:My_x0020_Gadgets/cm:gadget-review.txt

The event payload is telling us that a peer association of typefdk:reviews (i.e.data.resource.assocType) was set up between a gadget fileMy Gadget (i.e.data.resource.source) and a gadget reviewgadget-review.txt (i.e.data.resource.target).

When subscribing to theorg.alfresco.event.assoc.peer.Created event it’s possible to filter out anything that isof no interest. So for example, if you are only interested in associations of typefdk:reviews 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:

    import org.alfresco.event.sdk.handling.filter.AssocTypeFilter;import org.alfresco.event.sdk.handling.filter.EventFilter;import org.alfresco.event.sdk.handling.handler.OnPeerAssocCreatedEventHandler;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 peer-2-peer assoc being created.*/@Componentpublic class Peer2PeerAssocCreatedEventHandler implements OnPeerAssocCreatedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(Peer2PeerAssocCreatedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        PeerAssociationResource resource = (PeerAssociationResource) repoEvent.getData().getResource();        LOGGER.info("A Peer-Peer association was created: Source {} -> Target {}", resource.getSource().getId(),                resource.getTarget().getId());    }    public EventFilter getEventFilter() {        return AssocTypeFilter.of("fdk:reviews"); // Make sure the Peer-Peer association is of type FDK Reviews    }}

    This code uses theorg.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Peer-2-Peer association we are interested in.

    For more information about how to extract all the properties from the message payload seePeerAssociationResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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 peer-2-peer assoc is being created. */@Componentpublic class Peer2PeerAssocCreatedFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(Peer2PeerAssocCreatedFlow.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.PEER_ASSOC_CREATED)) // Filter events and select only Peer2Peer assoc created events                .filter(IntegrationEventFilter.of(AssocTypeFilter.of("fdk:reviews"))) // Make sure the Peer2Peer association is of type FDK Reviews                .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();        PeerAssociationResource resource = (PeerAssociationResource) repoEvent.getData().getResource();        LOGGER.info("A Peer-Peer association was created: Source {} -> Target {}", resource.getSource().getId(),                resource.getTarget().getId());    }}

    This code uses theorg.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Peer-2-Peer association we are interested in.

    For more information about how to extract all the properties from the message payload seePeerAssociationResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("PeerAssocCreatedRoute")            .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 peer assoc created            .jsonpath("$[?(@.type=='org.alfresco.event.assoc.peer.Created' && " +                    // and the association type is fdk:reviews                    "@.data.resource.assocType=='fdk:reviews')]" )            // Unpack the data into JSON format            .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data            .bean("peerAssocCreatedEventHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDpeerAssocCreatedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Peer association deleted event

This event is fired whenever a peer association is deleted, such as via the theDELETE nodes/{sourceId}/targets
ReST API. The full name of this event isorg.alfresco.event.assoc.peer.Deleted.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.assoc.peer.Deleted",  "id": "630a2b78-5832-42ad-89e0-bafaed73df3d",  "source": "/08d9b620-48de-4247-8f33-360988d3b19b",  "time": "2021-02-01T10:39:37.329006Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/peerAssocDeleted",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "27e7f158-707b-48ee-87ca-efd247e6cbb7",    "resource": {      "@type": "PeerAssociationResource",      "assocType": "fdk:reviews",      "source": {        "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"      },      "target": {        "id": "f826ac49-0262-48af-8f63-f87eb7007078"      }    }  }}

Using theNode Browser the followingNodeRefs were resolved as follows:

  "source": {    "id": "a4eb7684-0ffe-4bf5-b6f7-4297a6e4ee84"  /app:company_home/cm:My_x0020_Gadgets/cm:My_x0020_Gadget    },  "target": {    "id": "f826ac49-0262-48af-8f63-f87eb7007078"  /sys:archivedItem/gadget-review.txt

The event payload is telling us that a peer association of typefdk:reviews (i.e.data.resource.assocType) was deleted between a gadget fileMy Gadget (i.e.data.resource.source) and a gadget reviewgadget-review.txt (i.e.data.resource.target).

Note. when you use the Node Browser to look for the deletedgadget-review.txt file (i.e. with ID f826ac49-0262-48af-8f63-f87eb7007078) you have to search in thearchive://SpacesStore store to find it. This store contains soft deleted files.

When subscribing to theorg.alfresco.event.assoc.peer.Deleted event it’s possible to filter out anything that isof no interest. So for example, if you are only interested in associations of typefdk:reviews 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:

    import org.alfresco.event.sdk.handling.filter.AssocTypeFilter;import org.alfresco.event.sdk.handling.filter.EventFilter;import org.alfresco.event.sdk.handling.handler.OnPeerAssocDeletedEventHandler;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 peer-2-peer assoc being deleted.*/@Componentpublic class Peer2PeerAssocDeletedEventHandler implements OnPeerAssocDeletedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(Peer2PeerAssocDeletedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        PeerAssociationResource resource = (PeerAssociationResource) repoEvent.getData().getResource();        LOGGER.info("A Peer-Peer association was deleted: Source {} -> Target {}", resource.getSource().getId(),                resource.getTarget().getId());    }    public EventFilter getEventFilter() {        return AssocTypeFilter.of("fdk:reviews"); // Make sure the Peer-Peer association is of type FDK Reviews    }}

    This code uses theorg.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Peer-2-Peer association we are interested in.

    For more information about how to extract all the properties from the message payload seePeerAssociationResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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 peer-2-peer assoc is being deleted. */@Componentpublic class Peer2PeerAssocDeletedFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(Peer2PeerAssocDeletedFlow.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.PEER_ASSOC_DELETED)) // Filter events and select only Peer2Peer assoc deleted events                .filter(IntegrationEventFilter.of(AssocTypeFilter.of("fdk:reviews"))) // Make sure the Peer2Peer association is of type FDK Reviews                .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();        PeerAssociationResource resource = (PeerAssociationResource) repoEvent.getData().getResource();        LOGGER.info("A Peer-Peer association was deleted: Source {} -> Target {}", resource.getSource().getId(),                resource.getTarget().getId());    }}

    This code uses theorg.alfresco.event.sdk.handling.filter.AssocTypeFilter event filter to specify what type of Peer-2-Peer association we are interested in.

    For more information about how to extract all the properties from the message payload seePeerAssociationResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("PeerAssocDeletedRoute")            .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 peer assoc deleted            .jsonpath("$[?(@.type=='org.alfresco.event.assoc.peer.Deleted' && " +                    // and the association type is fdk:reviews                    "@.data.resource.assocType=='fdk:reviews')]" )            // Unpack the data into JSON format            .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data            .bean("peerAssocDeletedEventHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDpeerAssocDeletedEventHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Permission updated event (ENTERPRISE ONLY)

This event is fired whenever a permission is updated for a node, such as via the theManage Permissions action in the Share user interface. The full name of this event isorg.alfresco.event.permission.Updated.

Note. this event is not fired if you are using the Community Edition of Alfresco.

Here is an example payload for this event type:

{  "specversion": "1.0",  "type": "org.alfresco.event.permission.Updated",  "id": "ecf62eb0-55b5-4c42-969b-27bb24ad658d",  "source": "/bb4be766-5aeb-4bc9-bd23-948ae98e4e9f",  "time": "2021-04-07T09:10:33.825727Z",  "dataschema": "https://api.alfresco.com/schema/event/repo/v1/permissionUpdated",  "datacontenttype": "application/json",  "data": {    "eventGroupId": "8ddc1695-b911-40c4-b81c-05b549cd02dc",    "resource": {      "@type": "NodeResource",      "id": "018de31a-47bf-431f-9107-3aacb63fcb67",      "primaryHierarchy": [        "f813b415-aa71-43b9-9c8a-2ce92ab715f8",        "1f0371cf-ab5b-45f3-8d76-76699c82367d",        "341635c3-c089-4564-b5dd-8407498b7ea3"      ],      "name": "somefile.txt",      "nodeType": "cm:content",      "createdByUser": {        "id": "admin",        "displayName": "Administrator"      },      "createdAt": "2021-04-07T09:06:44.216Z",      "modifiedByUser": {        "id": "admin",        "displayName": "Administrator"      },      "modifiedAt": "2021-04-07T09:10:33.602Z",      "content": {        "mimeType": "text/plain",        "sizeInBytes": 9,        "encoding": "UTF-8"      },      "properties": {        "cm:title": "",        "app:editInline": true,        "cm:lastThumbnailModification": [          "pdf:1617786411514"        ],        "cm:description": ""      },      "aspectNames": [        "cm:thumbnailModification",        "cm:titled",        "app:inlineeditable",        "rn:renditioned",        "cm:auditable"      ],      "isFile": true,      "isFolder": false    },    "resourceReaderAuthorities": [      "GROUP_EVERYONE",      "abeecher",      "guest"    ],    "resourceDeniedAuthorities": []  }}

In this case the node permissions for userabeecher was updated. For information about what specific permissions were set or removed for the user use theReST API.

When subscribing to theorg.alfresco.event.permission.Updated event it’s possible to filter out anything that isof no interest. So for example, if you are only interested in permission updates for a specific node or folder 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:

    import org.alfresco.event.sdk.handling.filter.EventFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.handling.handler.OnPermissionUpdatedEventHandler;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 node permission being updated. *  * IMPORTANT! only works with ACS 7 Enterprise Edition. */@Componentpublic class PermissionUpdatedEventHandler implements OnPermissionUpdatedEventHandler {    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionUpdatedEventHandler.class);    public void handleEvent(final RepoEvent<DataAttributes<Resource>> repoEvent) {        NodeResource resource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("A node permission was updated: {}", resource.toString());    }        public EventFilter getEventFilter() {        return IsFileFilter.get() // permissions for a file is being updated                .and(ParentFolderFilter.of("55a21ec2-eaff-4e0f-b76b-c84e32d1c2fe")); // the file is located in a specific folder with this Node ID     }}

    This code uses theorg.alfresco.event.sdk.handling.filter.IsFileFilter event filter to specify that we are only interested in permission updates to files.

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses plain Java event handlers followthese instructions.

  • 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.EventTypeFilter;import org.alfresco.event.sdk.handling.filter.IsFileFilter;import org.alfresco.event.sdk.integration.EventChannels;import org.alfresco.event.sdk.integration.filter.IntegrationEventFilter;import org.alfresco.event.sdk.model.v1.model.DataAttributes;import org.alfresco.event.sdk.model.v1.model.NodeResource;import org.alfresco.event.sdk.model.v1.model.RepoEvent;import org.alfresco.event.sdk.model.v1.model.Resource;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 node permissions are being updated.* * IMPORTANT! only works with ACS 7 Enterprise Edition. */@Componentpublic class PermissionUpdatedFlow extends IntegrationFlowAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionUpdatedFlow.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.PERMISSION_UPDATED)) // Filter events and select only permission updated events                .filter(IntegrationEventFilter.of(IsFileFilter.get())) // Filter node and make sure it is a file node                .filter(IntegrationEventFilter.of(ParentFolderFilter.of("5f355d16-f824-4173-bf4b-b1ec37ef5549"))) // Filter node and make sure the file is in a folder with this Node ID                .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();        NodeResource resource = (NodeResource) repoEvent.getData().getResource();        LOGGER.info("Node permissions were updated: {} ", resource.toString());    }}

    This code uses theorg.alfresco.event.sdk.handling.filter.IsFileFilter event filter to specify that we are only interested in permission updates to files.

    This code uses a customParentFolderFilter.

    For more information about how to extract all the properties from the message payload seeNodeResource info.

    To create an SDK event handler project that uses Spring Integration followthese instructions.

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

    public class SimpleRoute extends RouteBuilder {    @Override    public void configure() {        from("amqpConnection:topic:alfresco.repo.event2")            .id("PermissionUpdatedRoute")            .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 permission udpated            .jsonpath("$[?(@.type=='org.alfresco.event.permission.Updated' && " +                // The node that was created is a file                "@.data.resource.nodeType=='cm:content' && " +                            // The file is located in a folder with this Node ID                "'5f355d16-f824-4173-bf4b-b1ec37ef5549' in @.data.resource.primaryHierarchy[:1])]")            // Unpack the data into JSON format            .unmarshal("publicDataFormat")            // Call a Spring Bean with the event data            .bean("permissionUpdatedHandlerImpl", "onReceive(*, COPY)")            .end();    }}

    Thejsonpath 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 IDpermissionUpdatedHandlerImpl is called at the end of the route from where you could make the necessary ReST API calls.

Edit this page

Suggest an edit on GitHub
By clicking "Accept Cookies", you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.View Cookie Policy.

[8]ページ先頭

©2009-2025 Movatter.jp