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
83 public static final String WILDCARD = "*";
84
85
86 public static final String ALL_WILDCARD = "**";
87
88
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
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
132 public void writeExternal(ObjectOutput stream)
133 throws IOException {
134 stream.writeLong(serialVersionUID);
135 super.writeExternal(stream);
136 }
137
138
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
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
173
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
183
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
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
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
255 matches = true;
256 break;
257 } else if (wildToken.equals(WILDCARD)) {
258
259 matches = true;
260 continue;
261 } else if (wildToken.equals(topicToken)) {
262
263 matches = true;
264 continue;
265 } else {
266
267 matches = false;
268 break;
269 }
270 }
271 }
272 }
273
274 return matches;
275 }
276
277
278 public Reference getReference() {
279 Reference reference = null;
280
281
282 reference = new Reference(JmsTopic.class.getName(),
283 new StringRefAddr("name", getName()),
284 JmsDestinationFactory.class.getName(), null);
285
286
287 reference.add(new StringRefAddr("persistent",
288 (getPersistent() ? "true" : "false")));
289
290 return reference;
291 }
292 }
293