summaryrefslogtreecommitdiff
path: root/qpid/extras/dispatch/src
diff options
context:
space:
mode:
authorTed Ross <tross@apache.org>2013-06-07 21:50:01 +0000
committerTed Ross <tross@apache.org>2013-06-07 21:50:01 +0000
commit81f63fd54da06ee73d61416ca409ccc2f8f61f8d (patch)
treecc8785b11da4726b0b48e5100074bfa0c3998c5c /qpid/extras/dispatch/src
parentcb03df252c59e38f20d4609094774115d50b83f1 (diff)
downloadqpid-python-81f63fd54da06ee73d61416ca409ccc2f8f61f8d.tar.gz
QPID-4913 - Work-in-progres for configuration file reader.
Note that this commit adds the use of embedded Python code. Installation support is needed to ensure that the embedded python components are installed in the libexec area. Also, the configuration file path is currently hard-coded. This will be fixed shortly. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1490848 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/extras/dispatch/src')
-rw-r--r--qpid/extras/dispatch/src/config.c203
-rw-r--r--qpid/extras/dispatch/src/config_private.h29
-rw-r--r--qpid/extras/dispatch/src/dispatch.c39
-rw-r--r--qpid/extras/dispatch/src/py/config/__init__.py20
-rw-r--r--qpid/extras/dispatch/src/py/config/configparse.py146
-rw-r--r--qpid/extras/dispatch/src/python_embedded.c64
-rw-r--r--qpid/extras/dispatch/src/python_embedded.h29
-rw-r--r--qpid/extras/dispatch/src/router_node.c2
-rw-r--r--qpid/extras/dispatch/src/server.c3
9 files changed, 533 insertions, 2 deletions
diff --git a/qpid/extras/dispatch/src/config.c b/qpid/extras/dispatch/src/config.c
new file mode 100644
index 0000000000..bc99d7f91c
--- /dev/null
+++ b/qpid/extras/dispatch/src/config.c
@@ -0,0 +1,203 @@
+/*
+ * 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 "python_embedded.h"
+#include "config_private.h"
+#include <qpid/dispatch/alloc.h>
+#include <qpid/dispatch/log.h>
+
+#define PYTHON_MODULE "config"
+
+static const char *log_module = "CONFIG";
+
+struct dx_config_t {
+ PyObject *pModule;
+ PyObject *pClass;
+ PyObject *pObject;
+};
+
+ALLOC_DECLARE(dx_config_t);
+ALLOC_DEFINE(dx_config_t);
+
+void dx_config_initialize()
+{
+ dx_python_start();
+}
+
+
+void dx_config_finalize()
+{
+ dx_python_stop();
+}
+
+
+dx_config_t *dx_config(char *filename)
+{
+ dx_config_t *config = new_dx_config_t();
+
+ //
+ // Load the Python configuration module and get a reference to the config class.
+ //
+ PyObject *pName = PyString_FromString(PYTHON_MODULE);
+ config->pModule = PyImport_Import(pName);
+ Py_DECREF(pName);
+
+ if (!config->pModule) {
+ PyErr_Print();
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Unable to load configuration module: %s", PYTHON_MODULE);
+ return 0;
+ }
+
+ config->pClass = PyObject_GetAttrString(config->pModule, "DXConfig");
+ if (!config->pClass || !PyClass_Check(config->pClass)) {
+ PyErr_Print();
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: Missing DXConfig class");
+ return 0;
+ }
+
+ //
+ // Instantiate the DXConfig class, passing in the configuration file name.
+ //
+ PyObject *pArgs = PyTuple_New(1);
+ PyObject *fname = PyString_FromString(filename);
+ PyTuple_SetItem(pArgs, 0, fname);
+ config->pObject = PyInstance_New(config->pClass, pArgs, 0);
+ Py_DECREF(pArgs);
+
+ if (config->pObject == 0) {
+ PyErr_Print();
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ dx_log(log_module, LOG_ERROR, "Configuration file '%s' could not be read", filename);
+ return 0;
+ }
+
+ return config;
+}
+
+
+void dx_config_free(dx_config_t *config)
+{
+ if (config) {
+ Py_DECREF(config->pClass);
+ Py_DECREF(config->pModule);
+ free_dx_config_t(config);
+ }
+}
+
+
+int dx_config_item_count(const dx_config_t *config, const char *section)
+{
+ PyObject *pSection;
+ PyObject *pMethod;
+ PyObject *pArgs;
+ PyObject *pResult;
+ int result = 0;
+
+ pMethod = PyObject_GetAttrString(config->pObject, "item_count");
+ if (!pMethod || !PyCallable_Check(pMethod)) {
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable 'item_count'");
+ if (pMethod)
+ Py_DECREF(pMethod);
+ return 0;
+ }
+
+ pSection = PyString_FromString(section);
+ pArgs = PyTuple_New(1);
+ PyTuple_SetItem(pArgs, 0, pSection);
+ pResult = PyObject_CallObject(pMethod, pArgs);
+ Py_DECREF(pArgs);
+ if (pResult && PyInt_Check(pResult))
+ result = (int) PyInt_AsLong(pResult);
+ if (pResult)
+ Py_DECREF(pResult);
+ Py_DECREF(pMethod);
+
+ return result;
+}
+
+
+static PyObject *item_value(const dx_config_t *config, const char *section, int index, const char* key, const char* method)
+{
+ PyObject *pSection;
+ PyObject *pIndex;
+ PyObject *pKey;
+ PyObject *pMethod;
+ PyObject *pArgs;
+ PyObject *pResult;
+
+ pMethod = PyObject_GetAttrString(config->pObject, method);
+ if (!pMethod || !PyCallable_Check(pMethod)) {
+ dx_log(log_module, LOG_ERROR, "Problem with configuration module: No callable '%s'", method);
+ if (pMethod)
+ Py_DECREF(pMethod);
+ return 0;
+ }
+
+ pSection = PyString_FromString(section);
+ pIndex = PyInt_FromLong((long) index);
+ pKey = PyString_FromString(key);
+ pArgs = PyTuple_New(3);
+ PyTuple_SetItem(pArgs, 0, pSection);
+ PyTuple_SetItem(pArgs, 1, pIndex);
+ PyTuple_SetItem(pArgs, 2, pKey);
+ pResult = PyObject_CallObject(pMethod, pArgs);
+ Py_DECREF(pArgs);
+ Py_DECREF(pMethod);
+
+ return pResult;
+}
+
+
+const char *dx_config_item_value_string(const dx_config_t *config, const char *section, int index, const char* key)
+{
+ PyObject *pResult = item_value(config, section, index, key, "value_string");
+ char *value = 0;
+
+ if (pResult && PyString_Check(pResult)) {
+ Py_ssize_t size = PyString_Size(pResult);
+ value = (char*) malloc(size + 1);
+ strncpy(value, PyString_AsString(pResult), size + 1);
+ }
+
+ if (pResult)
+ Py_DECREF(pResult);
+
+ return value;
+}
+
+
+uint32_t dx_config_item_value_int(const dx_config_t *config, const char *section, int index, const char* key)
+{
+ PyObject *pResult = item_value(config, section, index, key, "value_int");
+ uint32_t value = 0;
+
+ if (pResult && PyLong_Check(pResult))
+ value = (uint32_t) PyLong_AsLong(pResult);
+
+ if (pResult)
+ Py_DECREF(pResult);
+
+ return value;
+}
+
+
diff --git a/qpid/extras/dispatch/src/config_private.h b/qpid/extras/dispatch/src/config_private.h
new file mode 100644
index 0000000000..bb114ebde0
--- /dev/null
+++ b/qpid/extras/dispatch/src/config_private.h
@@ -0,0 +1,29 @@
+#ifndef __config_private_h__
+#define __config_private_h__ 1
+/*
+ * 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 <qpid/dispatch/config.h>
+
+void dx_config_initialize();
+void dx_config_finalize();
+dx_config_t *dx_config(char *filename);
+void dx_config_free(dx_config_t *config);
+
+#endif
diff --git a/qpid/extras/dispatch/src/dispatch.c b/qpid/extras/dispatch/src/dispatch.c
index 0176d3189e..3c8fa9ba83 100644
--- a/qpid/extras/dispatch/src/dispatch.c
+++ b/qpid/extras/dispatch/src/dispatch.c
@@ -17,10 +17,12 @@
* under the License.
*/
+#include "python_embedded.h"
#include <qpid/dispatch.h>
#include "dispatch_private.h"
#include "alloc_private.h"
#include "log_private.h"
+#include "config_private.h"
/**
* Private Function Prototypes
@@ -38,14 +40,43 @@ dx_agent_t *dx_agent(dx_dispatch_t *dx);
void dx_agent_free(dx_agent_t *agent);
-dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name,
- const char *router_area, const char *router_id)
+static const char *CONF_CONTAINER = "container";
+static const char *CONF_ROUTER = "router";
+
+
+dx_dispatch_t *dx_dispatch()
{
dx_dispatch_t *dx = NEW(dx_dispatch_t);
+ int thread_count = 0;
+ const char *container_name = 0;
+ const char *router_area = 0;
+ const char *router_id = 0;
+
+ dx_python_initialize();
dx_log_initialize();
dx_alloc_initialize();
+ dx_config_initialize();
+ dx_config_t *config = dx_config("../etc/qpid-dispatch.conf");
+
+ if (config) {
+ int count = dx_config_item_count(config, CONF_CONTAINER);
+ if (count == 1) {
+ thread_count = dx_config_item_value_int(config, CONF_CONTAINER, 0, "worker-threads");
+ container_name = dx_config_item_value_string(config, CONF_CONTAINER, 0, "container-name");
+ }
+
+ count = dx_config_item_count(config, CONF_ROUTER);
+ if (count == 1) {
+ router_area = dx_config_item_value_string(config, CONF_ROUTER, 0, "area");
+ router_id = dx_config_item_value_string(config, CONF_ROUTER, 0, "router-id");
+ }
+ }
+
+ if (thread_count == 0)
+ thread_count = 1;
+
if (!container_name)
container_name = "00000000-0000-0000-0000-000000000000"; // TODO - gen a real uuid
@@ -64,16 +95,20 @@ dx_dispatch_t *dx_dispatch(int thread_count, const char *container_name,
dx_container_setup_agent(dx);
dx_router_setup_agent(dx);
+ dx_config_free(config);
+
return dx;
}
void dx_dispatch_free(dx_dispatch_t *dx)
{
+ dx_config_finalize();
dx_agent_free(dx->agent);
dx_router_free(dx->router);
dx_container_free(dx->container);
dx_server_free(dx->server);
dx_log_finalize();
+ dx_python_finalize();
}
diff --git a/qpid/extras/dispatch/src/py/config/__init__.py b/qpid/extras/dispatch/src/py/config/__init__.py
new file mode 100644
index 0000000000..349026251a
--- /dev/null
+++ b/qpid/extras/dispatch/src/py/config/__init__.py
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+from config.configparse import DXConfig
diff --git a/qpid/extras/dispatch/src/py/config/configparse.py b/qpid/extras/dispatch/src/py/config/configparse.py
new file mode 100644
index 0000000000..051c3d3187
--- /dev/null
+++ b/qpid/extras/dispatch/src/py/config/configparse.py
@@ -0,0 +1,146 @@
+##
+## 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 json
+
+class DXConfig:
+ """
+ Configuration File Parser for Qpid Dispatch
+
+ Configuration files are made up of "sections" having the following form:
+
+ section-name {
+ key0: value0
+ key1: value1
+ ...
+ keyN: valueN
+ }
+
+ Sections may be repeated (i.e. there may be multiple instances with the same section name).
+ The keys must be unique within a section. Values can be of string or integer types. No
+ quoting is necessary anywhere in the configuration file. Values may contain whitespace.
+
+ Comment lines starting with the '#' character will be ignored.
+
+ This parser converts the configuration file into a json string where the file is represented
+ as a list of maps. Each map has one item, the key being the section name and the value being
+ a nested map of keys and values from the file. This json string is parsed into a data
+ structure that may then be queried.
+
+ """
+
+ def __init__(self, path):
+ self.path = path
+ self.config = None
+
+ cfile = open(self.path)
+ text = cfile.read()
+ cfile.close()
+
+ self.json_text = "[" + self._toJson(text) + "]"
+ self.config = json.loads(self.json_text);
+
+
+ def __repr__(self):
+ return "%r" % self.config
+
+
+ def _toJson(self, text):
+ lines = text.split('\n')
+ stripped = ""
+ for line in lines:
+ sline = line.strip()
+
+ #
+ # Ignore empty lines
+ #
+ if len(sline) == 0:
+ continue
+
+ #
+ # Ignore comment lines
+ #
+ if sline.find('#') == 0:
+ continue
+
+ #
+ # Convert section opens, closes, and colon-separated key:value lines into json
+ #
+ if sline[-1:] == '{':
+ sline = '{"' + sline[:-1].strip() + '" : {'
+ elif sline == '}':
+ sline = '}},'
+ else:
+ colon = sline.find(':')
+ if colon > 1:
+ sline = '"' + sline[:colon] + '":"' + sline[colon+1:].strip() + '",'
+ stripped += sline
+
+ #
+ # Remove the trailing commas in map entries
+ #
+ stripped = stripped.replace(",}", "}")
+
+ #
+ # Return the entire document minus the trailing comma
+ #
+ return stripped[:-1]
+
+
+ def _getSection(self, section):
+ result = []
+ for item in self.config:
+ if item.__class__ == dict and section in item:
+ result.append(item[section])
+ return result
+
+
+ def item_count(self, section):
+ """
+ Return the number of items in a section (i.e. the number if instances of a section-name).
+ """
+ sec = self._getSection(section)
+ return len(sec)
+
+ def _value(self, section, idx, key):
+ sec = self._getSection(section)
+ if idx >= len(sec):
+ return None
+ item = sec[idx]
+ if item.__class__ == dict and key in item:
+ return item[key]
+ return None
+
+ def value_string(self, section, idx, key):
+ """
+ Return the string value for the key in the idx'th item in the section.
+ """
+ value = self._value(section, idx, key)
+ if value:
+ return str(value)
+ return None
+
+ def value_int(self, section, idx, key):
+ """
+ Return the integer value for the key in the idx'th item in the section.
+ """
+ value = self._value(section, idx, key)
+ return long(value)
+
+
diff --git a/qpid/extras/dispatch/src/python_embedded.c b/qpid/extras/dispatch/src/python_embedded.c
new file mode 100644
index 0000000000..17c97ae10e
--- /dev/null
+++ b/qpid/extras/dispatch/src/python_embedded.c
@@ -0,0 +1,64 @@
+/*
+ * 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 "python_embedded.h"
+#include <qpid/dispatch/threading.h>
+#include <qpid/dispatch/log.h>
+
+static uint32_t ref_count = 0;
+static sys_mutex_t *lock = 0;
+static char *log_module = "PYTHON";
+
+void dx_python_initialize()
+{
+ lock = sys_mutex();
+}
+
+
+void dx_python_finalize()
+{
+ assert(ref_count == 0);
+ sys_mutex_free(lock);
+}
+
+
+void dx_python_start()
+{
+ sys_mutex_lock(lock);
+ if (ref_count == 0) {
+ Py_Initialize();
+ dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Initialized");
+ }
+ ref_count++;
+ sys_mutex_unlock(lock);
+}
+
+
+void dx_python_stop()
+{
+ sys_mutex_lock(lock);
+ ref_count--;
+ if (ref_count == 0) {
+ Py_Finalize();
+ dx_log(log_module, LOG_TRACE, "Embedded Python Interpreter Shut Down");
+ }
+ sys_mutex_unlock(lock);
+}
+
+
diff --git a/qpid/extras/dispatch/src/python_embedded.h b/qpid/extras/dispatch/src/python_embedded.h
new file mode 100644
index 0000000000..455925eecf
--- /dev/null
+++ b/qpid/extras/dispatch/src/python_embedded.h
@@ -0,0 +1,29 @@
+#ifndef __python_embedded_h__
+#define __python_embedded_h__ 1
+/*
+ * 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 <Python.h>
+
+void dx_python_initialize();
+void dx_python_finalize();
+void dx_python_start();
+void dx_python_stop();
+
+#endif
diff --git a/qpid/extras/dispatch/src/router_node.c b/qpid/extras/dispatch/src/router_node.c
index e361e9ce8e..bfa89eddf4 100644
--- a/qpid/extras/dispatch/src/router_node.c
+++ b/qpid/extras/dispatch/src/router_node.c
@@ -509,6 +509,8 @@ dx_router_t *dx_router(dx_dispatch_t *dx, const char *area, const char *id)
//
dx_field_iterator_set_address(area, id);
+ dx_log(module, LOG_INFO, "Router started, area=%s id=%s", area, id);
+
return router;
}
diff --git a/qpid/extras/dispatch/src/server.c b/qpid/extras/dispatch/src/server.c
index fccee7fac0..41df72e1b5 100644
--- a/qpid/extras/dispatch/src/server.c
+++ b/qpid/extras/dispatch/src/server.c
@@ -605,6 +605,8 @@ dx_server_t *dx_server(int thread_count, const char *container_name)
dx_server->pause_now_serving = 0;
dx_server->pending_signal = 0;
+ dx_log(module, LOG_INFO, "Container Name: %s", dx_server->container_name);
+
return dx_server;
}
@@ -727,6 +729,7 @@ void dx_server_signal(dx_dispatch_t *dx, int signum)
dx_server->pending_signal = signum;
sys_cond_signal_all(dx_server->cond);
+ pn_driver_wakeup(dx_server->driver);
}