PageRenderTime 73ms CodeModel.GetById 40ms app.highlight 16ms RepoModel.GetById 14ms app.codeStats 0ms

/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/*!
 27\class QxtWebServiceDirectory
 28
 29\inmodule QxtWeb
 30
 31\brief The QxtWebServiceDirectory class provides Path-based web service dispatcher
 32
 33QxtWebServiceDirectory allows multiple services to be associated with a single
 34session. Selection between services is determined by the first path component
 35in the URL. For example, the URL "/site/request?param=true" would relay the
 36URL "/request?param=true" to the service named "site".
 37
 38This class can be used recursively to declare a hierarchy of services. For
 39example:
 40\code
 41QxtWebServiceDirectory* top = new QxtWebServiceDirectory(sm, sm);
 42QxtWebServiceDirectory* service1 = new QxtWebServiceDirectory(sm, top);
 43QxtWebServiceDirectory* service2 = new QxtWebServiceDirectory(sm, top);
 44QxtWebServiceDirectory* service1a = new QxtWebServiceDirectory(sm, service1);
 45QxtWebServiceDirectory* service1b = new QxtWebServiceDirectory(sm, service1);
 46top->addService("1", service1);
 47top->addService("2", service2);
 48service1->addService("a", service1a);
 49service1->addService("b", service1b);
 50\endcode
 51This accepts the URLs "/1/a/", "/1/b/", and "/2/".
 52*/
 53
 54#include "qxtwebservicedirectory.h"
 55#include "qxtwebservicedirectory_p.h"
 56#include "qxtwebevent.h"
 57#include <QUrl>
 58#include <QtDebug>
 59
 60#ifndef QXT_DOXYGEN_RUN
 61QxtWebServiceDirectoryPrivate::QxtWebServiceDirectoryPrivate() : QObject(0)
 62{
 63    // initializers only
 64}
 65
 66void QxtWebServiceDirectoryPrivate::serviceDestroyed()
 67{
 68    QxtAbstractWebService* service = qobject_cast<QxtAbstractWebService*>(sender());
 69    if (!service) return; // this shouldn't happen
 70    QString path;
 71    while (!(path = services.key(service)).isNull())
 72    {
 73        services.remove(path);
 74    }
 75}
 76#endif
 77
 78/*!
 79 * Constructs a QxtWebServiceDirectory object with the specified session manager \a sm and \a parent.
 80 *
 81 * Often, the session manager will also be the parent, but this is not a requirement.
 82 */
 83QxtWebServiceDirectory::QxtWebServiceDirectory(QxtAbstractWebSessionManager* sm, QObject* parent) : QxtAbstractWebService(sm, parent)
 84{
 85    QXT_INIT_PRIVATE(QxtWebServiceDirectory);
 86}
 87
 88/*!
 89 * Adds a \a service to the directory at the given \a path.
 90 * \sa removeService(), service()
 91 */
 92void QxtWebServiceDirectory::addService(const QString& path, QxtAbstractWebService* service)
 93{
 94    if (qxt_d().services.contains(path))
 95    {
 96        qWarning() << "QxtWebServiceDirectory::addService:" << path << "already registered";
 97    }
 98
 99    qxt_d().services[path] = service;
100    if (qxt_d().defaultRedirect.isEmpty())
101        setDefaultRedirect(path);
102    connect(service, SIGNAL(destroyed()), &qxt_d(), SLOT(serviceDestroyed()));
103}
104
105/*!
106 * Removes the service at the given \a path.
107 *
108 * Note that the service object is not destroyed.
109 */
110void QxtWebServiceDirectory::removeService(const QString& path)
111{
112    if (!qxt_d().services.contains(path))
113    {
114        qWarning() << "QxtWebServiceDirectory::removeService:" << path << "not registered";
115    }
116    else
117    {
118        qxt_d().services.remove(path);
119    }
120}
121
122/*!
123 * Returns the service at the given \a path.
124 */
125QxtAbstractWebService* QxtWebServiceDirectory::service(const QString& path) const
126{
127    if (!qxt_d().services.contains(path))
128        return 0;
129    return qxt_d().services[path];
130}
131
132/*!
133 * \internal
134 * Returns the first path segment from the URL in the \a event object.
135 * (i.e. "a" from "/a/b/c") This also removes the path segment from the
136 * event object. (in the previous example, the event's URL is now "/b/c")
137 */
138static QString extractPathLevel(QxtWebRequestEvent* event)
139{
140    QString path = event->url.path();
141    int pos = path.indexOf("/", 1); // the path always starts with /
142    if (pos == -1)
143        event->url.setPath(""); // cue to redirect to /service/
144    else
145        event->url.setPath(path.mid(pos));
146    return path.mid(1, pos - 1);
147}
148
149/*!
150 * \reimp
151 */
152void QxtWebServiceDirectory::pageRequestedEvent(QxtWebRequestEvent* event)
153{
154    QString path = extractPathLevel(event);
155    if (path.isEmpty())
156    {
157        indexRequested(event);
158    }
159    else if (!qxt_d().services.contains(path))
160    {
161        unknownServiceRequested(event, path);
162    }
163    else if (event->url.path().isEmpty())
164    {
165        postEvent(new QxtWebRedirectEvent(event->sessionID, event->requestID, path + '/', 307));
166    }
167    else
168    {
169        qxt_d().services[path]->pageRequestedEvent(event);
170    }
171}
172
173/*
174 * \reimp unimplemented
175 */
176/*
177void QxtWebServiceDirectory::functionInvokedEvent(QxtWebRequestEvent* event) {
178    QString path = extractPathLevel(event);
179    if(path == "") {
180        indexRequested(event);
181    } else if(!qxt_d().services.contains(path)) {
182        unknownServiceRequested(event, path);
183    } else {
184        qxt_d().services[path]->functionInvokedEvent(event);
185    }
186}
187*/
188
189/*!
190 * This \a event handler is called whenever the URL requests a service with \a name that has
191 * not been added to the directory.
192 *
193 * The default implementation returns a 404 "Service not known" error.
194 * Subclasses may reimplement this event handler to customize this behavior.
195 */
196void QxtWebServiceDirectory::unknownServiceRequested(QxtWebRequestEvent* event, const QString& name)
197{
198    postEvent(new QxtWebErrorEvent(event->sessionID, event->requestID, 404, ("Service &quot;" + QString(name).replace('<', "&lt") + "&quot; not known").toUtf8()));
199}
200
201/*!
202 * This \a event handler is called whenever the URL does not contain a path, that
203 * is, the URL is "/" or empty.
204 *
205 * The default implementation redirects to the service specified by
206 * setDefaultRedirect(), or invokes unknownServiceRequested() if no default
207 * redirect has been set.
208 */
209void QxtWebServiceDirectory::indexRequested(QxtWebRequestEvent* event)
210{
211    if (defaultRedirect().isEmpty())
212    {
213        unknownServiceRequested(event, "/");
214    }
215    else
216    {
217        postEvent(new QxtWebRedirectEvent(event->sessionID, event->requestID, defaultRedirect() + '/', 307));
218    }
219}
220
221/*!
222 * Returns the path that will be used by default by the indexRequested event.
223 * \sa indexRequested(), setDefaultRedirect()
224 */
225QString QxtWebServiceDirectory::defaultRedirect() const
226{
227    return qxt_d().defaultRedirect;
228}
229
230/*!
231 * Sets the \a path that will be used by default by the indexRequested event.
232 * \sa indexRequested(), defaultRedirect()
233 */
234void QxtWebServiceDirectory::setDefaultRedirect(const QString& path)
235{
236    if (!qxt_d().services.contains(path))
237        qWarning() << "QxtWebServiceDirectory::setDefaultRedirect:" << path << "not registered";
238    qxt_d().defaultRedirect = path;
239}