/* * Copyright 2014, The Sporting Exchange Limited * * Licensed 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 com.betfair.cougar.core.impl.ev; import java.util.*; import com.betfair.cougar.core.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.ContextRefreshedEvent; import com.betfair.cougar.api.Service; import com.betfair.cougar.core.api.exception.PanicInTheCougar; import com.betfair.cougar.util.jmx.Exportable; import com.betfair.cougar.util.jmx.ExportableRegistration; import com.betfair.cougar.util.jmx.JMXControl; import com.betfair.tornjak.monitor.Status; import org.springframework.jmx.export.annotation.ManagedResource; /** * Implementation of ExecutionVenue which is aware of the Spring container, and of the JMXControl. * It will ensure that once the Spring application is loaded all registered Exportable * beans will be registered with the JMXControl. * This implementation is also a CougarStartingGate, and notifies any registered listeners of when * Spring is loaded and the application is ready to start. * */ @ManagedResource public class ContainerAwareExecutionVenue extends ServiceRegisterableExecutionVenue implements CougarStartingGate, ExportableRegistration { private final static Logger LOGGER = LoggerFactory.getLogger(ContainerAwareExecutionVenue.class); private List<GateListener> startingListeners = new ArrayList<GateListener>(); private List<Exportable> exportables = new ArrayList<Exportable>(); public ContainerAwareExecutionVenue() { super(); } @Override public void registerExportable(Exportable exportable) { exportables.add(exportable); } /** * In the case of ContextRefreshedEvent (that is, once all Spring configuration is loaded), the following actions * will be taken: * <list> * <li>the superclass's onAppEvent will initialise all services</li> * <li>The JMXControl will be retrieved from the application context and all registered Exportable implementations will be exported</li> * <li>All registered StartingGateListeners will be notified that the starting gate is open</li> * <li>A status check will be made on every registered service, with the status logged</li> * </list> */ @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { super.onApplicationEvent(event); try { final ApplicationContext ctx = ((ContextRefreshedEvent) event).getApplicationContext(); // Check that the JMXControl exists before registering all exportables // see JMXControl javadocs for why we have to do it this way JMXControl jmxControl = JMXControl.getFromContext(ctx); if (jmxControl == null) { throw new PanicInTheCougar("jmxControl bean not found in ApplicationContext"); } if (exportables != null) { for (Exportable exportable : exportables) { exportable.export(jmxControl); } } // Open the starting gate notifyStartingGateListeners(); Collection<ServiceAware> serviceAwareImpls = getServiceAwareImplementations(ctx); if (serviceAwareImpls != null && serviceAwareImpls.size() > 0) { Set<Service> services = new HashSet<Service>(); Collection<Map<ServiceDefinition, Service>> serviceDefinitions = getServiceImplementationMap().values(); for (Map<ServiceDefinition, Service> serviceDefinition : serviceDefinitions) { services.addAll(serviceDefinition.values()); } for (ServiceAware serviceAware : serviceAwareImpls) { serviceAware.setServices(services); } } Status status = monitorRegistry .getStatusAggregator() .getStatus(); if (status != Status.OK) { LOGGER.warn("Cougar returned status {} at startup", status); } else { LOGGER.info("Cougar returned status {} at startup", status); } } catch (Exception e) { throw new PanicInTheCougar("Failed to initialise server", e); } logSuccessfulCougarStartup(); } } private Collection<ServiceAware> getServiceAwareImplementations(ApplicationContext ctx) { Map<String, ServiceAware> serviceAwareBeans = ctx.getBeansOfType(ServiceAware.class); return serviceAwareBeans.values(); } private void logSuccessfulCougarStartup() { // Logging facade removes the ability for custom log levels, so just INFO LOGGER.info("**** COUGAR HAS STARTED *****"); } @Override public boolean registerStartingListener(GateListener listener) { LOGGER.info("Registering gate listener {} with priority {}", listener.getName(), listener.getPriority()); return startingListeners.add(listener); } private void notifyStartingGateListeners() { int numListeners = startingListeners.size(); int cnt = 0; Collections.sort(startingListeners, LISTENER_COMPARATOR); for (GateListener listener: startingListeners) { LOGGER.info("({} of {}) Calling gate listener {}", ++cnt, numListeners, listener.getName()); listener.onCougarStart(); } } private static Comparator<GateListener> LISTENER_COMPARATOR = new Comparator<GateListener>() { @Override public int compare(GateListener g1, GateListener g2) { if (g1.getPriority() == g2.getPriority()) { return g1.getName().compareTo(g2.getName()); } else if (g1.getPriority() < g2.getPriority()) { return 1; } else { return -1; } } }; }