View Javadoc

1   /*** 
2    * 
3    * Copyright 2004 Protique Ltd
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License"); 
6    * you may not use this file except in compliance with the License. 
7    * You may obtain a copy of the License at 
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License. 
16   * 
17   **/
18  
19  package org.codehaus.activemq.message;
20  
21  import org.codehaus.activemq.filter.DestinationFilter;
22  import org.codehaus.activemq.jndi.JNDIBaseStorable;
23  
24  import javax.jms.Destination;
25  import javax.jms.JMSException;
26  import javax.jms.Queue;
27  import javax.jms.TemporaryQueue;
28  import javax.jms.TemporaryTopic;
29  import javax.jms.Topic;
30  import java.io.DataInput;
31  import java.io.DataOutput;
32  import java.io.IOException;
33  import java.io.Serializable;
34  import java.util.Properties;
35  
36  /***
37   * A <CODE>Destination</CODE> object encapsulates a provider-specific
38   * address.
39   * The JMS API does not define a standard address syntax. Although a standard
40   * address syntax was considered, it was decided that the differences in
41   * address semantics between existing message-oriented middleware (MOM)
42   * products were too wide to bridge with a single syntax.
43   * <p/>
44   * <P>Since <CODE>Destination</CODE> is an administered object, it may
45   * contain
46   * provider-specific configuration information in addition to its address.
47   * <p/>
48   * <P>The JMS API also supports a client's use of provider-specific address
49   * names.
50   * <p/>
51   * <P><CODE>Destination</CODE> objects support concurrent use.
52   * <p/>
53   * <P>A <CODE>Destination</CODE> object is a JMS administered object.
54   * <p/>
55   * <P>JMS administered objects are objects containing configuration
56   * information that are created by an administrator and later used by
57   * JMS clients. They make it practical to administer the JMS API in the
58   * enterprise.
59   * <p/>
60   * <P>Although the interfaces for administered objects do not explicitly
61   * depend on the Java Naming and Directory Interface (JNDI) API, the JMS API
62   * establishes the convention that JMS clients find administered objects by
63   * looking them up in a JNDI namespace.
64   * <p/>
65   * <P>An administrator can place an administered object anywhere in a
66   * namespace. The JMS API does not define a naming policy.
67   * <p/>
68   * <P>It is expected that JMS providers will provide the tools an
69   * administrator needs to create and configure administered objects in a
70   * JNDI namespace. JMS provider implementations of administered objects
71   * should implement the <CODE>javax.naming.Referenceable</CODE> and
72   * <CODE>java.io.Serializable</CODE> interfaces so that they can be stored in
73   * all JNDI naming contexts. In addition, it is recommended that these
74   * implementations follow the JavaBeans<SUP><FONT SIZE="-2">TM</FONT></SUP>
75   * design patterns.
76   * <p/>
77   * <P>This strategy provides several benefits:
78   * <p/>
79   * <UL>
80   * <LI>It hides provider-specific details from JMS clients.
81   * <LI>It abstracts JMS administrative information into objects in the Java
82   * programming language ("Java objects")
83   * that are easily organized and administered from a common
84   * management console.
85   * <LI>Since there will be JNDI providers for all popular naming
86   * services, JMS providers can deliver one implementation
87   * of administered objects that will run everywhere.
88   * </UL>
89   * <p/>
90   * <P>An administered object should not hold on to any remote resources.
91   * Its lookup should not use remote resources other than those used by the
92   * JNDI API itself.
93   * <p/>
94   * <P>Clients should think of administered objects as local Java objects.
95   * Looking them up should not have any hidden side effects or use surprising
96   * amounts of local resources.
97   */
98  
99  public abstract class ActiveMQDestination extends JNDIBaseStorable implements Destination, Comparable, Serializable {
100 
101     private static final int NULL_DESTINATION = 10;
102     private static final String TEMP_PREFIX = "{TD{";
103     private static final String TEMP_POSTFIX = "}TD}";
104 
105     /***
106      * A helper method to return a descriptive string for the topic or queue
107      *
108      * @return a descriptive string for this queue or topic
109      */
110     public static String inspect(Destination destination) {
111         if (destination instanceof Topic) {
112             return "Topic(" + destination.toString() + ")";
113         }
114         else {
115             return "Queue(" + destination.toString() + ")";
116         }
117     }
118 
119     /***
120      * Topic Destination object
121      */
122     public static final int ACTIVEMQ_TOPIC = 1;
123     /***
124      * Temporary Topic Destination object
125      */
126     public static final int ACTIVEMQ_TEMPORARY_TOPIC = 2;
127 
128     /***
129      * Queue Destination object
130      */
131     public static final int ACTIVEMQ_QUEUE = 3;
132     /***
133      * Temporary Queue Destination object
134      */
135     public static final int ACTIVEMQ_TEMPORARY_QUEUE = 4;
136 
137 
138     private String physicalName;
139 
140     /***
141      * The Default Constructor
142      */
143     protected ActiveMQDestination() {
144     }
145 
146     /***
147      * Construct the ActiveMQDestination with a defined physical name;
148      *
149      * @param name
150      */
151 
152     protected ActiveMQDestination(String name) {
153         this.physicalName = name;
154     }
155 
156     /***
157      * @param o object to compare
158      * @return 1 if this > o else 0 if they are equal or -1 if this < o
159      */
160     public int compareTo(Object o) {
161         if (o instanceof ActiveMQDestination) {
162             return compareTo((ActiveMQDestination) o);
163         }
164         return -1;
165     }
166 
167     /***
168      * Lets sort by name first then lets sort topics greater than queues
169      *
170      * @param that another destination to compare against
171      * @return 1 if this > that else 0 if they are equal or -1 if this < that
172      */
173     public int compareTo(ActiveMQDestination that) {
174         int answer = 0;
175         if (physicalName != that.physicalName) {
176             if (physicalName == null) {
177                 return -1;
178             }
179             else if (that.physicalName == null) {
180                 return 1;
181             }
182             answer = physicalName.compareTo(that.physicalName);
183         }
184         if (answer == 0) {
185             if (isTopic()) {
186                 if (that.isQueue()) {
187                     return 1;
188                 }
189             }
190             else {
191                 if (that.isTopic()) {
192                     return -1;
193                 }
194             }
195         }
196         return answer;
197     }
198 
199 
200     /***
201      * @return Returns the Destination type
202      */
203 
204     public abstract int getDestinationType();
205 
206 
207     /***
208      * @return Returns the physicalName.
209      */
210     public String getPhysicalName() {
211         return this.physicalName;
212     }
213 
214     /***
215      * @param newPhysicalName The physicalName to set.
216      */
217     public void setPhysicalName(String newPhysicalName) {
218         this.physicalName = newPhysicalName;
219     }
220 
221     /***
222      * Set the properties that will represent the instance in JNDI
223      *
224      * @param props
225      */
226     protected void buildFromProperties(Properties props) {
227         this.physicalName = props.getProperty("physicalName", this.physicalName);
228 
229     }
230 
231     /***
232      * Initialize the instance from properties stored in JNDI
233      *
234      * @param props
235      */
236 
237     protected void populateProperties(Properties props) {
238         props.put("physicalName", this.physicalName);
239     }
240 
241     /***
242      * Returns true if a temporary Destination
243      *
244      * @return true/false
245      */
246 
247     public boolean isTemporary() {
248         return getDestinationType() == ACTIVEMQ_TEMPORARY_TOPIC ||
249                 getDestinationType() == ACTIVEMQ_TEMPORARY_QUEUE;
250     }
251 
252     /***
253      * Returns true if a Topic Destination
254      *
255      * @return true/false
256      */
257 
258     public boolean isTopic() {
259         return getDestinationType() == ACTIVEMQ_TOPIC ||
260                 getDestinationType() == ACTIVEMQ_TEMPORARY_TOPIC;
261     }
262 
263     /***
264      * Returns true if a Queue Destination
265      *
266      * @return true/false
267      */
268     public boolean isQueue() {
269         return !isTopic();
270     }
271 
272     /***
273      * @return string representation of this instance
274      */
275 
276     public String toString() {
277         return this.physicalName;
278     }
279 
280     /***
281      * @return hashCode for this instance
282      */
283 
284     public int hashCode() {
285         int answer = 0xcafebabe;
286 
287         if (this.physicalName != null) {
288             answer = physicalName.hashCode();
289         }
290         if (isTopic()) {
291             answer ^= 0xfabfab;
292         }
293         return answer;
294     }
295 
296     /***
297      * if the object passed in is equivalent, return true
298      *
299      * @param obj the object to compare
300      * @return true if this instance and obj are equivalent
301      */
302 
303     public boolean equals(Object obj) {
304         boolean result = this == obj;
305         if (!result && obj != null && obj instanceof ActiveMQDestination) {
306             ActiveMQDestination other = (ActiveMQDestination) obj;
307             result = this.getDestinationType() == other.getDestinationType() &&
308                     this.physicalName.equals(other.physicalName);
309         }
310         return result;
311     }
312 
313     /***
314      * Write an ActiveMQDestination to a Stream
315      *
316      * @param destination
317      * @param dataOut
318      * @throws IOException
319      */
320 
321     public static void writeToStream(ActiveMQDestination destination, DataOutput dataOut) throws IOException {
322         if (destination != null) {
323             dataOut.write(destination.getDestinationType());
324             dataOut.writeUTF(destination == null ? "" : destination.getPhysicalName());
325         }
326         else {
327             dataOut.write(NULL_DESTINATION);
328         }
329     }
330 
331     /***
332      * Read an ActiveMQDestination  from a Stream
333      *
334      * @param dataIn
335      * @return the ActiveMQDestination
336      * @throws IOException
337      */
338 
339     public static ActiveMQDestination readFromStream(DataInput dataIn) throws IOException {
340 
341         int type = dataIn.readByte();
342         if (type == NULL_DESTINATION) {
343             return null;
344         }
345         ActiveMQDestination result = null;
346         if (type == ACTIVEMQ_TOPIC) {
347             result = new ActiveMQTopic();
348         }
349         else if (type == ACTIVEMQ_TEMPORARY_TOPIC) {
350             result = new ActiveMQTemporaryTopic();
351         }
352         else if (type == ACTIVEMQ_QUEUE) {
353             result = new ActiveMQQueue();
354         }
355         else {
356             result = new ActiveMQTemporaryQueue();
357         }
358         result.setPhysicalName(dataIn.readUTF());
359         return result;
360 
361     }
362 
363     /***
364      * Create a temporary name from the clientId
365      *
366      * @param clientId
367      * @return
368      */
369     public static String createTemporaryName(String clientId) {
370         return TEMP_PREFIX + clientId + TEMP_POSTFIX;
371     }
372 
373     /***
374      * From a temporary destination find the clientId of the Connection that created it
375      *
376      * @param destination
377      * @return the clientId or null if not a temporary destination
378      */
379     public static String getClientId(ActiveMQDestination destination) {
380         String answer = null;
381         if (destination != null && destination.isTemporary()) {
382             String name = destination.getPhysicalName();
383             int start = name.indexOf(TEMP_PREFIX);
384             if (start >= 0) {
385                 start += TEMP_PREFIX.length();
386                 int stop = name.lastIndexOf(TEMP_POSTFIX);
387                 if (stop > start && stop < name.length()) {
388                     answer = name.substring(start, stop);
389                 }
390             }
391         }
392         return answer;
393     }
394 
395     /***
396      * @return true if the destination matches multiple possible destinations
397      */
398     public boolean isWildcard() {
399         if (physicalName != null) {
400             return physicalName.indexOf(DestinationFilter.ANY_CHILD) >= 0
401                     || physicalName.indexOf(DestinationFilter.ANY_DESCENDENT) >= 0;
402         }
403         return false;
404     }
405 
406     /***
407      * @param destination
408      * @return @throws JMSException
409      * @throws javax.jms.JMSException
410      */
411     public static ActiveMQDestination transformDestination(Destination destination) throws JMSException {
412         ActiveMQDestination result = null;
413         if (destination != null) {
414             if (destination instanceof ActiveMQDestination) {
415                 result = (ActiveMQDestination) destination;
416             }
417             else {
418                 if (destination instanceof TemporaryQueue) {
419                     result = new ActiveMQTemporaryQueue(((Queue) destination).getQueueName());
420                 }
421                 else if (destination instanceof TemporaryTopic) {
422                     result = new ActiveMQTemporaryTopic(((Topic) destination).getTopicName());
423                 }
424                 else if (destination instanceof Queue) {
425                     result = new ActiveMQTemporaryQueue(((Queue) destination).getQueueName());
426                 }
427                 else if (destination instanceof Topic) {
428                     result = new ActiveMQTemporaryTopic(((Topic) destination).getTopicName());
429                 }
430             }
431         }
432         return result;
433     }
434 }