blob: 750599b3508b2eebe0d8ea54d33a01da9e472d46 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.qpid.client;
import java.net.URISyntaxException;
import javax.jms.Destination;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.url.AMQBindingURL;
import org.apache.qpid.url.BindingURL;
import org.apache.qpid.url.URLHelper;
public abstract class AMQDestination implements Destination, Referenceable
{
protected final AMQShortString _exchangeName;
protected final AMQShortString _exchangeClass;
protected final boolean _isDurable;
protected final boolean _isExclusive;
protected final boolean _isAutoDelete;
private AMQShortString _queueName;
private AMQShortString _routingKey;
private AMQShortString[] _bindingKeys;
private String _url;
private AMQShortString _urlAsShortString;
private boolean _checkedForQueueBinding;
private boolean _exchangeExistsChecked;
private byte[] _byteEncoding;
private static final int IS_DURABLE_MASK = 0x1;
private static final int IS_EXCLUSIVE_MASK = 0x2;
private static final int IS_AUTODELETE_MASK = 0x4;
public static final int QUEUE_TYPE = 1;
public static final int TOPIC_TYPE = 2;
public static final int UNKNOWN_TYPE = 3;
protected AMQDestination(String url) throws URISyntaxException
{
this(new AMQBindingURL(url));
}
protected AMQDestination(BindingURL binding)
{
_exchangeName = binding.getExchangeName();
_exchangeClass = binding.getExchangeClass();
_isExclusive = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_EXCLUSIVE));
_isAutoDelete = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_AUTODELETE));
_isDurable = Boolean.parseBoolean(binding.getOption(BindingURL.OPTION_DURABLE));
_queueName = binding.getQueueName() == null ? null : binding.getQueueName();
_routingKey = binding.getRoutingKey() == null ? null : binding.getRoutingKey();
_bindingKeys = binding.getBindingKeys() == null || binding.getBindingKeys().length == 0 ? new AMQShortString[0] : binding.getBindingKeys();
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName)
{
this(exchangeName, exchangeClass, routingKey, false, false, queueName, null);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, AMQShortString queueName, AMQShortString[] bindingKeys)
{
this(exchangeName, exchangeClass, routingKey, false, false, queueName,bindingKeys);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString destinationName)
{
this(exchangeName, exchangeClass, destinationName, false, false, null,null);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName)
{
this(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, false,null);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName,AMQShortString[] bindingKeys)
{
this(exchangeName, exchangeClass, routingKey, isExclusive, isAutoDelete, queueName, false,bindingKeys);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName, boolean isDurable){
this (exchangeName, exchangeClass, routingKey, isExclusive,isAutoDelete,queueName,isDurable,null);
}
protected AMQDestination(AMQShortString exchangeName, AMQShortString exchangeClass, AMQShortString routingKey, boolean isExclusive,
boolean isAutoDelete, AMQShortString queueName, boolean isDurable,AMQShortString[] bindingKeys)
{
// If used with a fannout exchange, the routing key can be null
if ( !ExchangeDefaults.FANOUT_EXCHANGE_CLASS.equals(exchangeClass) && routingKey == null)
{
throw new IllegalArgumentException("routingKey exchange must not be null");
}
if (exchangeName == null)
{
throw new IllegalArgumentException("Exchange name must not be null");
}
if (exchangeClass == null)
{
throw new IllegalArgumentException("Exchange class must not be null");
}
_exchangeName = exchangeName;
_exchangeClass = exchangeClass;
_routingKey = routingKey;
_isExclusive = isExclusive;
_isAutoDelete = isAutoDelete;
_queueName = queueName;
_isDurable = isDurable;
_bindingKeys = bindingKeys == null || bindingKeys.length == 0 ? new AMQShortString[0] : bindingKeys;
}
public AMQShortString getEncodedName()
{
if(_urlAsShortString == null)
{
toURL();
}
return _urlAsShortString;
}
public boolean isDurable()
{
return _isDurable;
}
public AMQShortString getExchangeName()
{
return _exchangeName;
}
public AMQShortString getExchangeClass()
{
return _exchangeClass;
}
public boolean isTopic()
{
return ExchangeDefaults.TOPIC_EXCHANGE_CLASS.equals(_exchangeClass);
}
public boolean isQueue()
{
return ExchangeDefaults.DIRECT_EXCHANGE_CLASS.equals(_exchangeClass);
}
public String getQueueName()
{
return _queueName == null ? null : _queueName.toString();
}
public AMQShortString getAMQQueueName()
{
return _queueName;
}
public void setQueueName(AMQShortString queueName)
{
_queueName = queueName;
// calculated URL now out of date
_url = null;
_urlAsShortString = null;
_byteEncoding = null;
}
public AMQShortString getRoutingKey()
{
return _routingKey;
}
public AMQShortString[] getBindingKeys()
{
if (_bindingKeys != null && _bindingKeys.length > 0)
{
return _bindingKeys;
}
else
{
// catering to the common use case where the
//routingKey is the same as the bindingKey.
return new AMQShortString[]{_routingKey};
}
}
public boolean isExclusive()
{
return _isExclusive;
}
public boolean isAutoDelete()
{
return _isAutoDelete;
}
public abstract boolean isNameRequired();
public String toString()
{
return toURL();
}
public boolean isCheckedForQueueBinding()
{
return _checkedForQueueBinding;
}
public void setCheckedForQueueBinding(boolean checkedForQueueBinding)
{
_checkedForQueueBinding = checkedForQueueBinding;
}
public boolean isExchangeExistsChecked()
{
return _exchangeExistsChecked;
}
public void setExchangeExistsChecked(final boolean exchangeExistsChecked)
{
_exchangeExistsChecked = exchangeExistsChecked;
}
public String toURL()
{
String url = _url;
if(url == null)
{
StringBuffer sb = new StringBuffer();
sb.append(_exchangeClass);
sb.append("://");
sb.append(_exchangeName);
sb.append("/"+_routingKey+"/");
if (_queueName != null)
{
sb.append(_queueName);
}
sb.append('?');
if (_routingKey != null)
{
sb.append(BindingURL.OPTION_ROUTING_KEY);
sb.append("='");
sb.append(_routingKey).append("'");
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
// We can't allow both routingKey and bindingKey
if (_routingKey == null && _bindingKeys != null && _bindingKeys.length>0)
{
for (AMQShortString bindingKey:_bindingKeys)
{
sb.append(BindingURL.OPTION_BINDING_KEY);
sb.append("='");
sb.append(bindingKey);
sb.append("'");
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
}
if (_isDurable)
{
sb.append(BindingURL.OPTION_DURABLE);
sb.append("='true'");
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
if (_isExclusive)
{
sb.append(BindingURL.OPTION_EXCLUSIVE);
sb.append("='true'");
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
if (_isAutoDelete)
{
sb.append(BindingURL.OPTION_AUTODELETE);
sb.append("='true'");
sb.append(URLHelper.DEFAULT_OPTION_SEPERATOR);
}
//removeKey the last char '?' if there is no options , ',' if there are.
sb.deleteCharAt(sb.length() - 1);
url = sb.toString();
_url = url;
_urlAsShortString = new AMQShortString(url);
}
return url;
}
public byte[] toByteEncoding()
{
byte[] encoding = _byteEncoding;
if(encoding == null)
{
int size = _exchangeClass.length() + 1 +
_exchangeName.length() + 1 +
0 + // in place of the destination name
(_queueName == null ? 0 : _queueName.length()) + 1 +
1;
encoding = new byte[size];
int pos = 0;
pos = _exchangeClass.writeToByteArray(encoding, pos);
pos = _exchangeName.writeToByteArray(encoding, pos);
encoding[pos++] = (byte)0;
if(_queueName == null)
{
encoding[pos++] = (byte)0;
}
else
{
pos = _queueName.writeToByteArray(encoding,pos);
}
byte options = 0;
if(_isDurable)
{
options |= IS_DURABLE_MASK;
}
if(_isExclusive)
{
options |= IS_EXCLUSIVE_MASK;
}
if(_isAutoDelete)
{
options |= IS_AUTODELETE_MASK;
}
encoding[pos] = options;
_byteEncoding = encoding;
}
return encoding;
}
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
final AMQDestination that = (AMQDestination) o;
if (!_exchangeClass.equals(that._exchangeClass))
{
return false;
}
if (!_exchangeName.equals(that._exchangeName))
{
return false;
}
if ((_queueName == null && that._queueName != null) ||
(_queueName != null && !_queueName.equals(that._queueName)))
{
return false;
}
return true;
}
public int hashCode()
{
int result;
result = _exchangeName.hashCode();
result = 29 * result + _exchangeClass.hashCode();
//result = 29 * result + _destinationName.hashCode();
if (_queueName != null)
{
result = 29 * result + _queueName.hashCode();
}
return result;
}
public Reference getReference() throws NamingException
{
return new Reference(
this.getClass().getName(),
new StringRefAddr(this.getClass().getName(), toURL()),
AMQConnectionFactory.class.getName(),
null); // factory location
}
public static Destination createDestination(byte[] byteEncodedDestination)
{
AMQShortString exchangeClass;
AMQShortString exchangeName;
AMQShortString routingKey;
AMQShortString queueName;
boolean isDurable;
boolean isExclusive;
boolean isAutoDelete;
int pos = 0;
exchangeClass = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
pos+= exchangeClass.length() + 1;
exchangeName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
pos+= exchangeName.length() + 1;
routingKey = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
pos+= (routingKey == null ? 0 : routingKey.length()) + 1;
queueName = AMQShortString.readFromByteArray(byteEncodedDestination, pos);
pos+= (queueName == null ? 0 : queueName.length()) + 1;
int options = byteEncodedDestination[pos];
isDurable = (options & IS_DURABLE_MASK) != 0;
isExclusive = (options & IS_EXCLUSIVE_MASK) != 0;
isAutoDelete = (options & IS_AUTODELETE_MASK) != 0;
if (exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
{
return new AMQQueue(exchangeName,routingKey,queueName,isExclusive,isAutoDelete,isDurable);
}
else if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
{
return new AMQTopic(exchangeName,routingKey,isAutoDelete,queueName,isDurable);
}
else if (exchangeClass.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
{
return new AMQHeadersExchange(routingKey);
}
else
{
throw new IllegalArgumentException("Unknown Exchange Class:" + exchangeClass);
}
}
public static Destination createDestination(BindingURL binding)
{
AMQShortString type = binding.getExchangeClass();
if (type.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
{
return new AMQQueue(binding);
}
else if (type.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
{
return new AMQTopic(binding);
}
else if (type.equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
{
return new AMQHeadersExchange(binding);
}
else if (type.equals(ExchangeDefaults.FANOUT_EXCHANGE_CLASS))
{
return new AMQQueue(binding);
}
else
{
throw new IllegalArgumentException("Unknown Exchange Class:" + type + " in binding:" + binding);
}
}
}