001/** 002 * Copyright (C) 2014 Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/ 003 * 004 * This file is part of Dicoogle/dicoogle. 005 * 006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Dicoogle/dicoogle is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Dicoogle. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package pt.ua.dicoogle.plugins; 020 021import org.apache.commons.configuration.ConfigurationException; 022import org.apache.commons.io.FileUtils; 023import org.restlet.resource.ServerResource; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026import pt.ua.dicoogle.core.ServerSettings; 027import pt.ua.dicoogle.plugins.webui.WebUIPlugin; 028import pt.ua.dicoogle.plugins.webui.WebUIPluginManager; 029import pt.ua.dicoogle.sdk.*; 030import pt.ua.dicoogle.sdk.Utils.TaskQueue; 031import pt.ua.dicoogle.sdk.Utils.TaskRequest; 032import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface; 033import pt.ua.dicoogle.sdk.datastructs.Report; 034import pt.ua.dicoogle.sdk.datastructs.SearchResult; 035import pt.ua.dicoogle.sdk.settings.ConfigurationHolder; 036import pt.ua.dicoogle.sdk.task.JointQueryTask; 037import pt.ua.dicoogle.sdk.task.Task; 038import pt.ua.dicoogle.server.ControlServices; 039import pt.ua.dicoogle.server.PluginRestletApplication; 040import pt.ua.dicoogle.server.web.DicoogleWeb; 041import pt.ua.dicoogle.taskManager.RunningIndexTasks; 042import pt.ua.dicoogle.taskManager.TaskManager; 043 044import javax.swing.*; 045import java.io.File; 046import java.io.IOException; 047import java.net.URI; 048import java.util.*; 049import java.util.concurrent.Callable; 050import java.util.concurrent.ExecutionException; 051import java.util.zip.ZipFile; 052 053/** 054 * 055 * PluginController is the core of the Plugins architecture. 056 * 057 * <p> 058 * It loads the plugins, takes care of the list of active plugins and control 059 * the tasks that are exchanged between plugins and core plugins 060 * 061 * @author Carlos Ferreira 062 * @author Frederico Valente 063 * @author Luís A. Bastião Silva <bastiao@ua.pt> 064 * @author Tiago Marques Godinho 065 * @author Eduardo Pinho 066 */ 067public class PluginController{ 068 069 private static final Logger logger = LoggerFactory.getLogger(PluginController.class); 070 private static PluginController instance; 071 072 public synchronized static PluginController getInstance() { 073 if (instance == null) { 074 instance = new PluginController(new File("Plugins")); 075 } 076 return instance; 077 } 078 private final Collection<PluginSet> pluginSets; 079 private File pluginFolder; 080 private TaskQueue tasks = null; 081 082 private PluginSet remoteQueryPlugins = null; 083 private final WebUIPluginManager webUI; 084 private final DicooglePlatformProxy proxy; 085 private TaskManager taskManager = new TaskManager(Integer.parseInt(System.getProperty("dicoogle.taskManager.nThreads", "4"))); 086 087 public PluginController(File pathToPluginDirectory) { 088 logger.info("Creating PluginController Instance"); 089 pluginFolder = pathToPluginDirectory; 090 091 tasks = new TaskQueue(); 092 093 //the plugin directory does not exist. lets create it 094 if (!pathToPluginDirectory.exists()) { 095 logger.info("Creating new Plugin Folder"); 096 pathToPluginDirectory.mkdirs(); 097 } 098 099 //loads the plugins 100 pluginSets = PluginFactory.getPlugins(pathToPluginDirectory); 101 //load web UI plugins (they are not Java, so the process is delegated to another entity) 102 this.webUI = new WebUIPluginManager(); 103 // loadByPluginName all at "WebPlugins" 104 this.webUI.loadAll(new File("WebPlugins")); 105 106 // go through each jar'd plugin and fetch their WebPlugins 107 for (File j : FileUtils.listFiles(pluginFolder, new String[]{"jar", "zip"}, false)) { 108 try { 109 this.webUI.loadAllFromZip(new ZipFile(j)); 110 } catch (IOException ex) { 111 // ignore 112 logger.warn("Failed to load web UI plugins from {}: {}", j.getName(), ex.getMessage()); 113 } 114 } 115 116 logger.info("Loaded Local Plugins"); 117 118 //loads plugins' settings and passes them to the plugin 119 File settingsFolder = new File(pluginFolder.getPath() + "/settings/"); 120 if (!settingsFolder.exists()) { 121 logger.info("Creating Local Settings Folder"); 122 settingsFolder.mkdir(); 123 } 124 125 for (Iterator<PluginSet> it = pluginSets.iterator(); it.hasNext();) { 126 PluginSet plugin = it.next(); 127 logger.info("Loading plugin: " + plugin.getName()); 128 File pluginSettingsFile = new File(settingsFolder + "/" + plugin.getName().replace('/', '-') + ".xml"); 129 try { 130 ConfigurationHolder holder = new ConfigurationHolder(pluginSettingsFile); 131 if(plugin.getName().equals("RemotePluginSet")) { 132 this.remoteQueryPlugins = plugin; 133 holder.getConfiguration().setProperty("NodeName", ServerSettings.getInstance().getNodeName()); 134 holder.getConfiguration().setProperty("TemporaryPath", ServerSettings.getInstance().getPath()); 135 136 logger.info("Started Remote Communications Manager"); 137 } 138 applySettings(plugin, holder); 139 } 140 catch (ConfigurationException e){ 141 logger.error("Failed to create configuration holder", e); 142 } 143 catch (RuntimeException e) { 144 logger.error("Unexpected error while loading plugin set {}. Plugin disabled.", plugin.getName(), e); 145 it.remove(); 146 } 147 } 148 logger.info("Settings pushed to plugins"); 149 webUI.loadSettings(settingsFolder); 150 logger.info("Settings pushed to web UI plugins"); 151 152 pluginSets.add(new DefaultFileStoragePlugin()); 153 logger.info("Added default storage plugin"); 154 155 this.proxy = new DicooglePlatformProxy(this); 156 157 initializePlugins(pluginSets); 158 initRestInterface(pluginSets); 159 initJettyInterface(pluginSets); 160 logger.info("Initialized plugins"); 161 } 162 163 private void initializePlugins(Collection<PluginSet> plugins) { 164 for (PluginSet set : plugins) { 165 logger.debug("SetPlugins: {}", set); 166 167 // provide platform to each plugin interface 168 final Collection<Collection<?>> all = Arrays.asList( 169 set.getStoragePlugins(), 170 set.getIndexPlugins(), 171 set.getQueryPlugins(), 172 set.getJettyPlugins(), 173 set.getRestPlugins() 174 ); 175 for (Collection interfaces : all) { 176 if (interfaces == null) { 177 logger.debug("Plugin set {} provided a null collection!"); 178 continue; 179 } 180 for (Object o : interfaces) { 181 if (o instanceof PlatformCommunicatorInterface) { 182 ((PlatformCommunicatorInterface)o).setPlatformProxy(proxy); 183 } 184 } 185 } 186 187 // and to the set itself 188 if (set instanceof PlatformCommunicatorInterface) { 189 ((PlatformCommunicatorInterface) set).setPlatformProxy(proxy); 190 } 191 } 192 } 193 194 private void applySettings(PluginSet set, ConfigurationHolder holder) { 195 // provide platform to each plugin interface 196 final Collection<Collection<? extends DicooglePlugin>> all = Arrays.asList( 197 set.getStoragePlugins(), 198 set.getIndexPlugins(), 199 set.getQueryPlugins(), 200 set.getJettyPlugins() 201 ); 202 for (Collection<? extends DicooglePlugin> interfaces : all) { 203 if (interfaces == null) continue; 204 for (DicooglePlugin p : interfaces) { 205 p.setSettings(holder); 206 } 207 } 208 set.setSettings(holder); 209 210 } 211 212 /** 213 * Each pluginSet provides a collection of barebone rest interfaces Here we 214 * check which interfaces are present and create a restlet component to 215 * handle them. also we export them using common settings and security 216 * profiles 217 */ 218 private void initRestInterface(Collection<PluginSet> plugins) { 219 logger.info("Initializing plugin rest interfaces"); 220 221 ArrayList<ServerResource> restInterfaces = new ArrayList<>(); 222 for (PluginSet set : plugins) { 223 Collection<ServerResource> restInterface = set.getRestPlugins(); 224 if (restInterface == null) { 225 continue; 226 } 227 restInterfaces.addAll(restInterface); 228 } 229 230 for (ServerResource resource : restInterfaces) { 231 PluginRestletApplication.attachRestPlugin(resource); 232 } 233 logger.info("Finished initializing rest interfaces"); 234 } 235 236 private void initJettyInterface(Collection<PluginSet> plugins) { 237 logger.info("Initializing jetty interface"); 238 239 ArrayList<JettyPluginInterface> jettyInterfaces = new ArrayList<>(); 240 for(PluginSet set : plugins){ 241 Collection<JettyPluginInterface> jettyInterface = set.getJettyPlugins(); 242 if(jettyInterface == null) continue; 243 jettyInterfaces.addAll(jettyInterface); 244 } 245 246 DicoogleWeb jettyServer = ControlServices.getInstance().getWebServicePlatform(); 247 for(JettyPluginInterface resource : jettyInterfaces){ 248 jettyServer.addContextHandlers( resource.getJettyHandlers() ); 249 } 250 } 251 252 /** 253 * Stops the plugins and saves the settings 254 */ 255 public void shutdown() throws IOException { 256 for (PluginSet plugin : pluginSets) { 257 //TODO: I Think it is better to enable auto-save settings 258 /*Settings settings = plugin.getSettings(); 259 if (settings != null) { 260 settings.save(); 261 } 262 */ 263 //lets the plugin know we are shutting down 264 plugin.shutdown(); 265 } 266 } 267 268 /** 269 * stops a pluginset. this could be more efficient, however this is hardly a 270 * bottleneck TODO: needs more granularity, we should be able to stop only 271 * the indexers or the queryers 272 * 273 * @param pluginName 274 */ 275 public void stopPlugin(String pluginName) { 276 for (PluginSet pluginSet : pluginSets) { 277 if (pluginSet.getName().compareTo(pluginName) == 0) { 278 //pluginSet.stop(); 279 return; 280 } 281 } 282 } 283 284 public void startPlugin(String pluginName) { 285 for (PluginSet pluginSet : pluginSets) { 286 if (pluginSet.getName().compareTo(pluginName) == 0) { 287 //pluginSet.stop(); 288 return; 289 } 290 } 291 } 292 293 public Collection<IndexerInterface> getIndexingPlugins(boolean onlyEnabled) { 294 ArrayList<IndexerInterface> indexers = new ArrayList<>(); 295 for (PluginSet pSet : pluginSets) { 296 for (IndexerInterface index : pSet.getIndexPlugins()) { 297 if (!index.isEnabled() && onlyEnabled) { 298 continue; 299 } 300 indexers.add(index); 301 } 302 } 303 return indexers; 304 } 305 306 public Collection<StorageInterface> getStoragePlugins(boolean onlyEnabled) { 307 ArrayList<StorageInterface> storagePlugins = new ArrayList<>(); 308 for (PluginSet pSet : pluginSets) { 309 for (StorageInterface store : pSet.getStoragePlugins()) { 310 if (!store.isEnabled() && onlyEnabled) { 311 continue; 312 } 313 storagePlugins.add(store); 314 } 315 } 316 return storagePlugins; 317 } 318 319 /** 320 * Resolve a URI to a DicomInputStream 321 * @param location 322 * @param args 323 * @return 324 */ 325 public Iterable<StorageInputStream> resolveURI(URI location, Object ...args) 326 { 327 Collection<StorageInterface> storages = getStoragePlugins(true); 328 329 for (StorageInterface store : storages) { 330 if (store.handles(location)) 331 { 332 logger.debug("Resolving URI: {} Storage: {}", location, store.getName()); 333 return store.at(location, args); 334 } 335 } 336 337 logger.error("Could not resolve uri: {}", location); 338 return Collections.emptyList(); 339 } 340 341 /** Retrieve a storage interface capable of handling files on a given location. 342 * 343 * TODO: this can be heavily improved if we keep a map of scheme->indexer 344 * However we are not supposed to call this every other cycle. 345 * 346 * TODO: we should return a proxy storage that always returns error 347 * 348 * @todo "schema" is a typo, should read "scheme" 349 * 350 * @param location a URI of the location, only the scheme matters 351 * @return a storage interface capable of handling the location, null if no suitable plugin is found 352 */ 353 public StorageInterface getStorageForSchema(URI location) { 354 if(location == null){ 355 logger.warn("URI for retrieving storage interface is null, ignoring"); 356 return null; 357 } 358 Collection<StorageInterface> storages = getStoragePlugins(false); 359 360 for (StorageInterface store : storages) { 361 try { 362 if (store.handles(location)) { 363 logger.debug("Retrieved storage for scheme: {}", location); 364 return store; 365 } 366 } catch (RuntimeException ex) { 367 logger.warn("Storage plugin {} failed unexpectedly", store.getName(), ex); 368 } 369 } 370 logger.warn("Could not get storage for scheme: {}", location); 371 return null; 372 } 373 374 /** Retrieve a storage interface capable of handling files with the given scheme. 375 * 376 * TODO: this can be heavily improved if we keep a map of scheme->indexer 377 * However we are not supposed to call this every other cycle. 378 * 379 * TODO: we should return a proxy storage that always returns error 380 * 381 * @param scheme a URI of the location, only the scheme matters 382 * @return a storage interface capable of handling the location, null if no suitable plugin is found 383 */ 384 public StorageInterface getStorageForSchema(String scheme) { 385 URI uri = URI.create(scheme + ":/"); 386 return getStorageForSchema(uri); 387 } 388 389 public Collection<QueryInterface> getQueryPlugins(boolean onlyEnabled) { 390 ArrayList<QueryInterface> queriers = new ArrayList<>(); 391 for (PluginSet pSet : pluginSets) { 392 for (QueryInterface querier : pSet.getQueryPlugins()) { 393 if (!querier.isEnabled() && onlyEnabled) { 394 continue; 395 } 396 queriers.add(querier); 397 } 398 } 399 return queriers; 400 } 401 402 public void addTask(TaskRequest task) { 403 this.tasks.addTask(task); 404 } 405 406 407 408 public List<String> getQueryProvidersName(boolean enabled){ 409 Collection<QueryInterface> plugins = getQueryPlugins(enabled); 410 List<String> names = new ArrayList<>(plugins.size()); 411 for(QueryInterface p : plugins){ 412 names.add(p.getName()); 413 } 414 //logger.info("Query Providers: "+Arrays.toString(names.toArray()) ); 415 return names; 416 } 417 418 public QueryInterface getQueryProviderByName(String name, boolean onlyEnabled){ 419 Collection<QueryInterface> plugins = getQueryPlugins(onlyEnabled); 420 for(QueryInterface p : plugins){ 421 if(p.getName().equalsIgnoreCase(name)){ 422 //logger.info("Retrived Query Provider: "+name); 423 return p; 424 } 425 } 426 logger.error("Could not retrieve query provider {} for onlyEnabled = {}", name, onlyEnabled); 427 return null; 428 } 429 430 //TODO: CONVENIENCE METHOD 431 public IndexerInterface getIndexerByName(String name, boolean onlyEnabled){ 432 Collection<IndexerInterface> plugins = getIndexingPlugins(onlyEnabled); 433 for(IndexerInterface p : plugins){ 434 if(p.getName().equalsIgnoreCase(name)){ 435 //logger.info("Retrived Query Provider: "+name); 436 return p; 437 } 438 } 439 logger.error("No indexer matching name {} for onlyEnabled = {}", name, onlyEnabled); 440 return null; 441 } 442 443 public JointQueryTask queryAll(JointQueryTask holder, final String query, final Object ... parameters) 444 { 445 //logger.info("Querying all providers"); 446 List<String> providers = this.getQueryProvidersName(true); 447 448 return query(holder, providers, query, parameters); 449 } 450 451 public Task<Iterable<SearchResult>> query(String querySource, final String query, final Object ... parameters){ 452 Task<Iterable<SearchResult>> t = getTaskForQuery(querySource, query, parameters); 453 taskManager.dispatch(t); 454 //logger.info("Fired Query Task: "+querySource +" QueryString:"+query); 455 456 return t;//returns the handler to obtain the computation results 457 } 458 459 public JointQueryTask query(JointQueryTask holder, List<String> querySources, final String query, final Object ... parameters){ 460 if(holder == null) 461 return null; 462 463 List<Task<Iterable<SearchResult>>> tasks = new ArrayList<>(); 464 for(String p : querySources){ 465 Task<Iterable<SearchResult>> task = getTaskForQuery(p, query, parameters); 466 tasks.add(task); 467 holder.addTask(task); 468 } 469 470 //and executes said task asynchronously 471 for(Task<?> t : tasks) 472 taskManager.dispatch(t); 473 474 //logger.info("Fired Query Tasks: "+Arrays.toString(querySources.toArray()) +" QueryString:"+query); 475 return holder;//returns the handler to obtain the computation results 476 } 477 478 private Task<Iterable<SearchResult>> getTaskForQuery(final String querySource, final String query, final Object ... parameters){ 479 final QueryInterface queryEngine = getQueryProviderByName(querySource, true); 480 //returns a tasks that runs the query from the selected query engine 481 Task<Iterable<SearchResult>> queryTask = new Task<>(querySource, 482 new Callable<Iterable<SearchResult>>(){ 483 @Override public Iterable<SearchResult> call() throws Exception { 484 if(queryEngine == null) return Collections.emptyList(); 485 try { 486 return queryEngine.query(query, parameters); 487 } catch (RuntimeException ex) { 488 logger.warn("Query plugin {} failed unexpectedly", querySource, ex); 489 return Collections.EMPTY_LIST; 490 } 491 } 492 }); 493 //logger.info("Prepared Query Task: QueryString"); 494 return queryTask; 495 } 496 497 /* 498 * Given an URI (which may be a path to a dir or file, a web resource or whatever) 499 * this method creates a task that 500 * calls the appropriate indexers and instructs them to index the data pointed to by the URI 501 * it is up to the caller to run the task asynchronously by feeding it to an executor 502 * or in a blocking way by calling the get() method of the task 503 */ 504 public List<Task<Report>> index(URI path) { 505 logger.info("Starting Indexing procedure for {}", path.toString()); 506 StorageInterface store = getStorageForSchema(path); 507 508 if(store==null){ 509 logger.error("No storage plugin detected, ignoring index request"); 510 return Collections.emptyList(); 511 } 512 513 Collection<IndexerInterface> indexers= getIndexingPlugins(true); 514 //Collection<IndexerInterface> indexers = getIndexingPluginsByMimeType(path); 515 ArrayList<Task<Report>> rettasks = new ArrayList<>(); 516 final String pathF = path.toString(); 517 for(IndexerInterface indexer : indexers){ 518 try { 519 Task<Report> task = indexer.index(store.at(path)); 520 if(task == null) continue; 521 final String taskUniqueID = UUID.randomUUID().toString(); 522 task.setName(String.format("[%s]index %s", indexer.getName(), path)); 523 task.onCompletion(new Runnable() { 524 @Override 525 public void run() { 526 logger.info("Task [{}] complete: {} is indexed", taskUniqueID, pathF); 527 } 528 }); 529 530 taskManager.dispatch(task); 531 rettasks.add(task); 532 RunningIndexTasks.getInstance().addTask(taskUniqueID, task); 533 } catch (RuntimeException ex) { 534 logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex); 535 } 536 } 537 logger.info("Finished firing all indexing plugins for {}", path); 538 539 return rettasks; 540 } 541 542 // 543 public List<Task<Report>> index(String pluginName, URI path) { 544 logger.info("Starting Indexing procedure for {}", path); 545 StorageInterface store = getStorageForSchema(path); 546 547 if(store==null){ 548 logger.error("No storage plugin detected, ignoring index request"); 549 return Collections.emptyList(); 550 } 551 552 final String taskUniqueID = UUID.randomUUID().toString(); 553 554 IndexerInterface indexer = getIndexerByName(pluginName, true); 555 ArrayList<Task<Report>> rettasks = new ArrayList<>(); 556 final String pathF = path.toString(); 557 try { 558 Task<Report> task = indexer.index(store.at(path)); 559 if (task != null) { 560 task.setName(String.format("[%s]index %s", pluginName, path)); 561 task.onCompletion(new Runnable() { 562 563 @Override 564 public void run() { 565 logger.info("Task [{}] complete: {} is indexed", taskUniqueID, pathF); 566 567 //RunningIndexTasks.getInstance().removeTask(taskUniqueID); 568 } 569 }); 570 571 taskManager.dispatch(task); 572 573 rettasks.add(task); 574 logger.info("Fired indexer {} for URI {}", pluginName, path.toString()); 575 RunningIndexTasks.getInstance().addTask(taskUniqueID, task); 576 } 577 } catch (RuntimeException ex) { 578 logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex); 579 } 580 581 return rettasks; 582 } 583 584 public void unindex(URI path) { 585 logger.info("Starting unindexing procedure for {}", path.toString()); 586 this.doUnindex(path, this.getIndexingPlugins(true)); 587 } 588 589 /** Issue the removal of indexed entries in a path from the given indexers. 590 * 591 * @param path the URI of the directory or file to unindex 592 * @param indexProviders a collection of providers 593 */ 594 public void unindex(URI path, Collection<String> indexProviders) { 595 logger.info("Starting unindexing procedure for {}", path); 596 597 if (indexProviders != null) { 598 List<IndexerInterface> indexers = new ArrayList<>(); 599 for (String provider : indexProviders) { 600 indexers.add(this.getIndexerByName(provider, true)); 601 } 602 this.doUnindex(path, indexers); 603 } else { 604 this.doUnindex(path, this.getIndexingPlugins(true)); 605 } 606 } 607 608 /** Issue an unindexation procedure to the given indexers. 609 * 610 * @param path the URI of the directory or file to unindex 611 * @param indexers a collection of providers 612 */ 613 private void doUnindex(URI path, Collection<IndexerInterface> indexers) { 614 for (IndexerInterface indexer : indexers) { 615 try { 616 indexer.unindex(path); 617 } catch (RuntimeException ex) { 618 logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex); 619 } 620 } 621 logger.info("Finished unindexing {}", path); 622 } 623 624 public void remove(URI uri){ 625 StorageInterface si = getStorageForSchema(uri); 626 if(si != null) 627 doRemove(uri, si); 628 else 629 logger.error("Could not find storage plugin to handle URI: {}", uri); 630 } 631 632 public void doRemove(URI uri, StorageInterface si) { 633 try { 634 if (si.handles(uri)) { 635 si.remove(uri); 636 } else { 637 logger.warn("Storage Plugin does not handle URI: {},{}", uri, si); 638 } 639 logger.info("Finished removing {}", uri); 640 } catch (RuntimeException ex) { 641 logger.warn("Storage {} failed unexpectedly", si.getName(), ex); 642 } 643 } 644 645 /* 646 * Convenience method that calls index(URI) and runs the returned 647 * tasks on the executing thread 648 */ 649 public List<Report> indexBlocking(URI path) { 650 logger.info("Starting indexing blocking procedure for {}", path); 651 List<Task<Report>> ret = index(path); 652 653 ArrayList<Report> reports = new ArrayList<>(ret.size()); 654 for(Task<Report> t : ret){ 655 try { 656 reports.add(t.get()); 657 } 658 catch (InterruptedException | ExecutionException e) { 659 logger.error(e.getMessage(), e); 660 } catch (RuntimeException e) { 661 logger.warn("Indexer task failed unexpectedly", e); 662 } 663 } 664 logger.info("Finished indexing {}", path); 665 666 return reports; 667 } 668 669 //METHODs FOR PluginController4Users 670 //TODO:this method is a workaround! we do get rightmenu items, but only for the search window 671 //which should be moved to plugins and hence we are assuming too much in here! 672 673 @Deprecated 674 public List<JMenuItem> getRightButtonItems() { 675 logger.info("getRightButtonItems()"); 676 ArrayList<JMenuItem> rightMenuItems = new ArrayList<>(); 677 678 for (PluginSet set : pluginSets) { 679 logger.info("Set plugins: {}", set.getGraphicalPlugins()); 680 Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins(); 681 if (graphicalPlugins == null) { 682 continue; 683 } 684 logger.info("Looking for plugin"); 685 for (GraphicalInterface gpi : graphicalPlugins) { 686 logger.info("GPI: {}", gpi); 687 ArrayList<JMenuItem> rbPanels = gpi.getRightButtonItems(); 688 if (rbPanels == null) { 689 continue; 690 } 691 rightMenuItems.addAll(rbPanels); 692 } 693 } 694 return rightMenuItems; 695 } 696 697 //returns a list of tabs from all plugins 698 @Deprecated 699 public List<JPanel> getTabItems() { 700 logger.info("getTabItems"); 701 ArrayList<JPanel> panels = new ArrayList<>(); 702 703 for (PluginSet set : pluginSets) { 704 Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins(); 705 if (graphicalPlugins == null) { 706 continue; 707 } 708 for (GraphicalInterface gpi : graphicalPlugins) { 709 ArrayList<JPanel> tPanels = gpi.getTabPanels(); 710 if (tPanels == null) { 711 continue; 712 } 713 panels.addAll(tPanels); 714 } 715 } 716 return panels; 717 } 718 719 @Deprecated 720 public List<JMenuItem> getMenuItems() { 721 logger.info("getMenuItems"); 722 ArrayList<JMenuItem> items = new ArrayList<>(); 723 724 for (PluginSet set : pluginSets) { 725 Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins(); 726 if (graphicalPlugins == null) { 727 continue; 728 } 729 730 for (GraphicalInterface gpi : graphicalPlugins) { 731 Collection<JMenuItem> setItems = gpi.getMenuItems(); 732 if (setItems == null) { 733 continue; 734 } 735 items.addAll(setItems); 736 } 737 } 738 return items; 739 } 740 741 // Methods for Web UI 742 743 /** Retrieve all web UI plugin descriptors for the given slot id. 744 * 745 * @param ids the slot id's for the plugin ("query", "result", "menu", ...), empty or null for any slot 746 * @return a collection of web UI plugins. 747 */ 748 public Collection<WebUIPlugin> getWebUIPlugins(String... ids) { 749 logger.debug("getWebUIPlugins(slot ids: {})", ids != null ? Arrays.asList(ids) : "<any>"); 750 List<WebUIPlugin> plugins = new ArrayList<>(); 751 Set<String> idSet = Collections.EMPTY_SET; 752 if (ids != null) { 753 idSet = new HashSet<>(Arrays.asList(ids)); 754 } 755 for (WebUIPlugin plugin : webUI.pluginSet()) { 756 if (!plugin.isEnabled()) { 757 continue; 758 } 759 if (idSet.isEmpty() || idSet.contains(plugin.getSlotId())) { 760 plugins.add(plugin); 761 } 762 } 763 return plugins; 764 } 765 766 /** Retrieve the web UI plugin descriptor of the plugin with the given name. 767 * 768 * @param name the unique name of the plugin 769 * @return a web UI plugin descriptor object, or null if no such plugin exists or is inactive 770 */ 771 public WebUIPlugin getWebUIPlugin(String name) { 772 logger.debug("getWebUIPlugin(name: {})", name); 773 WebUIPlugin plugin = webUI.get(name); 774 return plugin == null ? null 775 : plugin.isEnabled() ? plugin : null; 776 } 777 778 /** Retrieve the web UI plugin descriptor package.json. 779 * 780 * @param name the unique name of the plugin 781 * @return the full contents of the package.json, null if the plugin is not available 782 */ 783 public String getWebUIPackageJSON(String name) { 784 logger.debug("getWebUIPackageJSON(name: {})", name); 785 try { 786 Object o = webUI.retrieveJSON(name); 787 return (o != null) 788 ? o.toString() 789 : null; 790 } catch (IOException ex) { 791 logger.error("Failed to retrieve package JSON", ex); 792 return null; 793 } 794 } 795 796 /** Retrieve the web UI plugin module code. 797 * 798 * @param name the unique name of the plugin 799 * @return the full contents of the module file, null if the plugin is not available 800 */ 801 public String getWebUIModuleJS(String name) { 802 logger.debug("getWebUIModuleJS(name: {})", name); 803 try { 804 return webUI.retrieveModuleJS(name); 805 } catch (IOException ex) { 806 logger.error("Failed to retrieve module", ex); 807 return null; 808 } 809 } 810 811 //METHODS FOR SERVICE:JAVA 812 /** 813 * 814 * TODO: REVIEW! BELOW 815 * 816 * Checks if the plugin exists and has advanced/internal settings. 817 * 818 * @param pluginName the name of the plugin. 819 * @return true if the plugin exists and has at least one advance/internal 820 * settings, false otherwise. 821 */ 822 public boolean hasAdvancedSettings(String pluginName) { 823 return false; 824 } 825 826 public HashMap<String, String> getAdvancedSettingsHelp(String pluginName) { 827 return null; 828 } 829}