/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jmeter.protocol.jms.sampler; import java.util.Date; import java.util.function.Predicate; import java.util.regex.Pattern; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.samplers.AbstractSampler; import org.apache.jmeter.samplers.Entry; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.util.JMeterUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * BaseJMSSampler is an abstract class which provides implementation for common * properties. Rather than duplicate the code, it's contained in the base class. */ public abstract class BaseJMSSampler extends AbstractSampler { private static final long serialVersionUID = 241L; private static final Logger LOGGER = LoggerFactory.getLogger(BaseJMSSampler.class); //++ These are JMX file attribute names and must not be changed private static final String JNDI_INITIAL_CONTEXT_FAC = "jms.initial_context_factory"; // $NON-NLS-1$ private static final String PROVIDER_URL = "jms.provider_url"; // $NON-NLS-1$ private static final String CONN_FACTORY = "jms.connection_factory"; // $NON-NLS-1$ // N.B. Cannot change value, as that is used in JMX files private static final String DEST = "jms.topic"; // $NON-NLS-1$ private static final String PRINCIPAL = "jms.security_principle"; // $NON-NLS-1$ private static final String CREDENTIALS = "jms.security_credentials"; // $NON-NLS-1$ /* * The number of samples to aggregate */ private static final String ITERATIONS = "jms.iterations"; // $NON-NLS-1$ private static final String USE_AUTH = "jms.authenticate"; // $NON-NLS-1$ private static final String USE_PROPERTIES_FILE = "jms.jndi_properties"; // $NON-NLS-1$ /* * If true, store the response in the sampleResponse * (N.B. do not change the value, as it is used in JMX files) */ private static final String STORE_RESPONSE = "jms.read_response"; // $NON-NLS-1$ // Is Destination setup static? else dynamic private static final String DESTINATION_STATIC = "jms.destination_static"; // $NON-NLS-1$ private static final boolean DESTINATION_STATIC_DEFAULT = true; // default to maintain compatibility /** Property name for regex of error codes which force reconnection **/ private static final String ERROR_RECONNECT_ON_CODES = "jms_error_reconnect_on_codes"; // $NON-NLS-1$ private transient Predicate<String> isReconnectErrorCode = e -> false; //-- End of JMX file attribute names // See BUG 45460. We need to keep the resource in order to interpret existing files private static final String REQUIRED = JMeterUtils.getResString("jms_auth_required"); // $NON-NLS-1$ public BaseJMSSampler() { } /** * {@inheritDoc} */ @Override public SampleResult sample(Entry e) { return this.sample(); } public abstract SampleResult sample(); // ------------- get/set properties ----------------------// /** * set the initial context factory * * @param icf the initial context factory */ public void setJNDIIntialContextFactory(String icf) { setProperty(JNDI_INITIAL_CONTEXT_FAC, icf); } /** * method returns the initial context factory for jndi initial context * lookup. * * @return the initial context factory */ public String getJNDIInitialContextFactory() { return getPropertyAsString(JNDI_INITIAL_CONTEXT_FAC); } /** * set the provider user for jndi * * @param url the provider URL */ public void setProviderUrl(String url) { setProperty(PROVIDER_URL, url); } /** * method returns the provider url for jndi to connect to * * @return the provider URL */ public String getProviderUrl() { return getPropertyAsString(PROVIDER_URL); } /** * set the connection factory for * * @param factory the connection factory */ public void setConnectionFactory(String factory) { setProperty(CONN_FACTORY, factory); } /** * return the connection factory parameter used to lookup the connection * factory from the JMS server * * @return the connection factory */ public String getConnectionFactory() { return getPropertyAsString(CONN_FACTORY); } /** * set the destination (topic or queue name) * * @param dest the destination */ public void setDestination(String dest) { setProperty(DEST, dest); } /** * return the destination (topic or queue name) * * @return the destination */ public String getDestination() { return getPropertyAsString(DEST); } /** * set the username to login into the jms server if needed * * @param user the name of the user */ public void setUsername(String user) { setProperty(PRINCIPAL, user); } /** * return the username used to login to the jms server * * @return the username used to login to the jms server */ public String getUsername() { return getPropertyAsString(PRINCIPAL); } /** * Set the password to login to the jms server * * @param pwd the password to use for login on the jms server */ public void setPassword(String pwd) { setProperty(CREDENTIALS, pwd); } /** * return the password used to login to the jms server * * @return the password used to login to the jms server */ public String getPassword() { return getPropertyAsString(CREDENTIALS); } /** * set the number of iterations the sampler should aggregate * * @param count the number of iterations */ public void setIterations(String count) { setProperty(ITERATIONS, count); } /** * get the number of samples to aggregate * * @return String containing the number of samples to aggregate */ public String getIterations() { return getPropertyAsString(ITERATIONS); } /** * get the number of samples to aggregate * * @return int containing the number of samples to aggregate */ public int getIterationCount() { return getPropertyAsInt(ITERATIONS); } /** * Set whether authentication is required for JNDI * * @param useAuth flag whether to use authentication */ public void setUseAuth(boolean useAuth) { setProperty(USE_AUTH, useAuth); } /** * return whether jndi requires authentication * * @return whether jndi requires authentication */ public boolean isUseAuth() { final String useAuth = getPropertyAsString(USE_AUTH); return useAuth.equalsIgnoreCase("true") || useAuth.equals(REQUIRED); // $NON-NLS-1$ } /** * set whether the sampler should store the response or not * * @param read whether the sampler should store the response or not */ public void setReadResponse(String read) { setProperty(STORE_RESPONSE, read); } /** * return whether the sampler should store the response * * @return whether the sampler should store the response */ public String getReadResponse() { return getPropertyAsString(STORE_RESPONSE); } /** * return whether the sampler should store the response * * @return boolean: whether the sampler should read the response */ public boolean getReadResponseAsBoolean() { return getPropertyAsBoolean(STORE_RESPONSE); } /** * if the sampler should use jndi.properties file, call the method with the string "true" * * @param properties flag whether to use <em>jndi.properties</em> file */ public void setUseJNDIProperties(String properties) { setProperty(USE_PROPERTIES_FILE, properties); } /** * return whether the sampler should use properties file instead of UI * parameters. * * @return the string "true" when the sampler should use properties file * instead of UI parameters, the string "false" otherwise. */ public String getUseJNDIProperties() { return getPropertyAsString(USE_PROPERTIES_FILE); } /** * return the properties as boolean true/false. * * @return whether the sampler should use properties file instead of UI parameters. */ public boolean getUseJNDIPropertiesAsBoolean() { return getPropertyAsBoolean(USE_PROPERTIES_FILE); } /** * if the sampler should use a static destination, call the method with true * * @param isStatic flag whether the destination is a static destination */ public void setDestinationStatic(boolean isStatic) { setProperty(DESTINATION_STATIC, isStatic, DESTINATION_STATIC_DEFAULT); } /** * return whether the sampler should use a static destination. * * @return whether the sampler should use a static destination. */ public boolean isDestinationStatic(){ return getPropertyAsBoolean(DESTINATION_STATIC, DESTINATION_STATIC_DEFAULT); } /** * Returns a String with the JMS Message Header values. * * @param message JMS Message * @return String with message header values. */ public static String getMessageHeaders(Message message) { final StringBuilder response = new StringBuilder(256); try { response.append("JMS Message Header Attributes:"); response.append("\n Correlation ID: "); response.append(message.getJMSCorrelationID()); response.append("\n Delivery Mode: "); if (message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT) { response.append("PERSISTANT"); } else { response.append("NON-PERSISTANT"); } final Destination destination = message.getJMSDestination(); response.append("\n Destination: "); response.append(destination == null ? null : destination .toString()); response.append("\n Expiration: "); response.append(new Date(message.getJMSExpiration())); response.append("\n Message ID: "); response.append(message.getJMSMessageID()); response.append("\n Priority: "); response.append(message.getJMSPriority()); response.append("\n Redelivered: "); response.append(message.getJMSRedelivered()); final Destination replyTo = message.getJMSReplyTo(); response.append("\n Reply to: "); response.append(replyTo == null ? null : replyTo.toString()); response.append("\n Timestamp: "); response.append(new Date(message.getJMSTimestamp())); response.append("\n Type: "); response.append(message.getJMSType()); response.append("\n\n"); } catch (JMSException e) { LOGGER.warn( "Can't extract message headers", e); } return response.toString(); } public String getReconnectionErrorCodes() { return getPropertyAsString(ERROR_RECONNECT_ON_CODES); } public void setReconnectionErrorCodes(String reconnectionErrorCodes) { setProperty(ERROR_RECONNECT_ON_CODES, reconnectionErrorCodes); } public Predicate<String> getIsReconnectErrorCode() { return isReconnectErrorCode; } /** * */ protected void configureIsReconnectErrorCode() { String regex = StringUtils.trimToEmpty(getReconnectionErrorCodes()); if (regex.isEmpty()) { isReconnectErrorCode = e -> false; } else { isReconnectErrorCode = Pattern.compile(regex).asPredicate(); } } }