Author: cziegeler Date: Wed Sep 16 18:00:01 2015 New Revision: 1703439 URL: http://svn.apache.org/r1703439 Log: SLING-4634 : Directly check if view is still current
Added: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java (with props) Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/TopologyCapabilities.java Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java?rev=1703439&r1=1703438&r2=1703439&view=diff ============================================================================== --- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java (original) +++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/JobManagerConfiguration.java Wed Sep 16 18:00:01 2015 @@ -456,7 +456,7 @@ public class JobManagerConfiguration imp public void queueConfigurationChanged() { final TopologyCapabilities caps = this.topologyCapabilities; if ( caps != null && this.isActive() ) { - this.startProcessing(Type.PROPERTIES_CHANGED, caps, true); + this.startProcessing(Type.PROPERTIES_CHANGED, caps, true, true); } } @@ -485,7 +485,9 @@ public class JobManagerConfiguration imp * @param newCaps The new capabilities * @param isConfigChange If a configuration change occured. */ - private void startProcessing(final Type eventType, final TopologyCapabilities newCaps, final boolean isConfigChange) { + private void startProcessing(final Type eventType, final TopologyCapabilities newCaps, + final boolean isConfigChange, + final boolean runMaintenanceTasks) { logger.debug("Starting job processing..."); // create new capabilities and update view this.topologyCapabilities = newCaps; @@ -499,9 +501,11 @@ public class JobManagerConfiguration imp rt.run(); } - // we run the checker task twice, now and shortly after the topology has changed. final CheckTopologyTask mt = new CheckTopologyTask(this); - mt.fullRun(!isConfigChange, isConfigChange); + if ( runMaintenanceTasks ) { + // we run the checker task twice, now and shortly after the topology has changed. + mt.fullRun(!isConfigChange, isConfigChange); + } if ( eventType == Type.TOPOLOGY_INIT ) { notifiyListeners(); @@ -514,8 +518,10 @@ public class JobManagerConfiguration imp @Override public void run() { - if ( newCaps.isLeader() && newCaps.isActive() ) { - mt.assignUnassignedJobs(); + if ( runMaintenanceTasks ) { + if ( newCaps.isLeader() && newCaps.isActive() ) { + mt.assignUnassignedJobs(); + } } // start listeners if ( newCaps.isActive() ) { @@ -543,12 +549,13 @@ public class JobManagerConfiguration imp public void handleTopologyEvent(final TopologyEvent event) { this.logger.debug("Received topology event {}", event); + boolean runMaintenanceTasks = true; // check if there is a change of properties which doesn't affect us if ( event.getType() == Type.PROPERTIES_CHANGED ) { final Map<String, String> newAllInstances = TopologyCapabilities.getAllInstancesMap(event.getNewView()); if ( this.topologyCapabilities != null && this.topologyCapabilities.isSame(newAllInstances) ) { - logger.debug("No changes in capabilities - ignoring event"); - return; + logger.debug("No changes in capabilities - restarting without maintenance tasks"); + runMaintenanceTasks = false; } } @@ -569,7 +576,7 @@ public class JobManagerConfiguration imp this.stopProcessing(); - this.startProcessing(eventType, new TopologyCapabilities(event.getNewView(), this), false); + this.startProcessing(eventType, new TopologyCapabilities(event.getNewView(), this), false, runMaintenanceTasks); } } Modified: sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/TopologyCapabilities.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/TopologyCapabilities.java?rev=1703439&r1=1703438&r2=1703439&view=diff ============================================================================== --- sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/TopologyCapabilities.java (original) +++ sling/trunk/bundles/extensions/event/src/main/java/org/apache/sling/event/impl/jobs/config/TopologyCapabilities.java Wed Sep 16 18:00:01 2015 @@ -173,7 +173,7 @@ public class TopologyCapabilities { * @return {@code true} if still active. */ public boolean isActive() { - return this.active && this.jobManagerConfiguration.isActive(); // TODO SLING-4634 && this.view.isCurrent(); + return this.active && this.jobManagerConfiguration.isActive() && this.view.isCurrent(); } /** Added: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java?rev=1703439&view=auto ============================================================================== --- sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java (added) +++ sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java Wed Sep 16 18:00:01 2015 @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sling.event.impl.jobs.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.sling.commons.scheduler.ScheduleOptions; +import org.apache.sling.commons.scheduler.Scheduler; +import org.apache.sling.discovery.ClusterView; +import org.apache.sling.discovery.InstanceDescription; +import org.apache.sling.discovery.TopologyEvent; +import org.apache.sling.discovery.TopologyView; +import org.junit.Test; +import org.mockito.Mockito; + +import junitx.util.PrivateAccessor; + +public class JobManagerConfigurationTest { + + private TopologyView createView() { + final TopologyView view = Mockito.mock(TopologyView.class); + Mockito.when(view.isCurrent()).thenReturn(true); + final InstanceDescription local = Mockito.mock(InstanceDescription.class); + Mockito.when(local.isLeader()).thenReturn(true); + Mockito.when(local.isLocal()).thenReturn(true); + Mockito.when(local.getSlingId()).thenReturn("id"); + + Mockito.when(view.getLocalInstance()).thenReturn(local); + final ClusterView localView = Mockito.mock(ClusterView.class); + Mockito.when(localView.getId()).thenReturn("1"); + Mockito.when(localView.getInstances()).thenReturn(Collections.singletonList(local)); + Mockito.when(view.getClusterViews()).thenReturn(Collections.singleton(localView)); + Mockito.when(local.getClusterView()).thenReturn(localView); + + return view; + } + + private static class ChangeListener implements ConfigurationChangeListener { + + public final List<Boolean> events = new ArrayList<Boolean>(); + private volatile CountDownLatch latch; + + public void init(final int count) { + events.clear(); + latch = new CountDownLatch(count); + } + + public void await() throws Exception { + if ( !latch.await(5000, TimeUnit.MILLISECONDS) ) { + throw new Exception("No configuration event within 5 seconds."); + } + } + + @Override + public void configurationChanged(boolean active) { + events.add(active); + latch.countDown(); + } + } + + private Scheduler createScheduler() { + return new Scheduler() { + + @Override + public boolean unschedule(String jobName) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean schedule(final Object job, ScheduleOptions options) { + if ( job instanceof Runnable ) { + final Timer t = new Timer(); + t.schedule(new TimerTask() { + + @Override + public void run() { + ((Runnable)job).run(); + } + }, 3000); + } + return false; + } + + @Override + public void removeJob(String name) throws NoSuchElementException { + // TODO Auto-generated method stub + + } + + @Override + public boolean fireJobAt(String name, Object job, Map<String, Serializable> config, Date date, int times, + long period) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void fireJobAt(String name, Object job, Map<String, Serializable> config, Date date) throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public boolean fireJob(Object job, Map<String, Serializable> config, int times, long period) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void fireJob(Object job, Map<String, Serializable> config) throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period, + boolean canRunConcurrently, boolean startImmediate) throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period, + boolean canRunConcurrently) throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void addJob(String name, Object job, Map<String, Serializable> config, String schedulingExpression, + boolean canRunConcurrently) throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public ScheduleOptions NOW(int times, long period) { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScheduleOptions NOW() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScheduleOptions EXPR(String expression) { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScheduleOptions AT(Date date, int times, long period) { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScheduleOptions AT(Date date) { + // TODO Auto-generated method stub + return null; + } + }; + } + + @Test public void testTopologyChange() throws Exception { + // mock scheduler + final Scheduler scheduler = this.createScheduler(); + final ChangeListener ccl = new ChangeListener(); + + // add change listener and verify + ccl.init(1); + final JobManagerConfiguration config = new JobManagerConfiguration(); + PrivateAccessor.setField(config, "scheduler", scheduler); + ((AtomicBoolean)PrivateAccessor.getField(config, "active")).set(true); + + config.addListener(ccl); + ccl.await(); + + assertEquals(1, ccl.events.size()); + assertFalse(ccl.events.get(0)); + + // create init view + ccl.init(1); + final TopologyView initView = createView(); + final TopologyEvent init = new TopologyEvent(TopologyEvent.Type.TOPOLOGY_INIT, null, initView); + config.handleTopologyEvent(init); + ccl.await(); + + assertEquals(1, ccl.events.size()); + assertTrue(ccl.events.get(0)); + + // change view, followed by change props + ccl.init(3); + final TopologyView view2 = createView(); + Mockito.when(initView.isCurrent()).thenReturn(false); + final TopologyEvent change1 = new TopologyEvent(TopologyEvent.Type.TOPOLOGY_CHANGED, initView, view2); + final TopologyView view3 = createView(); + final TopologyEvent change2 = new TopologyEvent(TopologyEvent.Type.PROPERTIES_CHANGED, view2, view3); + + config.handleTopologyEvent(change1); + Mockito.when(view2.isCurrent()).thenReturn(false); + config.handleTopologyEvent(change2); + + ccl.await(); + assertEquals(3, ccl.events.size()); + assertFalse(ccl.events.get(0)); + assertFalse(ccl.events.get(1)); + assertTrue(ccl.events.get(2)); + + // we wait another 4 secs to see if there is no another event + Thread.sleep(4000); + assertEquals(3, ccl.events.size()); + + } +} Propchange: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/extensions/event/src/test/java/org/apache/sling/event/impl/jobs/config/JobManagerConfigurationTest.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url