/* * Copyright 2013 Rackspace * * 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.rackspacecloud.blueflood.eventemitter; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.collect.Lists; import com.rackspacecloud.blueflood.concurrent.ThreadPoolBuilder; import com.rackspacecloud.blueflood.io.DiscoveryIO; import com.rackspacecloud.blueflood.service.CoreConfig; import com.rackspacecloud.blueflood.types.BasicRollup; import com.rackspacecloud.blueflood.utils.ModuleLoader; import com.rackspacecloud.blueflood.utils.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.concurrent.*; /** * @todo {@code RollupEventEmitter} should be modified so that it can be used * as a drop-in replacement for {@link Emitter<RollupEvent>}. * * The {@code RollupEventEmitter} class violates the Liskov substitution * principle, in that it doesn't behave the same as * {@link Emitter<RollupEvent>}. Moreover, the differences in behavior depend * upon particular details of the inputs. * * For example, if there is no listener registered for * {@link RollupEventEmitter#ROLLUP_EVENT_NAME}, then *ALL* events are silently * ignored. No other listeners will ever be notified of their events, even * events of other names. * * Also, if any event doesn't have a {@link RollupEvent#rollup} of type * {@link BasicRollup}, that event will be silently ignored. This is the case * if the event's {@link RollupEvent#rollup} field is {@code null}, or if it's * another rollup type * * @todo Merge {@code RollupEventEmitter} and {@link Emitter<>} into a single * class. {@link Emitter<>} doesn't appear to be used anywhere else. * * @todo Change the {@code eventPayload}/{@code args} parameter of * {@link RollupEventEmitter#emit} from an array to a single item. There don't * appear to be any parts of the codebase that use more than a single event * argument. */ public class RollupEventEmitter extends Emitter<RollupEvent> { private static final Logger log = LoggerFactory.getLogger(ModuleLoader.class); private static final int numberOfWorkers = 5; public static final String ROLLUP_EVENT_NAME = "rollup".intern(); private final ExecutorService eventExecutors; private static final RollupEventEmitter instance = new RollupEventEmitter(); public RollupEventEmitter() { this(new ThreadPoolBuilder() .withName("RollupEventEmitter ThreadPool") .withCorePoolSize(numberOfWorkers) .withMaxPoolSize(numberOfWorkers) .withUnboundedQueue() .build()); } @VisibleForTesting public RollupEventEmitter(ExecutorService executor) { eventExecutors = executor; } public static RollupEventEmitter getInstance() { return instance; } @Override public Future emit(final String event, final RollupEvent... eventPayload) { //TODO: This hack will go away after Kafka Serializer is made generic Future emitFuture = null; if(eventPayload[0].getRollup() instanceof BasicRollup && super.hasListeners(ROLLUP_EVENT_NAME)) { emitFuture = eventExecutors.submit(new Callable() { @Override public Future call() { if (Util.shouldUseESForUnits()) { final DiscoveryIO discoveryIO = (DiscoveryIO) ModuleLoader.getInstance(DiscoveryIO.class, CoreConfig.DISCOVERY_MODULES); // TODO: Sync for now, but we will have to make it async eventually Lists.transform(Arrays.asList(eventPayload), new Function<RollupEvent, RollupEvent>() { @Override public RollupEvent apply(RollupEvent event) { String unit; try { unit = discoveryIO.search(event.getLocator().getTenantId(), event.getLocator().getMetricName()).get(0).getUnit(); } catch (Exception e) { log.warn("Exception encountered while getting units out of ES : %s", e.getMessage()); unit = Util.UNKNOWN; } event.setUnit(unit); return event; } }); } return RollupEventEmitter.super.emit(event, eventPayload); } }); } return emitFuture; } }