diff options
-rw-r--r-- | cpp/Makefile.am | 2 | ||||
-rw-r--r-- | cpp/bindings/qmf2/Makefile.am | 33 | ||||
-rwxr-xr-x | cpp/bindings/qmf2/examples/python/agent.py | 150 | ||||
-rw-r--r-- | cpp/bindings/qmf2/python/Makefile.am | 46 | ||||
-rw-r--r-- | cpp/bindings/qmf2/python/python.i | 38 | ||||
-rw-r--r-- | cpp/bindings/qmf2/python/qmf2.py | 753 | ||||
-rw-r--r-- | cpp/bindings/qmf2/qmf2.i | 63 | ||||
-rw-r--r-- | cpp/bindings/qmf2/ruby/Makefile.am | 42 | ||||
-rw-r--r-- | cpp/bindings/qmf2/ruby/ruby.i | 35 | ||||
-rw-r--r-- | cpp/bindings/qpid/python/Makefile.am | 20 | ||||
-rw-r--r-- | cpp/bindings/qpid/python/python.i | 4 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/Makefile.am | 18 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/ruby.i | 2 | ||||
-rw-r--r-- | cpp/configure.ac | 3 |
14 files changed, 1187 insertions, 22 deletions
diff --git a/cpp/Makefile.am b/cpp/Makefile.am index 60ef976b07..f5f4a95be6 100644 --- a/cpp/Makefile.am +++ b/cpp/Makefile.am @@ -28,7 +28,7 @@ EXTRA_DIST = \ packaging/NSIS QPID_VERSION.txt bindings/swig_python_typemaps.i \ bindings/swig_ruby_typemaps.i -SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf bindings/qpid +SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf bindings/qpid bindings/qmf2 # Update libtool, if needed. libtool: $(LIBTOOL_DEPS) diff --git a/cpp/bindings/qmf2/Makefile.am b/cpp/bindings/qmf2/Makefile.am new file mode 100644 index 0000000000..9a8fc11222 --- /dev/null +++ b/cpp/bindings/qmf2/Makefile.am @@ -0,0 +1,33 @@ +# +# 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. +# + +if HAVE_SWIG + +EXTRA_DIST = qmf2.i +SUBDIRS = + +if HAVE_RUBY_DEVEL +SUBDIRS += ruby +endif + +if HAVE_PYTHON_DEVEL +SUBDIRS += python +endif + +endif diff --git a/cpp/bindings/qmf2/examples/python/agent.py b/cpp/bindings/qmf2/examples/python/agent.py new file mode 100755 index 0000000000..c092c5ac30 --- /dev/null +++ b/cpp/bindings/qmf2/examples/python/agent.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python + +# +# 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. +# + +import cqpid +from qmf2 import * + + +class ExampleAgent(AgentHandler): + """ + This example agent is implemented as a single class that inherits AgentHandler. + It does not use a separate thread since once set up, it is driven strictly by + incoming method calls. + """ + + def __init__(self, url): + ## + ## Create and open a messaging connection to a broker. + ## + self.connection = cqpid.Connection(url) + self.connection.open() + + ## + ## Create, configure, and open a QMFv2 agent session using the connection. + ## + self.session = AgentSession(self.connection, "{interval:30}") + self.session.setVendor('profitron.com') + self.session.setProduct('blastinator') + self.session.setAttribute('attr1', 1000) + self.session.open() + + ## + ## Initialize the parent class. + ## + AgentHandler.__init__(self, self.session) + + + def shutdown(self): + """ + Clean up the session and connection. + """ + self.session.close() + self.connection.close() + + + def method(self, handle, methodName, args, subtypes, addr, userId): + """ + Handle incoming method calls. + """ + if addr == self.controlAddr: + self.control.methodCount += 1 + + if methodName == "stop": + self.session.methodSuccess(handle) + self.cancel() + + elif methodName == "echo": + handle.addReturnArgument("sequence", args["sequence"]) + handle.addReturnArgument("map", args["map"]) + self.session.methodSuccess(handle) + + elif methodName == "fail": + if args['useString']: + self.session.raiseException(handle, args['stringVal']) + else: + ex = Data(self.sch_exception) + ex.whatHappened = "It Failed" + ex.howBad = 75 + ex.details = args['details'] + self.session.raiseException(handle, ex) + + + def setupSchema(self): + """ + Create and register the schema for this agent. + """ + package = "com.profitron.bntor" + + ## + ## Declare a schema for a structure exception that can be used in failed + ## method invocations. + ## + self.sch_exception = Schema(SCHEMA_TYPE_DATA, package, "exception") + self.sch_exception.addProperty(SchemaProperty("whatHappened", SCHEMA_DATA_STRING)) + self.sch_exception.addProperty(SchemaProperty("howBad", SCHEMA_DATA_INT)) + self.sch_exception.addProperty(SchemaProperty("details", SCHEMA_DATA_MAP)) + + ## + ## Declare a control object to test methods against. + ## + self.sch_control = Schema(SCHEMA_TYPE_DATA, package, "control") + self.sch_control.addProperty(SchemaProperty("state", SCHEMA_DATA_STRING)) + self.sch_control.addProperty(SchemaProperty("methodCount", SCHEMA_DATA_INT)) + + stopMethod = SchemaMethod("stop", desc="Stop Agent") + stopMethod.addArgument(SchemaProperty("message", SCHEMA_DATA_STRING, direction=DIR_IN)) + self.sch_control.addMethod(stopMethod) + + echoMethod = SchemaMethod("echo", desc="Echo Arguments") + echoMethod.addArgument(SchemaProperty("sequence", SCHEMA_DATA_INT, direction=DIR_IN_OUT)) + echoMethod.addArgument(SchemaProperty("map", SCHEMA_DATA_MAP, direction=DIR_IN_OUT)) + self.sch_control.addMethod(echoMethod) + + failMethod = SchemaMethod("fail", desc="Expected to Fail") + failMethod.addArgument(SchemaProperty("useString", SCHEMA_DATA_BOOL, direction=DIR_IN)) + failMethod.addArgument(SchemaProperty("stringVal", SCHEMA_DATA_STRING, direction=DIR_IN)) + failMethod.addArgument(SchemaProperty("details", SCHEMA_DATA_MAP, direction=DIR_IN)) + self.sch_control.addMethod(failMethod) + + ## + ## Register our schemata with the agent session. + ## + self.session.registerSchema(self.sch_exception) + self.session.registerSchema(self.sch_control) + + + def populateData(self): + """ + Create a control object and give it to the agent session to manage. + """ + self.control = Data(self.sch_control) + self.control.state = "OPERATIONAL" + self.control.methodCount = 0 + self.controlAddr = self.session.addData(self.control, "singleton") + + + +agent = ExampleAgent("localhost") +agent.setupSchema() +agent.populateData() +agent.run() # Use agent.start() to launch the agent in a separate thread +agent.shutdown() + diff --git a/cpp/bindings/qmf2/python/Makefile.am b/cpp/bindings/qmf2/python/Makefile.am new file mode 100644 index 0000000000..9165822f6e --- /dev/null +++ b/cpp/bindings/qmf2/python/Makefile.am @@ -0,0 +1,46 @@ +# +# 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. +# + +if HAVE_PYTHON_DEVEL + +INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) + +generated_file_list = \ + cqmf2.cpp \ + cqmf2.py + +EXTRA_DIST = python.i +BUILT_SOURCES = $(generated_file_list) + +$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_python_typemaps.i + swig -c++ -python -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i + +pylibdir = $(PYTHON_LIB) + +lib_LTLIBRARIES = _cqmf2.la + +_cqmf2_la_LDFLAGS = -avoid-version -module -shared +_cqmf2_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs $(top_builddir)/src/libqmf2.la +_cqmf2_la_CXXFLAGS = $(INCLUDES) -I$(srcdir)/qmf -I$(PYTHON_INC) +nodist__cqmf2_la_SOURCES = cqmf2.cpp + +CLEANFILES = $(generated_file_list) + +endif # HAVE_PYTHON_DEVEL + diff --git a/cpp/bindings/qmf2/python/python.i b/cpp/bindings/qmf2/python/python.i new file mode 100644 index 0000000000..7d83465bb3 --- /dev/null +++ b/cpp/bindings/qmf2/python/python.i @@ -0,0 +1,38 @@ +/* + * 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 cqmf2 +%include "std_string.i" +%include "../../swig_python_typemaps.i" + +/* Define the general-purpose exception handling */ +%exception { + try { + Py_BEGIN_ALLOW_THREADS + $action + Py_END_ALLOW_THREADS + } + catch (qpid::types::Exception& ex) { + PyErr_SetString(PyExc_RuntimeError, ex.what()); + return NULL; + } +} + +%include "../qmf2.i" + diff --git a/cpp/bindings/qmf2/python/qmf2.py b/cpp/bindings/qmf2/python/qmf2.py new file mode 100644 index 0000000000..f3ece32866 --- /dev/null +++ b/cpp/bindings/qmf2/python/qmf2.py @@ -0,0 +1,753 @@ +# +# 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. +# + +import cqmf2 +import cqpid +from threading import Thread +import time + +#=================================================================================================== +# CONSTANTS +#=================================================================================================== +SCHEMA_TYPE_DATA = cqmf2.SCHEMA_TYPE_DATA +SCHEMA_TYPE_EVENT = cqmf2.SCHEMA_TYPE_EVENT + +SCHEMA_DATA_VOID = cqmf2.SCHEMA_DATA_VOID +SCHEMA_DATA_BOOL = cqmf2.SCHEMA_DATA_BOOL +SCHEMA_DATA_INT = cqmf2.SCHEMA_DATA_INT +SCHEMA_DATA_FLOAT = cqmf2.SCHEMA_DATA_FLOAT +SCHEMA_DATA_STRING = cqmf2.SCHEMA_DATA_STRING +SCHEMA_DATA_MAP = cqmf2.SCHEMA_DATA_MAP +SCHEMA_DATA_LIST = cqmf2.SCHEMA_DATA_LIST +SCHEMA_DATA_UUID = cqmf2.SCHEMA_DATA_UUID + +ACCESS_READ_CREATE = cqmf2.ACCESS_READ_CREATE +ACCESS_READ_WRITE = cqmf2.ACCESS_READ_WRITE +ACCESS_READ_ONLY = cqmf2.ACCESS_READ_ONLY + +DIR_IN = cqmf2.DIR_IN +DIR_OUT = cqmf2.DIR_OUT +DIR_IN_OUT = cqmf2.DIR_IN_OUT + +SEV_EMERG = cqmf2.SEV_EMERG +SEV_ALERT = cqmf2.SEV_ALERT +SEV_CRIT = cqmf2.SEV_CRIT +SEV_ERROR = cqmf2.SEV_ERROR +SEV_WARN = cqmf2.SEV_WARN +SEV_NOTICE = cqmf2.SEV_NOTICE +SEV_INFORM = cqmf2.SEV_INFORM +SEV_DEBUG = cqmf2.SEV_DEBUG + + +#=================================================================================================== +# EXCEPTIONS +#=================================================================================================== +class QmfAgentException(Exception): + """ + This exception class represents an exception that was raised by a remote agent and propagated + to a console via QMFv2. + """ + def __init__(self, data): + self.value = data + + def __str__(self): + return "From Remote Agent: %r" % self.value.getProperties() + + +#=================================================================================================== +# AGENT HANDLER +#=================================================================================================== +class AgentHandler(Thread): + """ + Agent applications can create a subclass of AgentHandler to handle asynchronous events (like + incoming method calls) that occur on the agent session. AgentHandler contains a thread on which + the handler callbacks are invoked. + + There are two ways to operate the handler: Cause it to start its own thread by calling + start() and later stop it by calling cancel(); and directly calling run() to operate it on the + main thread. + + Example Usage: + + class MyAgentHandler(qmf2.AgentHandler): + def __init__(self, agentSession): + qmf2.AgentHandler.__init__(self, agentSession) + def method(self, handle, methodName, args, subtypes, addr, userId): + ...method handling code goes here... + For success, add output arguments: + handle.addReturnArgument("argname", argvalue) + ... + self.agent.methodSuccess(handle) + For failure, raise an exception: + self.agent.raiseException(handle, "error text") + Or, if you have created a schema for a structured exception: + ex = qmf2.Data(exceptionSchema) + ex.whatHappened = "it failed" + ex.howBad = 84 + ex.detailMap = {} + ... + self.agent.raiseException(handle, ex) + """ + + def __init__(self, agentSession): + Thread.__init__(self) + self.__agent = agentSession + self.__running = True + + def cancel(self): + """ + Stop the handler thread. + """ + self.__running = None + + def run(self): + event = cqmf2.AgentEvent() + while self.__running: + valid = self.__agent._impl.nextEvent(event, cqpid.Duration.SECOND) + if valid and self.__running: + if event.getType() == cqmf2.AGENT_METHOD: + self.method(event, event.getMethodName(), event.getArguments(), event.getArgumentSubtypes(), + DataAddr(event.getDataAddr()), event.getUserId()) + + def method(self, handle, methodName, args, subtypes, addr, userId): + """ + Override this method to create your own method handler. + """ + pass + + + +#=================================================================================================== +# CONSOLE SESSION +#=================================================================================================== +class ConsoleSession(object): + """ + """ + + def __init__(self, connection, options=""): + """ + """ + self._impl = cqmf2.ConsoleSession(connection, options) + + def setDomain(self, domain): + """ + """ + self._impl.setDomain(domain) + + def setAgentFilter(self, filt): + """ + """ + self.setAgentFilter(filt) + + def open(self): + """ + """ + self._impl.open() + + def close(self): + """ + """ + self._impl.close() + + def getAgents(self): + """ + """ + result = [] + count = self._impl.getAgentCount() + for i in range(count): + result.append(Agent(self._impl.getAgent(i))) + return result + + def getConnectedBrokerAgent(self): + """ + """ + return Agent(self._impl.getConnectedBrokerAgent()) + + ## TODO: Async methods + +#=================================================================================================== +# AGENT SESSION +#=================================================================================================== +class AgentSession(object): + """ + """ + + def __init__(self, connection, options=""): + """ + """ + self._impl = cqmf2.AgentSession(connection, options) + + def setDomain(self, domain): + """ + """ + self._impl.setDomain(domain) + + def setVendor(self, val): + """ + """ + self._impl.setVendor(val) + + def setProduct(self, val): + """ + """ + self._impl.setProduct(val) + + def setInstance(self, val): + """ + """ + self._impl.setInstance(val) + + def setAttribute(self, key, val): + """ + """ + self._impl.setAttribute(key, val) + + def open(self): + """ + """ + self._impl.open() + + def close(self): + """ + """ + self._impl.close() + + def registerSchema(self, schema): + """ + """ + self._impl.registerSchema(schema._impl) + + def addData(self, data, name="", persistent=False): + """ + """ + return DataAddr(self._impl.addData(data._impl, name, persistent)) + + def delData(self, addr): + """ + """ + self._impl.delData(addr._impl) + + def methodSuccess(self, handle): + """ + """ + self._impl.methodSuccess(handle) + + def raiseException(self, handle, data): + """ + """ + if data.__class__ == Data: + self._impl.raiseException(handle, data._impl) + else: + self._impl.raiseException(handle, data) + + ## TODO: async and external operations + + +#=================================================================================================== +# AGENT PROXY +#=================================================================================================== +class Agent(object): + """ + """ + + def __init__(self, impl): + self._impl = impl + + def __repr__(self): + return self.getName() + + def getName(self): + """ + """ + return self._impl.getName() + + def getEpoch(self): + """ + """ + return self._impl.getEpoch() + + def getVendor(self): + """ + """ + return self._impl.getVendor() + + def getProduct(self): + """ + """ + return self._impl.getProduct() + + def getInstance(self): + """ + """ + return self._impl.getInstance() + + def getAttributes(self): + """ + """ + return self._impl.getAttributes() + + def query(self, q, timeout=30): + """ + """ + if q.__class__ == Query: + q_arg = Query._impl + else: + q_arg = q + dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout) + result = self._impl.query(q_arg, dur) + if result.getType() == cqmf2.CONSOLE_EXCEPTION: + raise Exception(Data(result.getData(0))) + if result.getType() != cqmf2.CONSOLE_QUERY_RESPONSE: + raise Exception("Protocol error, expected CONSOLE_QUERY_RESPONSE, got %d" % result.getType()) + dataList = [] + count = result.getDataCount() + for i in range(count): + dataList.append(Data(result.getData(i))) + return dataList + + def getPackages(self): + """ + """ + result = [] + count = self._impl.getPackageCount() + for i in range(count): + result.append(self._impl.getPackage(i)) + return result + + def getSchemaIds(self, package): + """ + """ + result = [] + count = self._impl.getSchemaIdCount(package) + for i in range(count): + result.append(SchemaId(self._impl.getSchemaId(package, i))) + return result + + def getSchema(self, schemaId, timeout=30): + """ + """ + dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout) + return Schema(self._impl.getSchema(schemaId._impl, dur)) + + ## TODO: Async query + ## TODO: Agent method + +#=================================================================================================== +# QUERY +#=================================================================================================== +class Query(object): + """ + """ + + def __init__(self, *kwargs): + """ + """ + pass + +#=================================================================================================== +# DATA +#=================================================================================================== +class Data(object): + """ + """ + + def __init__(self, arg=None): + """ + """ + if arg == None: + self._impl = cqmf2.Data() + elif arg.__class__ == cqmf2.Data: + self._impl = arg + elif arg.__class__ == SchemaId: + self._impl = cqmf2.Data(arg._impl) + elif arg.__class__ == Schema: + self._impl = cqmf2.Data(arg.getSchemaId()._impl) + else: + raise Exception("Unsupported initializer for Data") + self._schema = None + + def getSchemaId(self): + """ + """ + if self._impl.hasSchema(): + return SchemaId(self._impl.getSchemaId()) + return None + + def getAddr(self): + """ + """ + if self._impl.hasAddr(): + return DataAddr(self._impl.getAddr()) + return None + + def getAgent(self): + """ + """ + return Agent(self._impl.getAgent()) + + def getProperties(self): + """ + """ + return self._impl.getProperties(); + + def _getSchema(self): + if not self._schema: + if not self._impl.hasSchema(): + raise Exception("Data object has no schema") + self._schema = Schema(self._impl.getAgent().getSchema(self._impl.getSchemaId())) + + def _invoke(self, name, args, kwargs): + ## + ## Get local copies of the agent and the address of the data object + ## + agent = self._impl.getAgent() + addr = self._impl.getAddr() + + ## + ## Set up the timeout duration for the method call. Set the default and override + ## it if the _timeout keyword arg was supplied. + ## + timeout = 30 + if '_timeout' in kwargs: + timeout = kwargs['_timeout'] + dur = cqpid.Duration(cqpid.Duration.SECOND.getMilliseconds() * timeout) + + ## + ## Get the list of arguments from the schema, isolate those that are IN or IN_OUT, + ## validate that we have the right number of arguments supplied, and marshall them + ## into a map for transmission. + ## + methods = self._schema.getMethods() + for m in methods: + if m.getName() == name: + arglist = m.getArguments() + break + argmap = {} + count = 0 + for a in arglist: + if a.getDirection() == DIR_IN or a.getDirection() == DIR_IN_OUT: + count += 1 + if count != len(args): + raise Exception("Wrong number of arguments: expected %d, got %d" % (count, len(args))) + i = 0 + for a in arglist: + if a.getDirection() == DIR_IN or a.getDirection() == DIR_IN_OUT: + argmap[a.getName()] = args[i] + i += 1 + + ## + ## Invoke the method through the agent proxy. + ## + result = agent.callMethod(name, argmap, addr, dur) + + ## + ## If the agent sent an exception, raise it in a QmfAgentExeption. + ## + if result.getType() == cqmf2.CONSOLE_EXCEPTION: + exdata = result.getData(0) + raise QmfAgentException(exdata) + + ## + ## If a successful method response was received, collect the output arguments into a map + ## and return them to the caller. + ## + if result.getType() != cqmf2.CONSOLE_METHOD_RESPONSE: + raise Exception("Protocol error: Unexpected event type in method-response: %d" % result.getType()) + return result.getArguments() + + def __getattr__(self, name): + ## + ## If we have a schema and an address, check to see if this name is the name of a method. + ## + if self._impl.hasSchema() and self._impl.hasAddr() and self._impl.hasAgent(): + ## + ## Get the schema for the data object. Note that this call will block if the remote agent + ## needs to be queried for the schema (i.e. the schema is not in the local cache). + ## + self._getSchema() + methods = self._schema.getMethods() + + ## + ## If the name matches a method in the schema, return a closure to be invoked. + ## + for method in methods: + if name == method.getName(): + return lambda *args, **kwargs : self._invoke(name, args, kwargs) + + ## + ## This is not a method call, return the property matching the name. + ## + return self._impl.getProperty(name) + + def __setattr__(self, name, value): + if name[0] == '_': + super.__setattr__(self, name, value) + return + self._impl.setProperty(name, value) + +#=================================================================================================== +# DATA ADDRESS +#=================================================================================================== +class DataAddr(object): + """ + """ + + def __init__(self, impl): + self._impl = impl + + def __repr__(self): + return "%s:%s" % (self.getAgentName(), self.getName()) + + def __eq__(self, other): + return self.getAgentName() == other.getAgentName() and \ + self.getName() == other.getName() and \ + self.getAgentEpoch() == other.getAgentEpoch() + + def getAgentName(self): + """ + """ + return self._impl.getAgentName() + + def getName(self): + """ + """ + return self._impl.getName() + + def getAgentEpoch(self): + """ + """ + return self._impl.getAgentEpoch() + +#=================================================================================================== +# SCHEMA ID +#=================================================================================================== +class SchemaId(object): + """ + """ + + def __init__(self, impl): + self._impl = impl + + def __repr__(self): + return "%s:%s" % (self.getPackageName(), self.getName()) + + def getType(self): + """ + """ + return self._impl.getType() + + def getPackageName(self): + """ + """ + return self._impl.getPackageName() + + def getName(self): + """ + """ + return self._impl.getName() + + def getHash(self): + """ + """ + return self._impl.getHash() + +#=================================================================================================== +# SCHEMA +#=================================================================================================== +class Schema(object): + """ + """ + + def __init__(self, stype, packageName=None, className=None, desc=None, sev=None): + if stype.__class__ == cqmf2.Schema: + self._impl = stype + else: + self._impl = cqmf2.Schema(stype, packageName, className) + if desc: + self._impl.setDesc(desc) + if sev: + self._impl.setDefaultSeverity(sev) + + def __repr__(self): + return "QmfSchema:%r" % SchemaId(self._impl.getSchemaId()) + + def finalize(self): + """ + """ + self._impl.finalize() + + def getSchemaId(self): + """ + """ + return SchemaId(self._impl.getSchemaId()) + + def getDesc(self): + """ + """ + return self._impl.getDesc() + + def getSev(self): + """ + """ + return self._impl.getDefaultSeverity() + + def addProperty(self, prop): + """ + """ + self._impl.addProperty(prop._impl) + + def addMethod(self, meth): + """ + """ + self._impl.addMethod(meth._impl) + + def getProperties(self): + """ + """ + props = [] + count = self._impl.getPropertyCount() + for i in range(count): + props.append(SchemaProperty(self._impl.getProperty(i))) + return props + + def getMethods(self): + """ + """ + meths = [] + count = self._impl.getMethodCount() + for i in range(count): + meths.append(SchemaMethod(self._impl.getMethod(i))) + return meths + +#=================================================================================================== +# SCHEMA PROPERTY +#=================================================================================================== +class SchemaProperty(object): + """ + """ + + def __init__(self, name, dtype=None, **kwargs): + """ + """ + if name.__class__ == cqmf2.SchemaProperty: + self._impl = name + else: + self._impl = cqmf2.SchemaProperty(name, dtype) + if 'access' in kwargs: + self._impl.setAccess(kwargs['access']) + if 'index' in kwargs: + self._impl.setIndex(kwargs['index']) + if 'optional' in kwargs: + self._impl.setOptional(kwargs['optional']) + if 'unit' in kwargs: + self._impl.setUnit(kwargs['unit']) + if 'desc' in kwargs: + self._impl.setDesc(kwargs['desc']) + if 'subtype' in kwargs: + self._impl.setSubtype(kwargs['subtype']) + if 'direction' in kwargs: + self._impl.setDirection(kwargs['direction']) + + def __repr__(self): + return self._impl.getName() + + def getName(self): + """ + """ + return self._impl.getName() + + def getAccess(self): + """ + """ + return self._impl.getAccess() + + def isIndex(self): + """ + """ + return self._impl.isIndex() + + def isOptional(self): + """ + """ + return self._impl.isOptional() + + def getUnit(self): + """ + """ + return self._impl.getUnit() + + def getDesc(self): + """ + """ + return self._impl.getDesc() + + def getSubtype(self): + """ + """ + return self._impl.getSubtype() + + def getDirection(self): + """ + """ + return self._impl.getDirection() + +#=================================================================================================== +# SCHEMA METHOD +#=================================================================================================== +class SchemaMethod(object): + """ + """ + + def __init__(self, name, **kwargs): + """ + """ + if name.__class__ == cqmf2.SchemaMethod: + self._impl = name + else: + self._impl = cqmf2.SchemaMethod(name) + if 'desc' in kwargs: + self._impl.setDesc(kwargs['desc']) + + def __repr__(self): + return "%s()" % self._impl.getName() + + def getName(self): + """ + """ + return self._impl.getName() + + def getDesc(self): + """ + """ + return self._impl.getDesc() + + def addArgument(self, arg): + """ + """ + self._impl.addArgument(arg._impl) + + def getArguments(self): + """ + """ + result = [] + count = self._impl.getArgumentCount() + for i in range(count): + result.append(SchemaProperty(self._impl.getArgument(i))) + return result + diff --git a/cpp/bindings/qmf2/qmf2.i b/cpp/bindings/qmf2/qmf2.i new file mode 100644 index 0000000000..73b7563498 --- /dev/null +++ b/cpp/bindings/qmf2/qmf2.i @@ -0,0 +1,63 @@ +/* + * 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. + */ + +%{ + +#include <qmf/exceptions.h> +#include <qmf/AgentEvent.h> +#include <qmf/Agent.h> +#include <qmf/AgentSession.h> +#include <qmf/ConsoleEvent.h> +#include <qmf/ConsoleSession.h> +#include <qmf/DataAddr.h> +#include <qmf/Data.h> +#include <qmf/Query.h> +#include <qmf/Schema.h> +#include <qmf/SchemaId.h> +#include <qmf/SchemaMethod.h> +#include <qmf/SchemaProperty.h> +#include <qmf/SchemaTypes.h> + +%} + +%include <qpid/messaging/ImportExport.h> +%include <qpid/messaging/Duration.h> + +%include <qmf/ImportExport.h> +%include <qmf/exceptions.h> +%include <qmf/AgentEvent.h> +%include <qmf/Agent.h> +%include <qmf/AgentSession.h> +%include <qmf/ConsoleEvent.h> +%include <qmf/ConsoleSession.h> +%include <qmf/DataAddr.h> +%include <qmf/Data.h> +%include <qmf/Query.h> +%include <qmf/Schema.h> +%include <qmf/SchemaId.h> +%include <qmf/SchemaMethod.h> +%include <qmf/SchemaProperty.h> +%include <qmf/SchemaTypes.h> + +%{ + +using namespace qmf; + +%}; + diff --git a/cpp/bindings/qmf2/ruby/Makefile.am b/cpp/bindings/qmf2/ruby/Makefile.am new file mode 100644 index 0000000000..90707a7f07 --- /dev/null +++ b/cpp/bindings/qmf2/ruby/Makefile.am @@ -0,0 +1,42 @@ +# +# 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. +# + +if HAVE_RUBY_DEVEL + +INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) + +EXTRA_DIST = ruby.i +BUILT_SOURCES = qmf2.cpp + +rubylibdir = $(RUBY_LIB) + +qmf2.cpp: $(srcdir)/ruby.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_ruby_typemaps.i + $(SWIG) -ruby -c++ -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o qmf2.cpp $(srcdir)/ruby.i + +rubylibarchdir = $(RUBY_LIB_ARCH) +rubylibarch_LTLIBRARIES = qmf2.la + +qmf2_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" +qmf2_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqmf2 $(top_builddir)/src/libqmf2.la +qmf2_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) +nodist_qmf2_la_SOURCES = qmf2.cpp + +CLEANFILES = qmf2.cpp + +endif # HAVE_RUBY_DEVEL diff --git a/cpp/bindings/qmf2/ruby/ruby.i b/cpp/bindings/qmf2/ruby/ruby.i new file mode 100644 index 0000000000..55dd75c082 --- /dev/null +++ b/cpp/bindings/qmf2/ruby/ruby.i @@ -0,0 +1,35 @@ +/* + * 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 qmf2 +%include "std_string.i" +%include "../../swig_ruby_typemaps.i" + +/* Define the general-purpose exception handling */ +%exception { + try { + $action + } + catch (qpid::types::Exception& mex) { + static VALUE qmferror = rb_define_class("QmfError", rb_eStandardError); + rb_raise(qmferror, mex.what()); + } +} + +%include "../qmf2.i" diff --git a/cpp/bindings/qpid/python/Makefile.am b/cpp/bindings/qpid/python/Makefile.am index 6701ce0ac3..0085a762e3 100644 --- a/cpp/bindings/qpid/python/Makefile.am +++ b/cpp/bindings/qpid/python/Makefile.am @@ -22,25 +22,25 @@ if HAVE_PYTHON_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_builddir)/src generated_file_list = \ - qpidw.cpp \ - qpidw.py + cqpid.cpp \ + cqpid.py EXTRA_DIST = python.i BUILT_SOURCES = $(generated_file_list) $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qpid.i $(srcdir)/../../swig_python_typemaps.i - swig -c++ -python -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qpidw.cpp $(srcdir)/python.i + swig -c++ -python -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) -lib_LTLIBRARIES = _qpidw.la +lib_LTLIBRARIES = _cqpid.la -#_qpidw_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)" -#_qpidw_la_LDFLAGS = -avoid-version -module -shrext ".so" -_qpidw_la_LDFLAGS = -avoid-version -module -shared -_qpidw_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -_qpidw_la_CXXFLAGS = $(INCLUDES) -I$(PYTHON_INC) -nodist__qpidw_la_SOURCES = qpidw.cpp +#_cqpid_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)" +#_cqpid_la_LDFLAGS = -avoid-version -module -shrext ".so" +_cqpid_la_LDFLAGS = -avoid-version -module -shared +_cqpid_la_LIBADD = $(PYTHON_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la +_cqpid_la_CXXFLAGS = $(INCLUDES) -I$(PYTHON_INC) +nodist__cqpid_la_SOURCES = cqpid.cpp CLEANFILES = $(generated_file_list) diff --git a/cpp/bindings/qpid/python/python.i b/cpp/bindings/qpid/python/python.i index 690ce57d85..85dc745783 100644 --- a/cpp/bindings/qpid/python/python.i +++ b/cpp/bindings/qpid/python/python.i @@ -17,14 +17,16 @@ * under the License. */ -%module qpidw +%module cqpid %include "std_string.i" %include "../../swig_python_typemaps.i" /* Define the general-purpose exception handling */ %exception { try { + Py_BEGIN_ALLOW_THREADS $action + Py_END_ALLOW_THREADS } catch (qpid::messaging::MessagingException& mex) { PyErr_SetString(PyExc_RuntimeError, mex.what()); diff --git a/cpp/bindings/qpid/ruby/Makefile.am b/cpp/bindings/qpid/ruby/Makefile.am index cb187f8dc3..fd23ace52e 100644 --- a/cpp/bindings/qpid/ruby/Makefile.am +++ b/cpp/bindings/qpid/ruby/Makefile.am @@ -22,22 +22,22 @@ if HAVE_RUBY_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src EXTRA_DIST = ruby.i -BUILT_SOURCES = qpidw.cpp +BUILT_SOURCES = cqpid.cpp rubylibdir = $(RUBY_LIB) -qpidw.cpp: $(srcdir)/ruby.i $(srcdir)/../qpid.i $(srcdir)/../../swig_ruby_typemaps.i - $(SWIG) -ruby -c++ -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o qpidw.cpp $(srcdir)/ruby.i +cqpid.cpp: $(srcdir)/ruby.i $(srcdir)/../qpid.i $(srcdir)/../../swig_ruby_typemaps.i + $(SWIG) -ruby -c++ -Wall $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid.cpp $(srcdir)/ruby.i rubylibarchdir = $(RUBY_LIB_ARCH) -rubylibarch_LTLIBRARIES = qpidw.la +rubylibarch_LTLIBRARIES = cqpid.la -qpidw_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" -qpidw_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ +cqpid_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" +cqpid_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -qpidw_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -nodist_qpidw_la_SOURCES = qpidw.cpp +cqpid_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) +nodist_cqpid_la_SOURCES = cqpid.cpp -CLEANFILES = qpidw.cpp +CLEANFILES = cqpid.cpp endif # HAVE_RUBY_DEVEL diff --git a/cpp/bindings/qpid/ruby/ruby.i b/cpp/bindings/qpid/ruby/ruby.i index baabeaede2..76463f7ddd 100644 --- a/cpp/bindings/qpid/ruby/ruby.i +++ b/cpp/bindings/qpid/ruby/ruby.i @@ -17,7 +17,7 @@ * under the License. */ -%module qpidw +%module cqpid %include "std_string.i" %include "../../swig_ruby_typemaps.i" diff --git a/cpp/configure.ac b/cpp/configure.ac index fe2179ad42..7f98ac1550 100644 --- a/cpp/configure.ac +++ b/cpp/configure.ac @@ -530,6 +530,9 @@ AC_CONFIG_FILES([ bindings/qmf/ruby/Makefile bindings/qmf/python/Makefile bindings/qmf/tests/Makefile + bindings/qmf2/Makefile + bindings/qmf2/ruby/Makefile + bindings/qmf2/python/Makefile managementgen/Makefile etc/Makefile src/Makefile |