View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Exoffice Technologies.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Exoffice Technologies. Exolab is a registered
23   *    trademark of Exoffice Technologies.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: JmsTopic.java,v 1.1 2004/11/26 01:50:40 tanderson Exp $
44   *
45   * Date         Author  Changes
46   * 3/21/2000    jima    Created
47   */
48  package org.exolab.jms.client;
49  
50  
51  import java.io.Externalizable;
52  import java.io.IOException;
53  import java.io.ObjectInput;
54  import java.io.ObjectOutput;
55  import java.util.StringTokenizer;
56  
57  import javax.jms.JMSException;
58  import javax.jms.Topic;
59  import javax.naming.Reference;
60  import javax.naming.Referenceable;
61  import javax.naming.StringRefAddr;
62  
63  
64  /***
65   * A topic is a destination specific for the puiblish-subscribe messaging
66   * model. OpenJMS also supports topic hierarchy and wild carding.
67   *
68   * @version     $Revision: 1.1 $ $Date: 2004/11/26 01:50:40 $
69   * @author      <a href="mailto:jima@exoffice.com">Jim Alateras</a>
70   * @author      <a href="mailto:mourikis@exoffice.com">Jim Mourikis</a>
71   * @see         org.exolab.jms.client.JmsDestination
72   **/
73  public class JmsTopic
74      extends JmsDestination
75      implements Topic, Externalizable, Referenceable {
76  
77      /***
78       * Used for serialization
79       */
80      static final long serialVersionUID = 1;
81  
82      // The wildcard character.
83      public static final String WILDCARD = "*";
84  
85      //Wilcard for this and subsequent levels
86      public static final String ALL_WILDCARD = "**";
87  
88      // The separator character for each topic level.
89      public static final String SEPARATOR = ".";
90  
91  
92      /***
93       * Need a default constructor for the serialization
94       */
95      public JmsTopic() {
96      }
97  
98      /***
99       * Instantiate an instance of this object with the specified string
100      *
101      * @param       name            name of the queue
102      */
103     public JmsTopic(String name) {
104         super(name);
105     }
106 
107     /***
108      * Return the name of the topic
109      *
110      * @return      name        name of  the topic
111      * @exception   JMSException
112      */
113     public String getTopicName()
114         throws JMSException {
115         return getName();
116     }
117 
118 
119     // implementation of Object.equals(Object)
120     public boolean equals(Object object) {
121         boolean result = false;
122 
123         if ((object instanceof JmsTopic) &&
124             (((JmsTopic) object).getName().equals(this.getName()))) {
125             result = true;
126         }
127 
128         return result;
129     }
130 
131     // implementation of Externalizable.writeExternal
132     public void writeExternal(ObjectOutput stream)
133         throws IOException {
134         stream.writeLong(serialVersionUID);
135         super.writeExternal(stream);
136     }
137 
138     // implementation of Externalizable.writeExternal
139     public void readExternal(ObjectInput stream)
140         throws IOException, ClassNotFoundException {
141         long version = stream.readLong();
142         if (version == serialVersionUID) {
143             super.readExternal(stream);
144         } else {
145             throw new IOException("JmsTopic with version " +
146                 version + " is not supported.");
147         }
148     }
149 
150     // implementation of Object.hashCode
151     public int hashCode() {
152         return getName().hashCode();
153     }
154 
155     /***
156      * Check whether this topic represents a wildcard expression.
157      *
158      * @return boolean true if the topic contains wildcards
159      */
160     public boolean isWildCard() {
161         return isWildCard(this.getName());
162     }
163 
164     /***
165      * A static method which checks a topic to determine whether or not it
166      * complies to a wildcard definition.
167      *
168      * @param topic - the topic to check
169      * @return boolean - true if it does
170      */
171     public static boolean isWildCard(String topic) {
172         // if the topic contains the "**" wildcard ensure that it is
173         // the last item, and no further tokens exist after it.
174         int pos = topic.indexOf(ALL_WILDCARD);
175 
176         if (pos >= 0 && (pos != topic.length() - 2)) {
177             return false;
178         }
179 
180         pos = topic.indexOf(WILDCARD);
181 
182         // if we have any wildcards, tokenize them and ensure that a
183         // "*" or "**" appear on their own with no characters mixed in.
184         if (pos >= 0) {
185             StringTokenizer tokens = new StringTokenizer(topic, SEPARATOR);
186             String token = null;
187 
188             while (tokens.hasMoreTokens()) {
189                 token = tokens.nextToken();
190                 // contains a wildcard
191                 if (token.indexOf(WILDCARD) >= 0) {
192                     if (!(token.equals(WILDCARD) ||
193                         token.equals(ALL_WILDCARD))) {
194                         return false;
195                     }
196                 }
197             }
198         }
199 
200         return (pos >= 0);
201     }
202 
203     /***
204      * If it is a wildcard check to see that it matches the specified topic.
205      *
206      * if wildcard is **, its a an imediate match for every topic.
207      * else
208      *  tokenize both the wildcard and the topic.
209      *  if the wildcard has less or equal no of tokens than the topic and
210      *      ends in "**" check tokens
211      *  if both wildcard and topic contain the same no of tokens check tokens
212      *  Otherwise topic and wildcard do not match so return false.
213      *
214      * <P>Note we treat "a.b.c.*.*" and "a.b.c" as not a match at this stage,
215      * since the wildcard is attempting to match more levels than exist in the
216      * topic. if this proves to be unpopular with the masses, its a very
217      * trivial change below to fix this problem.
218      *
219      * <P>Tokens are compared and must either be identical or the wildcard
220      * token must be a "*" to match at this level. Once a mismatch is detected
221      * the comparison is stopped and a false returned.
222      *
223      * <P>NOTE: This check assumes both the topic and wildcard topic have both
224      * already been validated. if the topics are inavlid this test can return
225      * arbitrary results.
226      *
227      * @param destination The specific topic to match to
228      * @return True if the wildcard matches.
229      */
230     public boolean match(JmsTopic destination) {
231         boolean matches = false;
232         String topic = destination.getName();
233         String wildcard = this.getName();
234         if (wildcard.equals(ALL_WILDCARD)) {
235             // Every topic match.
236             matches = true;
237         } else {
238             StringTokenizer wildTokens =
239                 new StringTokenizer(wildcard, SEPARATOR);
240             StringTokenizer topicTokens =
241                 new StringTokenizer(topic, SEPARATOR);
242             String wildToken = null;
243             String topicToken = null;
244             int tokenCountDiff =
245                 topicTokens.countTokens() - wildTokens.countTokens();
246             if ((tokenCountDiff == 0) ||
247                 (tokenCountDiff == -1) ||
248                 (tokenCountDiff > 0 && wildcard.indexOf(ALL_WILDCARD) >= 0)) {
249                 while (wildTokens.hasMoreTokens() &&
250                     topicTokens.hasMoreTokens()) {
251                     wildToken = wildTokens.nextToken();
252                     topicToken = topicTokens.nextToken();
253                     if (wildToken.equals(ALL_WILDCARD)) {
254                         // we have a match.
255                         matches = true;
256                         break;
257                     } else if (wildToken.equals(WILDCARD)) {
258                         // this token matches.
259                         matches = true;
260                         continue;
261                     } else if (wildToken.equals(topicToken)) {
262                         // this token matches.
263                         matches = true;
264                         continue;
265                     } else {
266                         // no match. No point continuing further.
267                         matches = false;
268                         break;
269                     }
270                 }
271             }
272         }
273 
274         return matches;
275     }
276 
277     // implementation of Referenceable.getReference
278     public Reference getReference() {
279         Reference reference = null;
280 
281         // create the reference
282         reference = new Reference(JmsTopic.class.getName(),
283             new StringRefAddr("name", getName()),
284             JmsDestinationFactory.class.getName(), null);
285 
286         // add the persistence attribute
287         reference.add(new StringRefAddr("persistent",
288             (getPersistent() ? "true" : "false")));
289 
290         return reference;
291     }
292 }
293