skip to content

Message and File Transports

The rest of the stock sampler surface - queues and topics, raw sockets, file transfer, mail and shelling out - and the escape hatch when no shipped element speaks your protocol.

on this pageshow

explore

questions

6

How does JMeter's JMS Publisher find the broker it publishes to?

level: juniorimportance: must knowfreq 60%

answer

  1. The download alone reaches no broker
  2. A directory service sits in front
  3. One checkbox swaps fields for a file
  4. lib takes the provider's client JAR

basics

~20 s

Through a JNDI lookup. Either tick Use jndi.properties file, or fill in Initial Context Factory and Provider URL on the sampler itself; Connection Factory and Destination name what is looked up either way. The provider's own client JAR must already sit in JMeter's lib directory.

solid answer

~50 s

JMeter's **JMS Publisher** never addresses a broker directly. It resolves a connection factory and a destination through **JNDI**, then drives them through the JMS API. Two routes exist. Ticking **Use jndi.properties file** makes JMeter read a `jndi.properties` found on the classpath, which normally means pointing the `user.classpath` property at the folder holding it. Leaving it unticked makes JMeter build the context from the sampler's own **Initial Context Factory** and **Provider URL** fields, with **User**/**Password** if **Use Authorization** is ticked. **Connection Factory** and **Destination** are used either way — they are the JNDI names looked up *in* whichever context was built, not part of building it. **Destination** names the queue or topic — with ActiveMQ, typically `dynamicQueues/ORDERS`. None of it works on a bare install: JMeter 6.0.0 ships the Jakarta Messaging API (`jakarta.jms-api` 3.1.0) but no provider implementation, so the broker's client JAR must be dropped into `lib` and JMeter restarted.

code

xml · 11 lines
xml
<PublisherSampler guiclass="JMSPublisherGui" testclass="PublisherSampler" testname="JMS Publisher" enabled="true">
  <stringProp name="jms.jndi_properties">false</stringProp>
  <stringProp name="jms.initial_context_factory">org.apache.activemq.jndi.ActiveMQInitialContextFactory</stringProp>
  <stringProp name="jms.provider_url">tcp://localhost:61616</stringProp>
  <stringProp name="jms.connection_factory">ConnectionFactory</stringProp>
  <stringProp name="jms.topic">dynamicQueues/ORDERS</stringProp>
  <stringProp name="jms.config_choice">jms_use_text</stringProp>
  <stringProp name="jms.config_msg_type">jms_text_message</stringProp>
  <stringProp name="jms.iterations">1</stringProp>
  <boolProp name="jms.authenticate">false</boolProp>
</PublisherSampler>

go deeper

for a junior

Recall that the JMS Publisher reaches its broker through JNDI and that JMeter ships no provider client, so a JAR has to go into lib before anything works.

for a middle

Explain the two routes to the context - the jndi.properties checkbox versus the Initial Context Factory and Provider URL fields - and what each field actually names, including the Connection Factory and Destination names that both routes look up.

for a senior

Show how you keep the lookup portable across environments: values driven from properties rather than hardcoded, and the client JAR present on every injector, not just the controller.

for a principal

Own the decision about how broker client JARs reach a fleet of injectors and how their versions are pinned, so a plan that runs today still runs after a broker upgrade.

A **JMS Publisher** aimed at an order queue looks deceptively simple in the GUI: a destination name, a message body, press play. In practice the first three failures a team hits are all about the lookup chain in front of the broker, not about the message. ## The lookup chain The sampler does not open a socket to a broker. It builds a JNDI `InitialContext`, looks up a connection factory in it by name, looks up the destination, and only then publishes. Every field on the JMS Publisher panel feeds one of those three steps: - **Initial Context Factory** — the class name of the JNDI provider, e.g. `org.apache.activemq.jndi.ActiveMQInitialContextFactory`. - **Provider URL** — where that factory should connect, e.g. `tcp://localhost:61616` or `vm://localhost`. - **Connection Factory** — the JNDI *name* under which the factory is registered, commonly `ConnectionFactory`. - **Destination** — the JNDI name of the queue or topic. ActiveMQ lets you create one on the fly with the `dynamicQueues/NAME` or `dynamicTopics/NAME` prefixes. - **Use Authorization**, **User**, **Password** — credentials for the JMS provider. The password is stored unencrypted in the `.jmx`. ## The two ways to supply the context The **Use jndi.properties file** checkbox switches off only the context-building fields. Ticked, JMeter calls `new InitialContext()` with no properties of its own, so the JNDI environment comes entirely from a `jndi.properties` resource on the classpath, and the GUI greys out **Initial Context Factory**, **Provider URL** and **Use Authorization** with its **User**/**Password**. The catch is the phrase *on the classpath* — dropping the file next to the `.jmx` is not enough; the usual fix is to add its directory to the `user.classpath` property. Unticked, those fields build the context instead. **Connection Factory** and **Destination** stay live in both modes: they name what is looked up in the context, not how the context is made. Teams that run one plan against several brokers usually keep the fields and drive them from properties rather than shipping a `jndi.properties` per environment. ## What the download does not ship JMeter's JMS samplers compile against the Jakarta Messaging API only. The component reference says it plainly for all three JMS elements: *"JMeter does not include any JMS implementation jar; this must be downloaded from the JMS provider and put in the lib directory."* So the checklist for a new machine is: 1. Download the broker's client JAR (and its own dependencies). 2. Copy them into JMeter's `lib` directory. 3. Restart JMeter — the classpath is built at startup. 4. Repeat on **every** injector, because a distributed run does not ship JARs to the remote engines. At 6.0.0 the API on the classpath is `jakarta.jms-api` 3.1.0 and every sampler class imports `jakarta.jms.*`. A client JAR written against the older `javax.jms` package therefore cannot satisfy the lookup at all — the `instanceof jakarta.jms.ConnectionFactory` check in `Utils.getConnection` simply never matches, and the lookup dies with `Expected jakarta.jms.ConnectionFactory, found <your class>`. (The JMS Point-to-Point sampler is the one that demands a `jakarta.jms.QueueConnectionFactory`.) When you pick a client build, pick the Jakarta one. ## Static or per-sample destinations The **Setup** radio decides when the destination name is resolved: | Setup | Meaning | |---|---| | `At startup` | the destination is looked up once per thread, on that thread's first sample, and reused for every later sample in that thread | | `Each sample` | the name is evaluated per sample, so it may contain a variable | Publishing to a per-order queue name needs `Each sample`; a single `ORDERS` queue is cheaper on `At startup`. ## The rest of the panel, briefly **Number of samples to aggregate** controls how many messages one sample publishes in a loop — the default is `1`. **Expiration** defaults to `0`, meaning the message never expires; **Priority** defaults to `4` on the JMS scale of `0` to `9`. **Message source** chooses between a file, a random file from a folder, and the text area; **Message type** chooses Text, Map, Object or Bytes. **Reconnect on error codes (regex)** is empty by default, which means an error never triggers a reconnect. ## Where it goes wrong - The client JAR was put in `lib/ext` (which is for JMeter plugins) instead of `lib`. - `jndi.properties` exists but is not on the classpath, so the lookup silently uses defaults and fails. - The connection factory *name* was confused with the factory *class name* — the Connection Factory field wants the JNDI name. - A `javax.jms`-era client JAR was downloaded for a JMeter 6 install. - The JAR was added on the controller only, and the remote engines fail at the first sample.

  • Where does JMeter look for jndi.properties, and how do you get your copy there?
    On the classpath, not next to the test plan. The usual fix is to add the directory holding the file to JMeter's `user.classpath` property in `user.properties`, then restart. A properties file dropped beside the `.jmx` is not on the classpath, so the lookup falls back to defaults and fails.
  • Does the JMS Publisher's Destination field accept a variable?
    Only if **Setup** is `Each sample`. With `At startup` JMeter resolves and looks up the destination once per thread — when that thread takes its first sample — and reuses it for the rest of that thread's run, so a variable in the field is frozen at that moment rather than re-read per sample (a thread-scoped variable will still differ between threads). `Each sample` re-evaluates the field per sample, which is what a per-order queue name needs.

saying these in an interview costs you the question

  • Claiming JMeter bundles a broker client so nothing needs installing
  • Putting the provider JAR in lib/ext instead of lib
  • Typing the factory class name into the Connection Factory field
  • Assuming jndi.properties is found beside the .jmx file
  • Adding the JAR on the controller only in a distributed run
open as a page

In JMeter's JMS Subscriber, what does Number of samples to aggregate change?

level: middleimportance: should knowfreq 44%

basics

~20 s

Number of samples to aggregate sets how many messages one sample result covers. The sampler keeps reading until it has that many or the Timeout expires, and the elapsed time spans the whole batch, not one message.

open as a page

A JMeter JMS Point-to-Point request_reply sampler times out although replies reach the reply queue. What do you check?

level: seniorimportance: should knowfreq 37%

basics

~20 s

Check the two correlation checkboxes under Use alternate fields for message correlation. JMeter files each reply under one id and waits on another; if they disagree the reply is discarded and the sample fails with No reply message received.

open as a page

In JMeter's TCP Sampler, what decides when the response read stops?

level: seniorimportance: should knowfreq 33%

basics

~20 s

The chosen TCPClient class. TCPClientImpl stops at the end-of-line byte if one is set, otherwise only when the stream ends. None is set by default, so a server holding the socket open makes every read wait out the response timeout.

open as a page

Your order pipeline uses a protocol no stock JMeter sampler speaks. How would you decide how to drive it?

level: principalimportance: should knowfreq 31%

basics

~20 s

Work outward from the cheapest hook. A pluggable TCPClient class, a Java Request client class, a scripted sampler and a third-party plugin all reach the protocol. They differ in who maintains the code and how it reaches every injector.

open as a page

In JMeter's OS Process Sampler, what makes a failing command fail the sample?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

Only the Check Return Code checkbox. The sampler always records the process exit code as the response code, but marks the sample successful whatever that code is unless Check Return Code is ticked and the code differs from Expected Return Code.

open as a page