Make sure you have completed prerequisites (see Prerequisites) and created a starter project (see Create a starting point Spring project).
To use pure Java event handlers follow these steps:
Add the following dependency in the Maven project file (i.e. pom.xml):
<dependencies>
<!-- Alfresco Java SDK 6 Java Event Handler API Spring Boot Starter -->
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-java-event-api-spring-boot-starter</artifactId>
<version>6.2.0</version>
</dependency>
</dependencies>
Remove the default Spring Boot starter dependency (i.e. <artifactId>spring-boot-starter</artifactId>).
Test it:
$ mvn clean package -Dlicense.skip=true
[INFO] Scanning for projects...
...
$ java -jar target/events-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.2)
2021-03-26 09:19:45.766 INFO 73086 --- [ main] o.a.tutorial.events.EventsApplication : Starting EventsApplication v0.0.1-SNAPSHOT using Java 11.0.2 on MBP512-MBERGLJUNG-0917 with PID 73086 (/Users/mbergljung/IDEAProjects/docs-new/sdk5/sdk5-pure-java-events-sample/target/events-0.0.1-SNAPSHOT.jar started by mbergljung in /Users/mbergljung/IDEAProjects/docs-new/sdk5/sdk5-pure-java-events-sample)
2021-03-26 09:19:45.769 INFO 73086 --- [ main] o.a.tutorial.events.EventsApplication : No active profile set, falling back to default profiles: default
2021-03-26 09:19:46.593 INFO 73086 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2021-03-26 09:19:46.598 INFO 73086 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
2021-03-26 09:19:46.606 INFO 73086 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2021-03-26 09:19:46.722 INFO 73086 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-03-26 09:19:46.738 INFO 73086 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationChannelResolver' of type [org.springframework.integration.support.channel.BeanFactoryChannelResolver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-03-26 09:19:46.739 INFO 73086 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationDisposableAutoCreatedBeans' of type [org.springframework.integration.config.annotation.Disposables] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-03-26 09:19:47.537 INFO 73086 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
2021-03-26 09:19:47.601 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s).
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger'
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {transformer} as a subscriber to the 'acsEventsListeningFlow.channel#0' channel
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.acsEventsListeningFlow.channel#0' has 1 subscriber(s).
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsListeningFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsListeningFlow'
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {recipient-list-router} as a subscriber to the 'acsEventsListeningFlow.channel#1' channel
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.acsEventsListeningFlow.channel#1' has 1 subscriber(s).
2021-03-26 09:19:47.602 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsListeningFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#1'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsListeningFlow'
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {bridge} as a subscriber to the 'alfresco.events.si.channel' channel
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.alfresco.events.si.channel' has 1 subscriber(s).
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsSpringIntegrationFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsSpringIntegrationFlow'
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {bridge} as a subscriber to the 'acsEventsSpringIntegrationFlow.channel#1' channel
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.acsEventsSpringIntegrationFlow.channel#1' has 1 subscriber(s).
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsSpringIntegrationFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#1'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsSpringIntegrationFlow'
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {bridge} as a subscriber to the 'alfresco.events.handlers.channel' channel
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.alfresco.events.handlers.channel' has 1 subscriber(s).
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsHandlersFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsHandlersFlow'
2021-03-26 09:19:47.603 INFO 73086 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.acsEventsHandlersFlow.channel#1' has 1 subscriber(s).
2021-03-26 09:19:47.604 INFO 73086 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'acsEventsHandlersFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#1'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsHandlersFlow'
2021-03-26 09:19:47.604 INFO 73086 --- [ main] ishingJmsMessageListener$GatewayDelegate : started org.springframework.integration.jms.ChannelPublishingJmsMessageListener$GatewayDelegate@53812a9b
2021-03-26 09:19:47.784 INFO 73086 --- [ main] o.s.i.jms.JmsMessageDrivenEndpoint : started bean 'acsEventsListeningFlow.jms:message-driven-channel-adapter#0'; defined in: 'class path resource [org/alfresco/event/sdk/autoconfigure/AlfrescoEventsAutoConfiguration.class]'; from source: 'bean method acsEventsListeningFlow'
2021-03-26 09:19:47.796 INFO 73086 --- [ main] o.a.tutorial.events.EventsApplication : Started EventsApplication in 2.509 seconds (JVM running for 3.005)
Looks ready for some event handler code.
Now, start adding your event handler code, let’s add an event handler that will be triggered when a new document/file is uploaded. To do this we need to create a class that implements the org.alfresco.event.sdk.handling.handler.OnNodeCreatedEventHandler. For more information, see event handler interface in Event handling library:
package org.alfresco.tutorial.events;
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.
*/
@Component
public 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());
}
}
Add the Spring Bean class into the same directory as the Spring Boot starter class. It doesn’t have to be added to this directory, but in this case we are just testing it, so no need to organize too much.
Now stop, build and start it up again:
$ ^C ... $ mvn spring-boot:run -Dlicense.skip=true ...
Add a file via the Share user interface, you should see the following in the logs:
2021-03-26 10:23:46.846 INFO 74020 --- [erContainer#0-1] o.a.t.e.ContentUploadedEventHandler : A file was uploaded to the repository: 13ba2bbf-2422-4152-832f-060e017ec09c, cm:content, some-file.txt
Now, this event handler will actually also be triggered when a folder is created. So how can we fix so the handler is only triggered when a file is created/uploaded? By adding a so called event filter to the class (see Event filter):
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.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.
*/
@Component
public 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();
}
}
Here we are using the org.alfresco.event.sdk.handling.filter.IsFileFilter, which will make sure that the event handler is triggered only when the node type is cm:content or subtype thereof, which represents files.
For a complete list of events with sample code, see the Events Extension Points section in the Alfresco Content Services documentation. For a complete list of Event Filters available in the SDK see Event handling library.
For information on how to implement a custom event filter see Implementing custom event filters.
For more information about how to extract all the properties from the message payload see The NodeResource object.