VPTissue Reference Manual
CoupledCliController.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
21 
22 #include "session/SimSession.h"
24 #include "workspace/CliWorkspace.h"
25 #include "ptree/PTreeUtils.h"
26 #include "util/misc/log_debug.h"
27 #include "util/misc/Exception.h"
29 
30 #include <boost/property_tree/exceptions.hpp>
31 #include <boost/property_tree/xml_parser.hpp>
32 #include <QApplication>
33 #include <QFileInfo>
34 
35 #include <cassert>
36 #include <csignal>
37 #include <cstdlib>
38 #include <sstream>
39 #include <stdexcept>
40 #include <string>
41 
42 namespace SimPT_Shell {
43 
44 using namespace std;
45 using namespace std::chrono;
46 using namespace std::placeholders;
47 using namespace boost::property_tree;
48 using namespace boost::property_tree::xml_parser;
49 using namespace SimPT_Sim::ClockMan;
50 using namespace SimPT_Sim::Util;
51 using namespace UA_CoMP_Adapt2rfp;
52 
53 
54 CoupledCliController::CoupledCliController(shared_ptr<Ws::CliWorkspace> workspace_model, bool quiet)
55  : m_workspace_model(move(workspace_model)), m_quiet(quiet),
56  m_sig_int_adaptor(bind(&CoupledCliController::SigIntHandler, this, placeholders::_1)),
57 #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
58  m_sig_qt_adaptor(bind(&CoupledCliController::SigQtHandler, this, placeholders::_1, placeholders::_2, placeholders::_3))
59 #else
60  m_sig_qt_adaptor(bind(&CoupledCliController::SigQtHandler, this, placeholders::_1, placeholders::_2))
61 #endif
62 {
63  // register interrupt handler (adaptor auto-converts to function pointer).
64  signal(SIGINT, m_sig_int_adaptor);
65 
66  // Register Qt error handler (adaptor auto-converts to function pointer).
67 #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
68  qInstallMessageHandler(m_sig_qt_adaptor);
69 #else
70  qInstallMsgHandler(m_sig_qt_adaptor);
71 #endif
72 }
73 
74 CoupledCliController::~CoupledCliController()
75 {
76  signal(SIGINT, SIG_DFL);
77 #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
78  qInstallMessageHandler(0);
79 #else
80  qInstallMsgHandler(0);
81 #endif
82 }
83 
84 std::shared_ptr<CoupledCliController> CoupledCliController::Create(const string& workspace, bool quiet)
85 {
86  const string here = string(VL_HERE) + " exception:\n";
87  shared_ptr<CoupledCliController> ptr;
88 
89  try {
90  // QApplication must have been instantiated for the Qt services we use.
91  // QApp i.o. QCoreApp because of production of graphics output.
92  if (static_cast<QApplication*>(QApplication::instance()) == nullptr) {
93  throw Exception(here + "No QApplication instantiated in calling context.");
94  }
95 
96  // Create workspace model.
97  auto workspace_model = make_shared<Ws::CliWorkspace>(workspace);
98  if (!quiet) {
99  UserMessage("Successfully opened workspace " + workspace_model->GetPath());
100  }
101  ptr = shared_ptr<CoupledCliController>(new CoupledCliController(workspace_model, quiet));
102  if (ptr == nullptr) {
103  throw Exception(here + "Produced nullptr for " + workspace);
104  }
105  } catch (Exception& e) {
106  UserError(here + e.what());
107  throw;
108  } catch(...) {
109  UserError(here + "Unknown exception!");
110  }
111 
112  return ptr;
113 }
114 
115 int CoupledCliController::Execute(CliSimulationTask task)
116 {
117  int exit_status = EXIT_SUCCESS;
118  Session::SimSession::Stopclock chrono_total("total", true);
119 
120  try {
121  bool status = SimulatorRun(task);
122  if (status == false) {
123  exit_status = EXIT_FAILURE;
124  }
125  }
126  catch (exception& e) {
127  exit_status = EXIT_FAILURE;
128  throw Exception(e.what());
129  }
130 
131  m_timings.Record(chrono_total.GetName(), chrono_total.Get());
132  return exit_status;
133 }
134 
135 CoupledCliController::Timings CoupledCliController::GetTimings() const
136 {
137  return m_timings.GetRecords();
138 }
139 
140 bool CoupledCliController::IsQuiet() const
141 {
142  return m_quiet;
143 }
144 
145 shared_ptr<Session::SimSessionCoupled>
146 CoupledCliController::OpenProject(const string& project_name, const string& file_name)
147 {
148  // TODO Refactor the opening of the project, so that the CoupledCliController isn't
149  // needed anymore and the CliController can handle both a normal and a coupled project.
150 
151  const string here = string(VL_HERE);
152  shared_ptr<Session::SimSessionCoupled> session;
153 
154  try {
155  auto project_it = m_workspace_model->Find(project_name); // may throw
156  auto file_it = project_it->second->Find(file_name); // may throw
157 
158  // Initialize project
159  auto file = file_it->second->GetPath();
160  const string extension = QFileInfo(QString::fromStdString(file)).suffix().toStdString();
161  if (extension == "xml") {
162  ptree sim_pt;
163  read_xml(file, sim_pt, trim_whitespace); // may throw
164  session = make_shared<Session::SimSessionCoupled>(
165  SimShell::Ws::MergedPreferences::Create(
166  m_workspace_model, project_it->second.Project()), sim_pt, m_workspace_model);
167  }
168 
169  if (!IsQuiet()) {
170  UserMessage("Successfully read coupled project from file " + file_it->second->GetPath());
171  }
172  }
173  catch (exception& e) {
174  throw Exception(here + " exception:\n" + e.what());
175  }
176 
177  return session;
178 }
179 
180 void CoupledCliController::SigIntHandler(int )
181 {
182  signal(SIGINT, SIG_DFL);
183  emit TerminationRequested();
184 }
185 
186 #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
187 void CoupledCliController::SigQtHandler(QtMsgType type, const QMessageLogContext& /*context*/, const QString& msg)
188 {
189  switch (type) {
190  case QtDebugMsg:
191  UserMessage("Qt debug: " + msg.toStdString());
192  break;
193  #if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
194  case QtInfoMsg:
195  UserMessage("Qt info: " + msg.toStdString());
196  break;
197  #endif
198  case QtWarningMsg:
199  UserMessage("Qt warning: " + msg.toStdString());
200  break;
201  case QtCriticalMsg:
202  UserError("Qt critical: " + msg.toStdString());
203  break;
204  case QtFatalMsg:
205  UserError("Qt fatal: " + msg.toStdString());
206  abort();
207  break;
208  default:
209  UserError("Qt fatal: " + msg.toStdString());
210  abort();
211  break;
212  }
213 }
214 #else
215 void CoupledCliController::SigQtHandler(QtMsgType type, const char* msg)
216 {
217  switch (type) {
218  case QtDebugMsg:
219  UserMessage("Qt debug: " + string(msg));
220  break;
221  case QtWarningMsg:
222  UserMessage("Qt warning: " + string(msg));
223  break;
224  case QtCriticalMsg:
225  UserError("Qt critical: " + string(msg));
226  break;
227  case QtFatalMsg:
228  UserError("Qt fatal: " + string(msg));
229  abort();
230  break;
231  default:
232  UserError("Qt fatal: " + string(msg));
233  abort();
234  break;
235  }
236 }
237 #endif
238 
239 void CoupledCliController::SimulationError(const std::string &error)
240 {
241  UserError(error);
242  emit TerminationRequested();
243 }
244 
245 void CoupledCliController::SimulationInfo(
246  const std::string &message, const Session::ISession::InfoMessageReason &reason)
247 {
248  switch (reason) {
249  case Session::ISession::InfoMessageReason::Stepped:
250  if (!IsQuiet()) {
251  UserMessage(message);
252  }
253  break;
254  case Session::ISession::InfoMessageReason::Stopped:
255  emit TerminationRequested();
256  break;
257  case Session::ISession::InfoMessageReason::Terminated:
258  emit TerminationRequested();
259  break;
260  default:
261  break;
262  }
263 }
264 
265 int CoupledCliController::SimulatorRun(CliSimulationTask task)
266 {
267  bool exit_status = EXIT_FAILURE;
268  const string here = string(VL_HERE) + "> ";
269  const string project_name = task.GetProjectName();
270  auto ws_project = m_workspace_model->Get(project_name);
271  const string file = task.IsLeafSet() ? task.GetLeaf() : (--ws_project->end())->first;
272 
273  auto session = OpenProject(project_name, file);
274  if (session) {
275  // Create root viewer and initialize its subviewers
276  auto rootViewer = session->CreateRootViewer();
277 
278  connect(session.get(), SIGNAL(InfoMessage(const std::string&, const InfoMessageReason&)),
279  this, SLOT(SimulationInfo(const std::string&, const InfoMessageReason&)));
280  connect(session.get(), SIGNAL(ErrorMessage(const std::string&)),
281  this, SLOT(SimulationError(const std::string&)));
282 
283  if (!IsQuiet()) {
284  UserMessage("Opened project " + project_name + " and " + file);
285  }
286 
287  // Run simulation inside an event loop, so this thread can receive signals
288  // from possibly other threads
289  // If TerminationRequested() would for some reason already be emitted during
290  // StartSimulation, then the connection to quit will be queued, so that the quit()
291  // slot of eventLoop will not be called before the call to exec()
292  QEventLoop eventLoop(this);
293  connect(this, SIGNAL(TerminationRequested()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
294  session->StartSimulation(task.IsNumStepsSet() ? task.GetNumSteps() : -1);
295  eventLoop.exec();
296 
297  exit_status = EXIT_SUCCESS;
298  // Get timings from simulation.
299  m_timings.Merge(session->GetTimings());
300  } else {
301  exit_status = EXIT_FAILURE;
302  UserError(here + "Failed to open project " + project_name + " and " + file);
303  }
304 
305  return exit_status;
306 }
307 
308 void CoupledCliController::Terminate()
309 {
310  emit TerminationRequested();
311 }
312 
313 void CoupledCliController::UserError(const string& msg)
314 {
315  std::cerr << msg << std::endl;
316 }
317 
318 void CoupledCliController::UserMessage(const string& msg)
319 {
320  std::cout << msg << std::endl;
321 }
322 
323 } // namespace
Interface for SimSessionCoupled.
STL namespace.
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
virtual const char * what() const noexcept
Return error message.
Definition: Exception.h:38
Namespace for SimPT shell package.
Definition: Client.cpp:50
std::string GetName() const
Return name of this stopwatch.
Definition: Stopwatch.h:88
Extremely simple Exception root class.
Definition: Exception.h:28
PTreeUtils interface.
Macro defs for debug and logging.
Interface for CoupledCliController.
Interface for workspace.
Interface for MergedPreferences.
Interfaces for simulator session.
T::duration Get() const
Returns the accumulated value without altering the stopwatch state.
Definition: Stopwatch.h:94
Provides a stopwatch interface to time: it accumulates time between start/stop pairs.
Definition: Stopwatch.h:39
Header file for Exception class.
A CliTask represents an invocation of the program from the command line.
Command line interface application controller.
Namespace for clock and timekeeping related classes.
Definition: ClockCLib.h:27