+1  A: 

Apache's Active MQ website gives an example on how to embed a broker in Spring: http://activemq.apache.org/spring-support.html and on how to define a JMS bridge: http://activemq.apache.org/jms-to-jms-bridge.html

Miklos
I'm trying :) Got as far as adding the xmlns:amq declaration at the top of the beans file, adding in the xbean-spring-3.4.jar file, and with a simple broker declaration (<amq:broker useJmx="false" persistent="false"><amq:transportConnectors><amq:transportConnector uri="tcp://localhost:0" /></amq:transportConnectors></amq:broker>) I'm now getting a org.springframework.beans.factory.BeanCreationException, which is because it can't find org/osgi/framework/BundleException, apparently. This is all why I asked the question :)
Robert Grant
Hunting for JAR files and setting up CLASSPATH is painful in Java programming. I found BundleException in org.osgi.core-4.1.0.jar, which is part of the Active MQ 5.3.2 package.
Miklos
Brilliant work! I'll keep going...
Robert Grant
A: 

This is how to do it.

Assumptions

  1. You're connecting to a remote destination on http://destination-box:61616
  2. You'll connect to your local broker via VM transport, on vm://localhost:7001
  3. You have two remote queues you want to bridge to: queue1 and queue2

Pre: namespaces

You need to declare the following namespaces:

xmlns:p="http://www.springframework.org/schema/p"
xmlns:jms="http://www.springframework.org/schema/jms"

1. Create a local broker:

<bean id="bridgedBroker" class="org.apache.activemq.broker.BrokerService"
 init-method="start" destroy-method="stop">
  <property name="brokerName" value="bridgedBroker"/>
  <property name="persistent" value="true"/>
  <property name="transportConnectorURIs"> 
    <value>vm://localhost:7001</value>
  </property>
  <property name="jmsBridgeConnectors">
    <bean class="org.apache.activemq.network.jms.JmsQueueConnector">
      <property name="outboundQueueConnectionFactory">
        <bean class="org.apache.activemq.ActiveMQConnectionFactory">
          <property name="brokerURL" 
           value="failover:(tcp://destination-box:61616)?maxReconnectDelay=10" />
        </bean>
      </property>
      <property name="outboundQueueBridges">
        <list>
          <bean class="org.apache.activemq.network.jms.OutboundQueueBridge">
            <constructor-arg value="queue1"/>
          </bean>
          <bean class="org.apache.activemq.network.jms.OutboundQueueBridge">
            <constructor-arg value="queue2"/>
          </bean>
        </list>
      </property>
    </bean>
  </property>
</bean>

So you're using persistence, activated by a property, and a Broker Configuration URI to configure retry behaviour. You have to list the name of each remote queue you want to connect to in the outboundBridgeQueues list.

2. Create broker connection factories

This one connects to the above broker:

<bean id="brokerConnectionFactory"
 class="org.apache.activemq.ActiveMQConnectionFactory"
 p:brokerURL="vm://localhost:7001" />

Then wrap it with a CachingConnectionFactory (almost always a good idea):

<bean id="cachingBrokerConnectionFactory"
 class="org.springframework.jms.connection.CachingConnectionFactory"
 p:targetConnectionFactory-ref="brokerConnectionFactory"
 p:sessionCacheSize="10" />

3. Create local equivalents of the remote destinations

Each destination you’ll be talking to now needs a local representation:

<bean id="queue1destination" class="org.apache.activemq.command.ActiveMQQueue">
  <constructor-arg value="queue1" />
</bean>

<bean id="queue2destination" class="org.apache.activemq.command.ActiveMQQueue">
  <constructor-arg value="queue2" />
</bean>

4. Create JMS templates to be wired into local beans

I’ll just make one for queue1 here; queue2 is exactly the same process:

<bean id="queue1JMSTemplate"
 class="org.springframework.jms.core.JmsTemplate"
 p:connectionFactory-ref="cachingBrokerConnectionFactory"
 p:defaultDestination-ref="queue1destination" />

5. Use the JMS template

Some sample code:

public class SendToQueue1
{
  @Autowired protected JmsTemplate queue1JMSTemplate; 

  public void sendMessage(final String message) throws JMSException
  {
    queue1JMSTemplate.send(new MessageCreator()
    {
      public Message createMessage(Session session) throws JMSException
      {
        return session.createTextMessage(message);
      }
    });
  }
}

And you're done! Not actually too painful, but it took a while to get it working. Hope this helps people in the future; it's a great way to quickly add persistent messaging to a small app.

Note: this isn't a great way to wire up the class. You'd probably pass in a JMSTemplate from config, so you could use one class definition and wire it into different templates for different queues. I've just done it like this for speed. Just use your Spring instincts :)

Robert Grant