1 /*
2     This file is part of KDE.
3 
4     Copyright (c) 2005 Tobias Koenig <tokoe@kde.org>
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15 
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21 
22 #include "definitions.h"
23 
24 #include <QDir>
25 #include <QFile>
26 #include <QUrl>
27 
28 #include <QXmlSimpleReader>
29 #include <common/nsmanager.h>
30 #include <common/fileprovider.h>
31 #include <common/messagehandler.h>
32 #include <common/parsercontext.h>
33 
34 #include <wsdl/port.h>
35 
36 #include <QDebug>
37 
38 using namespace KWSDL;
39 
Definitions()40 Definitions::Definitions()
41 {
42 }
43 
~Definitions()44 Definitions::~Definitions()
45 {
46 }
47 
setName(const QString & name)48 void Definitions::setName(const QString &name)
49 {
50     mName = name;
51 }
52 
name() const53 QString Definitions::name() const
54 {
55     return mName;
56 }
57 
setTargetNamespace(const QString & targetNamespace)58 void Definitions::setTargetNamespace(const QString &targetNamespace)
59 {
60     mTargetNamespace = targetNamespace;
61 
62     mType.setNameSpace(mTargetNamespace);
63 }
64 
targetNamespace() const65 QString Definitions::targetNamespace() const
66 {
67     return mTargetNamespace;
68 }
69 
70 #if 0
71 void Definitions::setBindings(const Binding::List &bindings)
72 {
73     mBindings = bindings;
74 }
75 #endif
76 
bindings() const77 Binding::List Definitions::bindings() const
78 {
79     return mBindings;
80 }
81 
82 #if 0
83 void Definitions::setImports(const Import::List &imports)
84 {
85     mImports = imports;
86 }
87 
88 Import::List Definitions::imports() const
89 {
90     return mImports;
91 }
92 #endif
93 
setMessages(const Message::List & messages)94 void Definitions::setMessages(const Message::List &messages)
95 {
96     mMessages = messages;
97 }
98 
messages() const99 Message::List Definitions::messages() const
100 {
101     return mMessages;
102 }
103 
setPortTypes(const PortType::List & portTypes)104 void Definitions::setPortTypes(const PortType::List &portTypes)
105 {
106     mPortTypes = portTypes;
107 }
108 
portTypes() const109 PortType::List Definitions::portTypes() const
110 {
111     return mPortTypes;
112 }
113 
114 #if 0
115 void Definitions::setService(const Service &service)
116 {
117     mService = service;
118 }
119 #endif
120 
services() const121 Service::List Definitions::services() const
122 {
123     return mServices;
124 }
125 
setType(const Type & type)126 void Definitions::setType(const Type &type)
127 {
128     mType = type;
129 }
130 
type() const131 Type Definitions::type() const
132 {
133     return mType;
134 }
135 
loadXML(ParserContext * context,const QDomElement & element)136 bool Definitions::loadXML(ParserContext *context, const QDomElement &element)
137 {
138     setTargetNamespace(element.attribute(QLatin1String("targetNamespace")));
139     mName = element.attribute(QLatin1String("name"));
140 
141     context->namespaceManager()->enterChild(element);
142 
143     QDomElement child = element.firstChildElement();
144     while (!child.isNull()) {
145         NSManager namespaceManager(context, child);
146         const QName tagName(child.tagName());
147         if (tagName.localName() == QLatin1String("import")) {
148             QString oldTn = targetNamespace();
149             QString oldName = mName;
150             importDefinition(context, child.attribute(QLatin1String("location")));
151             setTargetNamespace(oldTn);
152             mName = oldName;
153         } else if (tagName.localName() == QLatin1String("types")) {
154             if (!mType.loadXML(context, child)) {
155                 return false;
156             }
157         } else if (tagName.localName() == QLatin1String("message")) {
158             Message message(mTargetNamespace);
159             message.loadXML(context, child);
160             //qDebug() << "Definitions: found message" << message.name() << message.nameSpace();
161             mMessages.append(message);
162         } else if (tagName.localName() == QLatin1String("portType")) {
163             PortType portType(mTargetNamespace);
164             portType.loadXML(context, child);
165             mPortTypes.append(portType);
166         } else if (tagName.localName() == QLatin1String("binding")) {
167             Binding binding(mTargetNamespace);
168             binding.loadXML(context, child);
169             mBindings.append(binding);
170         } else if (tagName.localName() == QLatin1String("service")) {
171             const QString name = child.attribute(QLatin1String("name"));
172             //qDebug() << "Service:" << name << "looking for" << mWantedService;
173             // is this the service we want?
174             if (mWantedService.isEmpty() || mWantedService == name) {
175                 Service service(mTargetNamespace);
176                 service.loadXML(context, &mBindings, child);
177                 mServices.append(service);
178             }
179         } else if (tagName.localName() == QLatin1String("documentation")) {
180             // ignore documentation for now
181         } else {
182             context->messageHandler()->warning(QString::fromLatin1("Definitions: unknown tag %1").arg(child.tagName()));
183         }
184         child = child.nextSiblingElement();
185     }
186     return true;
187 }
188 
fixUpDefinitions()189 void Definitions::fixUpDefinitions(/*ParserContext *context, const QDomElement &element */)
190 {
191     if (mServices.isEmpty()) {
192         if (!mBindings.isEmpty()) {
193             qDebug() << "No service tag found in the wsdl file, generating one service per binding";
194             Q_FOREACH (const Binding &bind, mBindings) {
195                 Service service(mTargetNamespace);
196                 service.setName(bind.name() + "Service");
197 
198                 Port port(mTargetNamespace);
199                 port.setName(bind.name() + "Port");
200                 QName bindingName(bind.portTypeName().prefix() + ":" + bind.name());
201                 bindingName.setNameSpace(bind.nameSpace());
202                 port.setBindingName(bindingName);
203 
204                 Port::List portList;
205                 portList.append(port);
206                 service.setPorts(portList);
207                 mServices.append(service);
208             }
209         } else {
210             Q_ASSERT(!mPortTypes.isEmpty());
211             qDebug() << "No service or binding tag found in the wsdl file, generating only messages";
212             Q_FOREACH (const PortType &portType, mPortTypes) {
213                 Binding binding(mTargetNamespace);
214                 binding.setName(portType.name() + "Binding");
215                 binding.setPortTypeName(QName(portType.nameSpace(), portType.name()));
216                 binding.setType(Binding::UnknownBinding);
217                 mBindings.append(binding);
218 
219                 Port port(mTargetNamespace);
220                 port.setName(portType.name());
221                 port.setBindingName(QName(binding.nameSpace(), binding.name()));
222 
223                 Service service(mTargetNamespace);
224                 service.setName(portType.name() + "Service");
225                 service.setPorts(Port::List() << port);
226                 mServices.append(service);
227             }
228         }
229     }
230 }
231 
urlForLocation(ParserContext * context,const QString & location)232 static QUrl urlForLocation(ParserContext *context, const QString &location)
233 {
234     QUrl url(location);
235     if ((url.scheme().isEmpty() || url.scheme() == QLatin1String("file"))) {
236         QDir dir(location);
237         if (dir.isRelative()) {
238             url = context->documentBaseUrl();
239             url.setPath(url.path() + QLatin1Char('/') + location);
240         }
241     }
242     return url;
243 }
244 
importDefinition(ParserContext * context,const QString & location)245 void Definitions::importDefinition(ParserContext *context, const QString &location)
246 {
247     if (location.isEmpty()) {
248         context->messageHandler()->warning(QString::fromLatin1("Definitions import: location tag required: %1").arg(location));
249         return;
250     }
251     FileProvider provider;
252     QString fileName;
253     const QUrl locationUrl = urlForLocation(context, location);
254     qDebug("Importing wsdl definition at %s", locationUrl.toEncoded().constData());
255 
256     if (provider.get(locationUrl, fileName)) {
257         QFile file(fileName);
258         if (!file.open(QIODevice::ReadOnly)) {
259             qDebug("Unable to open file %s", qPrintable(file.fileName()));
260             return;
261         }
262 
263         QXmlInputSource source(&file);
264         QXmlSimpleReader reader;
265         reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true);
266 
267         QDomDocument doc(QLatin1String("kwsdl"));
268         QString errorMsg;
269         int errorLine, errorColumn;
270         bool ok = doc.setContent(&source, &reader, &errorMsg, &errorLine, &errorColumn);
271         if (!ok) {
272             qDebug("Error[%d:%d] %s", errorLine, errorColumn, qPrintable(errorMsg));
273             return;
274         }
275 
276         // prepare the new context to avoid infinite recursion
277         QDomElement rootNode = doc.documentElement();
278         NSManager namespaceManager(context, rootNode);
279 
280         const QName tagName(rootNode.tagName());
281         if (tagName.localName() == QLatin1String("definitions")) {
282             // recursivity
283             context->namespaceManager()->enterChild(rootNode);
284 
285             const QUrl oldBaseUrl = context->documentBaseUrl();
286             context->setDocumentBaseUrlFromFileUrl(locationUrl);
287 
288             loadXML(context, rootNode);
289 
290             context->setDocumentBaseUrl(oldBaseUrl);
291 
292         } else {
293             qDebug("No definition tag found in imported wsdl file %s", locationUrl.toEncoded().constData());
294         }
295 
296         file.close();
297 
298         provider.cleanUp();
299     }
300 }
301 
302 #if 0
303 void Definitions::saveXML(ParserContext *context, QDomDocument &document) const
304 {
305     QDomElement element = document.createElement("definitions");
306     document.appendChild(element);
307 
308     if (!mTargetNamespace.isEmpty()) {
309         element.setAttribute("targetNamespace", mTargetNamespace);
310     }
311     if (!mName.isEmpty()) {
312         element.setAttribute("name", mName);
313     }
314 
315     {
316         Import::List::ConstIterator it(mImports.begin());
317         const Import::List::ConstIterator endIt(mImports.end());
318         for (; it != endIt; ++it) {
319             (*it).saveXML(context, document, element);
320         }
321     }
322 
323     mType.saveXML(context, document, element);
324 
325     {
326         Message::List::ConstIterator it(mMessages.begin());
327         const Message::List::ConstIterator endIt(mMessages.end());
328         for (; it != endIt; ++it) {
329             (*it).saveXML(context, document, element);
330         }
331     }
332 
333     {
334         PortType::List::ConstIterator it(mPortTypes.begin());
335         const PortType::List::ConstIterator endIt(mPortTypes.end());
336         for (; it != endIt; ++it) {
337             (*it).saveXML(context, document, element);
338         }
339     }
340 
341     {
342         Binding::List::ConstIterator it(mBindings.begin());
343         const Binding::List::ConstIterator endIt(mBindings.end());
344         for (; it != endIt; ++it) {
345             (*it).saveXML(context, document, element);
346         }
347     }
348 
349     mService.saveXML(context, &mBindings, document, element);
350 }
351 #endif
352 
setWantedService(const QString & name)353 void Definitions::setWantedService(const QString &name)
354 {
355     mWantedService = name;
356 }
357