/thirdparty/qxt/qxtweb-standalone/qxtweb/qxtwebservicedirectory.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 239 lines · 107 code · 16 blank · 116 comment · 15 complexity · 0d3a2a8c7f2b9ec18eefa5602c5d4dcb MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) Qxt Foundation. Some rights reserved.
  4. **
  5. ** This file is part of the QxtWeb module of the Qxt library.
  6. **
  7. ** This library is free software; you can redistribute it and/or modify it
  8. ** under the terms of the Common Public License, version 1.0, as published
  9. ** by IBM, and/or under the terms of the GNU Lesser General Public License,
  10. ** version 2.1, as published by the Free Software Foundation.
  11. **
  12. ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
  13. ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
  14. ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
  15. ** FITNESS FOR A PARTICULAR PURPOSE.
  16. **
  17. ** You should have received a copy of the CPL and the LGPL along with this
  18. ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
  19. ** included with the source distribution for more information.
  20. ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
  21. **
  22. ** <http://libqxt.org> <foundation@libqxt.org>
  23. **
  24. ****************************************************************************/
  25. /*!
  26. \class QxtWebServiceDirectory
  27. \inmodule QxtWeb
  28. \brief The QxtWebServiceDirectory class provides Path-based web service dispatcher
  29. QxtWebServiceDirectory allows multiple services to be associated with a single
  30. session. Selection between services is determined by the first path component
  31. in the URL. For example, the URL "/site/request?param=true" would relay the
  32. URL "/request?param=true" to the service named "site".
  33. This class can be used recursively to declare a hierarchy of services. For
  34. example:
  35. \code
  36. QxtWebServiceDirectory* top = new QxtWebServiceDirectory(sm, sm);
  37. QxtWebServiceDirectory* service1 = new QxtWebServiceDirectory(sm, top);
  38. QxtWebServiceDirectory* service2 = new QxtWebServiceDirectory(sm, top);
  39. QxtWebServiceDirectory* service1a = new QxtWebServiceDirectory(sm, service1);
  40. QxtWebServiceDirectory* service1b = new QxtWebServiceDirectory(sm, service1);
  41. top->addService("1", service1);
  42. top->addService("2", service2);
  43. service1->addService("a", service1a);
  44. service1->addService("b", service1b);
  45. \endcode
  46. This accepts the URLs "/1/a/", "/1/b/", and "/2/".
  47. */
  48. #include "qxtwebservicedirectory.h"
  49. #include "qxtwebservicedirectory_p.h"
  50. #include "qxtwebevent.h"
  51. #include <QUrl>
  52. #include <QtDebug>
  53. #ifndef QXT_DOXYGEN_RUN
  54. QxtWebServiceDirectoryPrivate::QxtWebServiceDirectoryPrivate() : QObject(0)
  55. {
  56. // initializers only
  57. }
  58. void QxtWebServiceDirectoryPrivate::serviceDestroyed()
  59. {
  60. QxtAbstractWebService* service = qobject_cast<QxtAbstractWebService*>(sender());
  61. if (!service) return; // this shouldn't happen
  62. QString path;
  63. while (!(path = services.key(service)).isNull())
  64. {
  65. services.remove(path);
  66. }
  67. }
  68. #endif
  69. /*!
  70. * Constructs a QxtWebServiceDirectory object with the specified session manager \a sm and \a parent.
  71. *
  72. * Often, the session manager will also be the parent, but this is not a requirement.
  73. */
  74. QxtWebServiceDirectory::QxtWebServiceDirectory(QxtAbstractWebSessionManager* sm, QObject* parent) : QxtAbstractWebService(sm, parent)
  75. {
  76. QXT_INIT_PRIVATE(QxtWebServiceDirectory);
  77. }
  78. /*!
  79. * Adds a \a service to the directory at the given \a path.
  80. * \sa removeService(), service()
  81. */
  82. void QxtWebServiceDirectory::addService(const QString& path, QxtAbstractWebService* service)
  83. {
  84. if (qxt_d().services.contains(path))
  85. {
  86. qWarning() << "QxtWebServiceDirectory::addService:" << path << "already registered";
  87. }
  88. qxt_d().services[path] = service;
  89. if (qxt_d().defaultRedirect.isEmpty())
  90. setDefaultRedirect(path);
  91. connect(service, SIGNAL(destroyed()), &qxt_d(), SLOT(serviceDestroyed()));
  92. }
  93. /*!
  94. * Removes the service at the given \a path.
  95. *
  96. * Note that the service object is not destroyed.
  97. */
  98. void QxtWebServiceDirectory::removeService(const QString& path)
  99. {
  100. if (!qxt_d().services.contains(path))
  101. {
  102. qWarning() << "QxtWebServiceDirectory::removeService:" << path << "not registered";
  103. }
  104. else
  105. {
  106. qxt_d().services.remove(path);
  107. }
  108. }
  109. /*!
  110. * Returns the service at the given \a path.
  111. */
  112. QxtAbstractWebService* QxtWebServiceDirectory::service(const QString& path) const
  113. {
  114. if (!qxt_d().services.contains(path))
  115. return 0;
  116. return qxt_d().services[path];
  117. }
  118. /*!
  119. * \internal
  120. * Returns the first path segment from the URL in the \a event object.
  121. * (i.e. "a" from "/a/b/c") This also removes the path segment from the
  122. * event object. (in the previous example, the event's URL is now "/b/c")
  123. */
  124. static QString extractPathLevel(QxtWebRequestEvent* event)
  125. {
  126. QString path = event->url.path();
  127. int pos = path.indexOf("/", 1); // the path always starts with /
  128. if (pos == -1)
  129. event->url.setPath(""); // cue to redirect to /service/
  130. else
  131. event->url.setPath(path.mid(pos));
  132. return path.mid(1, pos - 1);
  133. }
  134. /*!
  135. * \reimp
  136. */
  137. void QxtWebServiceDirectory::pageRequestedEvent(QxtWebRequestEvent* event)
  138. {
  139. QString path = extractPathLevel(event);
  140. if (path.isEmpty())
  141. {
  142. indexRequested(event);
  143. }
  144. else if (!qxt_d().services.contains(path))
  145. {
  146. unknownServiceRequested(event, path);
  147. }
  148. else if (event->url.path().isEmpty())
  149. {
  150. postEvent(new QxtWebRedirectEvent(event->sessionID, event->requestID, path + '/', 307));
  151. }
  152. else
  153. {
  154. qxt_d().services[path]->pageRequestedEvent(event);
  155. }
  156. }
  157. /*
  158. * \reimp unimplemented
  159. */
  160. /*
  161. void QxtWebServiceDirectory::functionInvokedEvent(QxtWebRequestEvent* event) {
  162. QString path = extractPathLevel(event);
  163. if(path == "") {
  164. indexRequested(event);
  165. } else if(!qxt_d().services.contains(path)) {
  166. unknownServiceRequested(event, path);
  167. } else {
  168. qxt_d().services[path]->functionInvokedEvent(event);
  169. }
  170. }
  171. */
  172. /*!
  173. * This \a event handler is called whenever the URL requests a service with \a name that has
  174. * not been added to the directory.
  175. *
  176. * The default implementation returns a 404 "Service not known" error.
  177. * Subclasses may reimplement this event handler to customize this behavior.
  178. */
  179. void QxtWebServiceDirectory::unknownServiceRequested(QxtWebRequestEvent* event, const QString& name)
  180. {
  181. postEvent(new QxtWebErrorEvent(event->sessionID, event->requestID, 404, ("Service &quot;" + QString(name).replace('<', "&lt") + "&quot; not known").toUtf8()));
  182. }
  183. /*!
  184. * This \a event handler is called whenever the URL does not contain a path, that
  185. * is, the URL is "/" or empty.
  186. *
  187. * The default implementation redirects to the service specified by
  188. * setDefaultRedirect(), or invokes unknownServiceRequested() if no default
  189. * redirect has been set.
  190. */
  191. void QxtWebServiceDirectory::indexRequested(QxtWebRequestEvent* event)
  192. {
  193. if (defaultRedirect().isEmpty())
  194. {
  195. unknownServiceRequested(event, "/");
  196. }
  197. else
  198. {
  199. postEvent(new QxtWebRedirectEvent(event->sessionID, event->requestID, defaultRedirect() + '/', 307));
  200. }
  201. }
  202. /*!
  203. * Returns the path that will be used by default by the indexRequested event.
  204. * \sa indexRequested(), setDefaultRedirect()
  205. */
  206. QString QxtWebServiceDirectory::defaultRedirect() const
  207. {
  208. return qxt_d().defaultRedirect;
  209. }
  210. /*!
  211. * Sets the \a path that will be used by default by the indexRequested event.
  212. * \sa indexRequested(), defaultRedirect()
  213. */
  214. void QxtWebServiceDirectory::setDefaultRedirect(const QString& path)
  215. {
  216. if (!qxt_d().services.contains(path))
  217. qWarning() << "QxtWebServiceDirectory::setDefaultRedirect:" << path << "not registered";
  218. qxt_d().defaultRedirect = path;
  219. }