/** * 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.ambari.server.utils; import java.lang.reflect.Field; import org.apache.ambari.server.events.listeners.alerts.AlertAggregateListener; import org.apache.ambari.server.events.listeners.alerts.AlertLifecycleListener; import org.apache.ambari.server.events.listeners.alerts.AlertMaintenanceModeListener; import org.apache.ambari.server.events.listeners.alerts.AlertReceivedListener; import org.apache.ambari.server.events.listeners.alerts.AlertServiceStateListener; import org.apache.ambari.server.events.listeners.alerts.AlertStateChangedListener; import org.apache.ambari.server.events.listeners.upgrade.DistributeRepositoriesActionListener; import org.apache.ambari.server.events.listeners.upgrade.HostVersionOutOfSyncListener; import org.apache.ambari.server.events.publishers.AlertEventPublisher; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import com.google.inject.Binder; import com.google.inject.Injector; /** * The {@link EventBusSynchronizer} is used to replace the {@link AsyncEventBus} * used by Guava with a synchronous, serial {@link EventBus} instance. This * enables testing that relies on testing the outcome of asynchronous events by * executing the events on the current thread serially. */ public class EventBusSynchronizer { /** * Force the {@link EventBus} from {@link AmbariEventPublisher} to be serial * and synchronous. * * @param binder */ public static void synchronizeAmbariEventPublisher(Binder binder) { EventBus synchronizedBus = new EventBus(); AmbariEventPublisher ambariEventPublisher = new AmbariEventPublisher(); replaceEventBus(AmbariEventPublisher.class, ambariEventPublisher, synchronizedBus); binder.bind(AmbariEventPublisher.class).toInstance(ambariEventPublisher); } /** * Force the {@link EventBus} from {@link AlertEventPublisher} to be serial * and synchronous. Also register the known listeners. Registering known * listeners is necessary since the event bus was replaced. * * @param injector */ public static EventBus synchronizeAmbariEventPublisher(Injector injector) { EventBus synchronizedBus = new EventBus(); AmbariEventPublisher publisher = injector.getInstance(AmbariEventPublisher.class); replaceEventBus(AmbariEventPublisher.class, publisher, synchronizedBus); // register common ambari event listeners registerAmbariListeners(injector, synchronizedBus); return synchronizedBus; } /** * Force the {@link EventBus} from {@link AlertEventPublisher} to be serial * and synchronous. Also register the known listeners. Registering known * listeners is necessary since the event bus was replaced. * * @param injector */ public static EventBus synchronizeAlertEventPublisher(Injector injector) { EventBus synchronizedBus = new EventBus(); AlertEventPublisher publisher = injector.getInstance(AlertEventPublisher.class); replaceEventBus(AlertEventPublisher.class, publisher, synchronizedBus); // register common alert event listeners registerAlertListeners(injector, synchronizedBus); return synchronizedBus; } /** * Register the normal listeners with the replaced synchronous bus. * * @param injector * @param synchronizedBus */ private static void registerAmbariListeners(Injector injector, EventBus synchronizedBus) { synchronizedBus.register(injector.getInstance(AlertMaintenanceModeListener.class)); synchronizedBus.register(injector.getInstance(AlertLifecycleListener.class)); synchronizedBus.register(injector.getInstance(AlertServiceStateListener.class)); synchronizedBus.register(injector.getInstance(DistributeRepositoriesActionListener.class)); synchronizedBus.register(injector.getInstance(HostVersionOutOfSyncListener.class)); } /** * Register the normal listeners with the replaced synchronous bus. * * @param injector * @param synchronizedBus */ private static void registerAlertListeners(Injector injector, EventBus synchronizedBus) { synchronizedBus.register(injector.getInstance(AlertAggregateListener.class)); synchronizedBus.register(injector.getInstance(AlertReceivedListener.class)); synchronizedBus.register(injector.getInstance(AlertStateChangedListener.class)); } private static void replaceEventBus(Class<?> eventPublisherClass, Object instance, EventBus eventBus) { try { Field field = eventPublisherClass.getDeclaredField("m_eventBus"); field.setAccessible(true); field.set(instance, eventBus); } catch (Exception exception) { throw new RuntimeException(exception); } } }