001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy 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 * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package plugins.kernel.searchprovider; 020 021import icy.gui.plugin.PluginDetailPanel; 022import icy.main.Icy; 023import icy.network.NetworkUtil; 024import icy.plugin.PluginDescriptor; 025import icy.plugin.PluginInstaller; 026import icy.plugin.PluginLauncher; 027import icy.plugin.PluginLoader; 028import icy.plugin.PluginRepositoryLoader; 029import icy.search.OnlineSearchResultProducer; 030import icy.search.SearchEngine; 031import icy.search.SearchResult; 032import icy.search.SearchResultConsumer; 033import icy.search.SearchResultProducer; 034import icy.system.thread.ThreadUtil; 035import icy.util.XMLUtil; 036 037import java.util.ArrayList; 038import java.util.List; 039 040import org.w3c.dom.Document; 041import org.w3c.dom.Element; 042 043import plugins.kernel.searchprovider.LocalPluginSearchResultProducer.LocalPluginResult; 044import plugins.kernel.searchprovider.PluginSearchResultProducerHelper.SearchWord; 045 046/** 047 * This class is used to provide online plugin elements to the search engine. 048 * 049 * @author Stephane 050 */ 051public class OnlinePluginSearchResultProducer extends OnlineSearchResultProducer 052{ 053 /** 054 * @author Stephane 055 */ 056 public static class OnlinePluginResult extends PluginSearchResult 057 { 058 public OnlinePluginResult(SearchResultProducer provider, PluginDescriptor plugin, String text, 059 List<SearchWord> searchWords, int priority) 060 { 061 super(provider, plugin, text, searchWords, priority); 062 } 063 064 @Override 065 public String getTooltip() 066 { 067 return "Left click: Install and Run - Right click: Online documentation"; 068 } 069 070 @Override 071 public void execute() 072 { 073 // can take sometime, better to execute it in background 074 ThreadUtil.bgRun(new Runnable() 075 { 076 @Override 077 public void run() 078 { 079 // plugin locally installed ? (result transfer to local plugin provider) 080 if (PluginLoader.isLoaded(plugin.getClassName())) 081 { 082 if (plugin.isActionable()) 083 PluginLauncher.start(plugin); 084 else 085 { 086 ThreadUtil.invokeLater(new Runnable() 087 { 088 @Override 089 public void run() 090 { 091 new PluginDetailPanel(plugin); 092 } 093 }); 094 } 095 } 096 else 097 { 098 // install and run the plugin (if user ok with install) 099 PluginInstaller.install(plugin, true); 100 // wait for installation complete 101 PluginInstaller.waitInstall(); 102 103 // find the new installed plugin 104 final PluginDescriptor localPlugin = PluginLoader.getPlugin(plugin.getClassName()); 105 // plugin found ? 106 if (localPlugin != null) 107 { 108 // launch it if actionable 109 if (localPlugin.isActionable()) 110 PluginLauncher.start(localPlugin); 111 else 112 { 113 // just display info 114 ThreadUtil.invokeLater(new Runnable() 115 { 116 @Override 117 public void run() 118 { 119 new PluginDetailPanel(localPlugin); 120 } 121 }); 122 } 123 } 124 } 125 } 126 }); 127 } 128 } 129 130 private static final String ID_SEARCH_RESULT = "searchresult"; 131 private static final String ID_PLUGIN = "plugin"; 132 private static final String ID_CLASSNAME = "classname"; 133 // private static final String ID_NAME = "name"; 134 private static final String ID_TEXT = "string"; 135 136 @Override 137 public int getOrder() 138 { 139 // should be right after local plugin 140 return 6; 141 } 142 143 @Override 144 public String getName() 145 { 146 return "Online plugins"; 147 } 148 149 @Override 150 public String getTooltipText() 151 { 152 return "Result(s) from online plugin"; 153 } 154 155 @Override 156 public void doSearch(Document doc, String text, SearchResultConsumer consumer) 157 { 158 // Online plugin loader failed --> exit 159 if (!ensureOnlineLoaderLoaded()) 160 return; 161 162 // no need to spent more time here... 163 if (hasWaitingSearch()) 164 return; 165 166 // get online plugins 167 final List<PluginDescriptor> onlinePlugins = PluginRepositoryLoader.getPlugins(); 168 // get online result node 169 final Element resultElement = XMLUtil.getElement(doc.getDocumentElement(), ID_SEARCH_RESULT); 170 171 if (resultElement == null) 172 return; 173 174 // get the local plugin search provider from search engine 175 final SearchEngine se = Icy.getMainInterface().getSearchEngine(); 176 LocalPluginSearchResultProducer lpsrp = null; 177 178 if (se != null) 179 { 180 for (SearchResultProducer srp : se.getSearchResultProducers()) 181 if (srp instanceof LocalPluginSearchResultProducer) 182 lpsrp = (LocalPluginSearchResultProducer) srp; 183 } 184 185 final List<SearchWord> words = PluginSearchResultProducerHelper.getSearchWords(text); 186 final List<SearchResult> tmpResults = new ArrayList<SearchResult>(); 187 188 for (Element plugin : XMLUtil.getElements(resultElement, ID_PLUGIN)) 189 { 190 // abort 191 if (hasWaitingSearch()) 192 return; 193 194 final SearchResult result = getResult(consumer, onlinePlugins, plugin, words, lpsrp); 195 196 if (result != null) 197 tmpResults.add(result); 198 } 199 200 // use a copy to avoid future concurrent accesses 201 results = new ArrayList<SearchResult>(tmpResults); 202 consumer.resultsChanged(this); 203 204 // load descriptions 205 for (SearchResult result : tmpResults) 206 { 207 // abort 208 if (hasWaitingSearch()) 209 return; 210 211 ((OnlinePluginResult) result).getPlugin().loadDescriptor(); 212 consumer.resultChanged(this, result); 213 } 214 215 // load images 216 for (SearchResult result : tmpResults) 217 { 218 // abort 219 if (hasWaitingSearch()) 220 return; 221 222 ((OnlinePluginResult) result).getPlugin().loadImages(); 223 consumer.resultChanged(this, result); 224 } 225 } 226 227 private static boolean ensureOnlineLoaderLoaded() 228 { 229 PluginRepositoryLoader.waitLoaded(); 230 231 // repository loader failed --> retry once 232 if (PluginRepositoryLoader.failed() && NetworkUtil.hasInternetAccess()) 233 { 234 PluginRepositoryLoader.reload(); 235 PluginRepositoryLoader.waitLoaded(); 236 } 237 238 return !PluginRepositoryLoader.failed(); 239 } 240 241 private OnlinePluginResult getResult(SearchResultConsumer consumer, List<PluginDescriptor> onlinePlugins, 242 Element pluginNode, List<SearchWord> words, LocalPluginSearchResultProducer lpsrp) 243 { 244 final String className = XMLUtil.getElementValue(pluginNode, ID_CLASSNAME, ""); 245 final String text = XMLUtil.getElementValue(pluginNode, ID_TEXT, ""); 246 int priority; 247 248 final PluginDescriptor localPlugin = PluginLoader.getPlugin(className); 249 // exists in local ? 250 if (localPlugin != null) 251 { 252 // if we have the local search provider, we try to add result if not already existing 253 if (lpsrp != null) 254 { 255 final List<SearchResult> localResults = lpsrp.getResults(); 256 boolean alreadyExists = false; 257 258 synchronized (localResults) 259 { 260 for (SearchResult result : localResults) 261 { 262 if (((LocalPluginResult) result).getPlugin() == localPlugin) 263 { 264 alreadyExists = true; 265 break; 266 } 267 } 268 } 269 270 // not already present in local result --> add it 271 if (!alreadyExists) 272 { 273 priority = PluginSearchResultProducerHelper.searchInPlugin(localPlugin, words); 274 275 // not found in local description --> assume low priority 276 if (priority == 0) 277 priority = 1; 278 279 lpsrp.addResult(new LocalPluginResult(lpsrp, localPlugin, text, words, priority), consumer); 280 } 281 } 282 283 // don't return it for online result 284 return null; 285 } 286 287 final PluginDescriptor onlinePlugin = PluginDescriptor.getPlugin(onlinePlugins, className); 288 // cannot be found in online ? --> no result 289 if (onlinePlugin == null) 290 return null; 291 292 // try to get priority on result 293 onlinePlugin.loadDescriptor(); 294 priority = PluginSearchResultProducerHelper.searchInPlugin(onlinePlugin, words); 295 296 // only keep high priority info from local data 297 if (priority <= 5) 298 priority = 1; 299 300 return new OnlinePluginResult(this, onlinePlugin, text, words, priority); 301 } 302}