com.betfair.cougar.core.impl.ev.ServiceRegisterableExecutionVenue.java Source code

Java tutorial

Introduction

Here is the source code for com.betfair.cougar.core.impl.ev.ServiceRegisterableExecutionVenue.java

Source

/*
 * Copyright 2014, The Sporting Exchange Limited
 * Copyright 2014, Simon Mati Langford
 *
 * 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.api.*;
import com.betfair.cougar.core.api.ServiceDefinition;
import com.betfair.cougar.core.api.ServiceRegistrar;
import com.betfair.cougar.core.api.ServiceVersion;
import com.betfair.cougar.core.api.ev.*;
import com.betfair.cougar.core.api.security.IdentityResolverFactory;
import com.betfair.cougar.core.api.tracing.Tracer;
import com.betfair.cougar.core.impl.CougarInternalOperations;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.betfair.cougar.util.configuration.PropertyConfigurer;
import com.betfair.tornjak.kpi.KPIMonitor;
import com.betfair.tornjak.monitor.MonitorRegistry;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

/**
 * Implementation of ExecutionVenue which facilitates service registration.
 *
 */
public class ServiceRegisterableExecutionVenue extends BaseExecutionVenue
        implements ApplicationListener, ServiceRegistrar {

    private final static Logger LOGGER = LoggerFactory.getLogger(ServiceRegisterableExecutionVenue.class);

    private Map<String, Map<ServiceDefinition, Service>> serviceImplementationMap = new HashMap<String, Map<ServiceDefinition, Service>>();
    private Map<ServiceKey, String> serviceStatNames = new HashMap<>();
    private Map<ServiceKey, ServiceLogManager> serviceLogManagers = new HashMap<>();
    private KPIMonitor stats;
    private ServiceLogManagerFactory serviceLogManagerFactory;
    private IdentityResolverFactory identityResolverFactory;
    protected MonitorRegistry monitorRegistry;
    private Tracer tracer;

    public void setIdentityResolverFactory(IdentityResolverFactory identityResolverFactory) {
        this.identityResolverFactory = identityResolverFactory;
    }

    public void setServiceLogManagerFactory(ServiceLogManagerFactory serviceLogManagerFactory) {
        this.serviceLogManagerFactory = serviceLogManagerFactory;
    }

    public void setStats(KPIMonitor stats) {
        this.stats = stats;
    }

    public void setMonitorRegistry(MonitorRegistry monitorRegistry) {
        this.monitorRegistry = monitorRegistry;
    }

    public void setTracer(Tracer tracer) {
        this.tracer = tracer;
    }

    public Tracer getTracer() {
        return tracer;
    }

    private void registerServiceDefinition(String namespace, ServiceDefinition serviceDefinition,
            ExecutableResolver resolver) {
        String serviceStatName = getServiceStatName(namespace, serviceDefinition);
        for (OperationDefinition op : serviceDefinition.getOperationDefinitions()) {
            OperationKey namespacedOperationKey = namespace == null ? op.getOperationKey()
                    : new OperationKey(op.getOperationKey(), namespace);
            String timeoutPropertyName = "timeout." + namespacedOperationKey;
            String timeoutValue = PropertyConfigurer.getAllLoadedProperties().get(timeoutPropertyName);
            if (LOGGER.isInfoEnabled() && timeoutValue != null) {
                LOGGER.info("Setting timeout for " + namespacedOperationKey + " to " + timeoutValue + "ms");
            }
            registerOperation(namespace, op, resolver.resolveExecutable(namespacedOperationKey, this),
                    stats != null
                            ? new ServiceOperationExecutionTimingRecorder(stats, serviceStatName,
                                    op.getOperationKey().getOperationName())
                            : new NullExecutionTimingRecorder(),
                    timeoutValue != null ? Long.parseLong(timeoutValue) : 0);
        }
    }

    private Map<ServiceDefinition, Service> getImplementationMapForNamespace(String namespace) {
        Map<ServiceDefinition, Service> namespacedMap = serviceImplementationMap.get(namespace);
        if (namespacedMap == null) {
            namespacedMap = new HashMap<ServiceDefinition, Service>();
            serviceImplementationMap.put(namespace, namespacedMap);
        }
        return namespacedMap;
    }

    @Override
    public void registerService(ServiceDefinition serviceDefinition, Service implementation,
            ExecutableResolver resolver) {
        registerService(null, serviceDefinition, implementation, resolver);
    }

    @Override
    public void registerService(String namespace, ServiceDefinition serviceDefinition, Service implementation,
            ExecutableResolver resolver) {
        getImplementationMapForNamespace(namespace).put(serviceDefinition, implementation);
        // register the real service executables
        registerServiceDefinition(namespace, serviceDefinition, resolver);
        if (namespace == null) {
            // register the in process one if this is the core service binding
            final InProcessExecutable inProcessExecutable = new InProcessExecutable(tracer);
            registerServiceDefinition(CougarInternalOperations.COUGAR_IN_PROCESS_NAMESPACE, serviceDefinition,
                    new ExecutableResolver() {
                        @Override
                        public Executable resolveExecutable(OperationKey operationKey, ExecutionVenue ev) {
                            return inProcessExecutable;
                        }
                    });
        }

        LOGGER.info("Initialising {} Service version {}", serviceDefinition.getServiceName(),
                serviceDefinition.getServiceVersion().toString());

        implementation.init(getContainerContext(getServiceLogManager(namespace, serviceDefinition)));

        LOGGER.info("Initialisation complete");
    }

    protected Map<String, Map<ServiceDefinition, Service>> getServiceImplementationMap() {
        return serviceImplementationMap;
    }

    /**
     * This method returns an unmodifiable map between each namespace and the set of serviceDefinitions bound
     * to that namespace.  Note that by default the namespace is null, so there could be a null
     * namespace with services enumerated within
     * @return
     */
    public Map<String, Set<ServiceDefinition>> getNamespaceServiceDefinitionMap() {
        Map<String, Set<ServiceDefinition>> namespaceServiceDefinitionMap = new HashMap<String, Set<ServiceDefinition>>();

        for (String namespace : serviceImplementationMap.keySet()) {
            Set<ServiceDefinition> serviceDefinitions = new HashSet<ServiceDefinition>();
            namespaceServiceDefinitionMap.put(namespace, serviceDefinitions);
            for (ServiceDefinition sd : serviceImplementationMap.get(namespace).keySet()) {
                serviceDefinitions.add(sd);
            }
        }
        return Collections.unmodifiableMap(namespaceServiceDefinitionMap);
    }

    /**
     * In the case of ContextRefreshedEvent (that is, once all Spring configuration is loaded), the services will be
      * initialised
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            // Firstly dump out all the properties read from the various files
            dumpProperties();
            // now init the identity resolver
            setIdentityResolver(identityResolverFactory.getIdentityResolver());
            // start
            start();
        }
    }

    private void dumpProperties() {
        final Map<String, String> props = PropertyConfigurer.getAllLoadedProperties();
        LOGGER.info("Properties loaded from config files and system property overrides");
        int longest = 0;
        for (Map.Entry<String, String> me : props.entrySet()) {
            longest = Math.max(longest, me.getKey().length());
        }
        for (Map.Entry<String, String> me : props.entrySet()) {
            String sysOverride = System.getProperty(me.getKey());
            String value = (sysOverride == null ? me.getValue() : sysOverride);
            if (me.getKey().toLowerCase().contains("password")) {
                value = "*****";
            }
            LOGGER.info("  {} = {}{2}", StringUtils.rightPad(value, longest), me.getKey(), value,
                    (sysOverride == null ? "" : " [OVERRIDDEN]"));
        }
    }

    private ContainerContext getContainerContext(final ServiceLogManager logManager) {
        return new ContainerContext() {

            @Override
            public ServiceInfo[] getRegisteredServices() {
                List<ServiceInfo> services = new ArrayList<ServiceInfo>();
                for (Map.Entry<String, Map<ServiceDefinition, Service>> e : getServiceImplementationMap()
                        .entrySet()) {
                    String namespace = e.getKey();
                    for (Map.Entry<ServiceDefinition, Service> namespacedEntry : e.getValue().entrySet()) {
                        services.add(
                                makeServiceInfo(namespace, namespacedEntry.getKey(), namespacedEntry.getValue()));
                    }
                }
                Collections.sort(services, new Comparator<ServiceInfo>() {
                    public int compare(ServiceInfo o1, ServiceInfo o2) {
                        int result = o1.getServiceName().compareTo(o2.getServiceName());
                        if (result == 0) {
                            result = o1.getVersion().compareTo(o2.getVersion());
                        }
                        return result;
                    }
                });
                return services.toArray(new ServiceInfo[services.size()]);
            }

            @Override
            public void registerExtensionLoggerClass(Class<? extends LogExtension> clazz, int numFieldsLogged) {
                logManager.registerExtensionLoggerClass(clazz, numFieldsLogged);
            }

            @Override
            public void registerConnectedObjectExtensionLoggerClass(Class<? extends LogExtension> clazz,
                    int numFieldsLogged) {
                logManager.registerConnectedObjectExtensionLoggerClass(clazz, numFieldsLogged);
            }

            @Override
            public MonitorRegistry getMonitorRegistry() {
                return monitorRegistry;
            }
        };
    }

    private ServiceInfo makeServiceInfo(String namespace, ServiceDefinition serviceDefinition,
            Service implementation) {
        List<String> operations = new ArrayList<>();
        for (OperationDefinition operationDefinition : serviceDefinition.getOperationDefinitions()) {
            operations.add(operationDefinition.getOperationKey().getOperationName());
        }
        return new ServiceInfo(namespace, implementation, serviceDefinition.getServiceName(),
                serviceDefinition.getServiceVersion().toString(), operations);
    }

    private ServiceLogManager getServiceLogManager(String namespace, ServiceDefinition serviceDefinition) {
        ServiceKey key = new ServiceKey(namespace, serviceDefinition.getServiceName(),
                serviceDefinition.getServiceVersion());
        ServiceLogManager ret = serviceLogManagers.get(key);
        if (ret == null) {
            ret = serviceLogManagerFactory.create(namespace, serviceDefinition.getServiceName(),
                    serviceDefinition.getServiceVersion());
            serviceLogManagers.put(key, ret);
        }
        return ret;
    }

    public ServiceLogManager getServiceLogManager(String namespace, String serviceName, ServiceVersion version) {
        ServiceKey key = new ServiceKey(namespace, serviceName, version);
        ServiceLogManager ret = serviceLogManagers.get(key);
        if (ret == null) {
            ret = serviceLogManagerFactory.create(namespace, serviceName, version);
            serviceLogManagers.put(key, ret);
        }
        return ret;
    }

    private String getServiceStatName(String namespace, ServiceDefinition serviceDefinition) {
        return getServiceStatName(namespace, serviceDefinition.getServiceName(),
                serviceDefinition.getServiceVersion());
    }

    private String getServiceStatName(String namespace, String serviceName, ServiceVersion version) {
        ServiceKey key = new ServiceKey(namespace, serviceName, version);
        String ret = serviceStatNames.get(key);
        if (ret == null) {
            ret = serviceName + "." + version + ((namespace == null) ? "" : "." + namespace);
            serviceStatNames.put(key, ret);
        }
        return ret;
    }

    private static class ServiceKey {
        private String namespace;
        private String serviceName;
        private ServiceVersion version;

        private ServiceKey(String namespace, String serviceName, ServiceVersion version) {
            this.namespace = namespace;
            this.serviceName = serviceName;
            this.version = version;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            ServiceKey serviceKey = (ServiceKey) o;

            if (namespace != null ? !namespace.equals(serviceKey.namespace) : serviceKey.namespace != null)
                return false;
            if (serviceName != null ? !serviceName.equals(serviceKey.serviceName) : serviceKey.serviceName != null)
                return false;
            if (version != null ? !version.equals(serviceKey.version) : serviceKey.version != null)
                return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = namespace != null ? namespace.hashCode() : 0;
            result = 43 * result + (serviceName != null ? serviceName.hashCode() : 0);
            result = 43 * result + (version != null ? version.hashCode() : 0);
            return result;
        }
    }

}