MNT-23411 Option to disable events2 (#1703)

* Added configuration to disable events2 so the behaviours are not bootstrapped. Additionally added options to enable/disable on runtime
* Added unit test
This commit is contained in:
evasques
2023-01-25 16:15:17 +00:00
committed by GitHub
parent 5cba07d8de
commit 9637d514dd
6 changed files with 315 additions and 23 deletions

View File

@@ -169,6 +169,12 @@ public class FixedAclUpdater extends TransactionListenerAdapter implements Appli
listeners.add(listener);
}
/** Unregister a {@link FixedAclUpdaterListener} to be notified when a node is updated by an instance of this class. */
public static void unregisterListener(FixedAclUpdaterListener listener)
{
listeners.remove(listener);
}
public void init()
{
onInheritPermissionsDisabledDelegate = policyComponent

View File

@@ -31,8 +31,10 @@ import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.alfresco.repo.domain.node.NodeDAO;
@@ -54,8 +56,11 @@ import org.alfresco.repo.node.NodeServicePolicies.OnMoveNodePolicy;
import org.alfresco.repo.node.NodeServicePolicies.OnRemoveAspectPolicy;
import org.alfresco.repo.node.NodeServicePolicies.OnSetNodeTypePolicy;
import org.alfresco.repo.node.NodeServicePolicies.OnUpdatePropertiesPolicy;
import org.alfresco.repo.policy.Behaviour;
import org.alfresco.repo.policy.BehaviourDefinition;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.ServiceBehaviourBinding;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -103,10 +108,27 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
private ChildAssociationTypeFilter childAssociationTypeFilter;
private EventUserFilter userFilter;
protected final EventTransactionListener transactionListener = new EventTransactionListener();
protected boolean enabled;
private Set<Behaviour> behaviours;
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public boolean isEnabled()
{
return enabled;
}
@Override
public void afterPropertiesSet()
{
if (!isEnabled())
{
return;
}
PropertyCheck.mandatory(this, "policyComponent", policyComponent);
PropertyCheck.mandatory(this, "nodeService", nodeService);
PropertyCheck.mandatory(this, "namespaceService", namespaceService);
@@ -126,28 +148,56 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
private void bindBehaviours()
{
policyComponent.bindClassBehaviour(OnCreateNodePolicy.QNAME, this,
new JavaBehaviour(this, "onCreateNode"));
policyComponent.bindClassBehaviour(BeforeDeleteNodePolicy.QNAME, this,
new JavaBehaviour(this, "beforeDeleteNode"));
policyComponent.bindClassBehaviour(OnUpdatePropertiesPolicy.QNAME, this,
new JavaBehaviour(this, "onUpdateProperties"));
policyComponent.bindClassBehaviour(OnSetNodeTypePolicy.QNAME, this,
new JavaBehaviour(this, "onSetNodeType"));
policyComponent.bindClassBehaviour(OnAddAspectPolicy.QNAME, this,
new JavaBehaviour(this, "onAddAspect"));
policyComponent.bindClassBehaviour(OnRemoveAspectPolicy.QNAME, this,
new JavaBehaviour(this, "onRemoveAspect"));
policyComponent.bindClassBehaviour(OnMoveNodePolicy.QNAME, this,
new JavaBehaviour(this, "onMoveNode"));
policyComponent.bindAssociationBehaviour(OnCreateChildAssociationPolicy.QNAME, this,
new JavaBehaviour(this, "onCreateChildAssociation"));
policyComponent.bindAssociationBehaviour(BeforeDeleteChildAssociationPolicy.QNAME, this,
new JavaBehaviour(this, "beforeDeleteChildAssociation"));
policyComponent.bindAssociationBehaviour(OnCreateAssociationPolicy.QNAME, this,
new JavaBehaviour(this, "onCreateAssociation"));
policyComponent.bindAssociationBehaviour(BeforeDeleteAssociationPolicy.QNAME, this,
new JavaBehaviour(this, "beforeDeleteAssociation"));
setClassBehaviour(OnCreateNodePolicy.QNAME, "onCreateNode");
setClassBehaviour(BeforeDeleteNodePolicy.QNAME, "beforeDeleteNode");
setClassBehaviour(OnUpdatePropertiesPolicy.QNAME, "onUpdateProperties");
setClassBehaviour(OnSetNodeTypePolicy.QNAME, "onSetNodeType");
setClassBehaviour(OnAddAspectPolicy.QNAME, "onAddAspect");
setClassBehaviour(OnRemoveAspectPolicy.QNAME, "onRemoveAspect");
setClassBehaviour(OnMoveNodePolicy.QNAME, "onMoveNode");
setAssociationBehaviour(OnCreateChildAssociationPolicy.QNAME, "onCreateChildAssociation");
setAssociationBehaviour(BeforeDeleteChildAssociationPolicy.QNAME, "beforeDeleteChildAssociation");
setAssociationBehaviour(OnCreateAssociationPolicy.QNAME, "onCreateAssociation");
setAssociationBehaviour(BeforeDeleteAssociationPolicy.QNAME, "beforeDeleteAssociation");
}
/**
* Disable Events2 generated events
*/
public void disable()
{
if (!isEnabled())
{
return;
}
setEnabled(false);
disableBehaviours();
}
/**
* Enable Events2 generated events
*/
public void enable()
{
if (isEnabled())
{
return;
}
setEnabled(true);
if (behaviours == null)
{
behaviours = new HashSet<Behaviour>();
afterPropertiesSet();
bindBehaviours();
}
else
{
enableBehaviours();
}
}
public void setNodeDAO(NodeDAO nodeDAO)
@@ -289,6 +339,62 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
return new PeerAssociationEventConsolidator(peerAssociationRef, nodeResourceHelper);
}
private void setClassBehaviour(QName policyQName, String method)
{
Behaviour behaviour = bindClassBehaviour(policyQName, method);
behaviours.add(behaviour);
}
private void setAssociationBehaviour(QName policyQName, String method)
{
Behaviour behaviour = bindAssociationBehaviour(policyQName, method);
behaviours.add(behaviour);
}
protected Behaviour bindClassBehaviour(QName policyQName, String method)
{
BehaviourDefinition<ServiceBehaviourBinding> behaviourDef = policyComponent.bindClassBehaviour(policyQName, this,
new JavaBehaviour(this, method));
return behaviourDef.getBehaviour();
}
protected Behaviour bindAssociationBehaviour(QName policyQName, String method)
{
BehaviourDefinition<ServiceBehaviourBinding> behaviourDef = policyComponent.bindAssociationBehaviour(policyQName, this,
new JavaBehaviour(this, method));
return behaviourDef.getBehaviour();
}
private void disableBehaviours()
{
disableBehaviours(behaviours);
}
protected void disableBehaviours(Set<Behaviour> bindedBehaviours)
{
if (bindedBehaviours != null)
{
bindedBehaviours.forEach(behaviour -> {
behaviour.disable();
});
}
}
private void enableBehaviours()
{
enableBehaviours(behaviours);
}
protected void enableBehaviours(Set<Behaviour> bindedBehaviours)
{
if (bindedBehaviours != null)
{
bindedBehaviours.forEach(behaviour -> {
behaviour.enable();
});
}
}
/**
* @return the {@link EventConsolidator} for the supplied {@code nodeRef} from
* the current transaction context.
@@ -396,6 +502,11 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
@Override
protected void onBootstrap(ApplicationEvent applicationEvent)
{
if (!isEnabled())
{
return;
}
behaviours = new HashSet<Behaviour>();
bindBehaviours();
}

View File

@@ -43,6 +43,9 @@
<property name="nodeResourceHelper" ref="nodeResourceHelper"/>
<property name="eventGeneratorQueue" ref="eventGeneratorQueue"/>
<property name="nodeDAO" ref="nodeDAO"/>
<property name="enabled">
<value>${repo.event2.enabled}</value>
</property>
</bean>
<bean id="baseNodeResourceHelper" abstract="true">

View File

@@ -1219,6 +1219,7 @@ contentPropertyRestrictions.enabled=true
contentPropertyRestrictions.whitelist=
# Repo events2
repo.event2.enabled=true
# Type and aspect filters which should be excluded
# Note: System folders node types are added by default
repo.event2.filter.nodeTypes=sys:*, fm:*, cm:thumbnail, cm:failedThumbnail, cm:rating, rma:rmsite include_subtypes

View File

@@ -0,0 +1,170 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.event2;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.event.v1.model.RepoEvent;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.awaitility.Awaitility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.fasterxml.jackson.databind.ObjectMapper;
public class EventGeneratorDisabledTest extends AbstractContextAwareRepoEvent
{
private static final String EVENT2_TOPIC_NAME = "alfresco.repo.event2";
private static final String BROKER_URL = "tcp://localhost:61616";
@Autowired @Qualifier("event2ObjectMapper")
private ObjectMapper objectMapper;
@Autowired
protected ObjectMapper event2ObjectMapper;
//private EventGenerator eventGenerator;
private ActiveMQConnection connection;
protected List<RepoEvent<?>> receivedEvents;
@Before
public void setup() throws Exception
{
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
connection = (ActiveMQConnection) connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createTopic(EVENT2_TOPIC_NAME);
MessageConsumer consumer = session.createConsumer(destination);
receivedEvents = Collections.synchronizedList(new LinkedList<>());
consumer.setMessageListener(new MessageListener()
{
@Override
public void onMessage(Message message)
{
String text = getText(message);
RepoEvent<?> event = toRepoEvent(text);
receivedEvents.add(event);
}
private RepoEvent<?> toRepoEvent(String json)
{
try
{
return objectMapper.readValue(json, RepoEvent.class);
} catch (Exception e)
{
e.printStackTrace();
return null;
}
}
});
}
@After
public void shutdownTopicListener() throws Exception
{
connection.close();
connection = null;
}
@Test
public void shouldNotReceiveEvent2EventsOnNodeCreation() throws Exception
{
if (eventGenerator.isEnabled())
{
eventGenerator.disable();
}
createNode(ContentModel.TYPE_CONTENT);
Awaitility.await().pollDelay(6, TimeUnit.SECONDS).until(() -> receivedEvents.size() == 0);
assertTrue(EVENT_CONTAINER.getEvents().size() == 0);
assertTrue(receivedEvents.size() == 0);
eventGenerator.enable();
}
@Test
public void shouldReceiveEvent2EventsOnNodeCreation() throws Exception
{
if (!eventGenerator.isEnabled())
{
eventGenerator.enable();
}
createNode(ContentModel.TYPE_CONTENT);
Awaitility.await().atMost(6, TimeUnit.SECONDS).until(() -> receivedEvents.size() == 1);
assertTrue(EVENT_CONTAINER.getEvents().size() == 1);
assertTrue(receivedEvents.size() == 1);
RepoEvent<?> sent = getRepoEvent(1);
RepoEvent<?> received = receivedEvents.get(0);
assertEventsEquals("Events are different!", sent, received);
}
private void assertEventsEquals(String message, RepoEvent<?> expected, RepoEvent<?> current)
{
assertEquals(message, expected, current);
}
private static String getText(Message message)
{
try
{
ActiveMQTextMessage am = (ActiveMQTextMessage) message;
return am.getText();
} catch (JMSException e)
{
return null;
}
}
}

View File

@@ -35,7 +35,8 @@ import org.junit.runners.Suite.SuiteClasses;
DeleteRepoEventIT.class,
ChildAssociationRepoEventIT.class,
PeerAssociationRepoEventIT.class,
EventGeneratorTest.class
EventGeneratorTest.class,
EventGeneratorDisabledTest.class
})
public class RepoEvent2ITSuite
{