blob: 9d45bf54ee1e7b86db237556bd97e78b94b1e051 [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 cqpid
%include "std_string.i"
%include "../../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 _cqpid.so have the same
* names as in the C++ library. They get renamed to their Python
* equivalents when brought into the Python wrapping
*/
%{
static PyObject* pNoMessageAvailable;
static PyObject* pTargetCapacityExceeded;
static PyObject* pNotFound;
static PyObject* pTransportFailure;
%}
%init %{
pNoMessageAvailable = PyErr_NewException(
"_cqpid.NoMessageAvailable", NULL, NULL);
Py_INCREF(pNoMessageAvailable);
PyModule_AddObject(m, "NoMessageAvailable", pNoMessageAvailable);
pTargetCapacityExceeded = PyErr_NewException(
"_cqpid.TargetCapacityExceeded", NULL, NULL);
Py_INCREF(pTargetCapacityExceeded);
PyModule_AddObject(m, "TargetCapacityExceeded", pTargetCapacityExceeded);
pNotFound = PyErr_NewException(
"_cqpid.NotFound", NULL, NULL);
Py_INCREF(pNotFound);
PyModule_AddObject(m, "NotFound", pNotFound);
pTransportFailure = PyErr_NewException(
"_cqpid.TransportFailure", NULL, NULL);
Py_INCREF(pTransportFailure);
PyModule_AddObject(m, "TransportFailure", pTransportFailure);
%}
%pythoncode %{
Empty = _cqpid.NoMessageAvailable
TargetCapacityExceeded = _cqpid.TargetCapacityExceeded
NotFound = _cqpid.NotFound
ConnectError = _cqpid.TransportFailure
%}
/* Define the general-purpose exception handling */
%exception {
PyObject * pExceptionType = NULL;
std::string error;
Py_BEGIN_ALLOW_THREADS;
try {
$action
} catch (qpid::messaging::NoMessageAvailable & ex) {
pExceptionType = pNoMessageAvailable;
error = ex.what();
} catch (qpid::messaging::TargetCapacityExceeded & ex) {
pExceptionType = pTargetCapacityExceeded;
error = ex.what();
} catch (qpid::messaging::NotFound & ex) {
pExceptionType = pNotFound;
error = ex.what();
} catch (qpid::messaging::TransportFailure & ex) {
pExceptionType = pTransportFailure;
error = ex.what();
} catch (qpid::types::Exception& ex) {
pExceptionType = PyExc_RuntimeError;
error = ex.what();
}
Py_END_ALLOW_THREADS;
if (!error.empty()) {
PyErr_SetString(pExceptionType, error.c_str());
return NULL;
}
}
/* 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(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(_fetch) qpid::messaging::Receiver::fetch;
%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;
%include "../qpid.i"
%extend qpid::messaging::Connection {
%pythoncode %{
# Handle the different options by converting underscores to hyphens.
# Also, the sasl_mechanisms option in Python has no direct
# equivalent in C++, so we will translate them to sasl_mechanism
# when possible.
def __init__(self, url=None, **options):
args = [url] if url else []
if options :
if "sasl_mechanisms" in options :
if ' ' in options.get("sasl_mechanisms",'') :
raise Exception(
"C++ Connection objects are unable to handle "
"multiple sasl-mechanisms")
options["sasl_mechanism"] = options.pop("sasl_mechanisms")
args.append(options)
this = _cqpid.new_Connection(*args)
try: self.this.append(this)
except: self.this = this
%}
/* 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, **options) :
conn = Connection(url, **options)
conn.open()
return conn
%}
}
%extend qpid::messaging::Session {
%pythoncode %{
def acknowledge(self, message=None, disposition=None, sync=True) :
if disposition :
raise Exception("SWIG does not support dispositions yet. Use "
"Session.reject and Session.release instead")
if message :
self._acknowledge_msg(message, sync)
else :
self._acknowledge_all(sync)
__swig_getmethods__["connection"] = getConnection
if _newclass: connection = _swig_property(getConnection)
%}
}
%extend qpid::messaging::Receiver {
%pythoncode %{
__swig_getmethods__["capacity"] = getCapacity
__swig_setmethods__["capacity"] = setCapacity
if _newclass: capacity = _swig_property(getCapacity, setCapacity)
__swig_getmethods__["session"] = getSession
if _newclass: session = _swig_property(getSession)
%}
%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)))
%}
}
%extend qpid::messaging::Sender {
%pythoncode %{
def send(self, object, sync=True) :
if isinstance(object, Message):
message = object
else:
message = Message(object)
return self._send(message, sync)
__swig_getmethods__["capacity"] = getCapacity
__swig_setmethods__["capacity"] = setCapacity
if _newclass: capacity = _swig_property(getCapacity, setCapacity)
__swig_getmethods__["session"] = getSession
if _newclass: session = _swig_property(getSession)
%}
}
%extend qpid::messaging::Message {
%pythoncode %{
# 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 = _cqpid.new_Message('')
try: self.this.append(this)
except: self.this = this
if content :
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 :
# Can't set properties via (inst).getProperties, because
# the typemaps make a copy of the underlying properties.
# Instead, set via setProperty for the time-being
for k, v in properties.iteritems() :
self.setProperty(k, v)
def _get_content(self) :
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, basestring) :
self.setContent(content)
elif isinstance(content, list) or isinstance(content, dict) :
encode(content, self)
else :
# Not a type we can handle. Try setting it anyway,
# although this will probably lead to a swig error
self.setContent(content)
__swig_getmethods__["content"] = _get_content
__swig_setmethods__["content"] = _set_content
if _newclass: content = _swig_property(_get_content, _set_content)
__swig_getmethods__["content_type"] = getContentType
__swig_setmethods__["content_type"] = setContentType
if _newclass: content_type = _swig_property(getContentType,
setContentType)
__swig_getmethods__["id"] = getMessageId
__swig_setmethods__["id"] = setMessageId
if _newclass: id = _swig_property(getMessageId, setMessageId)
__swig_getmethods__["subject"] = getSubject
__swig_setmethods__["subject"] = setSubject
if _newclass: subject = _swig_property(getSubject, setSubject)
__swig_getmethods__["priority"] = getPriority
__swig_setmethods__["priority"] = setPriority
if _newclass: priority = _swig_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 = _swig_property(getTtl, setTtl)
__swig_getmethods__["user_id"] = getUserId
__swig_setmethods__["user_id"] = setUserId
if _newclass: user_id = _swig_property(getUserId, setUserId)
__swig_getmethods__["correlation_id"] = getCorrelationId
__swig_setmethods__["correlation_id"] = setCorrelationId
if _newclass: correlation_id = _swig_property(getCorrelationId,
setCorrelationId)
__swig_getmethods__["redelivered"] = getRedelivered
__swig_setmethods__["redelivered"] = setRedelivered
if _newclass: redelivered = _swig_property(getRedelivered,
setRedelivered)
__swig_getmethods__["durable"] = getDurable
__swig_setmethods__["durable"] = setDurable
if _newclass: durable = _swig_property(getDurable, setDurable)
__swig_getmethods__["properties"] = getProperties
if _newclass: properties = _swig_property(getProperties)
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 = _swig_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
%}