pqPluginManager.cxx 12.8 KB
Newer Older
1
2
3
/*=========================================================================

   Program: ParaView
4
   Module:    $RCSfile$
5

6
   Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
7
8
9
   All rights reserved.

   ParaView is a free software; you can redistribute it and/or modify it
10
   under the terms of the ParaView license version 1.2.
11

12
   See License_v1.2.txt for the full ParaView license.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   A copy of this license can be obtained by contacting
   Kitware Inc.
   28 Corporate Drive
   Clifton Park, NY 12065
   USA

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

31
========================================================================*/
32
#include "pqPluginManager.h"
33
#include "ui_pqPluginEULADialog.h"
34

35
#include "pqApplicationCore.h"
36
#include "pqCoreUtilities.h"
37
#include "pqObjectBuilder.h"
38
#include "pqServer.h"
39
#include "pqServerConfiguration.h"
40
#include "pqServerManagerModel.h"
41
#include "pqSettings.h"
42
#include "vtkPVLogger.h"
43
44
#include "vtkPVPlugin.h"
#include "vtkPVPluginLoader.h"
45
#include "vtkPVPluginsInformation.h"
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
46
#include "vtkSMPluginLoaderProxy.h"
47
#include "vtkSMPluginManager.h"
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
48
49
#include "vtkSMPropertyHelper.h"
#include "vtkSMProxyManager.h"
50
#include "vtkSMSession.h"
51
#include "vtkSmartPointer.h"
52
#include "vtkWeakPointer.h"
53

54
#include <QCoreApplication>
55
#include <QPointer>
56
#include <QPushButton>
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
57
#include <QSet>
58
#include <QTextStream>
59

60
#include <cassert>
61
#include <sstream>
62

63
class pqPluginManager::pqInternals
64
{
65
public:
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
66
67
  QSet<QString> LocalHiddenPlugins;
  QSet<QString> RemoteHiddenPlugins;
68
  QList<QPointer<pqServer> > Servers;
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
69
70

  QString getXML(vtkPVPluginsInformation* info, bool remote)
Kitware Robot's avatar
Kitware Robot committed
71
  {
72
    std::ostringstream stream;
73
74
    stream << "<?xml version=\"1.0\" ?>\n";
    stream << "<Plugins>\n";
Kitware Robot's avatar
Kitware Robot committed
75
76
77
78
    for (unsigned int cc = 0; cc < info->GetNumberOfPlugins(); cc++)
    {
      if ((remote && this->RemoteHiddenPlugins.contains(info->GetPluginFileName(cc))) ||
        (!remote && this->LocalHiddenPlugins.contains(info->GetPluginFileName(cc))))
79
      {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
80
        continue;
Kitware Robot's avatar
Kitware Robot committed
81
      }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
82

83
      stream << "  <Plugin name=\"" << info->GetPluginName(cc) << "\""
Kitware Robot's avatar
Kitware Robot committed
84
85
86
             << " filename=\"" << info->GetPluginFileName(cc) << "\""
             << " auto_load=\"" << (info->GetAutoLoad(cc) ? 1 : 0) << "\" />\n";
    }
87
    stream << "</Plugins>\n";
Kitware Robot's avatar
Kitware Robot committed
88
    // cout << stream.str().c_str() << endl;
89
    return QString(stream.str().c_str());
Kitware Robot's avatar
Kitware Robot committed
90
  }
91
92
};

93
94
95
//=============================================================================
static QString pqPluginManagerSettingsKeyForRemote(pqServer* server)
{
96
  assert(server && server->isRemote());
97
98
99
  // locate the xml-config from settings associated with this server and ask
  // the server to parse it.
  const pqServerResource& resource = server->getResource();
Kitware Robot's avatar
Kitware Robot committed
100
101
102
  QString uri = resource.configuration().isNameDefault() ? resource.schemeHostsPorts().toURI()
                                                         : resource.configuration().name();
  QString key = QString("/PluginsList/%1:%2").arg(uri).arg(QCoreApplication::applicationFilePath());
103
104
105
106
107
108
  return key;
}

//=============================================================================
static QString pqPluginManagerSettingsKeyForLocal()
{
Kitware Robot's avatar
Kitware Robot committed
109
  return QString("/PluginsList/Local:%1").arg(QCoreApplication::applicationFilePath());
110
111
}

Clinton Stimpson's avatar
   
Clinton Stimpson committed
112
//-----------------------------------------------------------------------------
113
114
pqPluginManager::pqPluginManager(QObject* parentObject)
  : Superclass(parentObject)
Clinton Stimpson's avatar
   
Clinton Stimpson committed
115
{
116
117
118
119
  // setup EULA confirmation callback. Note that is still too late for auto-load
  // plugins. For auto-load plugins, the EULA is always auto-accepted.
  vtkPVPlugin::SetEULAConfirmationCallback(pqPluginManager::confirmEULA);

120
  this->Internals = new pqInternals();
121

Kitware Robot's avatar
Kitware Robot committed
122
  pqServerManagerModel* smmodel = pqApplicationCore::instance()->getServerManagerModel();
123

124
125
126
  // we ensure that the auto-load plugins are loaded before the application
  // realizes that a new server connection has been made.
  // (BUG #12238).
Kitware Robot's avatar
Kitware Robot committed
127
128
129
130
  QObject::connect(
    smmodel, SIGNAL(serverReady(pqServer*)), this, SLOT(loadPluginsFromSettings(pqServer*)));
  QObject::connect(
    smmodel, SIGNAL(serverRemoved(pqServer*)), this, SLOT(onServerDisconnected(pqServer*)));
131
132
133

  // After the new server has been setup, we can validate if the plugin
  // requirements have been met successfully.
134
  QObject::connect(pqApplicationCore::instance()->getObjectBuilder(),
Kitware Robot's avatar
Kitware Robot committed
135
    SIGNAL(finishedAddingServer(pqServer*)), this, SLOT(onServerConnected(pqServer*)));
136
137
138

  // observer plugin loaded events from PluginManager to detect plugins loaded
  // from Python or otherwise.
Kitware Robot's avatar
Kitware Robot committed
139
140
141
  vtkSMPluginManager* mgr = vtkSMProxyManager::GetProxyManager()->GetPluginManager();
  mgr->AddObserver(
    vtkSMPluginManager::PluginLoadedEvent, this, &pqPluginManager::updatePluginLists);
142
143
144
145
146
}

//-----------------------------------------------------------------------------
pqPluginManager::~pqPluginManager()
{
147
148
  // save all settings for each open server session.
  foreach (pqServer* server, this->Internals->Servers)
Kitware Robot's avatar
Kitware Robot committed
149
  {
150
    this->onServerDisconnected(server);
Kitware Robot's avatar
Kitware Robot committed
151
  }
152
153
  delete this->Internals;
}
Clinton Stimpson's avatar
   
Clinton Stimpson committed
154

155
156
157
//-----------------------------------------------------------------------------
void pqPluginManager::loadPluginsFromSettings()
{
158
159
  // Load local plugins information and then load those plugins.
  pqSettings* settings = pqApplicationCore::instance()->settings();
160
  QString key = pqPluginManagerSettingsKeyForLocal();
161
  QString local_plugin_config = settings->value(key).toString();
162
  if (!local_plugin_config.isEmpty())
Kitware Robot's avatar
Kitware Robot committed
163
  {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
164
    vtkVLogScopeF(PARAVIEW_LOG_PLUGIN_VERBOSITY(),
165
      "Loading local Plugin configuration using settings key: %s", key.toLocal8Bit().data());
Kitware Robot's avatar
Kitware Robot committed
166
    vtkSMProxyManager::GetProxyManager()->GetPluginManager()->LoadPluginConfigurationXMLFromString(
167
      local_plugin_config.toUtf8().data(), NULL, false);
Kitware Robot's avatar
Kitware Robot committed
168
  }
169
170

  Q_EMIT this->initialPluginsLoaded();
Clinton Stimpson's avatar
   
Clinton Stimpson committed
171
172
}

173
//-----------------------------------------------------------------------------
174
void pqPluginManager::loadPluginsFromSettings(pqServer* server)
Clinton Stimpson's avatar
   
Clinton Stimpson committed
175
{
176
  // Tell the server to load all default-plugins.
177
  if (server && server->isRemote())
Kitware Robot's avatar
Kitware Robot committed
178
  {
179
180
    // locate the xml-config from settings associated with this server and ask
    // the server to parse it.
181
    QString key = pqPluginManagerSettingsKeyForRemote(server);
182
183
    pqSettings* settings = pqApplicationCore::instance()->settings();
    QString remote_plugin_config = settings->value(key).toString();
184
    // now pass this xml to the vtkPVPluginTracker on the remote
185
    // processes.
186
    if (!remote_plugin_config.isEmpty())
Kitware Robot's avatar
Kitware Robot committed
187
    {
188
189
      vtkVLogF(PARAVIEW_LOG_PLUGIN_VERBOSITY(),
        "Loading remote Plugin configuration using settings key: %s", key.toLocal8Bit().data());
Kitware Robot's avatar
Kitware Robot committed
190
191
192
      vtkSMProxyManager::GetProxyManager()
        ->GetPluginManager()
        ->LoadPluginConfigurationXMLFromString(
193
          remote_plugin_config.toUtf8().data(), server->session(), true);
194
    }
Kitware Robot's avatar
Kitware Robot committed
195
  }
196
}
197

198
199
200
//-----------------------------------------------------------------------------
void pqPluginManager::onServerConnected(pqServer* server)
{
201
202
203
204
205
206
  this->Internals->Servers.push_back(server);
  this->updatePluginLists();

  // Validate plugins i.e. check plugins that are required on client and server
  // are indeed present on both.
  if (!this->verifyPlugins(server))
Kitware Robot's avatar
Kitware Robot committed
207
  {
208
    Q_EMIT this->requiredPluginsNotLoaded(server);
Kitware Robot's avatar
Kitware Robot committed
209
  }
210
}
211

212
//-----------------------------------------------------------------------------
213
void pqPluginManager::onServerDisconnected(pqServer* server)
214
{
215
  pqSettings* settings = pqApplicationCore::instance()->settings();
216
  if (server && server->isRemote())
Kitware Robot's avatar
Kitware Robot committed
217
  {
218
    QString remoteKey = pqPluginManagerSettingsKeyForRemote(server);
219
220
    // locate the xml-config from settings associated with this server and ask
    // the server to parse it.
Kitware Robot's avatar
Kitware Robot committed
221
222
    settings->setValue(
      remoteKey, this->Internals->getXML(this->loadedExtensions(server, true), true));
223
224
    vtkVLogF(PARAVIEW_LOG_PLUGIN_VERBOSITY(),
      "Saving remote Plugin configuration using settings key: %s", remoteKey.toLocal8Bit().data());
Kitware Robot's avatar
Kitware Robot committed
225
  }
226
227

  // just save the local plugin info to be on the safer side.
228
  QString key = pqPluginManagerSettingsKeyForLocal();
Kitware Robot's avatar
Kitware Robot committed
229
  settings->setValue(key, this->Internals->getXML(this->loadedExtensions(server, false), false));
230
231
  vtkVLogF(PARAVIEW_LOG_PLUGIN_VERBOSITY(),
    "Saving local Plugin configuration using settings key: %s", key.toLocal8Bit().data());
232

233
  this->Internals->Servers.removeAll(server);
234
235
236
}

//-----------------------------------------------------------------------------
237
void pqPluginManager::updatePluginLists()
238
{
239
  Q_EMIT this->pluginsUpdated();
240
241
242
}

//-----------------------------------------------------------------------------
Kitware Robot's avatar
Kitware Robot committed
243
vtkPVPluginsInformation* pqPluginManager::loadedExtensions(pqServer* session, bool remote)
244
{
245
  vtkSMPluginManager* mgr = vtkSMProxyManager::GetProxyManager()->GetPluginManager();
Kitware Robot's avatar
Kitware Robot committed
246
247
  return (remote && session && session->isRemote()) ? mgr->GetRemoteInformation(session->session())
                                                    : mgr->GetLocalInformation();
248
249
}

250
//-----------------------------------------------------------------------------
251
pqPluginManager::LoadStatus pqPluginManager::loadExtension(
252
  pqServer* server, const QString& lib, QString* vtkNotUsed(errorMsg), bool remote)
253
{
254
255
256
  vtkSMPluginManager* mgr = vtkSMProxyManager::GetProxyManager()->GetPluginManager();

  bool ret_val = false;
Sebastien Jourdain's avatar
Sebastien Jourdain committed
257
  if (remote && server && server->isRemote())
Kitware Robot's avatar
Kitware Robot committed
258
  {
259
    ret_val = mgr->LoadRemotePlugin(lib.toUtf8().data(), server->session());
Kitware Robot's avatar
Kitware Robot committed
260
  }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
261
  else
Kitware Robot's avatar
Kitware Robot committed
262
  {
263
    // All Load*Plugin* call need a utf8 encoded filename or
264
265
266
    // xmlcontent, since vtksys::DynamicLoader itself takes care
    // Of converting to local8bit, even locally.
    ret_val = mgr->LoadLocalPlugin(lib.toUtf8().data());
Kitware Robot's avatar
Kitware Robot committed
267
  }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
268

Kitware Robot's avatar
Kitware Robot committed
269
  return ret_val ? LOADED : NOTLOADED;
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
270
271
272
}

//-----------------------------------------------------------------------------
273
QStringList pqPluginManager::pluginPaths(pqServer* session, bool remote)
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
274
{
275
  vtkSMPluginManager* mgr = vtkSMProxyManager::GetProxyManager()->GetPluginManager();
Kitware Robot's avatar
Kitware Robot committed
276
277
  QString paths =
    remote ? mgr->GetRemotePluginSearchPaths(session->session()) : mgr->GetLocalPluginSearchPaths();
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
278
279
280
281
282
283
284
  return paths.split(';', QString::SkipEmptyParts);
}

//-----------------------------------------------------------------------------
void pqPluginManager::hidePlugin(const QString& lib, bool remote)
{
  if (remote)
Kitware Robot's avatar
Kitware Robot committed
285
  {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
286
    this->Internals->RemoteHiddenPlugins.insert(lib);
Kitware Robot's avatar
Kitware Robot committed
287
  }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
288
  else
Kitware Robot's avatar
Kitware Robot committed
289
  {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
290
    this->Internals->LocalHiddenPlugins.insert(lib);
Kitware Robot's avatar
Kitware Robot committed
291
  }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
292
293
294
295
296
}

//-----------------------------------------------------------------------------
bool pqPluginManager::isHidden(const QString& lib, bool remote)
{
Kitware Robot's avatar
Kitware Robot committed
297
298
  return remote ? this->Internals->RemoteHiddenPlugins.contains(lib)
                : this->Internals->LocalHiddenPlugins.contains(lib);
299
}
300
301

//-----------------------------------------------------------------------------
302
bool pqPluginManager::verifyPlugins(pqServer* activeServer)
303
{
Kitware Robot's avatar
Kitware Robot committed
304
305
  if (!activeServer || !activeServer->isRemote())
  {
306
    // no verification needed for non-remote servers.
307
    return true;
Kitware Robot's avatar
Kitware Robot committed
308
  }
309

310
311
  vtkPVPluginsInformation* local_info = this->loadedExtensions(activeServer, false);
  vtkPVPluginsInformation* remote_info = this->loadedExtensions(activeServer, true);
Kitware Robot's avatar
Kitware Robot committed
312
  return vtkPVPluginsInformation::PluginRequirementsSatisfied(local_info, remote_info);
313
}
314
315
316
317

//-----------------------------------------------------------------------------
bool pqPluginManager::confirmEULA(vtkPVPlugin* plugin)
{
318
  assert(plugin->GetEULA() != nullptr);
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349

  pqSettings* settings = pqApplicationCore::instance()->settings();

  QString pluginKey;
  QTextStream(&pluginKey) << "EULAConfirmation-" << plugin->GetPluginName() << "-"
                          << plugin->GetPluginVersionString() << "-Confirmed";
  if (settings->value(pluginKey, false).toBool() == true)
  {
    // previously accepted.
    return true;
  }

  QDialog dialog(pqCoreUtilities::mainWidget());
  Ui::PluginEULADialog ui;
  ui.setupUi(&dialog);
  ui.buttonBox->button(QDialogButtonBox::Yes)->setText("Accept");
  ui.buttonBox->button(QDialogButtonBox::No)->setText("Decline");
  ui.buttonBox->button(QDialogButtonBox::No)->setDefault(true);

  dialog.setWindowTitle(
    QString("End User License Agreement for '%1'").arg(plugin->GetPluginName()));
  ui.textEdit->setText(plugin->GetEULA());

  if (dialog.exec() == QDialog::Accepted)
  {
    settings->setValue(pluginKey, true);
    return true;
  }

  return false;
}