Information | Behaviors | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Support Status | Full Support | ||||||||||
Architecture Information | Platform Architecture | ||||||||||
Description | Sometimes, using rules might not be enough for what we want to do. Let's say that we wanted to execute a business rule just before a node is deleted and a business rule after the node has been deleted. This cannot be done with rules, as they allow us to execute business rules only when nodes are created, deleted, or updated. Other examples are executing business logic after document version changes or when an association is deleted. In these cases we have to turn to the event model, which enables us to execute Java or JavaScript code when an event happens in the system. These events are referred to as behavior policies. The events that we can listen to are associated with the service that triggers them. Here's a list of some of the event policies:
The following table summarizes some of the policies that can be hooked up to:
To create an "event handler", we first start with the event handler implementation itself. In this example, we will listen to a couple of content events and do some logging when they occur: public class DocumentEventHandler { private static Logger logger = LoggerFactory.getLogger(DocumentEventHandler.class); private PolicyComponent eventManager; private ServiceRegistry serviceRegistry; public void setServiceRegistry(ServiceRegistry serviceRegistry) { this.serviceRegistry = serviceRegistry; } public void setPolicyComponent(PolicyComponent policyComponent) { this.eventManager = policyComponent; } public void registerEventHandlers() { eventManager.bindClassBehaviour( NodeServicePolicies.OnCreateNodePolicy.QNAME, ContentModel.TYPE_CONTENT, new JavaBehaviour(this, "onAddDocument", Behaviour.NotificationFrequency.TRANSACTION_COMMIT)); eventManager.bindClassBehaviour( NodeServicePolicies.OnUpdateNodePolicy.QNAME, ContentModel.TYPE_CONTENT, new JavaBehaviour(this, "onUpdateDocument", Behaviour.NotificationFrequency.TRANSACTION_COMMIT)); eventManager.bindClassBehaviour( NodeServicePolicies.OnDeleteNodePolicy.QNAME, ContentModel.TYPE_CONTENT, new JavaBehaviour(this, "onDeleteDocument", Behaviour.NotificationFrequency.TRANSACTION_COMMIT)); } public void onAddDocument(ChildAssociationRef parentChildAssocRef) { NodeRef parentFolderRef = parentChildAssocRef.getParentRef(); NodeRef docRef = parentChildAssocRef.getChildRef(); // Check if node exists, might be moved, or created and deleted in same transaction. if (docRef == null || !serviceRegistry.getNodeService().exists(docRef)) { // Does not exist, nothing to do logger.warn("onAddDocument: A new document was added but removed in same transaction"); return; } else { logger.info("onAddDocument: A new document with ref ({}) was just created in folder ({})", docRef, parentFolderRef); } } public void onUpdateDocument(NodeRef docNodeRef) { // Check if node exists, might be moved, or created and deleted in same transaction. if (docNodeRef == null || !serviceRegistry.getNodeService().exists(docNodeRef)) { // Does not exist, nothing to do logger.warn("onUpdateDocument: A document was updated but removed in same transaction"); return; } else { NodeRef parentFolderRef = serviceRegistry.getNodeService().getPrimaryParent(docNodeRef).getParentRef(); logger.info("onUpdateDocument: A document with ref ({}) was just updated in folder ({})", docNodeRef, parentFolderRef); } } public void onDeleteDocument(ChildAssociationRef parentChildAssocRef, boolean isNodeArchived) { NodeRef parentFolderRef = parentChildAssocRef.getParentRef(); NodeRef docRef = parentChildAssocRef.getChildRef(); logger.info("onDeleteDocument: A document with ref ({}) was just deleted in folder ({})", docRef, parentFolderRef); } } The event handler should contain one method per event we want to handle (i.e. run some code for). In this case we want to log some stuff when the user adds content files (onAddDocument), updates content files (onUpdateDocument), and deletes content files (onDeleteDocument). These method names can actually be called whatever you want, but it is obviously good to name them so it is easy to see what event they handle. These methods are however expected to take certain parameters. To find out which ones we need to look in the source code for the org.alfresco.repo.node.NodeServicePolicies class and look up the specific policy interface such as OnCreateNodePolicy, it will have the method signature that we need to follow, such as public void onCreateNode(ChildAssociationRef childAssocRef) in the case of the onAddDocument method. This just defines our event handling methods and we need to also register them with the Event Manager (referred to as the Policy Component), so that they get called when these events happens. To do this we have created another method called registerEventHandlers that will be used to register our event methods with the event manager. There are three things you need to tell the Event Manager when you register an event handler method:
To complete a Behavior Policy implementation we need to add the DocumentEventHandler class to the Spring context and make sure that the registerEventHandlers method is called: <bean id="org.alfresco.tutorial.policy.documentEventHandler" class="org.alfresco.tutorial.policy.DocumentEventHandler" init-method="registerEventHandlers"> <property name="policyComponent"> <ref bean="policyComponent"/> </property> <property name="serviceRegistry"> <ref bean="ServiceRegistry" /> </property> </bean> This makes it possible to pinpoint exactly what content should be affected by the business logic when the event occurs. Besides being able to bind the business logic to a particular content model class (that is, type or aspect), it can also be bound to either a content model association or a content model property. When an operation such as adding a document is executed, it is done in a transaction. During this, any registered event handlers are called in the same transaction and in the order they were registered. Because of this, a faulty event handler could prohibit the system from working properly. Let's say, we install an event handler that triggers when content is added to the system (that is, onCreateNode) and we have made a mistake when coding it. If this coding mistake results in an exception being thrown, then that rolls back the transaction. This would effectively block anybody from adding content to the system. So if unexpected errors happen after installing a lot of event handlers, it might be a good idea to remove them and see if they are the cause of the problem. It is possible to do even more fine-tuning of where in the transaction event handlers should be called (that is, compared to just before or after an operation). There are three different stages (SkyVault Content Services calls it notification frequencies) where the custom handler could be configured to be invoked:
Important: When using the event manager it is important to know that
it manages synchronous events. So whatever code we implement in the event
handler will be executed in the same transaction as the main SkyVault Content Services code that
triggered the event. This means that the code in the event handler will impact
the performance of general SkyVault Content Services operations
such as adding a document. So we need to be careful about this and use this
event system only when it is really necessary.
|
||||||||||
Deployment - App Server |
|
||||||||||
Deployment - SDK Project |
|
||||||||||
Sample Code | Not available | ||||||||||
Tutorials |
|
You are here
Behaviors/Policies
Behavior Policies can be used to run custom code when an event, such as adding a content
item or deleting a content item, happens.
© 2017 TBS-LLC. All Rights Reserved. Follow @twitter