View Javadoc

1   /**
2    * Copyright 2005-2006 the original author or authors.
3    *
4    * Licensed under the Gnu General Pubic License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    *
8    *      http://www.opensource.org/licenses/gpl-license.php
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13   * See the Gnu General Public License for more details.
14   */
15  package org.figure8.join.core.messaging;
16  
17  import org.figure8.join.core.ContainerContextHandler;
18  import org.figure8.join.core.InfrastructureException;
19  import org.figure8.join.core.InvalidParameterException;
20  import org.figure8.join.core.setup.ApplicationConfig;
21  import org.figure8.join.core.setup.ActiveMQConfigurator;
22  import org.figure8.join.util.LogUtil;
23  
24  import org.apache.commons.logging.Log;
25  
26  import javax.jms.Queue;
27  import javax.jms.Topic;
28  import javax.naming.InitialContext;
29  import javax.naming.NameNotFoundException;
30  import javax.naming.NamingException;
31  
32  import java.util.Properties;
33  /**
34   * This is an implementation of {@link JMSDestinationResolver} for resolving
35   * ActiveMQ provider destinations. It uses ActiveMQ Jndi integration to resolve
36   * remote destinations.
37   * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
38   * @version $Revision: 1.1 $
39   */
40  public class ActiveMQDestinationResolver implements JMSDestinationResolver{
41  
42     // Static -------------------------------------------------------------------
43  
44     /** Get a commons logger. */
45     private static final Log log = LogUtil.getLog(ActiveMQDestinationResolver.class);
46  
47     /** Value of naming factory for ActiveMQ Jndi implementation */
48     public static final String AMQ_NAMING_FACTORY = "org.activemq.jndi.ActiveMQInitialContextFactory";
49     /** Name of ActiveMQ properties prefix for queue names */
50     public static final String AMQ_QUEUE_PREFIX = "queue.";
51     /** Name of ActiveMQ properties preix for topic names */
52     public static final String AMQ_TOPIC_PREFIX = "topic.";
53  
54  
55     // Attributes ---------------------------------------------------------------
56  
57     /** The application configuration to use for acquiring destinations */
58     protected ApplicationConfig configuration;
59  
60  
61     // Constructors -------------------------------------------------------------
62  
63     /** Creates a new instance of ActiveMQDestinationResolver */
64     public ActiveMQDestinationResolver(){
65     }
66  
67  
68     // Implementation of JMSDestinationResolver ---------------------------------
69  
70     /**
71      * Set the current application conifguration to this resolver
72      * @param configuration The application configured settings
73      */
74     public void setApplicationConfig(ApplicationConfig configuration){
75        this.configuration = configuration;
76     }
77  
78     /**
79      * Resolve a JMS queue using its name. Resolution means name resolution and
80      * application of mechanism necessary to acquire the queue (may be a remote queue)
81      * @param name The name of the queue to retrive
82      * @throws InfrastructureException if acquisition context (Jndi for example) is not available
83      * @throws InvalidParameterException if the specified destination name is unknown by resolution system
84      * @return The acquired queue
85      */
86     public Queue resolveQueue(String name) throws InfrastructureException, InvalidParameterException{
87        // Prepare result object.
88        Object object = null;
89  
90        // Depending on application config, resolve locally ...
91        if (!configuration.isDissociatedSetup())
92           object = resolveLocalObject(name);
93        // ... or remotely.
94        else object = resolveRemoteObject(name, true);
95  
96        // Check it's a queue.
97        if (!(object instanceof Queue)){
98           // Log and wrap into an invalid parameter exception.
99           log.error("Context object denoted by '" + name + "' is not a javax.jms.Queue !");
100          throw new InvalidParameterException("Context object '" + name + "' is not a Queue");
101       }
102       return (Queue)object;
103    }
104 
105    /**
106     * Resolve a JMS topic using its name. Resolution means name resolution and
107     * application of mechanism necessary to acquire the topic (may be a remote topic)
108     * @param name The name of the topic to retrieve
109     * @throws InfrastructureException if acquisition context (Jndi for example) is not available
110     * @throws InvalidParameterException if the specified destination name is unknown by resolution system
111     * @return The acquired topic
112     */
113    public Topic resolveTopic(String name) throws InfrastructureException, InvalidParameterException{
114       // Prepare result object.
115       Object object = null;
116 
117       // Depending on application config, resolve locally ...
118       if (!configuration.isDissociatedSetup())
119          object = resolveLocalObject(name);
120       // ... or remotely.
121       else object = resolveRemoteObject(name, false);
122 
123       // Check it's a topic.
124       if (!(object instanceof Topic)){
125          // Log and wrap into an invalid parameter exception.
126          log.error("Context object denoted by '" + name + "' is not a javax.jms.Topic !");
127          throw new InvalidParameterException("Context object '" + name + "' is not a Topic");
128       }
129       return (Topic)object;
130    }
131 
132 
133    // Protected ----------------------------------------------------------------
134 
135    /**
136     * Resolve destination as a locally available object through container context.
137     * @param name The name of destination to lookup
138     * @return The resolved local object
139     */
140    protected Object resolveLocalObject(String name) throws InfrastructureException, InvalidParameterException{
141       if (log.isDebugEnabled())
142          log.debug("Resolving '" + name + "' destination using local container context");
143       // Use the handler on container runtime context.
144       ContainerContextHandler handler = ContainerContextHandler.getInstance();
145       return handler.getComponent(name);
146    }
147 
148    /**
149     * Resolve destination as a remote object bound into a Jndi tree.
150     * @param name The jndi name of destination to lookup
151     * @param isQueue Flag telling telling whether destination is a queue or a topic
152     * @return The resolved remote object
153     */
154    protected Object resolveRemoteObject(String name, boolean isQueue) throws InfrastructureException, InvalidParameterException{
155       if (log.isDebugEnabled())
156          log.debug("Resolving '" + name + "' queue using remote container definition");
157       try{
158          // Use the jndi integration of ActiveMQ for retrieving destination.
159          Properties environment = buildEnvironment(name, isQueue);
160          if (log.isDebugEnabled())
161             log.debug("Looking for destination '" + name + "' using environment " + environment);
162          InitialContext ctx = new InitialContext(environment);
163          return ctx.lookup(name);
164       }
165       catch (NameNotFoundException nnfe){
166          // Log and wrap into InvalidParameterException.
167          log.error("The remote destination " + name + " cannot be found");
168          throw new InvalidParameterException("The remote destintion cannot be found", nnfe);
169       }
170       catch (NamingException ne){
171          // Log and wrap into InfrastructureException.
172          log.error("Remote connection failed with NamingException: " + ne.getMessage());
173          throw new InfrastructureException("Remote connection failed with NamingException", ne);
174       }
175    }
176 
177 
178    // Private ------------------------------------------------------------------
179 
180    /**
181     * @param name The name of destination to build environment for
182     * @param isQueue Whether destination corresponding to name is a queue
183     * @return The set of properties for initializing Jndi context
184     */
185    private Properties buildEnvironment(String name, boolean isQueue){
186       // Build environment properties.
187       Properties environment = new Properties();
188       environment.put(InitialContext.INITIAL_CONTEXT_FACTORY, AMQ_NAMING_FACTORY);
189       environment.put(InitialContext.PROVIDER_URL, configuration.getProperty(ActiveMQConfigurator.AMQ_BROKER_URL));
190       environment.put(ActiveMQConfigurator.AMQ_BROKER_URL, configuration.getProperty(ActiveMQConfigurator.AMQ_BROKER_URL));
191       // Use appropriate prefix depending on queue/topic nature.
192       if (isQueue)
193          environment.put(AMQ_QUEUE_PREFIX + name, name);
194       else
195          environment.put(AMQ_TOPIC_PREFIX + name, name);
196       return environment;
197    }
198 }