001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.client;
022
023 import java.net.URISyntaxException;
024
025 import javax.jms.Destination;
026 import javax.naming.NamingException;
027 import javax.naming.Reference;
028 import javax.naming.Referenceable;
029 import javax.naming.StringRefAddr;
030
031 import org.apache.qpid.exchange.ExchangeDefaults;
032 import org.apache.qpid.framing.AMQShortString;
033 import org.apache.qpid.url.AMQBindingURL;
034 import org.apache.qpid.url.BindingURL;
035 import org.apache.qpid.url.URLHelper;
036
037
038 public abstract class AMQDestination implements Destination, Referenceable
039 {
040 protected final AMQShortString _exchangeName;
041
042 protected final AMQShortString _exchangeClass;
043
044 protected final boolean _isDurable;
045
046 protected final boolean _isExclusive;
047
048 protected final boolean _isAutoDelete;
049
050 private AMQShortString _queueName;
051
052 private AMQShortString _routingKey;
053
054 private AMQShortString[] _bindingKeys;
055
056 private String _url;
057 private AMQShortString _urlAsShortString;
058
059 private boolean _checkedForQueueBinding;
060
061 private boolean _exchangeExistsChecked;
062
063 private byte[] _byteEncoding;
064 private static final int IS_DURABLE_MASK = 0x1;
065 private static final int IS_EXCLUSIVE_MASK = 0x2;
066 private static final int IS_AUTODELETE_MASK = 0x4;
067
068 public static final int QUEUE_TYPE = 1;
069 public static final int TOPIC_TYPE = 2;
070 public static final int UNKNOWN_TYPE = 3;
071
072 protected AMQDestination(String url) throws URISyntaxException
073 {
074 this(new AMQBindingURL(url));
075 }
076
077 protected AMQDestination(BindingURL binding)
078 {
079 _exchangeName = binding.getExchangeName();
080 _exchangeClass = binding.getExchangeClass();
081
082 _isExclusive = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_EXCLUSIVE));
083 _isAutoDelete = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_AUTODELETE));
084 _isDurable = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_DURABLE));
085 _queueName = binding.getQueueName() == null ? null : binding.getQueueName();
086 _routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey();
087 _bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys();
088 }
089
090 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName)
091 {
092 this(exchangeName, exchangeClass, routingKey, false, false, queueName, null);
093 }
094
095 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName, AMQShortString[] bindingKeys)
096 {
097 this(exchangeName, exchangeClass, routingKey, false, false, queueName,bindingKeys);
098 }
099
100 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName)
101 {
102 this(exchangeName, exchangeClass, destinationName, false, false, null,null);
103 }
104
105 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
106 boolean isAutoDelete, AMQShortString queueName)
107 {
108 this(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, false,null);
109 }
110
111 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
112 boolean isAutoDelete, AMQShortString queueName,AMQShortString[] bindingKeys)
113 {
114 this(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, false,bindingKeys);
115 }
116
117 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
118 boolean isAutoDelete, AMQShortString queueName, boolean isDurable){
119 this (exchangeName, exchangeClass, routingKey, isExclusive,isAutoDelete,queueName,isDurable,null);
120 }
121
122 protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
123 boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys)
124 {
125 if ( (ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(exchangeClass) ||
126 ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(exchangeClass))
127 && routingKey == null)
128 {
129 throw new IllegalArgumentException("routing/binding key must not be null");
130 }
131 if (exchangeName == null)
132 {
133 throw new IllegalArgumentException("Exchange name must not be null");
134 }
135 if (exchangeClass == null)
136 {
137 throw new IllegalArgumentException("Exchange class must not be null");
138 }
139 _exchangeName = exchangeName;
140 _exchangeClass = exchangeClass;
141 _routingKey = routingKey;
142 _isExclusive = isExclusive;
143 _isAutoDelete = isAutoDelete;
144 _queueName = queueName;
145 _isDurable = isDurable;
146 _bindingKeys = bindingKeys == null || bindingKeys.length == 0 ? new AMQShortString[0] : bindingKeys;
147 }
148
149 public AMQShortString getEncodedName()
150 {
151 if(_urlAsShortString == null)
152 {
153 toURL();
154 }
155 return _urlAsShortString;
156 }
157
158 public boolean isDurable()
159 {
160 return _isDurable;
161 }
162
163 public AMQShortString getExchangeName()
164 {
165 return _exchangeName;
166 }
167
168 public AMQShortString getExchangeClass()
169 {
170 return _exchangeClass;
171 }
172
173 public boolean isTopic()
174 {
175 return ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(_exchangeClass);
176 }
177
178 public boolean isQueue()
179 {
180 return ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(_exchangeClass);
181 }
182
183 public String getQueueName()
184 {
185 return _queueName == null ? null : _queueName.toString();
186 }
187
188 public AMQShortString getAMQQueueName()
189 {
190 return _queueName;
191 }
192
193 public void setQueueName(AMQShortString queueName)
194 {
195
196 _queueName = queueName;
197 // calculated URL now out of date
198 _url = null;
199 _urlAsShortString = null;
200 _byteEncoding = null;
201 }
202
203 public AMQShortString getRoutingKey()
204 {
205 return _routingKey;
206 }
207
208 public AMQShortString[] getBindingKeys()
209 {
210 if (_bindingKeys != null && _bindingKeys.length > 0)
211 {
212 return _bindingKeys;
213 }
214 else
215 {
216 // catering to the common use case where the
217 //routingKey is the same as the bindingKey.
218 return new AMQShortString[]{_routingKey};
219 }
220 }
221
222 public boolean isExclusive()
223 {
224 return _isExclusive;
225 }
226
227 public boolean isAutoDelete()
228 {
229 return _isAutoDelete;
230 }
231
232 public abstract boolean isNameRequired();
233
234 public String toString()
235 {
236 return toURL();
237
238 }
239
240 public boolean isCheckedForQueueBinding()
241 {
242 return _checkedForQueueBinding;
243 }
244
245 public void setCheckedForQueueBinding(boolean checkedForQueueBinding)
246 {
247 _checkedForQueueBinding = checkedForQueueBinding;
248 }
249
250
251 public boolean isExchangeExistsChecked()
252 {
253 return _exchangeExistsChecked;
254 }
255
256 public void setExchangeExistsChecked(final boolean exchangeExistsChecked)
257 {
258 _exchangeExistsChecked = exchangeExistsChecked;
259 }
260
261 public String toURL()
262 {
263 String url = _url;
264 if(url == null)
265 {
266
267
268 StringBuffer sb = new StringBuffer();
269
270 sb.append(_exchangeClass);
271 sb.append("://");
272 sb.append(_exchangeName);
273
274 sb.append("/"+_routingKey+"/");
275
276 if (_queueName != null)
277 {
278 sb.append(_queueName);
279 }
280
281 sb.append('?');
282
283 if (_routingKey != null)
284 {
285 sb.append(BindingURL.OPTION_ROUTING_KEY);
286 sb.append("='");
287 sb.append(_routingKey).append("'");
288 sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
289 }
290
291 // We can't allow both routingKey and bindingKey
292 if (_routingKey == null && _bindingKeys != null && _bindingKeys.length>0)
293 {
294
295 for (AMQShortString bindingKey:_bindingKeys)
296 {
297 sb.append(BindingURL.OPTION_BINDING_KEY);
298 sb.append("='");
299 sb.append(bindingKey);
300 sb.append("'");
301 sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
302
303 }
304 }
305
306 if (_isDurable)
307 {
308 sb.append(BindingURL.OPTION_DURABLE);
309 sb.append("='true'");
310 sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
311 }
312
313 if (_isExclusive)
314 {
315 sb.append(BindingURL.OPTION_EXCLUSIVE);
316 sb.append("='true'");
317 sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
318 }
319
320 if (_isAutoDelete)
321 {
322 sb.append(BindingURL.OPTION_AUTODELETE);
323 sb.append("='true'");
324 sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
325 }
326
327 //removeKey the last char '?' if there is no options , ',' if there are.
328 sb.deleteCharAt(sb.length() - 1);
329 url = sb.toString();
330 _url = url;
331 _urlAsShortString = new AMQShortString(url);
332 }
333 return url;
334 }
335
336 public byte[] toByteEncoding()
337 {
338 byte[] encoding = _byteEncoding;
339 if(encoding == null)
340 {
341 int size = _exchangeClass.length() + 1 +
342 _exchangeName.length() + 1 +
343 0 + // in place of the destination name
344 (_queueName == null ? 0 : _queueName.length()) + 1 +
345 1;
346 encoding = new byte[size];
347 int pos = 0;
348
349 pos = _exchangeClass.writeToByteArray(encoding, pos);
350 pos = _exchangeName.writeToByteArray(encoding, pos);
351
352 encoding[pos++] = (byte)0;
353
354 if(_queueName == null)
355 {
356 encoding[pos++] = (byte)0;
357 }
358 else
359 {
360 pos = _queueName.writeToByteArray(encoding,pos);
361 }
362 byte options = 0;
363 if(_isDurable)
364 {
365 options |= IS_DURABLE_MASK;
366 }
367 if(_isExclusive)
368 {
369 options |= IS_EXCLUSIVE_MASK;
370 }
371 if(_isAutoDelete)
372 {
373 options |= IS_AUTODELETE_MASK;
374 }
375 encoding[pos] = options;
376
377
378 _byteEncoding = encoding;
379
380 }
381 return encoding;
382 }
383
384 public boolean equals(Object o)
385 {
386 if (this == o)
387 {
388 return true;
389 }
390 if (o == null || getClass() != o.getClass())
391 {
392 return false;
393 }
394
395 final AMQDestination that = (AMQDestination) o;
396
397 if (!_exchangeClass.equals(that._exchangeClass))
398 {
399 return false;
400 }
401 if (!_exchangeName.equals(that._exchangeName))
402 {
403 return false;
404 }
405 if ((_queueName == null && that._queueName != null) ||
406 (_queueName != null && !_queueName.equals(that._queueName)))
407 {
408 return false;
409 }
410
411 return true;
412 }
413
414 public int hashCode()
415 {
416 int result;
417 result = _exchangeName.hashCode();
418 result = 29 * result + _exchangeClass.hashCode();
419 //result = 29 * result + _destinationName.hashCode();
420 if (_queueName != null)
421 {
422 result = 29 * result + _queueName.hashCode();
423 }
424
425 return result;
426 }
427
428 public Reference getReference() throws NamingException
429 {
430 return new Reference(
431 this.getClass().getName(),
432 new StringRefAddr(this.getClass().getName(), toURL()),
433 AMQConnectionFactory.class.getName(),
434 null); // factory location
435 }
436
437
438 public static Destination createDestination(byte[] byteEncodedDestination)
439 {
440 AMQShortString exchangeClass;
441 AMQShortString exchangeName;
442 AMQShortString routingKey;
443 AMQShortString queueName;
444 boolean isDurable;
445 boolean isExclusive;
446 boolean isAutoDelete;
447
448 int pos = 0;
449 exchangeClass = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
450 pos+= exchangeClass.length() + 1;
451 exchangeName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
452 pos+= exchangeName.length() + 1;
453 routingKey = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
454 pos+= (routingKey == null ? 0 : routingKey.length()) + 1;
455 queueName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
456 pos+= (queueName == null ? 0 : queueName.length()) + 1;
457 int options = byteEncodedDestination[pos];
458 isDurable = (options & IS_DURABLE_MASK) != 0;
459 isExclusive = (options & IS_EXCLUSIVE_MASK) != 0;
460 isAutoDelete = (options & IS_AUTODELETE_MASK) != 0;
461
462 if (exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
463 {
464 return new AMQQueue(exchangeName,routingKey,queueName,isExclusive,isAutoDelete,isDurable);
465 }
466 else if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
467 {
468 return new AMQTopic(exchangeName,routingKey,isAutoDelete,queueName,isDurable);
469 }
470 else if (exchangeClass.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
471 {
472 return new AMQHeadersExchange(routingKey);
473 }
474 else
475 {
476 return new AMQAnyDestination(exchangeName,exchangeClass,
477 routingKey,isExclusive,
478 isAutoDelete,queueName,
479 isDurable, new AMQShortString[0]);
480 }
481
482 }
483
484 public static Destination createDestination(BindingURL binding)
485 {
486 AMQShortString type = binding.getExchangeClass();
487
488 if (type.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
489 {
490 return new AMQQueue(binding);
491 }
492 else if (type.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
493 {
494 return new AMQTopic(binding);
495 }
496 else if (type.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
497 {
498 return new AMQHeadersExchange(binding);
499 }
500 else
501 {
502 return new AMQAnyDestination(binding);
503 }
504 }
505 }
|