package com.linkedin.databus.container.request; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Formatter; import java.util.List; import java.util.concurrent.ExecutorService; import org.apache.log4j.Logger; import com.linkedin.databus.container.netty.HttpRelay; import com.linkedin.databus.core.data_model.LogicalSource; import com.linkedin.databus.core.monitoring.mbean.DbusEventsStatisticsCollector; import com.linkedin.databus.core.monitoring.mbean.StatsCollectors; import com.linkedin.databus.core.util.DatabusEventProducer; import com.linkedin.databus.core.util.IdNamePair; import com.linkedin.databus2.core.container.request.DatabusRequest; import com.linkedin.databus2.core.container.request.InvalidRequestParamValueException; import com.linkedin.databus2.core.container.request.RequestProcessingException; import com.linkedin.databus2.core.container.request.RequestProcessor; /** * Generates random data events for a source and stores them in an event buffer for testing purposes. * @author cbotev * */ public class GenerateDataEventsRequestProcessor implements RequestProcessor { public static final String MODULE = GenerateDataEventsRequestProcessor.class.getName(); public static final Logger LOG = Logger.getLogger(MODULE); public static final String COMMAND_NAME = "genDataEvents"; public static final String SOURCES_NAME_PARAM = "src_ids"; public static final String SCN_PARAM = "fromScn"; public static final String EVENTS_PER_SEC_PARAM = "eventsPerSec"; public static final String DURATION_MS = "duration"; public static final String NUM_EVENTS_TO_GENERATE = "eventsToGenerate"; public static final String PERCENT_BUFFER_TO_GENERATE = "percentBuffer"; public static final String KEY_MIN_PARAM = "keyMin"; public static final String KEY_MAX_PARAM = "keyMax"; private final ExecutorService _executorService; private final HttpRelay _relay; private final DbusEventsStatisticsCollector _relayStatsCollector; private final DatabusEventProducer _producer; public GenerateDataEventsRequestProcessor(ExecutorService executorService, HttpRelay relay, DatabusEventProducer eventProducer) { super(); _executorService = executorService; _relay = relay; _producer = eventProducer; //currently generateDataEvents does not support generation across multiple partitions //for statistics, we'll make up a "virtual" partition _relayStatsCollector = new DbusEventsStatisticsCollector( _relay.getContainerStaticConfig().getId(), _producer.toString(), true, false, _relay.getMbeanServer()); _relay.getInBoundStatsCollectors().addStatsCollector("GenerateDataEventsRequestProcessor", _relayStatsCollector); } @Override public ExecutorService getExecutorService() { return _executorService; } @Override public DatabusRequest process(DatabusRequest request) throws IOException, RequestProcessingException { String action = request.getParams().getProperty(DatabusRequest.PATH_PARAM_NAME, ""); if (action.equals("check")) { boolean genRunning = _producer.checkRunning(); StringBuilder resBuilder = new StringBuilder(1024); Formatter fmt = new Formatter(resBuilder); fmt.format("{\"genDataEventsRunning\":\"%b\"}", genRunning); request.getResponseContent().write(ByteBuffer.wrap(resBuilder.toString().getBytes(Charset.defaultCharset()))); } else if (action.equals("stop")) { _producer.stopGeneration(); request.getResponseContent().write(ByteBuffer.wrap("{\"genDataEventsRunning\":\"send-stop\"}".getBytes(Charset.defaultCharset()))); } else if (action.equals("suspend")) { _producer.suspendGeneration(); request.getResponseContent().write(ByteBuffer.wrap("{\"genDataEventsRunning\":\"send-suspend\"}".getBytes(Charset.defaultCharset()))); } else if (action.equals("resume")) { long numEventToGenerate = request.getOptionalLongParam(NUM_EVENTS_TO_GENERATE, Long.MAX_VALUE); long keyMin = request.getOptionalLongParam(KEY_MIN_PARAM, 0L); long keyMax = request.getOptionalLongParam(KEY_MAX_PARAM, Long.MAX_VALUE); int percentOfBufferToGenerate = request.getOptionalIntParam(PERCENT_BUFFER_TO_GENERATE, Integer.MAX_VALUE); _producer.resumeGeneration(numEventToGenerate, percentOfBufferToGenerate, keyMin, keyMax); request.getResponseContent().write(ByteBuffer.wrap("{\"genDataEventsRunning\":\"send-resume\"}".getBytes(Charset.defaultCharset()))); } else if (action.equals("start")) { long fromScn = request.getRequiredLongParam(SCN_PARAM); long durationMs = request.getRequiredLongParam(DURATION_MS); int eventsPerSec = request.getRequiredIntParam(EVENTS_PER_SEC_PARAM); long numEventToGenerate = request.getOptionalLongParam(NUM_EVENTS_TO_GENERATE, Long.MAX_VALUE); int percentOfBufferToGenerate = request.getOptionalIntParam(PERCENT_BUFFER_TO_GENERATE, Integer.MAX_VALUE); long keyMin = request.getOptionalLongParam(KEY_MIN_PARAM, 0L); long keyMax = request.getOptionalLongParam(KEY_MAX_PARAM, Long.MAX_VALUE); String sourcesListStr = request.getRequiredStringParam(SOURCES_NAME_PARAM); String[] sourcesStrArray = sourcesListStr.split(","); List<IdNamePair> sourcesIdList = new ArrayList<IdNamePair>(sourcesStrArray.length); for (String sourceIdStr: sourcesStrArray) { try { Integer id = Integer.valueOf(sourceIdStr); LogicalSource source = _relay.getSourcesIdNameRegistry().getSource(id); if (null != source) sourcesIdList.add(source.asIdNamePair()); else LOG.error("unable to find source id: " + id); } catch (NumberFormatException nfe) { throw new InvalidRequestParamValueException(COMMAND_NAME, SOURCES_NAME_PARAM, sourceIdStr); } } //We have to use the global stats collector because the generation can go beyond the lifespan //of the connection boolean tryStart = _producer.startGeneration(fromScn, eventsPerSec, durationMs, numEventToGenerate, percentOfBufferToGenerate, keyMin, keyMax, sourcesIdList, _relayStatsCollector); StringBuilder resBuilder = new StringBuilder(1024); Formatter fmt = new Formatter(resBuilder); fmt.format("{\"genDataEventsStarted\":\"%b\"}", tryStart); request.getResponseContent().write(ByteBuffer.wrap(resBuilder.toString().getBytes(Charset.defaultCharset()))); } else { throw new InvalidRequestParamValueException(COMMAND_NAME, "request path", action); } return request; } }