blob: 68b63a316f4d9c76920af660cc645ea590ef083c [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.
*/
%module qpid_messaging
%include "std_string.i"
%include "qpid/swig_python_typemaps.i"
/* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't
* convert uint8_t by default. */
%apply unsigned char { uint8_t };
/*
* Exceptions
*
* The convention below is that exceptions in _qpid_messaging.so have the same
* names as in the C++ library. They get renamed to their Python
* equivalents when brought into the Python wrapping
*/
%define QPID_EXCEPTION(exception, parent)
%{
static PyObject* exception;
%}
%init %{
exception = PyErr_NewException(
(char *) ("_qpid_messaging." #exception), parent, NULL);
Py_INCREF(exception);
PyModule_AddObject(m, #exception, exception);
%}
%pythoncode %{
exception = _qpid_messaging. ## exception
%}
%enddef
/* Python equivalents of C++ exceptions. */
/* */
/* Commented out lines are exceptions in the Python library, but not */
/* in the C++ library. */
QPID_EXCEPTION(MessagingError, NULL)
QPID_EXCEPTION(LinkError, MessagingError)
QPID_EXCEPTION(AddressError, LinkError)
QPID_EXCEPTION(ResolutionError, AddressError)
QPID_EXCEPTION(AssertionFailed, ResolutionError)
QPID_EXCEPTION(NotFound, ResolutionError)
QPID_EXCEPTION(InvalidOption, LinkError)
QPID_EXCEPTION(MalformedAddress, LinkError)
QPID_EXCEPTION(ReceiverError, LinkError)
QPID_EXCEPTION(FetchError, ReceiverError)
QPID_EXCEPTION(Empty, FetchError)
/* QPID_EXCEPTION(InsufficientCapacity, LinkError) */
/* QPID_EXCEPTION(LinkClosed, LinkError) */
QPID_EXCEPTION(SenderError, LinkError)
QPID_EXCEPTION(SendError, SenderError)
QPID_EXCEPTION(TargetCapacityExceeded, SendError)
QPID_EXCEPTION(ConnectionError, MessagingError)
QPID_EXCEPTION(ConnectError, ConnectionError)
/* QPID_EXCEPTION(AuthenticationFailure, ConnectError) */
/* QPID_EXCEPTION(VersionError, ConnectError) */
/* QPID_EXCEPTION(ConnectionClosed, ConnectionError) */
/* QPID_EXCEPTION(HeartbeartTimeout, ConnectionError) */
QPID_EXCEPTION(SessionError, MessagingError)
/* QPID_EXCEPTION(Detached, SessionError) */
/* QPID_EXCEPTION(NontransactionalSession, SessionError) */
/* QPID_EXCEPTION(ServerError, SessionError) */
/* QPID_EXCEPTION(SessionClosed, SessionError) */
QPID_EXCEPTION(TransactionError, SessionError)
QPID_EXCEPTION(TransactionAborted, TransactionError)
QPID_EXCEPTION(TransactionUnknown, TransactionError)
QPID_EXCEPTION(UnauthorizedAccess, SessionError)
/* QPID_EXCEPTION(InternalError, MessagingError) */
%define TRANSLATE_EXCEPTION(cpp_exception, py_exception)
catch ( cpp_exception & ex) {
pExceptionType = py_exception;
error = ex.what();
}
%enddef
/* Define the general-purpose exception handling */
%exception {
PyObject * pExceptionType = NULL;
bool failed = true;
std::string error;
Py_BEGIN_ALLOW_THREADS;
try {
$action
failed = false;
}
/* Catch and translate exceptions. */
TRANSLATE_EXCEPTION(qpid::messaging::NoMessageAvailable, Empty)
TRANSLATE_EXCEPTION(qpid::messaging::NotFound, NotFound)
TRANSLATE_EXCEPTION(qpid::messaging::AssertionFailed, AssertionFailed)
TRANSLATE_EXCEPTION(qpid::messaging::ResolutionError, ResolutionError)
TRANSLATE_EXCEPTION(qpid::messaging::TargetCapacityExceeded,
TargetCapacityExceeded)
TRANSLATE_EXCEPTION(qpid::messaging::TransportFailure, ConnectError)
TRANSLATE_EXCEPTION(qpid::messaging::MalformedAddress, MalformedAddress)
TRANSLATE_EXCEPTION(qpid::messaging::AddressError, AddressError)
TRANSLATE_EXCEPTION(qpid::messaging::FetchError, FetchError)
TRANSLATE_EXCEPTION(qpid::messaging::ReceiverError, ReceiverError)
TRANSLATE_EXCEPTION(qpid::messaging::SendError, SendError)
TRANSLATE_EXCEPTION(qpid::messaging::SenderError, SenderError)
TRANSLATE_EXCEPTION(qpid::messaging::InvalidOptionString, InvalidOption)
TRANSLATE_EXCEPTION(qpid::messaging::LinkError, LinkError)
TRANSLATE_EXCEPTION(qpid::messaging::TransactionAborted, TransactionAborted)
TRANSLATE_EXCEPTION(qpid::messaging::TransactionUnknown, TransactionUnknown)
TRANSLATE_EXCEPTION(qpid::messaging::TransactionError, TransactionError)
TRANSLATE_EXCEPTION(qpid::messaging::UnauthorizedAccess, UnauthorizedAccess)
TRANSLATE_EXCEPTION(qpid::messaging::SessionError, SessionError)
TRANSLATE_EXCEPTION(qpid::messaging::ConnectionError, ConnectionError)
TRANSLATE_EXCEPTION(qpid::messaging::KeyError, PyExc_KeyError)
TRANSLATE_EXCEPTION(qpid::messaging::MessagingException, MessagingError)
TRANSLATE_EXCEPTION(qpid::types::Exception, PyExc_RuntimeError)
Py_END_ALLOW_THREADS;
if (failed) {
if (!error.empty()) {
PyErr_SetString(pExceptionType, error.c_str());
}
SWIG_fail;
}
}
/* This only renames the non-const version (I believe). Then again, I
* don't even know why there is a non-const version of the method. */
%rename(opened) qpid::messaging::Connection::isOpen();
%rename(_close) qpid::messaging::Connection::close();
%rename(_receiver) qpid::messaging::Session::createReceiver;
%rename(_sender) qpid::messaging::Session::createSender;
%rename(_acknowledge_all) qpid::messaging::Session::acknowledge(bool);
%rename(_acknowledge_msg) qpid::messaging::Session::acknowledge(
Message &, bool);
%rename(_next_receiver) qpid::messaging::Session::nextReceiver;
%rename(_fetch) qpid::messaging::Receiver::fetch;
%rename(_get) qpid::messaging::Receiver::get;
%rename(unsettled) qpid::messaging::Receiver::getUnsettled;
%rename(available) qpid::messaging::Receiver::getAvailable;
%rename(unsettled) qpid::messaging::Sender::getUnsettled;
%rename(available) qpid::messaging::Sender::getAvailable;
%rename(_send) qpid::messaging::Sender::send;
%rename(_getReplyTo) qpid::messaging::Message::getReplyTo;
%rename(_setReplyTo) qpid::messaging::Message::setReplyTo;
%rename(_getTtl) qpid::messaging::Message::getTtl;
%rename(_setTtl) qpid::messaging::Message::setTtl;
%rename(_sync) qpid::messaging::Session::sync;
// Capitalize constant names correctly for python
%rename(TRACE) qpid::messaging::trace;
%rename(DEBUG) qpid::messaging::debug;
%rename(INFO) qpid::messaging::info;
%rename(NOTICE) qpid::messaging::notice;
%rename(WARNING) qpid::messaging::warning;
%rename(ERROR) qpid::messaging::error;
%rename(CRITICAL) qpid::messaging::critical;
%include "qpid/qpid.i"
%extend qpid::messaging::Connection {
%pythoncode %{
def __init__(self, url=None, **options):
if url:
args = [str(url)]
else:
args = []
if options:
# remove null valued options
clean_opts = {}
for k, v in options.iteritems():
if v:
clean_opts[k] = v
args.append(clean_opts)
this = _qpid_messaging.new_Connection(*args)
try: self.this.append(this)
except: self.this = this
def attached(self):
return self.opened()
def close(self, timeout=None):
#timeout not supported in c++
self._close()
%}
/* Return a pre-existing session with the given name, if one
* exists, otherwise return a new one. (Note that if a
* pre-existing session exists, the transactional argument is
* ignored, and the returned session might not satisfy the desired
* setting. */
qpid::messaging::Session _session(const std::string & name,
bool transactional) {
if (!name.empty()) {
try {
return self->getSession(name);
}
catch (const qpid::messaging::KeyError &) {
}
}
if (transactional) {
return self->createTransactionalSession(name);
}
else {
return self->createSession(name);
}
}
%pythoncode %{
def session(self, name=None, transactional=False) :
if name is None :
name = ''
return self._session(name, transactional)
%}
%pythoncode %{
@staticmethod
def establish(url=None, timeout=None, **options) :
if timeout and "reconnect-timeout" not in options:
options["reconnect-timeout"] = timeout
conn = Connection(url, **options)
conn.open()
return conn
%}
}
%pythoncode %{
# Disposition class from messaging/message.py
class Disposition:
def __init__(self, type, **options):
self.type = type
self.options = options
def __repr__(self):
args = [str(self.type)] + ["%s=%r" % (k, v) for k, v in self.options.items()]
return "Disposition(%s)" % ", ".join(args)
# Consntants from messaging/constants.py
__SELF__ = object()
class Constant:
def __init__(self, name, value=__SELF__):
self.name = name
if value is __SELF__:
self.value = self
else:
self.value = value
def __repr__(self):
return self.name
AMQP_PORT = 5672
AMQPS_PORT = 5671
UNLIMITED = Constant("UNLIMITED", 0xFFFFFFFF)
REJECTED = Constant("REJECTED")
RELEASED = Constant("RELEASED")
%}
%extend qpid::messaging::Session {
%pythoncode %{
def acknowledge(self, message=None, disposition=None, sync=True) :
if message :
if disposition is None: self._acknowledge_msg(message, sync)
# FIXME aconway 2014-02-11: the following does not repsect the sync flag.
elif disposition.type == REJECTED: self.reject(message)
elif disposition.type == RELEASED: self.release(message)
else :
if disposition : # FIXME aconway 2014-02-11: support this
raise Exception("SWIG does not support dispositions yet. Use "
"Session.reject and Session.release instead")
self._acknowledge_all(sync)
__swig_getmethods__["connection"] = getConnection
if _newclass: connection = property(getConnection)
def receiver(self, source, capacity=None):
r = self._receiver(source)
if capacity is not None: r.capacity = capacity
return r
def sender(self, target, durable=None, capacity=None) :
s = self._sender(target)
if capacity is not None: s.capacity = capacity
s._setDurable(durable)
return s
def next_receiver(self, timeout=None) :
if timeout is None :
return self._next_receiver()
else :
# Python API uses timeouts in seconds,
# but C++ API uses milliseconds
return self._next_receiver(Duration(int(1000*timeout)))
def sync(self, timeout=None):
if timeout == 0: self._sync(False) # Non-blocking sync
else: self._sync(True) # Blocking sync, C++ has not timeout.
%}
}
%extend qpid::messaging::Receiver {
%pythoncode %{
def _get_source(self):
return self.getAddress().str()
__swig_getmethods__["capacity"] = getCapacity
__swig_setmethods__["capacity"] = setCapacity
if _newclass: capacity = property(getCapacity, setCapacity)
__swig_getmethods__["session"] = getSession
if _newclass: session = property(getSession)
__swig_getmethods__["source"] = _get_source
if _newclass: source = property(_get_source)
%}
%pythoncode %{
def fetch(self, timeout=None) :
if timeout is None :
return self._fetch()
else :
# Python API uses timeouts in seconds,
# but C++ API uses milliseconds
return self._fetch(Duration(int(1000*timeout)))
%}
%pythoncode %{
def get(self, timeout=None) :
if timeout is None :
return self._get()
else :
# Python API uses timeouts in seconds,
# but C++ API uses milliseconds
return self._get(Duration(int(1000*timeout)))
%}
}
%extend qpid::messaging::Sender {
%pythoncode %{
def _get_target(self):
return self.getAddress().str()
def _setDurable(self, d):
self.durable = d
def send(self, object, sync=True) :
if isinstance(object, Message):
message = object
else:
message = Message(object)
if self.durable and message.durable is None:
message.durable = self.durable
return self._send(message, sync)
def sync(self, timeout=None): self.session.sync(timeout)
__swig_getmethods__["capacity"] = getCapacity
__swig_setmethods__["capacity"] = setCapacity
if _newclass: capacity = property(getCapacity, setCapacity)
__swig_getmethods__["session"] = getSession
if _newclass: session = property(getSession)
__swig_getmethods__["target"] = _get_target
if _newclass: source = property(_get_target)
%}
}
%extend qpid::messaging::Message {
%pythoncode %{
class MessageProperties:
def __init__(self, msg):
self.msg = msg
self.properties = self.msg.getProperties()
def __len__(self):
return self.properties.__len__()
def __getitem__(self, key):
return self.properties[key];
def get(self, key):
return self.__getitem__(key)
def __setitem__(self, key, value):
self.properties[key] = value
self.msg.setProperty(key, value)
def set(self, key, value):
self.__setitem__(key, value)
def __delitem__(self, key):
del self.properties[key]
self.msg.setProperties(self.properties)
def __iter__(self):
return self.properties.iteritems()
def __repr__(self):
return str(self.properties)
# UNSPECIFIED was module level before, but I do not
# know how to insert python code at the top of the module.
# (A bare "%pythoncode" inserts at the end.
UNSPECIFIED=object()
def __init__(self, content=None, content_type=UNSPECIFIED, id=None,
subject=None, user_id=None, reply_to=None,
correlation_id=None, durable=None, priority=None,
ttl=None, properties=None):
this = _qpid_messaging.new_Message('')
try: self.this.append(this)
except: self.this = this
if not content is None:
self.content = content
if content_type != UNSPECIFIED :
self.content_type = content_type
if id is not None :
self.id = id
if subject is not None :
self.subject = subject
if user_id is not None :
self.user_id = user_id
if reply_to is not None :
self.reply_to = reply_to
if correlation_id is not None :
self.correlation_id = correlation_id
if durable is not None :
self.durable = durable
if priority is not None :
self.priority = priority
if ttl is not None :
self.ttl = ttl
if properties is not None :
self.setProperties(properties)
def _get_msg_props(self):
try:
return self._msg_props
except AttributeError:
self._msg_props = Message.MessageProperties(self)
return self._msg_props
def _get_content(self) :
obj = self.getContentObject()
if obj is not None:
return obj
if self.content_type == "amqp/list" :
return decodeList(self)
if self.content_type == "amqp/map" :
return decodeMap(self)
return self.getContent()
def _set_content(self, content) :
if isinstance(content, str) :
self.setContent(content)
elif isinstance(content, unicode) :
if not self.content_type: self.content_type = "text/plain"
self.setContent(str(content))
elif isinstance(content, list) or isinstance(content, dict) :
encode(content, self)
else :
self.setContentObject(content)
__swig_getmethods__["content"] = _get_content
__swig_setmethods__["content"] = _set_content
if _newclass: content = property(_get_content, _set_content)
def _get_content_type(self) :
ct = self.getContentType()
if ct == "": return None
else: return ct
__swig_getmethods__["content_type"] = _get_content_type
__swig_setmethods__["content_type"] = setContentType
if _newclass: content_type = property(_get_content_type, setContentType)
__swig_getmethods__["id"] = getMessageId
__swig_setmethods__["id"] = setMessageId
if _newclass: id = property(getMessageId, setMessageId)
__swig_getmethods__["subject"] = getSubject
__swig_setmethods__["subject"] = setSubject
if _newclass: subject = property(getSubject, setSubject)
__swig_getmethods__["priority"] = getPriority
__swig_setmethods__["priority"] = setPriority
if _newclass: priority = property(getPriority, setPriority)
def getTtl(self) :
return self._getTtl().getMilliseconds()/1000.0
def setTtl(self, duration) :
self._setTtl(Duration(int(1000*duration)))
__swig_getmethods__["ttl"] = getTtl
__swig_setmethods__["ttl"] = setTtl
if _newclass: ttl = property(getTtl, setTtl)
__swig_getmethods__["user_id"] = getUserId
__swig_setmethods__["user_id"] = setUserId
if _newclass: user_id = property(getUserId, setUserId)
__swig_getmethods__["correlation_id"] = getCorrelationId
__swig_setmethods__["correlation_id"] = setCorrelationId
if _newclass: correlation_id = property(getCorrelationId, setCorrelationId)
__swig_getmethods__["redelivered"] = getRedelivered
__swig_setmethods__["redelivered"] = setRedelivered
if _newclass: redelivered = property(getRedelivered, setRedelivered)
__swig_getmethods__["durable"] = getDurable
__swig_setmethods__["durable"] = setDurable
if _newclass: durable = property(getDurable, setDurable)
__swig_getmethods__["properties"] = _get_msg_props
if _newclass: properties = property(_get_msg_props)
def getReplyTo(self) :
return self._getReplyTo().str()
def setReplyTo(self, address_str) :
self._setReplyTo(Address(address_str))
__swig_getmethods__["reply_to"] = getReplyTo
__swig_setmethods__["reply_to"] = setReplyTo
if _newclass: reply_to = property(getReplyTo, setReplyTo)
def __repr__(self):
args = []
for name in ["id", "subject", "user_id", "reply_to",
"correlation_id", "priority", "ttl",
"durable", "redelivered", "properties",
"content_type"] :
value = getattr(self, name)
if value : args.append("%s=%r" % (name, value))
if self.content is not None:
if args:
args.append("content=%r" % self.content)
else:
args.append(repr(self.content))
return "Message(%s)" % ", ".join(args)
%}
}
%pythoncode %{
# Bring into module scope
UNSPECIFIED = Message.UNSPECIFIED
%}