added first attempt to read xml config files
[metaproxy-moved-to-github.git] / src / p2_config.cpp
1 /* $Id: p2_config.cpp,v 1.2 2005-10-07 09:21:41 marc Exp $
2    Copyright (c) 1998-2005, Index Data.
3
4 This file is part of the yaz-proxy.
5
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <yaz/log.h>
25 #include <yaz/options.h>
26 #include <yaz/diagbib1.h>
27 #include "p2_config.h"
28 #include "config.hpp"
29
30 #if HAVE_XSLT
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libxml/xinclude.h>
34 #include <libxslt/xsltutils.h>
35 #include <libxslt/transform.h>
36 #endif
37
38 #include <iostream>
39
40 using namespace std;
41
42 class P2_Config::Rep {
43     
44 public:
45     Rep();
46     ~Rep();
47 public:
48 #if HAVE_XSLT
49     xmlDocPtr m_docPtr;
50     xmlNodePtr m_proxyPtr;
51 #endif
52 };
53
54 P2_Config::Rep::Rep()
55 {
56 #if HAVE_XSLT
57     m_docPtr = 0;
58     m_proxyPtr = 0;
59 #endif
60 }
61
62 P2_Config::Rep::~Rep()
63 {
64 #if HAVE_XSLT
65     if (m_docPtr)
66         xmlFreeDoc(m_docPtr);
67 #endif
68 }
69     
70 P2_Config::P2_Config()
71 {
72     m_max_clients = 500;
73     m_client_idletime = 600;
74     m_debug_mode = 0;
75     m_no_limit_files = 0;
76     m_no_threads = 20;
77     m_target_idletime = 600;
78
79     m_rep = new Rep();
80 }
81
82 bool P2_Config::parse_options(int argc, char **argv)
83 {
84     char *arg;
85     int ret;
86     bool show_config = false;
87     while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:n:h:XS",
88                           argv, argc, &arg)) != -2)
89     {
90         switch (ret)
91         {
92         case 0:
93             if (m_listen_address.length())
94             {
95                 yaz_log(YLOG_FATAL, "Multiple listener address given");
96                 return false;
97             }
98             m_listen_address = arg;
99             break;
100         case 'a':
101             m_apdu_log = arg;
102             break;
103         case 'c':
104             if (m_xml_fname.length())
105             {
106                 yaz_log(YLOG_FATAL, "Multiple -c options given");
107                 return false;
108             }
109             if (!read_xml_config(arg))
110             {
111                 return false;
112             }
113             m_xml_fname = arg;
114             break;
115         case 'i':
116             m_client_idletime = atoi(arg);
117             break;
118         case 'l':
119             m_log_file = arg;
120             break;
121         case 'm':
122             m_max_clients = atoi(arg);
123             break;
124         case 'n':
125             m_no_limit_files = atoi(arg);
126             break;
127         case 'h':
128             m_no_threads = atoi(arg);
129             break;
130         case 'o':
131             m_optimize_flags = arg;
132             break;
133         case 'p':
134             if (m_pid_fname.length())
135             {
136                 yaz_log(YLOG_LOG, "Multiple -p options given");
137                 return false;
138             }
139             m_pid_fname = arg;
140             break;
141         case 't':
142             if (m_default_target.length())
143             {
144                 yaz_log(YLOG_LOG, "Multiple -t options given");
145                 return false;
146             }
147             m_default_target = arg;
148             break;
149         case 'T':
150             m_target_idletime = atoi(arg);
151             break;
152         case 'u':
153             if (m_uid.length())
154             {
155                 yaz_log(YLOG_FATAL, "-u specified more than once");
156                 return false;
157             }
158             m_uid = arg;
159             break;
160         case 'v':
161             yaz_log_init_level(yaz_log_mask_str(arg));
162             break;
163         case 'X':
164             m_debug_mode = 1;
165             break;
166         case 'S':
167             show_config = true;
168             break;
169         default:
170             yaz_log(YLOG_FATAL, "Bad option %s", arg);
171             return false;
172         }
173     } 
174     if (m_log_file.length())
175         yaz_log_init_file(m_log_file.c_str());
176     if (show_config)
177         print();
178     return true;
179 }
180
181 bool P2_Config::parse_xml_text(void *xml_ptr, bool &val)
182 {
183     string v;
184     if (!parse_xml_text(xml_ptr, v))
185         return false;
186     if (v.length() == 1 && v[0] == '1')
187         val = true;
188     else
189         val = false;
190     return true;
191 }
192
193 bool P2_Config::parse_xml_text(void *xml_ptr, string &val)
194 {
195     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
196     bool found = false;
197     string v;
198     for(ptr = ptr->children; ptr; ptr = ptr->next)
199         if (ptr->type == XML_TEXT_NODE)
200         {
201             xmlChar *t = ptr->content;
202             if (t)
203             {
204                 v += (const char *) t;
205                 found = true;
206             }
207         }
208     if (found)
209         val = v;
210     return found;
211 }
212
213 void P2_Config::parse_xml_element_target(void *xml_ptr,
214                                          P2_ConfigTarget *t)
215 {
216     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
217
218     for (ptr = ptr->children; ptr; ptr = ptr->next)
219     {
220         if (ptr->type != XML_ELEMENT_NODE)
221             continue;
222         if (!strcmp((const char *) ptr->name, "url"))
223         {
224             parse_xml_text(ptr, t->m_target_address);
225         }
226         else if (!strcmp((const char *) ptr->name, "database"))
227         {
228             parse_xml_text(ptr, t->m_target_database);
229         }
230         else
231         {
232             yaz_log(YLOG_WARN, "Unknown element '%s' inside target",
233                     (const char *) ptr->name);
234             m_errors++;
235         }
236     }
237 }
238
239 void P2_Config::parse_xml_element_proxy(void *xml_ptr)
240 {
241     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
242
243     for (ptr = ptr->children; ptr; ptr = ptr->next)
244     {
245         if (ptr->type != XML_ELEMENT_NODE)
246             continue;
247         if (!strcmp((const char *) ptr->name, "target"))
248         {
249             P2_ConfigTarget *t = new P2_ConfigTarget();
250
251             struct _xmlAttr *attr;
252             for (attr = ptr->properties; attr; attr = attr->next)
253                 if (!strcmp((const char *) attr->name, "name")
254                     || !strcmp((const char *) attr->name, "host"))
255                 {
256                     parse_xml_text(attr, t->m_virt_address);
257                 }
258                 else if (!strcmp((const char *) attr->name, "database"))
259                 {
260                     parse_xml_text(attr, t->m_virt_database);
261                 }
262                 else if (!strcmp((const char *) attr->name, "default"))
263                 {
264                     parse_xml_text(attr, t->m_default);
265                 }
266                 else if (!strcmp((const char *) attr->name, "type"))
267                 {
268                     parse_xml_text(attr, t->m_type);
269                 }
270                 else
271                 {
272                     yaz_log(YLOG_WARN, "Unknown attribute '%s' for "
273                             "element proxy",
274                             (const char *) attr->name);
275                     m_errors++;
276                 }
277             parse_xml_element_target(ptr, t);
278             m_target_list.push_back(t);
279         }
280         else if (!strcmp((const char *) ptr->name, "max-clients"))
281         {
282             string v;
283             if (parse_xml_text(ptr, v))
284                 m_max_clients = atoi(v.c_str());
285         }
286         else if (!strcmp((const char *) ptr->name, "module"))
287         {
288             P2_ConfigModule *t = new P2_ConfigModule();
289
290             string v;
291             if (parse_xml_text(ptr, v))
292             {
293                 t->m_fname = v;
294                 m_modules.push_back(t);
295             }
296         }
297         else
298         {
299             yaz_log(YLOG_WARN, "Unknown element '%s' inside proxy", ptr->name);
300             m_errors++;
301         }
302     }
303 }
304
305 void P2_Config::print()
306 {
307     cout << "max_clients=" << m_max_clients << endl;
308     list<P2_ConfigTarget *>::const_iterator it;
309     
310     for (it = m_target_list.begin(); it != m_target_list.end(); it++)
311     {
312         cout << "type=" << (*it)->m_type << " ";
313         cout << "v-address=" << (*it)->m_virt_address << " ";
314         cout << "v-db=" << (*it)->m_virt_database << " ";
315         cout << "t-address=" << (*it)->m_target_address << " ";
316         cout << "t-db=" << (*it)->m_target_database << " ";
317         cout << "default=" << (*it)->m_default << endl;
318     }
319 }
320
321 bool P2_Config::read_xml_config(const char *fname)
322 {
323     xmlDocPtr ndoc = xmlParseFile(fname);
324
325     if (!ndoc)
326     {
327         yaz_log(YLOG_WARN, "Config file %s not found or parse error", fname);
328         return false;
329     }
330     int noSubstitutions = xmlXIncludeProcess(ndoc);
331     if (noSubstitutions == -1)
332         yaz_log(YLOG_WARN, "XInclude processing failed on config %s", fname);
333
334     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
335     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
336         strcmp((const char *) proxyPtr->name, "proxy"))
337     {
338         yaz_log(YLOG_WARN, "No proxy element in %s", fname);
339         xmlFreeDoc(ndoc);
340         return false;
341     }
342     m_rep->m_proxyPtr = proxyPtr;
343     
344     // OK: release previous and make it the current one.
345     if (m_rep->m_docPtr)
346         xmlFreeDoc(m_rep->m_docPtr);
347     m_rep->m_docPtr = ndoc;
348
349     m_errors = 0;
350     parse_xml_element_proxy(proxyPtr);
351     if (m_errors && !m_debug_mode)
352         return false;
353     return true;
354 }
355
356 P2_Config::~P2_Config()
357 {
358     delete m_rep;
359 }
360
361 P2_ConfigTarget::P2_ConfigTarget()
362 {
363     m_default = false;
364 }
365
366 P2_ConfigTarget *P2_Config::find_target(string db)
367 {
368     list<P2_ConfigTarget *>::const_iterator it;
369     for (it = m_target_list.begin(); it != m_target_list.end(); it++)
370     {
371         if ((*it)->m_virt_database == db)
372             return (*it);
373     }
374     return 0;
375 }
376
377
378 /*
379  * Local variables:
380  * c-basic-offset: 4
381  * indent-tabs-mode: nil
382  * End:
383  * vim: shiftwidth=4 tabstop=8 expandtab
384  */