I've investigated this further - durable topics are OK, but seem to me to be intended to handle the case where you'll have a well-managed lifecycle for the subscriber, like one of a set of client systems that may be intermittently available.
In my case I'm trying to handle transient clients on users workstations that come and go and there may be an unknown number of them at any one time.
I got some results, which I think are specific to ActiveMQ, using the consumer.retroactive=true property on the queue URI.
For those who are interested in the exact Spring configuration, here's the publisher config:
Code:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="pubSubDomain" value="true"/>
<property name="defaultDestinationName" value="TEST.TOPIC"/>
</bean>
And here's the subscriber config:
Code:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
<property name="physicalName" value="TEST.TOPIC?consumer.retroactive=true&consumer.prefetchSize=10"/>
</bean>
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="pubSubDomain" value="true"/>
<property name="messageListener" ref="subscriber"/>
<property name="messageSelector" value="username = '${username}'"/>
<property name="recoveryInterval" value="60000"/>
</bean>
(Note sure setting recoveryInterval did anything I could determine while I paused by subscribers in the debugger.)
I still don't think this addresses my original question of how I could publish a message to a topic that would live for say, an hour, and be picked up by any interested subscribers who happen to be around for that hour, and then be cleaned up by the queue manager.