Cutelyst  2.13.0
application.cpp
1 /*
2  * Copyright (C) 2013-2020 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "application_p.h"
19 
20 #include "config.h"
21 #include "common.h"
22 #include "context_p.h"
23 #include "enginerequest.h"
24 #include "request.h"
25 #include "request_p.h"
26 #include "controller.h"
27 #include "controller_p.h"
28 #include "response.h"
29 #include "response_p.h"
30 #include "dispatchtype.h"
31 #include "view.h"
32 #include "stats.h"
33 #include "utils.h"
34 
35 #include <QtCore/QDir>
36 #include <QtCore/QStringList>
37 #include <QtCore/QDataStream>
38 #include <QtCore/QCoreApplication>
39 #include <QtCore/QPluginLoader>
40 #include <QtCore/QTranslator>
41 #include <QtCore/QFileInfo>
42 #include <QtCore/QLocale>
43 
44 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER, "cutelyst.dispatcher", QtWarningMsg)
45 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_PATH, "cutelyst.dispatcher.path", QtWarningMsg)
46 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_CHAINED, "cutelyst.dispatcher.chained", QtWarningMsg)
47 Q_LOGGING_CATEGORY(CUTELYST_CONTROLLER, "cutelyst.controller", QtWarningMsg)
48 Q_LOGGING_CATEGORY(CUTELYST_CORE, "cutelyst.core", QtWarningMsg)
49 Q_LOGGING_CATEGORY(CUTELYST_ENGINE, "cutelyst.engine", QtWarningMsg)
50 Q_LOGGING_CATEGORY(CUTELYST_UPLOAD, "cutelyst.upload", QtWarningMsg)
51 Q_LOGGING_CATEGORY(CUTELYST_MULTIPART, "cutelyst.multipart", QtWarningMsg)
52 Q_LOGGING_CATEGORY(CUTELYST_VIEW, "cutelyst.view", QtWarningMsg)
53 Q_LOGGING_CATEGORY(CUTELYST_REQUEST, "cutelyst.request", QtWarningMsg)
54 Q_LOGGING_CATEGORY(CUTELYST_RESPONSE, "cutelyst.response", QtWarningMsg)
55 Q_LOGGING_CATEGORY(CUTELYST_STATS, "cutelyst.stats", QtWarningMsg)
56 Q_LOGGING_CATEGORY(CUTELYST_COMPONENT, "cutelyst.component", QtWarningMsg)
57 
58 using namespace Cutelyst;
59 
60 Application::Application(QObject *parent) :
61  QObject(parent),
62  d_ptr(new ApplicationPrivate)
63 {
64  Q_D(Application);
65 
66  d->q_ptr = this;
67 
68  qRegisterMetaType<ParamsMultiMap>();
69  qRegisterMetaTypeStreamOperators<ParamsMultiMap>("ParamsMultiMap");
70 
71  d->dispatcher = new Dispatcher(this);
72 
73  loadTranslations(QStringLiteral("cutelystcore"));
74 }
75 
76 Application::~Application()
77 {
78  delete d_ptr;
79 }
80 
82 {
83  qCDebug(CUTELYST_CORE) << "Default Application::init called on pid:" << QCoreApplication::applicationPid();
84  return true;
85 }
86 
88 {
89  qCDebug(CUTELYST_CORE) << "Default Application::postFork called on pid:" << QCoreApplication::applicationPid();
90  return true;
91 }
92 
94 {
95  Q_D(Application);
96  return d->headers;
97 }
98 
100 {
101  Q_D(Application);
102  d->headers.setHeader(QStringLiteral("X_CUTELYST"), QStringLiteral(VERSION));
103 }
104 
106 {
107  Q_D(Application);
108  if (d->plugins.contains(plugin)) {
109  return false;
110  }
111  d->plugins.append(plugin);
112  return true;
113 }
114 
116 {
117  Q_D(Application);
118  const auto name = QString::fromLatin1(controller->metaObject()->className());
119  if (d->controllersHash.contains(name)) {
120  return false;
121  }
122  d->controllersHash.insert(name, controller);
123  d->controllers.append(controller);
124  return true;
125 }
126 
128 {
129  Q_D(Application);
130  if (d->views.contains(view->name())) {
131  qCWarning(CUTELYST_CORE) << "Not registering View." << view->metaObject()->className()
132  << "There is already a view with this name:" << view->name();
133  return false;
134  }
135  d->views.insert(view->name(), view);
136  return true;
137 }
138 
140 {
141  Q_D(Application);
142  if (d->dispatchers.contains(dispatcher)) {
143  return false;
144  }
145  d->dispatchers.append(dispatcher);
146  return true;
147 }
148 
149 Component *Application::createComponentPlugin(const QString &name, QObject *parent)
150 {
151  Q_D(Application);
152  auto it = d->factories.constFind(name);
153  if (it != d->factories.constEnd()) {
154  ComponentFactory *factory = it.value();
155  if (factory) {
156  return factory->createComponent(parent);
157  } else {
158  return nullptr;
159  }
160  }
161 
162  const QByteArrayList dirs = QByteArrayList{ QByteArrayLiteral(CUTELYST_PLUGINS_DIR) } + qgetenv("CUTELYST_PLUGINS_DIR").split(';');
163  for (const QByteArray &dir : dirs) {
164  Component *component = d->createComponentPlugin(name, parent, QString::fromLocal8Bit(dir));
165  if (component) {
166  return component;
167  }
168  }
169  qCDebug(CUTELYST_CORE) << "Did not find plugin" << name << "on" << dirs << "for" << parent;
170 
171  return nullptr;
172 }
173 
175 {
176  return VERSION;
177 }
178 
179 QVector<Cutelyst::Controller *> Application::controllers() const
180 {
181  Q_D(const Application);
182  return d->controllers;
183 }
184 
185 View *Application::view(const QString &name) const
186 {
187  Q_D(const Application);
188  return d->views.value(name);
189 }
190 
191 QVariant Application::config(const QString &key, const QVariant &defaultValue) const
192 {
193  Q_D(const Application);
194  auto it = d->config.constFind(key);
195  if (it != d->config.constEnd()) {
196  return it.value();
197  }
198  return defaultValue;
199 }
200 
202 {
203  Q_D(const Application);
204  return d->dispatcher;
205 }
206 
207 QVector<Cutelyst::DispatchType *> Application::dispatchers() const
208 {
209  Q_D(const Application);
210  return d->dispatcher->dispatchers();
211 }
212 
213 QVector<Plugin *> Application::plugins() const
214 {
215  Q_D(const Application);
216  return d->plugins;
217 }
218 
219 QVariantMap Application::config() const
220 {
221  Q_D(const Application);
222  return d->config;
223 }
224 
225 QString Application::pathTo(const QString &path) const
226 {
227  QDir home = config(QStringLiteral("home")).toString();
228  return home.absoluteFilePath(path);
229 }
230 
231 QString Cutelyst::Application::pathTo(const QStringList &path) const
232 {
233  QDir home = config(QStringLiteral("home")).toString();
234  return home.absoluteFilePath(path.join(QLatin1Char('/')));
235 }
236 
238 {
239  Q_D(const Application);
240  return d->init;
241 }
242 
244 {
245  Q_D(const Application);
246  return d->engine;
247 }
248 
249 void Application::setConfig(const QString &key, const QVariant &value)
250 {
251  Q_D(Application);
252  d->config.insert(key, value);
253 }
254 
256 {
257  Q_D(Application);
258 
259  if (d->init) {
260  return true;
261  }
262  d->init = true;
263 
264  d->useStats = CUTELYST_STATS().isDebugEnabled();
265  d->engine = engine;
266  d->config = engine->config(QLatin1String("Cutelyst"));
267 
268  d->setupHome();
269 
270  // Call the virtual application init
271  // to setup Controllers plugins stuff
272  if (init()) {
273  d->setupChildren(children());
274 
275  bool zeroCore = engine->workerCore() == 0;
276 
277  QVector<QStringList> tablePlugins;
278  const auto plugins = d->plugins;
279  for (Plugin *plugin : plugins) {
280  if (plugin->objectName().isEmpty()) {
281  plugin->setObjectName(QString::fromLatin1(plugin->metaObject()->className()));
282  }
283  tablePlugins.append({ plugin->objectName() });
284  // Configure plugins
285  plugin->setup(this);
286  }
287 
288  if (zeroCore && !tablePlugins.isEmpty()) {
289  qCDebug(CUTELYST_CORE) << Utils::buildTable(tablePlugins, QStringList(),
290  QLatin1String("Loaded plugins:")).constData();
291  }
292 
293  if (zeroCore) {
294  QVector<QStringList> tableDataHandlers;
295  tableDataHandlers.append({ QLatin1String("application/x-www-form-urlencoded") });
296  tableDataHandlers.append({ QLatin1String("application/json") });
297  tableDataHandlers.append({ QLatin1String("multipart/form-data") });
298  qCDebug(CUTELYST_CORE) << Utils::buildTable(tableDataHandlers, QStringList(),
299  QLatin1String("Loaded Request Data Handlers:")).constData();
300 
301  qCDebug(CUTELYST_CORE) << "Loaded dispatcher" << QString::fromLatin1(d->dispatcher->metaObject()->className());
302  qCDebug(CUTELYST_CORE) << "Using engine" << QString::fromLatin1(d->engine->metaObject()->className());
303  }
304 
305  QString home = d->config.value(QLatin1String("home")).toString();
306  if (home.isEmpty()) {
307  if (zeroCore) {
308  qCDebug(CUTELYST_CORE) << "Couldn't find home";
309  }
310  } else {
311  QFileInfo homeInfo = home;
312  if (homeInfo.isDir()) {
313  if (zeroCore) {
314  qCDebug(CUTELYST_CORE) << "Found home" << home;
315  }
316  } else {
317  if (zeroCore) {
318  qCDebug(CUTELYST_CORE) << "Home" << home << "doesn't exist";
319  }
320  }
321  }
322 
323  QVector<QStringList> table;
324  QStringList controllerNames = d->controllersHash.keys();
325  controllerNames.sort();
326  for (const QString &controller : controllerNames) {
327  table.append({ controller, QLatin1String("Controller")});
328  }
329 
330  const auto views = d->views;
331  for (View *view : views) {
332  if (view->reverse().isEmpty()) {
333  const QString className = QString::fromLatin1(view->metaObject()->className()) + QLatin1String("->execute");
334  view->setReverse(className);
335  }
336  table.append({ view->reverse(), QLatin1String("View")});
337  }
338 
339  if (zeroCore && !table.isEmpty()) {
340  qCDebug(CUTELYST_CORE) << Utils::buildTable(table, {
341  QLatin1String("Class"), QLatin1String("Type")
342  },
343  QLatin1String("Loaded components:")).constData();
344  }
345 
346  const auto controllers = d->controllers;
347  for (Controller *controller : controllers) {
348  controller->d_ptr->init(this, d->dispatcher);
349  }
350 
351  d->dispatcher->setupActions(d->controllers, d->dispatchers, d->engine->workerCore() == 0);
352 
353  if (zeroCore) {
354  qCInfo(CUTELYST_CORE) << qPrintable(QString::fromLatin1("%1 powered by Cutelyst %2, Qt %3.")
355  .arg(QCoreApplication::applicationName(),
356  QLatin1String(Application::cutelystVersion()),
357  QLatin1String(qVersion())));
358  }
359 
360  Q_EMIT preForked(this);
361 
362  return true;
363  }
364 
365  return false;
366 }
367 
369 {
370  Q_D(Application);
371 
372  Engine *engine = d->engine;
373 
374  auto priv = new ContextPrivate(this, engine, d->dispatcher, d->plugins);
375  auto c = new Context(priv);
376 
377  request->context = c;
378  priv->engineRequest = request;
379  priv->response = new Response(d->headers, request);
380  priv->request = new Request(request);
381 
382  if (d->useStats) {
383  priv->stats = new Stats(request);
384  }
385 
386  // Process request
387  bool skipMethod = false;
388  Q_EMIT beforePrepareAction(c, &skipMethod);
389 
390  if (!skipMethod) {
391  static bool log = CUTELYST_REQUEST().isEnabled(QtDebugMsg);
392  if (log) {
393  d->logRequest(priv->request);
394  }
395 
396  d->dispatcher->prepareAction(c);
397 
398  Q_EMIT beforeDispatch(c);
399 
400  d->dispatcher->dispatch(c);
401 
402  if (request->status & EngineRequest::Async) {
403  return;
404  }
405 
406  Q_EMIT afterDispatch(c);
407  }
408 
409  c->finalize();
410 }
411 
413 {
414  Q_D(Application);
415 
416  if (!postFork()) {
417  return false;
418  }
419 
420  const auto controllers = d->controllers;
421  for (Controller *controller : controllers) {
422  if (!controller->postFork(this)) {
423  return false;
424  }
425  }
426 
427  Q_EMIT postForked(this);
428 
429  return true;
430 }
431 
432 void Application::addTranslator(const QLocale &locale, QTranslator *translator)
433 {
434  Q_D(Application);
435  Q_ASSERT_X(translator, "add translator to application", "invalid QTranslator object");
436  auto it = d->translators.find(locale);
437  if (it != d->translators.end()) {
438  it.value().prepend(translator);
439  } else {
440  d->translators.insert(locale, QVector<QTranslator*>(1, translator));
441  }
442 }
443 
444 void Application::addTranslator(const QString &locale, QTranslator *translator)
445 {
446  addTranslator(QLocale(locale), translator);
447 }
448 
449 void Application::addTranslators(const QLocale &locale, const QVector<QTranslator *> &translators)
450 {
451  Q_D(Application);
452  Q_ASSERT_X(!translators.empty(), "add translators to application", "empty translators vector");
453  auto transIt = d->translators.find(locale);
454  if (transIt != d->translators.end()) {
455  for (auto it = translators.crbegin(); it != translators.crend(); ++it) {
456  transIt.value().prepend(*it);
457  }
458  } else {
459  d->translators.insert(locale, translators);
460  }
461 }
462 
463 static void replacePercentN(QString *result, int n)
464 {
465  if (n >= 0) {
466  auto percentPos = 0;
467  auto len = 0;
468  while ((percentPos = result->indexOf(QLatin1Char('%'), percentPos + len)) != -1) {
469  len = 1;
470  QString fmt;
471  if (result->at(percentPos + len) == QLatin1Char('L')) {
472  ++len;
473  fmt = QStringLiteral("%L1");
474  } else {
475  fmt = QStringLiteral("%1");
476  }
477  if (result->at(percentPos + len) == QLatin1Char('n')) {
478  fmt = fmt.arg(n);
479  ++len;
480  result->replace(percentPos, len, fmt);
481  len = fmt.length();
482  }
483  }
484  }
485 }
486 
487 QString Application::translate(const QLocale &locale, const char *context, const char *sourceText, const char *disambiguation, int n) const
488 {
489  QString result;
490 
491  if (!sourceText) {
492  return result;
493  }
494 
495  Q_D(const Application);
496 
497  const QVector<QTranslator*> translators = d->translators.value(locale);
498  if (translators.empty()) {
499  result = QString::fromUtf8(sourceText);
500  replacePercentN(&result, n);
501  return result;
502  }
503 
504  for (QTranslator *translator : translators) {
505  result = translator->translate(context, sourceText, disambiguation, n);
506  if (!result.isEmpty()) {
507  break;
508  }
509  }
510 
511  if (result.isEmpty()) {
512  result = QString::fromUtf8(sourceText);
513  }
514 
515  replacePercentN(&result, n);
516  return result;
517 }
518 
519 void Application::loadTranslations(const QString &filename, const QString &directory, const QString &prefix, const QString &suffix)
520 {
521  loadTranslationsFromDir(filename, directory, prefix, suffix);
522 }
523 
524 QVector<QLocale> Application::loadTranslationsFromDir(const QString &filename, const QString &directory, const QString &prefix, const QString &suffix)
525 {
526  QVector<QLocale> locales;
527 
528  if (Q_LIKELY(!filename.isEmpty())) {
529  const QString _dir = directory.isEmpty() ? QStringLiteral(I18NDIR) : directory;
530  const QDir i18nDir(_dir);
531  if (Q_LIKELY(i18nDir.exists())) {
532  const QString _prefix = prefix.isEmpty() ? QStringLiteral(".") : prefix;
533  const QString _suffix = suffix.isEmpty() ? QStringLiteral(".qm") : suffix;
534  const QStringList namesFilter = QStringList({filename + _prefix + QLatin1Char('*') + _suffix});
535 
536  const QFileInfoList tsFiles = i18nDir.entryInfoList(namesFilter, QDir::Files);
537  if (Q_LIKELY(!tsFiles.empty())) {
538  locales.reserve(tsFiles.size());
539  for (const QFileInfo &ts : tsFiles) {
540  const QString fn = ts.fileName();
541  const int prefIdx = fn.indexOf(_prefix);
542  const QString locString = fn.mid(prefIdx + _prefix.length(), fn.length() - prefIdx - _suffix.length() - _prefix.length());
543  QLocale loc(locString);
544  if (Q_LIKELY(loc.language() != QLocale::C)) {
545  auto trans = new QTranslator(this);
546  if (Q_LIKELY(trans->load(loc, filename, _prefix, _dir))) {
547  addTranslator(loc, trans);
548  locales.append(loc);
549  qCDebug(CUTELYST_CORE) << "Loaded translations for" << loc << "from" << ts.absoluteFilePath();
550  } else {
551  delete trans;
552  qCWarning(CUTELYST_CORE) << "Can not load translations for" << loc << "from" << ts.absoluteFilePath();
553  }
554  } else {
555  qCWarning(CUTELYST_CORE) << "Can not load translations for invalid locale string" << locString;
556  }
557  }
558  locales.squeeze();
559  } else {
560  qCWarning(CUTELYST_CORE) << "Can not find translation files for" << filename << "in directory" << _dir;
561  }
562  } else {
563  qCWarning(CUTELYST_CORE) << "Can not load translations from not existing directory:" << _dir;
564  }
565  } else {
566  qCWarning(CUTELYST_CORE) << "Can not load translations for empty file name.";
567  }
568 
569  return locales;
570 }
571 
572 QVector<QLocale> Application::loadTranslationsFromDirs(const QString &directory, const QString &filename)
573 {
574  QVector<QLocale> locales;
575 
576  if (Q_LIKELY(!directory.isEmpty() && !filename.isEmpty())) {
577  const QDir dir(directory);
578  if (Q_LIKELY(dir.exists())) {
579  const auto dirs = dir.entryList(QDir::AllDirs);
580  if (Q_LIKELY(!dirs.empty())) {
581  locales.reserve(dirs.size());
582  for (const QString &subDir : dirs) {
583  const QString relFn = subDir + QLatin1Char('/') + filename;
584  if (dir.exists(relFn)) {
585  const QLocale l(subDir);
586  if (Q_LIKELY(l.language() != QLocale::C)) {
587  auto trans = new QTranslator(this);
588  const QFileInfo fi(dir, relFn);
589  if (Q_LIKELY(trans->load(l, fi.baseName(), QString(), fi.absolutePath(), fi.suffix()))) {
590  addTranslator(l, trans);
591  locales.append(l);
592  qCDebug(CUTELYST_CORE) << "Loaded translations for" << l << "from" << fi.absoluteFilePath();
593  } else {
594  delete trans;
595  qCWarning(CUTELYST_CORE) << "Can not load translations for" << l << "from" << fi.absoluteFilePath();
596  }
597  } else {
598  qCWarning(CUTELYST_CORE) << "Can not load translations for invalid locale string:" << subDir;
599  }
600  }
601  }
602  locales.squeeze();
603  } else {
604  qCWarning(CUTELYST_CORE) << "Can not find locale dirs under" << directory;
605  }
606  } else {
607  qCWarning(CUTELYST_CORE) << "Can not load translations from not existing directory:" << directory;
608  }
609  } else {
610  qCWarning(CUTELYST_CORE) << "Can not load translations for empty file name or directory name";
611  }
612 
613  return locales;
614 }
615 
616 void Cutelyst::ApplicationPrivate::setupHome()
617 {
618  // Hook the current directory in config if "home" is not set
619  if (!config.contains(QLatin1String("home"))) {
620  config.insert(QStringLiteral("home"), QDir::currentPath());
621  }
622 
623  if (!config.contains(QLatin1String("root"))) {
624  QDir home = config.value(QLatin1String("home")).toString();
625  config.insert(QStringLiteral("root"), home.absoluteFilePath(QLatin1String("root")));
626  }
627 }
628 
629 void ApplicationPrivate::setupChildren(const QObjectList &children)
630 {
631  Q_Q(Application);
632  for (QObject *child : children) {
633  auto controller = qobject_cast<Controller *>(child);
634  if (controller) {
635  q->registerController(controller);
636  continue;
637  }
638 
639  auto plugin = qobject_cast<Plugin *>(child);
640  if (plugin) {
641  q->registerPlugin(plugin);
642  continue;
643  }
644 
645  auto view = qobject_cast<View *>(child);
646  if (view) {
647  q->registerView(view);
648  continue;
649  }
650 
651  auto dispatchType = qobject_cast<DispatchType *>(child);
652  if (dispatchType) {
653  q->registerDispatcher(dispatchType);
654  continue;
655  }
656  }
657 }
658 
659 void Cutelyst::ApplicationPrivate::logRequest(Request *req)
660 {
661  QString path = req->path();
662  if (path.isEmpty()) {
663  path = QStringLiteral("/");
664  }
665  qCDebug(CUTELYST_REQUEST) << req->method() << "request for" << path << "from" << req->addressString();
666 
667  ParamsMultiMap params = req->queryParameters();
668  if (!params.isEmpty()) {
669  logRequestParameters(params, QLatin1String("Query Parameters are:"));
670  }
671 
672  params = req->bodyParameters();
673  if (!params.isEmpty()) {
674  logRequestParameters(params, QLatin1String("Body Parameters are:"));
675  }
676 
677  const auto uploads = req->uploads();
678  if (!uploads.isEmpty()) {
679  logRequestUploads(uploads);
680  }
681 }
682 
683 void Cutelyst::ApplicationPrivate::logRequestParameters(const ParamsMultiMap &params, const QString &title)
684 {
685  QVector<QStringList> table;
686  auto it = params.constBegin();
687  while (it != params.constEnd()) {
688  table.append({ it.key(), it.value() });
689  ++it;
690  }
691  qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table, {
692  QLatin1String("Parameter"),
693  QLatin1String("Value"),
694  },
695  title).constData();
696 }
697 
698 void Cutelyst::ApplicationPrivate::logRequestUploads(const QVector<Cutelyst::Upload *> &uploads)
699 {
700  QVector<QStringList> table;
701  for (Upload *upload : uploads) {
702  table.append({ upload->name(),
703  upload->filename(),
704  upload->contentType(),
705  QString::number(upload->size())
706  });
707  }
708  qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table, {
709  QLatin1String("Parameter"),
710  QLatin1String("Filename"),
711  QLatin1String("Type"),
712  QLatin1String("Size"),
713  },
714  QLatin1String("File Uploads are:")).constData();
715 }
716 
717 Component *ApplicationPrivate::createComponentPlugin(const QString &name, QObject *parent, const QString &directory)
718 {
719  Component *component = nullptr;
720 
721  QDir pluginsDir(directory);
722  QPluginLoader loader;
723  ComponentFactory *factory = nullptr;
724  const auto plugins = pluginsDir.entryList(QDir::Files);
725  for (const QString &fileName : plugins) {
726  loader.setFileName(pluginsDir.absoluteFilePath(fileName));
727  const QJsonObject json = loader.metaData()[QLatin1String("MetaData")].toObject();
728  if (json[QLatin1String("name")].toString() == name) {
729  QObject *plugin = loader.instance();
730  if (plugin) {
731  factory = qobject_cast<ComponentFactory *>(plugin);
732  if (!factory) {
733  qCCritical(CUTELYST_CORE) << "Could not create a factory for" << loader.fileName();
734  } else {
735  component = factory->createComponent(parent);
736  }
737  break;
738  } else {
739  qCCritical(CUTELYST_CORE) << "Could not load plugin" << loader.fileName() << loader.errorString();
740  }
741  }
742  }
743 
744  if (factory) {
745  factories.insert(name, factory);
746  }
747 
748  return component;
749 }
750 
751 #include "moc_application.cpp"
Cutelyst::EngineRequest::status
Status status
Connection status.
Definition: enginerequest.h:167
Cutelyst::Controller
Cutelyst Controller base class
Definition: controller.h:102
Cutelyst::Application::postForked
void postForked(Cutelyst::Application *app)
Cutelyst::Plugin
Definition: plugin.h:30
Cutelyst::ParamsMultiMap
QMap< QString, QString > ParamsMultiMap
Definition: paramsmultimap.h:36
Cutelyst::Application::registerView
bool registerView(View *view)
Definition: application.cpp:127
Cutelyst::Request::addressString
QString addressString() const
Definition: request.cpp:52
Cutelyst::ComponentFactory
Definition: componentfactory.h:26
Cutelyst::Application::plugin
T plugin()
Returns the registered plugin that casts to the template type T.
Definition: application.h:115
Cutelyst::Application
The Cutelyst Application.
Definition: application.h:55
Cutelyst::Dispatcher
The Cutelyst Dispatcher.
Definition: dispatcher.h:40
Cutelyst::Application::view
View * view(const QString &name=QString()) const
Definition: application.cpp:185
Cutelyst::Application::config
QVariantMap config() const
Definition: application.cpp:219
Cutelyst::Application::plugins
QVector< Plugin * > plugins() const
Definition: application.cpp:213
Cutelyst::Engine::workerCore
int workerCore() const
Each worker process migth have a number of worker cores (threads), a single process with two worker t...
Definition: engine.cpp:119
Cutelyst::Context
The Cutelyst Context.
Definition: context.h:50
Cutelyst::Application::addXCutelystVersionHeader
void addXCutelystVersionHeader()
Definition: application.cpp:99
Cutelyst::Application::controllers
QVector< Controller * > controllers() const
Definition: application.cpp:179
Cutelyst::Component
The Cutelyst Component base class.
Definition: component.h:38
Cutelyst::Application::loadTranslations
void loadTranslations(const QString &filename, const QString &directory=QString(), const QString &prefix=QString(), const QString &suffix=QString())
Definition: application.cpp:519
Cutelyst::Application::createComponentPlugin
Component * createComponentPlugin(const QString &name, QObject *parent=nullptr)
Definition: application.cpp:149
Cutelyst::Request
Definition: request.h:42
Cutelyst::Application::defaultHeaders
Headers & defaultHeaders()
Definition: application.cpp:93
Cutelyst::Request::uploads
QVector< Upload * > uploads() const
Definition: request.cpp:387
Cutelyst::Application::handleRequest
void handleRequest(Cutelyst::EngineRequest *request)
Called by the Engine to handle a new Request object.
Definition: application.cpp:368
Cutelyst::Application::setup
bool setup(Engine *engine)
Called by the Engine to setup the internal data.
Definition: application.cpp:255
Cutelyst::Application::engine
Engine * engine() const
Definition: application.cpp:243
Cutelyst::Application::init
virtual bool init()
Definition: application.cpp:81
Cutelyst::EngineRequest
Definition: enginerequest.h:31
Cutelyst::Application::preForked
void preForked(Cutelyst::Application *app)
Cutelyst::Application::pathTo
QString pathTo(const QString &path) const
Definition: application.cpp:225
Cutelyst::Application::registerDispatcher
bool registerDispatcher(DispatchType *dispatcher)
Definition: application.cpp:139
Cutelyst::Component::setReverse
void setReverse(const QString &reverse)
Definition: component.cpp:62
Cutelyst::Application::beforePrepareAction
void beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
Cutelyst::Application::addTranslator
void addTranslator(const QLocale &locale, QTranslator *translator)
Definition: application.cpp:432
Cutelyst::Application::registerController
bool registerController(Controller *controller)
Definition: application.cpp:115
Cutelyst::DispatchType
Definition: dispatchtype.h:31
Cutelyst::Request::queryParameters
ParamsMultiMap queryParameters() const
Definition: request.cpp:263
Cutelyst::Application::dispatcher
Dispatcher * dispatcher() const
Definition: application.cpp:201
Cutelyst::Application::beforeDispatch
void beforeDispatch(Cutelyst::Context *c)
Cutelyst::Headers
Definition: headers.h:29
Cutelyst::Stats
Definition: stats.h:29
Cutelyst::EngineRequest::context
Context * context
The Cutelyst::Context of this request.
Definition: enginerequest.h:175
Cutelyst::Application::Application
Application(QObject *parent=nullptr)
Definition: application.cpp:60
Cutelyst::Application::afterDispatch
void afterDispatch(Cutelyst::Context *c)
Cutelyst::View
Cutelyst View abstract view component
Definition: view.h:34
Cutelyst::Application::dispatchers
QVector< DispatchType * > dispatchers() const
Definition: application.cpp:207
Cutelyst
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
Cutelyst::Component::name
QString name() const
Definition: component.cpp:44
Cutelyst::Application::registerPlugin
bool registerPlugin(Plugin *plugin)
Definition: application.cpp:105
Cutelyst::Application::addTranslators
void addTranslators(const QLocale &locale, const QVector< QTranslator * > &translators)
Definition: application.cpp:449
Cutelyst::ComponentFactory::createComponent
virtual Component * createComponent(QObject *parent=nullptr)=0
Cutelyst::Application::enginePostFork
bool enginePostFork()
Called by the Engine once post fork happened.
Definition: application.cpp:412
Cutelyst::Engine
The Cutelyst Engine.
Definition: engine.h:33
Cutelyst::Application::loadTranslationsFromDir
QVector< QLocale > loadTranslationsFromDir(const QString &filename, const QString &directory=QString(), const QString &prefix=QStringLiteral("."), const QString &suffix=QStringLiteral(".qm"))
Definition: application.cpp:524
Cutelyst::Engine::config
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:320
Cutelyst::Application::inited
bool inited() const
Definition: application.cpp:237
Cutelyst::Application::postFork
virtual bool postFork()
Definition: application.cpp:87
Cutelyst::Application::setConfig
void setConfig(const QString &key, const QVariant &value)
Definition: application.cpp:249
Cutelyst::Component::reverse
QString reverse() const
Definition: component.cpp:56
Cutelyst::Upload
Cutelyst Upload handles file upload request
Definition: upload.h:35
Cutelyst::Request::bodyParameters
ParamsMultiMap bodyParameters() const
Definition: request.cpp:227
Cutelyst::Application::loadTranslationsFromDirs
QVector< QLocale > loadTranslationsFromDirs(const QString &directory, const QString &filename)
Definition: application.cpp:572
Cutelyst::Application::cutelystVersion
static const char * cutelystVersion()
Definition: application.cpp:174
Cutelyst::Response
Definition: response.h:34
Cutelyst::Application::translate
QString translate(const QLocale &locale, const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
Definition: application.cpp:487