/* * -----------------------------------------------------------------------\ * PerfCake *   * Copyright (C) 2010 - 2016 the original author or authors. *   * 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 org.perfcake.scenario; import org.perfcake.PerfCakeException; import org.perfcake.RunInfo; import org.perfcake.message.MessageTemplate; import org.perfcake.message.correlator.Correlator; import org.perfcake.message.generator.MessageGenerator; import org.perfcake.message.receiver.Receiver; import org.perfcake.message.sender.MessageSender; import org.perfcake.message.sender.MessageSenderManager; import org.perfcake.message.sequence.Sequence; import org.perfcake.message.sequence.SequenceManager; import org.perfcake.reporting.ReportManager; import org.perfcake.reporting.reporter.Reporter; import org.perfcake.util.ObjectFactory; import org.perfcake.validation.MessageValidator; import org.perfcake.validation.ValidationManager; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Properties; /** * A Java based builder for creating {@link org.perfcake.scenario.Scenario} instance, which can be run by {@link org.perfcake.ScenarioExecution}. * * @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a> */ public class ScenarioBuilder { private Scenario scenario; /** * Gets a new ScenarioBuilder instance. Mandatory objects must be passed in. * * @param runInfo * RunInfo specifying the test run time. * @param messageGenerator * Message generator to be used to generate messages during test. * @param messageSender * Sender template which will be copied to create all sender instances. Only the bean properties with proper get methods will be set on the new sender instances. * @throws PerfCakeException * When any of the parameters are not set or creation of the underlying classes fails. */ public ScenarioBuilder(final RunInfo runInfo, final MessageGenerator messageGenerator, final MessageSender messageSender) throws PerfCakeException { if (runInfo == null) { throw new PerfCakeException("RunInfo is not set."); } if (messageGenerator == null) { throw new PerfCakeException("Generator is not set."); } if (messageSender == null) { throw new PerfCakeException("Sender is not set."); } Properties props; try { props = ObjectFactory.getObjectProperties(messageSender); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new PerfCakeException(String.format("Cannot access properties of the message sender template '%s':", messageSender.toString()), e); } initScenario(runInfo, messageGenerator, messageSender.getClass().getName(), props); } /** * Gets a new ScenarioBuilder instance. Mandatory objects must be passed in. Sender can be described as a class name and properties. * * @param runInfo * RunInfo specifying the test run time. * @param messageGenerator * Message generator to be used to generate messages during test. * @param senderClass * Name of the sender class, instances will be used to send message in the scenario. * @param senderProperties * Properties that will be set on the sender instances. * @throws PerfCakeException * When any of the parameters are not set or creation of the underlying classes fails. */ public ScenarioBuilder(final RunInfo runInfo, final MessageGenerator messageGenerator, final String senderClass, final Properties senderProperties) throws PerfCakeException { if (runInfo == null) { throw new PerfCakeException("RunInfo is not set."); } if (messageGenerator == null) { throw new PerfCakeException("Generator is not set."); } if (senderClass == null) { throw new PerfCakeException("Sender is not set."); } initScenario(runInfo, messageGenerator, senderClass, senderProperties); } private void initScenario(final RunInfo runInfo, final MessageGenerator messageGenerator, final String senderClass, final Properties senderProperties) throws PerfCakeException { scenario = new Scenario(); messageGenerator.setRunInfo(runInfo); scenario.setGenerator(messageGenerator); final MessageSenderManager messageSenderManager = new MessageSenderManager(); messageSenderManager.setSenderClass(senderClass); messageSenderManager.addMessageSenderProperties(senderProperties); messageSenderManager.setSenderPoolSize(messageGenerator.getThreads()); scenario.setMessageSenderManager(messageSenderManager); final ReportManager reportManager = new ReportManager(); reportManager.setRunInfo(runInfo); scenario.setReportManager(reportManager); scenario.setMessageStore(new ArrayList<MessageTemplate>()); scenario.setValidationManager(new ValidationManager()); scenario.setSequenceManager(new SequenceManager()); } /** * Sets the receiver to receive message responses from a separate message channel. Null disables this feature. * * @param r * The receiver to be used to receive responses from a separate message channel. * @return Instance of this for fluent API. */ public ScenarioBuilder setReceiver(final Receiver r) { scenario.setReceiver(r); return this; } /** * Sets the correlator to match request and response messages when a receiver is used. It must be set when receiver is used. * * @param c * The correlator to match request and response messages. * @return Instance of this for fluent API. */ public ScenarioBuilder setCorrelator(final Correlator c) { scenario.setCorrelator(c); if (scenario.getReceiver() != null) { scenario.getReceiver().setCorrelator(c); } return this; } /** * Adds a {@link Reporter}, which will be used in {@link org.perfcake.scenario.Scenario} for reporting results. More reporters can be added * * @param r * A {@link Reporter} implementation. * @return Instance of this for fluent API. */ public ScenarioBuilder addReporter(final Reporter r) { scenario.getReportManager().registerReporter(r); return this; } /** * Adds a {@link MessageTemplate}, which will be used in the {@link org.perfcake.scenario.Scenario} * * @param messageTemplate * A message template to be added to the list of messages to be send during in one sender cycle. * @return Instance of this for fluent API. */ public ScenarioBuilder addMessage(final MessageTemplate messageTemplate) { scenario.getMessageStore().add(messageTemplate); return this; } /** * Puts a validator under the given key. * * @param validatorId * Id of the new validator. * @param messageValidator * The message validator to be registered. * @return Instance of this for fluent API. */ public ScenarioBuilder putMessageValidator(final String validatorId, final MessageValidator messageValidator) { scenario.getValidationManager().addValidator(validatorId, messageValidator); scenario.getValidationManager().setEnabled(true); return this; } /** * Registers a new sequence under the given property name. * * @param sequenceId * The id of the sequence (the name of the placeholder). * @param sequence * The new sequence to be registered. * @return Instance of this for fluent API. * @throws PerfCakeException * When it was not possible to properly initialize the newly added sequence. */ public ScenarioBuilder putSequence(final String sequenceId, final Sequence sequence) throws PerfCakeException { scenario.getSequenceManager().addSequence(sequenceId, sequence); return this; } /** * Builds the usable {@link org.perfcake.scenario.Scenario} object, which can be then used for executing the scenario. * * @return The finished {@link org.perfcake.scenario.Scenario}. */ public Scenario build() { return scenario; } }