/*
* -----------------------------------------------------------------------\
* 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.message.sender;
import org.perfcake.PerfCakeException;
import org.perfcake.message.Message;
import org.perfcake.reporting.MeasurementUnit;
import org.perfcake.util.StringTemplate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
import java.util.Properties;
/**
* The common ancestor for all senders. Facilitates logging and target specification.
*
* @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a>
*/
public abstract class AbstractSender implements MessageSender {
/**
* The sender's logger.
*/
private static final Logger log = LogManager.getLogger(AbstractSender.class);
/**
* We need to cache the value to be really fast.
*/
private boolean isTraceEnabled = false;
/**
* The target where to send the messages.
*/
private StringTemplate target = new StringTemplate("");
/**
* Keeps the same connection to the target between individual invocations.
* This can achieve higher throughput, however, target cannot be changed for individual
* invocations and it does not make sense to use placeholders in target.
*/
protected boolean keepConnection = true;
@Override
public final void init() throws PerfCakeException {
if (keepConnection) { // otherwise this is done in preSend()
doInit(null);
}
isTraceEnabled = log.isTraceEnabled();
}
public abstract void doInit(final Properties messageAttributes) throws PerfCakeException;
@Override
public final void close() throws PerfCakeException {
if (keepConnection) { // otherwise this is done in postSend()
doClose();
}
}
public abstract void doClose() throws PerfCakeException;
@Override
public final Serializable send(final Message message, final MeasurementUnit measurementUnit) throws Exception {
return doSend(message, measurementUnit);
}
@Override
public void preSend(final Message message, final Properties messageAttributes) throws Exception {
if (isTraceEnabled) {
log.trace(String.format("Message content: %s", (message == null) ? null : message.toString()));
}
if (!keepConnection) {
doInit(messageAttributes);
}
}
/**
* Actually performs the send operation. Should be overridden by specific implementations.
*
* @param message
* Message to be sent.
* @param measurementUnit
* Measurement unit carrying the current stop-watch.
* @return Response to the message.
* @throws Exception
* When the sending operation failed.
* @see org.perfcake.message.sender.MessageSender#send(org.perfcake.message.Message, org.perfcake.reporting.MeasurementUnit)
*/
public abstract Serializable doSend(final Message message, final MeasurementUnit measurementUnit) throws Exception;
@Override
public void postSend(final Message message) throws Exception {
if (!keepConnection) {
doClose();
}
}
@Override
public final String getTarget() {
return target.toString();
}
@Override
public final String getTarget(final Properties properties) {
return target.toString(properties);
}
/**
* Gets the target in a safe way to avoid NPE when properties are null.
*
* @param properties
* Properties to replace placeholders in the target.
* @return The target template with placeholders replaced.
*/
public final String safeGetTarget(final Properties properties) {
if (properties == null) {
return getTarget();
} else {
return getTarget(properties);
}
}
@Override
public final AbstractSender setTarget(final String target) {
this.target = new StringTemplate(target);
return this;
}
/**
* Should we try to preserve connection between sending of individual messages?
* Placeholders in the target address cannot be replaced with properties nor sequences when set to true.
* Defaults to true.
*
* @return True iff the connection is kept open.
*/
public boolean isKeepConnection() {
return keepConnection;
}
/**
* Should we try to preserve connection between sending of individual messages?
* Placeholders in the target address cannot be replaced with properties nor sequences when set to true.
* Defaults to true.
*
* @param keepConnection
* True when the connection should be kept open.
* @return Instance of this to support fluent API.
*/
public AbstractSender setKeepConnection(final boolean keepConnection) {
this.keepConnection = keepConnection;
return this;
}
}