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