/* * -----------------------------------------------------------------------\ * 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.util.properties.MandatoryProperty; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Properties; import java.util.Set; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.naming.InitialContext; /** * Common ancestor of {@link JmsSender} and {@link Jms11Sender}. * * @author <a href="mailto:marvenec@gmail.com">Martin Večeřa</a> */ abstract public class AbstractJmsSender extends AbstractSender { /** * JMS message type. */ public enum MessageType { /** * Object message. * * @see javax.jms.ObjectMessage */ OBJECT, /** * String message. * * @see javax.jms.TextMessage */ STRING, /** * Byte array message. * * @see javax.jms.BytesMessage */ BYTEARRAY } /** * The sender's logger. */ private static final Logger log = LogManager.getLogger(AbstractJmsSender.class); /** * JMS initial context. */ protected InitialContext ctx = null; /** * JMS destination connection factory. */ protected ConnectionFactory qcf = null; /** * JMS username. */ protected String username = null; /** * JMS password. */ protected String password = null; /** * JMS replyTo address. */ protected String replyTo = ""; /** * JMS replyTo destination. */ protected Destination replyToDestination = null; /** * Indicates whether the JMS transport is transacted or not. */ protected boolean transacted = false; /** * Indicates whether the JMS message is persisted during transport or not. */ protected boolean persistent = true; /** * Specifies that the payload should be send as one of {@link JmsSender.MessageType}. Default value * is set to MessageType.STRING. */ protected MessageType messageType = MessageType.STRING; /** * JMS connection factory property. */ @MandatoryProperty protected String connectionFactory = "ConnectionFactory"; /** * JNDI context factory property. */ @MandatoryProperty protected String jndiContextFactory = null; /** * JNDI URL property. */ @MandatoryProperty protected String jndiUrl = null; /** * JNDI username property. */ protected String jndiSecurityPrincipal = null; /** * JNDI password. */ protected String jndiSecurityCredentials = null; /** * JMS message to send. */ protected Message mess = null; /** * Use safe message property names because some messaging implementations do not allow anything but valid Java identifiers. */ protected boolean safePropertyNames = true; protected void setMessageProperties(final org.perfcake.message.Message message, final Properties messageAttributes) throws Exception { final Set<String> propertyNameSet = message.getProperties().stringPropertyNames(); for (final String property : propertyNameSet) { mess.setStringProperty(safePropertyNames ? property.replaceAll("[^a-zA-Z0-9_]", "_") : property, message.getProperty(property)); } // set additional properties if (messageAttributes != null) { for (String prop : messageAttributes.stringPropertyNames()) { mess.setStringProperty(safePropertyNames ? prop.replaceAll("[^a-zA-Z0-9_]", "_") : prop, messageAttributes.getProperty(prop)); } } final Properties headers = message.getHeaders(); headers.forEach((k, v) -> { try { mess.setStringProperty(safePropertyNames ? k.toString().replaceAll("[^a-zA-Z0-9_]", "_") : k.toString(), v.toString()); } catch (JMSException e) { log.warn("Unknown message header " + k.toString() + "=>" + v.toString() + ": ", e); } }); if (replyToDestination != null) { mess.setJMSReplyTo(replyToDestination); } } /** * Checks if both of the provided credentials are set. * * @param username * The user name credential. * @param password * The password credential. * @return <code>true</code> if both of the credentials are set and <code>false</code> if neither of them is set. * @throws PerfCakeException * If one of the credentials is not set. */ protected static boolean checkCredentials(final String username, final String password) throws PerfCakeException { if (username == null && password == null) { return false; } else if (username == null || password == null) { throw new PerfCakeException("For Secured JMS message, both username and password must be set."); } else { return true; } } /** * Gets the JMS username. * * @return The JMS username. */ public String getUsername() { return username; } /** * Sets the JMS username. * * @param username * The JMS username. * @return Instance of this for fluent API. */ public AbstractJmsSender setUsername(final String username) { this.username = username; return this; } /** * Gets the JMS password. * * @return The JMS password. */ public String getPassword() { return password; } /** * Sets the JMS password. * * @param password * The JMS password. * @return Instance of this for fluent API. */ public AbstractJmsSender setPassword(final String password) { this.password = password; return this; } /** * Is JMS message delivery transacted? * * @return The transacted mode. */ public boolean isTransacted() { return transacted; } /** * Sets the JMS delivery transaction mode. * * @param transacted * The transacted mode. * @return Instance of this for fluent API. */ public AbstractJmsSender setTransacted(final boolean transacted) { this.transacted = transacted; return this; } /** * Is JMS message persisted? * * @return <code>true</code> if JMS message is persisted. */ public boolean isPersistent() { return persistent; } /** * Enables/disables persistent delivery mode. * * @param persistent * <code>true</code> to persist JMS messages. * @return Instance of this for fluent API. */ public AbstractJmsSender setPersistent(final boolean persistent) { this.persistent = persistent; return this; } /** * Set the JMS message type. * * @param messageType * The JMS message type. * @return Instance of this for fluent API. */ public AbstractJmsSender setMessageType(final JmsSender.MessageType messageType) { this.messageType = messageType; return this; } /** * Get the JMS message type. * * @return The JMS message type. */ public JmsSender.MessageType getMessageType() { return messageType; } /** * Gets the connection factory. * * @return The connection factory. */ public String getConnectionFactory() { return connectionFactory; } /** * Sets the connection factory. * * @param connectionFactory * The connectionf actory. * @return Instance of this for fluent API. */ public AbstractJmsSender setConnectionFactory(final String connectionFactory) { this.connectionFactory = connectionFactory; return this; } /** * Gets the JNDI context factory. * * @return The JNDI context factory. */ public String getJndiContextFactory() { return jndiContextFactory; } /** * Sets the JNDI context factory. * * @param jndiContextFactory * The JNDI context factory. * @return Instance of this for fluent API. */ public AbstractJmsSender setJndiContextFactory(final String jndiContextFactory) { this.jndiContextFactory = jndiContextFactory; return this; } /** * Gets the JNDI URL. * * @return The JNDI URL. */ public String getJndiUrl() { return jndiUrl; } /** * Sets the value of JNDI URL. * * @param jndiUrl * The JNDI URL. * @return Instance of this for fluent API. */ public AbstractJmsSender setJndiUrl(final String jndiUrl) { this.jndiUrl = jndiUrl; return this; } /** * Gets the JNDI username. * * @return The JNDI username. */ public String getJndiSecurityPrincipal() { return jndiSecurityPrincipal; } /** * Sets the JNDI username. * * @param jndiSecurityPrincipal * The JNDI username. * @return Instance of this for fluent API. */ public AbstractJmsSender setJndiSecurityPrincipal(final String jndiSecurityPrincipal) { this.jndiSecurityPrincipal = jndiSecurityPrincipal; return this; } /** * Gets the JNDI password. * * @return The JNDI password. */ public String getJndiSecurityCredentials() { return jndiSecurityCredentials; } /** * Sets the JNDI password. * * @param jndiSecurityCredentials * The JNDI password. * @return Instance of this for fluent API. */ public AbstractJmsSender setJndiSecurityCredentials(final String jndiSecurityCredentials) { this.jndiSecurityCredentials = jndiSecurityCredentials; return this; } /** * Gets the value of <code>replyTo</code> header of the JMS message. * * @return The <code>replyTo</code> header of the JMS message. */ public String getReplyTo() { return replyTo; } /** * Sets the value of <code>replyTo</code> header of the JMS message. * * @param replyTo * The <code>replyTo</code> header of the JMS message. * @return Instance of this for fluent API. */ public AbstractJmsSender setReplyTo(final String replyTo) { this.replyTo = replyTo; return this; } /** * Gets the value of same message property name handling. Some messaging implementations do not allow anything but valid Java identifiers. * Defaults to true. * * @return True if and only if the safe message property name handling is on. */ public boolean isSafePropertyNames() { return safePropertyNames; } /** * Sets the value of same message property name handling. Some messaging implementations do not allow anything but valid Java identifiers. * * @param safePropertyNames * True if and only if the safe message property name handling should be switched on. * @return Instance of this for fluent API. */ public AbstractJmsSender setSafePropertyNames(final boolean safePropertyNames) { this.safePropertyNames = safePropertyNames; return this; } }