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.rGUI.server.controllers; 020 021import java.io.File; 022import java.net.InetAddress; 023import java.net.URI; 024import java.rmi.RemoteException; 025import java.rmi.server.RemoteServer; 026import java.util.*; 027import java.util.AbstractMap.SimpleEntry; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import pt.ua.dicoogle.core.QueryExpressionBuilder; 034import pt.ua.dicoogle.plugins.NetworkMember; 035import pt.ua.dicoogle.plugins.PluginController; 036import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile; 037import pt.ua.dicoogle.rGUI.fileTransfer.FileSender; 038import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch; 039import pt.ua.dicoogle.rGUI.interfaces.signals.ISearchSignal; 040import pt.ua.dicoogle.rGUI.server.SearchHelper; 041import pt.ua.dicoogle.sdk.utils.DictionaryAccess; 042import pt.ua.dicoogle.sdk.Utils.TaskRequest; 043import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants; 044import pt.ua.dicoogle.sdk.datastructs.SearchResult; 045import pt.ua.dicoogle.sdk.observables.FileObservable; 046import pt.ua.dicoogle.sdk.observables.ListObservableSearch; 047import pt.ua.dicoogle.sdk.utils.TagValue; 048import pt.ua.dicoogle.sdk.utils.TagsStruct; 049 050/** 051 * This class is the controller to search in IndexEngine or P2P Network 052 * 053 * @author Samuel Campos <samuelcampos@ua.pt> 054 */ 055public class Search implements ISearch 056{ 057 058 private ISearchSignal searchSignal; 059 private ArrayList<String> extrafields; 060 private ArrayList<SearchResult> resultList; 061 private ArrayList<SearchResult> P2PResultList; 062 private ArrayList<SearchResult> pendingP2PThumbnails; 063 private ArrayList<SearchResult> exportList; 064 private SearchHelper searchHelper; 065 private long searchTime; 066 067 public Search() 068 { 069 extrafields = new ArrayList<String>(); 070 071 extrafields.add("PatientName"); 072 extrafields.add("PatientID"); 073 extrafields.add("Modality"); 074 extrafields.add("StudyDate"); 075 extrafields.add("SOPInstanceUID"); 076 //extrafields.add("Thumbnail"); 077 078 searchHelper = new SearchHelper(this); 079 } 080 081 public void setSearchTime(long time) 082 { 083 searchTime = time; 084 085 /* 086 try { 087 if(searchSignal != null) 088 searchSignal.sendSearchSignal(2); 089 } catch (RemoteException ex) { 090 searchSignal = null; 091 DebugManager.getInstance().debug("Failure to send the signal to the client.."); 092 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 093 } 094 * 095 */ 096 } 097 098 // SearchHelper sends the local searchResults 099 public void setLocalSearchResult(ArrayList<SearchResult> sResult) 100 { 101 this.resultList = sResult; 102 103 try 104 { 105 if (searchSignal != null) 106 { 107 searchSignal.sendSearchSignal(0); 108 } 109 } catch (RemoteException ex) 110 { 111 searchSignal = null; 112 //DebugManager.getInstance().debug("Failure to send the signal to the client.."); 113 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 114 } 115 } 116 117 118 public void queryFinished() 119 { 120 121 try 122 { 123 if (searchSignal != null) 124 { 125 searchSignal.sendSearchSignal(5); 126 } 127 } catch (RemoteException ex) 128 { 129 searchSignal = null; 130 //DebugManager.getInstance().debug("Failure to send the signal to the client.."); 131 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 132 } 133 } 134 135 // SearchHelper sends the new P2P searchResults 136 public void setP2PSearchResult(ArrayList<SearchResult> sResult) 137 { 138 //System.out.println("entrou no setP2PSearchResult com " + sResult.size() + " resultados"); 139 this.P2PResultList = sResult; 140 141 try 142 { 143 if (searchSignal != null) 144 { 145 //System.out.println("there is searchsignal"); 146 searchSignal.sendSearchSignal(1); 147 } 148 } catch (RemoteException ex) 149 { 150 searchSignal = null; 151 //DebugManager.getInstance().debug("Failure to send the signal to the client.."); 152 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 153 } 154 } 155 156 public void setExportSearchResult(ArrayList<SearchResult> sResult) 157 { 158 if (this.exportList != null) 159 { 160 exportList.addAll(sResult); 161 } 162 else 163 { 164 this.exportList = sResult; 165 } 166 167 try 168 { 169 170 if (searchSignal != null) 171 { 172 searchSignal.sendSearchSignal(4); 173 } 174 } catch (RemoteException ex) 175 { 176 searchSignal = null; 177 //DebugManager.getInstance().debug("Failure to send the signal to the client.."); 178 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 179 } 180 181 } 182 183 public void setP2PThumbnails(ArrayList<SearchResult> sResult) 184 { 185 if (pendingP2PThumbnails != null) 186 { 187 pendingP2PThumbnails.addAll(sResult); 188 } else 189 { 190 pendingP2PThumbnails = sResult; 191 } 192 193 try 194 { 195 if (searchSignal != null) 196 { 197 searchSignal.sendSearchSignal(3); 198 } 199 200 } catch (RemoteException ex) 201 { 202 searchSignal = null; 203 //DebugManager.getInstance().debug("Failure to send the signal to the client.."); 204 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 205 } 206 } 207 208 209 210 @Override 211 public void Search(String query, boolean keywords, HashMap<String,Boolean> plugins) throws RemoteException 212 213 { 214 if (query.isEmpty()) 215 216 { 217 query = "*:*"; 218 } else 219 { 220 if (!keywords) 221 { 222 /** 223 * Write the QueryString respecting BNF grammer 224 * defined regarding Lucene documentation 2.4.X branch 225 */ 226 QueryExpressionBuilder _expression = new QueryExpressionBuilder(query); 227 query = _expression.getQueryString(); 228 } 229 //DebugManager.getInstance().debug(">>> New Query String is:" + query); 230 231 } 232 searchTime = 0; 233 searchHelper.search(query, extrafields, plugins, false); 234 } 235 236 @Override 237 public ListObservableSearch<SearchResult> SearchToExport(String query, boolean keywords, HashMap<String, Boolean> plugins, ArrayList<String> eFields, Observer obs) throws RemoteException 238 { 239 if (query.isEmpty()) 240 { 241 query = "*:*"; 242 } else 243 { 244 if (!keywords) 245 { 246 QueryExpressionBuilder _expression = new QueryExpressionBuilder(query); 247 query = _expression.getQueryString(); 248 } 249 } 250 251 return searchHelper.search(query, eFields, plugins, true, obs); 252 253 } 254 255 @Override 256 public void pruneQuery(String id) throws RemoteException 257 { 258 PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_QUERY_PRUNE, null, null)); 259 } 260 261 class SearchDumper implements Observer 262 { 263 264 static final int WAIT_TIME = 10; 265 266 ListObservableSearch<SearchResult> result = null; 267 268 ArrayList<SearchResult> resultArr = new ArrayList<SearchResult>(); 269 270 public ArrayList<SearchResult> search(SearchResult r, String query, ArrayList<String> extrafields) 271 { 272 return null; 273 /*synchronized(this) 274 { 275 //TODO: DELETED 276 //result = PluginController.getInstance().searchOne(r.getURI().toString(), 277 //query , extrafields, r.getURI().toString(), this); 278 279 280 //System.out.println("Query: " + query); 281 //System.out.println("Plugin: " + r.getPluginName()); 282 //System.out.println("Waiting for results"); 283 resultArr.addAll(result.getArray()); 284 try { 285 this.wait(WAIT_TIME); 286 } catch (InterruptedException ex) { 287 LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex); 288 } 289 } 290 //System.out.println("Received the results + "+resultArr.size()); 291 //System.out.println("Received the results + "+result.getArray()); 292 return resultArr;*/ 293 } 294 295 public List<SearchResult> getResults() 296 { 297 //System.out.println("Received the results2 + "+resultArr.size()); 298 //System.out.println("Received the results2 + "+result.getArray()); 299 return this.resultArr; 300 } 301 302 @Override 303 public void update(Observable o, Object o1) 304 { 305 //System.out.println("Update + "+o); 306 if (o1==null) 307 { 308 synchronized(this) 309 { 310 this.notifyAll(); 311 } 312 return; 313 } 314 ArrayList tmp = ((ListObservableSearch) o1).getArray(); 315 //System.out.println("Result_: " + tmp); 316 //System.out.println("Received a result_"); 317 synchronized(this) 318 { 319 resultArr.addAll(tmp); 320 this.notifyAll(); 321 } 322 //System.out.println("Received a result - done notification_"); 323 324 } 325 } 326 327 @Override 328 public ArrayList<SearchResult> SearchIndexedMetaData(SearchResult searchResult) throws RemoteException { 329 330 TagsStruct tags = TagsStruct.getInstance(); 331 332 ArrayList<String> extraFields = new ArrayList<>(); 333 334 for(TagValue tag : tags.getAllFields()) 335 extraFields.add(tag.getAlias()); 336 337 String query = "FileName:" + searchResult.getURI() + " AND FileHash:"+ searchResult.get("filehash"); 338 339 340 SearchDumper sdumper = new SearchDumper(); 341 sdumper.search(searchResult, query, extraFields); 342 List<SearchResult> result = sdumper.getResults(); 343 //System.out.println("Result + " +result); 344 if (result.size() > 0) { 345 346 SearchResult r = (SearchResult) result.get(0); 347 for (String s:r.getExtraData().keySet()) 348 { 349 if (s.contains("Sequence")) 350 { 351 String [] fields = r.getExtraData().get(s).toString().split(" "); 352 for (int i = 0 ; i<fields.length; i++) 353 { 354 extraFields.add(fields[i]); 355 } 356 357 } 358 } 359 360 sdumper = new SearchDumper(); 361 sdumper.search(searchResult, query, extraFields); 362 result = sdumper.getResults(); 363 364 } 365 366 return (ArrayList<SearchResult>) result; 367 } 368 369 370 371 372 @Override 373 public long getSearchTime() throws RemoteException 374 { 375 return searchTime; 376 } 377 378 @Override 379 public void RegisterSignalBack(ISearchSignal signalBack) throws RemoteException 380 { 381 //System.out.println("Registring SignalBack"); 382 383 //if(signalBack == null) 384 // System.out.println("signalBack == null"); 385 //else 386 // System.out.println("signalBack != null"); 387 388 searchSignal = signalBack; 389 390 //System.out.println("SignalBack Registered"); 391 } 392 393 @Override 394 public FileObservable RequestP2PFile(SearchResult file) throws RemoteException 395 { 396 //TOSO: fix this 397 // return PluginController.getInstance().requestFile(file.getURI(), file.getURI(), file.getURI(), file.get("filehash")); 398 //PeerEngine.getInstance().requestFile(file.getAddress(), file.getFileName(), file.getFileHash()); 399 return null; 400 } 401 402 /** 403 * Don't work with SearchResultP2P 404 * 405 * @param file 406 * @return 407 * @throws RemoteException 408 */ 409 @Override 410 public SimpleEntry<RemoteFile, Integer> downloadFile(SearchResult result) throws RemoteException 411 { 412 /*if (!PluginController.getInstance().isLocalPlugin(result.getPluginName())) 413 { 414 return null; 415 }*/ 416 try 417 { 418 String path = result.getURI().toString().replace('\\', '/'); 419 420 File file = new File(path); 421 InetAddress client = InetAddress.getByName(RemoteServer.getClientHost()); 422 423 FileSender sender = new FileSender(file, client); 424 425 SimpleEntry<RemoteFile, Integer> entry = new SimpleEntry<RemoteFile, Integer>(new RemoteFile(file), sender.getListenerPort()); 426 427 //DebugManager.getInstance().debug("Transfering file: " + entry.getKey().getName() + ", listening port: " + entry.getValue()); 428 429 Thread tSender = sender; 430 tSender.start(); 431 432 return entry; 433 434 } catch (Exception e) 435 { 436 e.printStackTrace(); 437 } 438 return null; 439 } 440 441 @Override 442 public List<NetworkMember> getPeerList() throws RemoteException 443 { 444 //TODO: DELETED 445 //return PluginController.getInstance().getMembers(); 446 return null; 447 } 448 449 @Override 450 public ArrayList<SearchResult> getSearchResults() throws RemoteException 451 { 452 ArrayList<SearchResult> returnResultList = resultList; 453 454 resultList = null; 455 456 return returnResultList; 457 } 458 459 @Override 460 public ArrayList<SearchResult> getP2PSearchResults() throws RemoteException 461 { 462 ArrayList<SearchResult> returnResultList = P2PResultList; 463 464 P2PResultList = null; 465 466 return returnResultList; 467 } 468 469 @Override 470 public ArrayList<SearchResult> getExportSearchResults() throws RemoteException 471 { 472 ArrayList<SearchResult> returnResultList = exportList; 473 474 exportList = null; 475 476 return returnResultList; 477 } 478 479 @Override 480 public SearchResult getThumbnail(URI FileName, String FileHash) throws RemoteException 481 { 482 return searchHelper.searchThumbnail(FileName, FileHash); 483 } 484 485 @Override 486 public void getP2PThumbnail(URI FileName, String FileHash, String addr) throws RemoteException 487 { 488 searchHelper.searchP2PThumbnail(FileName, FileHash, addr); 489 } 490 491 @Override 492 public ArrayList<SearchResult> getPendingP2PThumnails() throws RemoteException 493 { 494 ArrayList<SearchResult> returnResultList = pendingP2PThumbnails; 495 496 pendingP2PThumbnails = null; 497 498 return returnResultList; 499 } 500 501 @Override 502 public HashMap<String, Integer> getTagList() throws RemoteException 503 { 504 return DictionaryAccess.getInstance().getTagList(); 505 } 506 507 @Override 508 public HashMap<Integer, TagValue> getDIMFields() throws RemoteException 509 { 510 Set<TagValue> fields = TagsStruct.getInstance().getDIMFields(); 511 HashMap<Integer, TagValue> map = new HashMap<>(fields.size()); 512 for(TagValue tag : fields) 513 map.put(tag.getTagNumber(), tag); 514 515 return map; 516 } 517}