LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
limaSimpleClientDelegate.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 by CEA - LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
7
8#include "common/LimaCommon.h"
9#include "common/LimaVersion.h"
17#include "common/QsLog/QsLog.h"
22
27
28#include <boost/algorithm/string/regex.hpp>
29#include <QtCore/QFileInfo>
30#include <QtCore/QTimer>
31#include <QMetaType>
32
33using namespace Lima::LinguisticProcessing;
34using namespace Lima::Common::MediaticData;
35using namespace Lima::Common::Misc;
36using namespace std;
37
38namespace Lima {
39
40// initialize delegate static members
41int LimaSimpleClientDelegate::argc = 1;
42char* LimaSimpleClientDelegate::argv[2] = {(char*)("LimaSimpleClientDelegate"), NULL};
43QCoreApplication* LimaSimpleClientDelegate::app=nullptr;
44//QThread* LimaSimpleClientDelegate::thread=nullptr;
45boost::thread* LimaSimpleClientDelegate::thread=nullptr;
46std::shared_ptr<LimaWorker> LimaSimpleClientDelegate::m_worker(nullptr);
47std::shared_ptr<LimaController> LimaSimpleClientDelegate::m_controller(nullptr);
48
49// needed to pass string in signals/slots
50int metatype_string_id=qRegisterMetaType<std::string>("std::string");
51
52//***********************************************************************
53LimaWorker::LimaWorker(QObject* parent):
54 QObject(parent),
55 m_language(),
56 m_pipeline(),
57 m_client(nullptr),
58 m_handler(nullptr),
59 m_handlers(),
60 m_firstInitialization(true)
61{
62}
63
65{
66 //cout << "thread=" << getThreadId() << " LimaWorker destructor " << this << endl;
67 if (m_handler!=nullptr) {
68 delete m_handler;
69 }
70}
71
73{
74 // clear the linguistic resources: must be done inside the worker thread because they use QObjects
75 // (otherwise, warning: QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread)
77}
78
80QObject(parent),
81m_finishedInit(false),
82m_finishedAnalyze(false)
83{
84}
85
86
88{
89 //cout << "thread=" << getThreadId() << " LimaController destructor " << this;
90}
91
93{
94 //cout << getThreadId() << " LimaController::stop()" << endl;
95 Q_EMIT(closeWorker());
96 Q_EMIT(closeApp());
97}
98
100{
101 // initialize the internal thread
102 if (thread == nullptr)
103 {
104 thread = new boost::thread(LimaSimpleClientDelegate::onStarted);
105 //cout << "thread created: "<< thread << endl;
106 while (! m_worker) {
107 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
108 }
109 if (m_worker) {
110 //cout << "create connections" << endl;
111 }
112 }
113}
114
116{
117 //cout << getThreadId() << " LimaSimpleClientDelegate destructor" << endl;
118 // do not join lightly: app.exec() does not finish
119 // first stop the app and delete the linguistic resources associated to the worker
120 m_controller->stop();
121 // then wait for the thread to finish (so that everything is properly stopped before deleting the worker and controller
122 thread->join();
123 // do not delete worker or controller: shared pointers
124}
125
126void LimaSimpleClientDelegate::onStarted()
127{
128 //cout << "LimaSimpleClientDelegate::onStarted begin" << endl;
129 if (QCoreApplication::instance() == NULL)
130 {
131 app = new QCoreApplication(argc, argv);
132
133 m_worker=std::shared_ptr<LimaWorker>(new LimaWorker());
134 m_controller=std::shared_ptr<LimaController>(new LimaController());
135
136 // connectors to call the functions of the worker
137 QObject::connect(m_controller.get(), SIGNAL(doInitialize(std::string,std::string)), m_worker.get(), SLOT(initialize(std::string,std::string)));
138 QObject::connect(m_controller.get(), SIGNAL(doAnalyze(std::string)), m_worker.get(), SLOT(analyze(std::string)));
139 QObject::connect(m_worker.get(), SIGNAL(finishedInit()), m_controller.get(), SLOT(endInit()));
140 QObject::connect(m_worker.get(), SIGNAL(finishedAnalyze()), m_controller.get(), SLOT(endAnalyze()));
141 QObject::connect(m_controller.get(), SIGNAL(closeApp()), app, SLOT(quit()));
142 QObject::connect(m_controller.get(), SIGNAL(closeWorker()), m_worker.get(), SLOT(quit()));
143
144 app->exec();
145 }
146 //cout << "LimaSimpleClientDelegate::onStarted end" << endl;
147}
148
149void LimaController::initialize(const std::string& language,
150 const std::string& pipeline)
151{
152 //cout << "thread=" << getThreadId() << " LimaController::initialize " << this << endl;
153 // pass the command to the worker in the thread, through a signal
154 m_finishedInit=false;
155 Q_EMIT(doInitialize(language,pipeline));
156}
157
158void LimaSimpleClientDelegate::initialize(const std::string& language,
159 const std::string& pipeline)
160{
161 //cout << "LimaSimpleClientDelegate::initialize " << this << endl;
162 //cout << ",controller=" << m_controller << ",worker=" << m_worker << endl;
163 m_controller->initialize(language,pipeline);
164 // wait until initialization is finished
165 while (! m_controller->hasFinishedInit()) {
166 //cerr << "waiting for initialization to finish" << endl;
167 boost::this_thread::sleep( boost::posix_time::milliseconds(10) );
168 }
169}
170
171void LimaController::analyze(const std::string& text)
172{
174 // pass the command to the worker in the thread, through a signal
175 m_finishedAnalyze=false;
176 Q_EMIT(doAnalyze(text));
177}
178
179std::string LimaSimpleClientDelegate::analyze(const std::string& text)
180{
181 //cout << getThreadId() << " LimaSimpleClientDelegate::analyze" << endl;
182 // pass the command to the worker in the thread, through a signal
183 m_controller->analyze(text);
184 while (! m_controller->hasFinishedAnalyze()) {
185 boost::this_thread::sleep( boost::posix_time::milliseconds(10) );
186 }
187 return m_worker->getResult();
188}
189
190void LimaWorker::initialize(const std::string& language,
191 const std::string& pipeline)
192{
193 //cout << getThreadId() << " LimaWorker::initialize " << m_firstInitialization << endl;
194 m_language=language;
195 m_pipeline=pipeline;
196 string clientId("lima-coreclient");
197
198 QStringList configDirs = buildConfigurationDirectoriesList(QStringList({"lima"}),
199 QStringList());
200 QString configPath = configDirs.join(LIMA_PATH_SEPARATOR);
201
202 QStringList resourcesDirs = buildResourcesDirectoriesList(QStringList({"lima"}),
203 QStringList());
204 QString resourcesPath = resourcesDirs.join(LIMA_PATH_SEPARATOR);
205
206 // default values for lima configuration
207 string commonConfigFile("lima-common.xml");
208 string lpConfigFile("lima-analysis.xml");
209
210 std::deque<std::string> langs(1,language);
211 std::deque<std::string> pipelines(1,pipeline);
212
214 QsLogging::initQsLog(configPath);
215 // Necessary to initialize factories
217 if (!Lima::AmosePluginsManager::changeable().loadPlugins(configPath))
218 throw InvalidConfiguration("loadPlugins method failed.");
219
221
222
224 m_handlers.insert(std::make_pair("simpleStreamHandler", m_handler));
225 }
226 else {
227 cerr << "Factory already initialized" << endl;
228 }
229
230 // initialize common
232 init(resourcesPath.toUtf8().constData(),
233 configPath.toUtf8().constData(),
234 commonConfigFile,
235 langs);
236
237 bool clientFactoryConfigured = false;
238 Q_FOREACH(QString configDir, configDirs)
239 {
240 if (QFileInfo::exists(configDir + "/" + lpConfigFile.c_str()))
241 {
242 // initialize linguistic processing
244 configDir + "/" + lpConfigFile.c_str());
245 LinguisticProcessingClientFactory::changeable().configureClientFactory(
246 clientId,
247 lpconfig,
248 langs,
249 pipelines);
250 clientFactoryConfigured = true;
251 break;
252 }
253 }
254
255 if(!clientFactoryConfigured)
256 {
257 std::cerr << "No LinguisticProcessingClientFactory were configured with"
258 << configDirs.join(LIMA_PATH_SEPARATOR).toStdString() << "and"
259 << lpConfigFile << std::endl;
260 }
261
262 m_client = std::dynamic_pointer_cast<AbstractLinguisticProcessingClient>(
263 LinguisticProcessingClientFactory::single().createClient(clientId));
264
265 Q_EMIT(finishedInit());
266}
267
268void LimaWorker::analyze(const std::string& text)
269{
270 //cout << getThreadId() << " LimaWorker::analyze start" << endl;
271 std::map<std::string,std::string> metaData;
272 metaData["Lang"]=m_language;
273 string pseudofilename=text.substr(0,10);
274 boost::regex_replace(pseudofilename,
275 boost::regex("[.,-;:!?\",& <>\n\t ]"),
276 "_",
277 boost::format_all);
278 metaData["FileName"]=pseudofilename;
279
280 ostringstream oss;
281 m_handler->setOut(&oss);
282 m_client->analyze(text, metaData, m_pipeline, m_handlers);
283 //cout << getThreadId() << " LimaWorker::analyze end" << endl;
284 //cout << oss.str();
285 //cout << getThreadId() << " LimaWorker::analyze emit setResult" << endl;
286 m_result=oss.str();
287 Q_EMIT(finishedAnalyze());
288}
289
290
291} // end namespace
#define LIMA_PATH_SEPARATOR
Definition FileUtils.h:25
Parser class for the lima's xml configuration files.
Use this exception to signal an error in one of the configuration files.
Definition LimaCommon.h:345
void doAnalyze(const std::string &text)
void analyze(const std::string &text)
LimaController(QObject *parent=nullptr)
void initialize(const std::string &language, const std::string &pipeline)
void doInitialize(const std::string &language, const std::string &pipeline)
void initialize(const std::string &language, const std::string &pipeline)
std::string analyze(const std::string &text)
void finishedAnalyze()
void initialize(const std::string &language, const std::string &pipeline)
std::map< std::string, Lima::AbstractAnalysisHandler * > m_handlers
void analyze(const std::string &text)
LimaWorker(QObject *parent=nullptr)
std::shared_ptr< Lima::LinguisticProcessing::AbstractLinguisticProcessingClient > m_client
Lima::LinguisticProcessing::SimpleStreamHandler * m_handler
void setOut(std::ostream *out) override
set the output stream.
static const AmosePluginsManager & single()
const singleton accessor
Definition Singleton.h:51
static LinguisticResources & changeable()
singleton accessor
Definition Singleton.h:71
QStringList buildResourcesDirectoriesList(const QStringList &projects, const QStringList &paths)
Build a list of resources directories from a list of project names and a list of paths.
QStringList buildConfigurationDirectoriesList(const QStringList &projects, const QStringList &paths)
Build a list of configuration directories from a list of project names and a list of paths.
NAUTITIA.
LIMA_COMMONQSLOG_EXPORT bool initQsLog(const QString &configString)
STL namespace.