1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 28 package com.sun.javatest.exec; 29 30 import com.sun.javatest.exec.Session.Event; 31 import java.awt.BorderLayout; 32 import java.awt.EventQueue; 33 import java.util.Collection; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.Vector; 38 39 import javax.swing.Action; 40 import javax.swing.JCheckBox; 41 import javax.swing.JComponent; 42 import javax.swing.JDialog; 43 import javax.swing.JMenu; 44 import javax.swing.JOptionPane; 45 import javax.swing.JPanel; 46 import javax.swing.JTextArea; 47 48 import com.sun.javatest.AllTestsFilter; 49 import com.sun.javatest.Harness; 50 import com.sun.javatest.InterviewParameters; 51 import com.sun.javatest.LastRunFilter; 52 import com.sun.javatest.ParameterFilter; 53 import com.sun.javatest.Parameters; 54 import com.sun.javatest.TestFilter; 55 import com.sun.javatest.TestResult; 56 import com.sun.javatest.TestSuite; 57 import com.sun.javatest.tool.Preferences; 58 import com.sun.javatest.tool.UIFactory; 59 import com.sun.javatest.util.PrefixMap; 60 61 /** 62 * This class handles all the special filter juggling that exec tool needs to do. 63 */ 64 public class ET_FilterHandler implements ET_FilterControl, Session.Observer { 65 ET_FilterHandler(JComponent parent, ExecModel model, Harness h, UIFactory uif, 66 Map map) { 67 this(parent, model, uif); 68 setHarness(h); 69 restore(map); 70 } 71 72 protected ET_FilterHandler(JComponent parent, ExecModel model, UIFactory uif) { 73 this.uif = uif; 74 this.model = model; 75 this.parentComponent = parent; 76 77 allFilters = new Vector<>(); 78 79 } 80 81 public void setHarness(Harness h) { 82 h.addObserver(new Watcher()); 83 } 84 85 FilterConfig loadFilters() { 86 // this method may eventually do fancy things to scan the classpath or 87 // preferences for custom plugin tools, for now it is hardcoded 88 89 if (fConfig != null) 90 return fConfig; 91 92 fConfig = new FilterConfig(model, parentComponent, uif); 93 94 fHandler = fConfig.createFilterSelectionHandler(); 95 96 // add observer here so that the menu gets the additions 97 // also watches for user selection of new filter 98 /* 99 filterWatcher = new FilterWatcher(); 100 filterHandler.addObserver(filterWatcher); 101 */ 102 103 // last run filter 104 TestFilter filter = ltrFilter = new LastRunFilter(); 105 allFilters.add(filter); 106 fConfig.add(filter); 107 108 // current parameter filter 109 filter = paramFilter = new ParameterFilter(); 110 allFilters.add(filter); 111 fConfig.add(filter); 112 113 List<TestFilter> usersFilters = getUsersFilters(); 114 if (usersFilters != null) { 115 for (TestFilter tf: usersFilters) { 116 allFilters.add(tf); 117 fConfig.add(tf); 118 } 119 } 120 /* 121 if (model.getContextManager() != null && 122 model.getContextManager().getFeatureManager() != null) { 123 if (model.getContextManager().getFeatureManager().isEnabled(FeatureManager.TEMPLATE_USAGE)) { 124 tfilter = new TemplateParameterFilter(); 125 allFilters.add(tfilter); 126 fConfig.add(tfilter); 127 } 128 } 129 */ 130 131 // filter which accepts all tests 132 allFilter = new AllTestsFilter(); 133 allFilters.add(allFilter); 134 fConfig.add(allFilter); 135 136 updateCustomFilter(); 137 138 // establish the default 139 fHandler.setFilter(getDefaultFilter(map)); 140 141 return fConfig; 142 } 143 144 /** 145 * Subclasses may override this method to insert filters 146 * like TemplateFilter 147 * 148 * @return list of filters defined for the User's TestSuite, or null 149 */ 150 protected List<TestFilter> getUsersFilters() { 151 return null; 152 } 153 154 public JMenu getFilterMenu() { 155 return getFilterSelectionHandler().getFilterMenu(); 156 } 157 158 FilterSelectionHandler getFilterSelectionHandler() { 159 loadFilters(); 160 return fHandler; 161 } 162 163 private TestFilter getDefaultFilter(Map map) { 164 if (map != null) { 165 String pref = (String)(map.get(ExecTool.ACTIVE_FILTER)); 166 167 // try to use filter indicated in preference 168 for (int i = 0; i < allFilters.size(); i++) { 169 if (allFilters.elementAt(i).getClass().getName().equals(pref)) 170 return (TestFilter)allFilters.elementAt(i); 171 } // for 172 } 173 174 // default filter 175 return allFilter; 176 } 177 178 protected void updateFilters() { 179 loadFilters(); 180 181 // special code for custom filter loading 182 updateCustomFilter(); 183 184 // update Last Test Run filtered if needed 185 if (!ltrFilter.isWorkDirectorySet()) 186 ltrFilter.setWorkDirectory(model.getWorkDirectory()); 187 188 InterviewParameters ips = model.getInterviewParameters(); 189 if (ips == null) // this filter does not apply now 190 return; 191 192 paramFilter.update(ips); 193 194 TestFilter newCertFilter = ips.getRelevantTestFilter(); 195 // check for filter behavior equality 196 if (newCertFilter == null) { 197 if (certFilter != null) { 198 // we had a certification filter earlier, now it is gone 199 if (fHandler.getActiveFilter() == certFilter) { 200 // switch to another filter before removing 201 // XXX may want to notify user! 202 fHandler.setFilter(paramFilter); 203 } 204 205 fConfig.remove(certFilter); 206 } 207 else { 208 // FilterConfig is clean 209 } 210 } // outer if 211 else if (!newCertFilter.equals(certFilter)) { 212 // check for reference equality 213 if (newCertFilter == certFilter) { 214 // this is ignored by fConfig if it is not relevant 215 fConfig.notifyUpdated(certFilter); 216 } 217 else { 218 // rm old one, put in new one 219 fConfig.add(newCertFilter); 220 221 if (fHandler.getActiveFilter() == certFilter) { 222 // switch to another filter before removing 223 // XXX may want to notify user! 224 fHandler.setFilter(newCertFilter); 225 } 226 227 fConfig.remove(certFilter); 228 certFilter = newCertFilter; 229 } 230 } 231 else { 232 // filter is the same 233 } 234 } 235 236 public JMenu getMenu() { 237 loadFilters(); 238 return null; 239 //return fHandler.getFilterMenu(); 240 } 241 242 public FilterConfig getFilterConfig() { 243 return fConfig; 244 } 245 246 /** 247 * Save internal state. 248 */ 249 public void save(Map<String, String> m) { 250 // -------- saved to given map (desktop) ------- 251 Preferences prefs = Preferences.access(); 252 TestFilter aFilter = fHandler.getActiveFilter(); 253 m.put(ExecTool.ACTIVE_FILTER, aFilter.getClass().getName()); 254 255 // -------- saved to global prefs ------- 256 TestSuite ts = model.getTestSuite(); 257 String tsId = null; 258 String tsName = null; 259 if (ts != null) { 260 tsId = ts.getID(); 261 tsName = ts.getName(); 262 } 263 264 int prefIndex = getPreferenceIndexForWrite(prefs, tsId); 265 266 ConstrainedPreferenceMap cpm = new ConstrainedPreferenceMap(prefs); 267 // using meta_ prefix for info not written by the filter itself 268 PrefixMap<String> pm = new PrefixMap<>(cpm, FILTER_PREFIX + prefIndex); 269 270 // it's really a special case to have a pref. entry which does not 271 // have a tsId associated 272 // it should really only be used (if at all) if a default set of 273 // settings is being saved 274 if (tsId != null) { 275 pm.put(META_ID, tsId); 276 pm.put(META_NAME, tsName); 277 } 278 279 pm.put(META_CLASS, bctf.getClass().getName()); 280 bctf.save(pm); 281 282 prefs.save(); 283 } 284 public void restore(Map m) { 285 this.map = m; 286 fHandler.setFilter(getDefaultFilter(m)); 287 } 288 public void updateGUI() { 289 // do nothing 290 } 291 292 public List<Action> getToolBarActionList() { 293 return null; 294 } 295 296 public void dispose() { 297 // do nothing 298 } 299 300 301 private void updateCustomFilter() { 302 // we only go thru here once per init. 303 if (lastTs != null) 304 return; 305 306 // load from prefs 307 lastTs = model.getTestSuite(); 308 String tsId = null; 309 String tsName = null; 310 311 // may be null, meaning that the exec tool has no TS 312 if (lastTs != null) { 313 tsId = lastTs.getID(); 314 tsName = lastTs.getName(); 315 } 316 317 Preferences prefs = Preferences.access(); 318 int prefIndex = getPreferenceIndexForRead(prefs, tsId); 319 320 // using META_ prefix for info not written by the filter itself 321 // XXX could check value of c in the future 322 //String c = prefs.getPreference(FILTER_PREFIX + "." + prefIndex + META_CLASS); 323 324 if (prefIndex >= 0) { 325 // load previous settings 326 ConstrainedPreferenceMap cpm = new ConstrainedPreferenceMap(prefs); 327 PrefixMap<String> pm = new PrefixMap<>(cpm, FILTER_PREFIX + prefIndex); 328 329 if (bctf == null) { // init 330 bctf = new BasicCustomTestFilter(pm, model, uif); 331 allFilters.add(bctf); 332 fConfig.add(bctf); 333 } 334 else { // tell filter load settings 335 bctf.load(pm); 336 fHandler.updateFilterMetaInfo(bctf); 337 } 338 } 339 else if (bctf == null) { 340 // no previous settings to use 341 bctf = new BasicCustomTestFilter(model, uif); 342 allFilters.add(bctf); 343 fConfig.add(bctf); 344 } 345 346 } 347 348 /** 349 * Find the index in the preferences which is appropriate for this filter 350 * to save its info in. Returns the next available one if there isn't 351 * an existing one. 352 * @param tsId May be null. 353 */ 354 private int getPreferenceIndexForWrite(Preferences p, String tsId) { 355 // pref. index 0 is the default when no tsId is available 356 // pref. encoding is: 357 // FILTER_PREFIX + <number> + <filter data> 358 int index = 0; 359 int numFilters = getPreferenceCount(p); 360 361 if (tsId != null && numFilters != 0) { 362 index = getPreferenceIndex(p, tsId, numFilters); 363 364 if (index == -1) { // not found 365 index = ++numFilters; 366 p.setPreference(FILTER_PREFIX + ".count", 367 Integer.toString(numFilters)); 368 } 369 } 370 else if (tsId != null && numFilters == 0) { 371 index = 1; 372 numFilters = 1; 373 p.setPreference(FILTER_PREFIX + ".count", 374 Integer.toString(numFilters)); 375 } 376 else { 377 // index remains 0, the default 378 } 379 return index; 380 } 381 382 /** 383 * Which pref index should be read for the given test suite. 384 * @return -1 if there is no pref. to read. 385 */ 386 private int getPreferenceIndexForRead(Preferences p, String tsId) { 387 int numFilters = getPreferenceCount(p); 388 int result = -1; 389 390 if (numFilters == 0) 391 result = -1; 392 else { 393 result = getPreferenceIndex(p, tsId, numFilters); 394 395 // read default values from index 0 if a match for the given 396 // TS was not found 397 /* 398 if (result == -1 && numFilters > 0) 399 result = 0; 400 */ 401 } 402 403 return result; 404 } 405 406 /** 407 * Do not call this directly. 408 * @param numFilters A number greater than zero. 409 * @return -1 if not found. 410 */ 411 private int getPreferenceIndex(Preferences p, String tsId, int numFilters) { 412 int index = -1; 413 414 for (int i = 1; i <= numFilters; i++) { 415 String id = p.getPreference(FILTER_PREFIX + i + "." + META_ID); 416 if (id.equals(tsId)) { 417 index = i; 418 break; 419 } 420 } // for 421 422 if (index > numFilters) 423 return -1; 424 else 425 return index; 426 } 427 428 /** 429 * How many indexes are we using for filters right now. 430 * @return -1 for none. 431 */ 432 private int getPreferenceCount(Preferences p) { 433 int numFilters = Integer.parseInt( 434 p.getPreference(FILTER_PREFIX + ".count", "0")); 435 436 return numFilters; 437 } 438 439 private FilterConfig fConfig; 440 private FilterSelectionHandler fHandler; 441 private ExecModel model; 442 private UIFactory uif; 443 private JComponent parentComponent; 444 private Map map; // saved desktop map to restore from 445 446 // filters 447 private LastRunFilter ltrFilter; // last test run 448 private ParameterFilter paramFilter; // current param filter 449 private BasicCustomTestFilter bctf; // "custom" filter 450 private AllTestsFilter allFilter; 451 private TestFilter certFilter; // "certification" filter 452 protected Vector<TestFilter> allFilters; 453 454 // custom filter info 455 private TestSuite lastTs; 456 457 // preferences constants 458 private static final String FILTER_PREFIX = "exec.vfilters"; 459 private static final String BTF_PREFIX = FILTER_PREFIX + ".btf"; 460 private static final String META_ID = "meta_tsid"; 461 private static final String META_NAME = "meta_tsn"; 462 private static final String META_CLASS = "meta_class"; 463 464 public void updated(Event ev) { 465 if (ev instanceof BasicSession.E_NewConfig) { 466 paramFilter.update(((BasicSession.E_NewConfig)ev).ip); 467 } 468 updateFilters(); 469 } 470 471 /** 472 * This class is completely private and only implements what we 473 * want to use here. 474 */ 475 private static class ConstrainedPreferenceMap implements Map<String, String> { 476 ConstrainedPreferenceMap(Preferences p) { 477 prefs = p; 478 } 479 480 public void clear() { 481 throw new UnsupportedOperationException(); 482 } 483 484 public boolean containsKey(Object o) { 485 throw new UnsupportedOperationException(); 486 } 487 488 public boolean containsValue(Object v) { 489 throw new UnsupportedOperationException(); 490 } 491 492 public Set<Map.Entry<String, String>> entrySet() { 493 throw new UnsupportedOperationException(); 494 } 495 496 public String get(Object key) { 497 if (!(key instanceof String)) 498 throw new IllegalArgumentException("key must be a string"); 499 500 return prefs.getPreference((String)key); 501 } 502 503 public boolean isEmpty() { 504 throw new UnsupportedOperationException(); 505 } 506 507 public Set<String> keySet() { 508 throw new UnsupportedOperationException(); 509 } 510 511 public String put(String key, String value) { 512 if (!(key instanceof String) || 513 !(value instanceof String)) 514 throw new IllegalArgumentException("both args must be strings"); 515 516 prefs.setPreference(key, value); 517 518 return null; 519 } 520 521 public void putAll(Map t) { 522 throw new UnsupportedOperationException(); 523 } 524 525 public String remove(Object key) { 526 throw new UnsupportedOperationException(); 527 } 528 529 public int size() { 530 throw new UnsupportedOperationException(); 531 } 532 533 public Collection<String> values() { 534 throw new UnsupportedOperationException(); 535 } 536 537 public String get(String key) { 538 return (String)(prefs.getPreference(key)); 539 } 540 541 private Preferences prefs; 542 } 543 544 private class FilterWatcher implements FilterSelectionHandler.Observer { 545 // NOTE: disconnected in loadFilters() 546 // ---------- FilterConfig.Observer ---------- 547 public void filterUpdated(TestFilter f) { 548 // ignore here 549 } 550 551 public void filterSelected(TestFilter f) { 552 // change menu selection 553 /* XXX not implemented yet 554 int index = items.getValueIndex(f); 555 556 if (index != -1) { 557 filterMenu.setSelected((Component)(items.getKeyAt(index))); 558 } 559 */ 560 561 // XXX avoid poking an uninitialized GUI what is a better check 562 //if (testTreePanel != null) 563 // updateGUI(); 564 } 565 566 public void filterAdded(TestFilter f) { 567 // add to menu 568 /* XXX not implemented yet 569 JMenuItem mi = new JRadioButtonMenuItem(f.getName()); 570 mi.addActionListener(this); 571 filterMenu.add(mi); 572 items.put(mi, f); 573 */ 574 } 575 576 public void filterRemoved(TestFilter f) { 577 // rm from menu 578 /* XXX not implemented yet 579 int index = items.getValueIndex(f); 580 filterMenu.remove(index); 581 items.remove(index); 582 */ 583 } 584 } 585 586 class Watcher implements Harness.Observer { 587 public void startingTestRun(Parameters params) { 588 ltrFilter.setLastStartTime(System.currentTimeMillis()); 589 ltrFilter.clearTestURLs(); 590 591 if (fHandler.getActiveFilter() == allFilter) { 592 final Preferences p = Preferences.access(); 593 if (p.getPreference(ExecTool.FILTER_WARN_PREF, "true").equals("true")) { 594 final JPanel pan = uif.createPanel("notagain", false); 595 final JCheckBox cb = uif.createCheckBox("exec.fltr.noShow", 596 false); 597 final JTextArea msg = uif.createMessageArea("exec.fltr.note"); 598 EventQueue.invokeLater(new Runnable() { 599 public void run() { 600 pan.setLayout(new BorderLayout()); 601 pan.add(cb, BorderLayout.SOUTH); 602 pan.add(msg, BorderLayout.CENTER); 603 604 JOptionPane pane = new JOptionPane(pan, JOptionPane.INFORMATION_MESSAGE, 605 JOptionPane.DEFAULT_OPTION, null, null, null); 606 JDialog dialog = pane.createDialog(parentComponent, uif.getI18NString("exec.fltr.note.title")); 607 dialog.show(); 608 609 // can't use this, it doesn't indicate if the user pressed 610 // OK or canceled the dialog some other way 611 //uif.showCustomOptionDialog("exec.fltr.note", pan); 612 613 Object selectedValue = pane.getValue(); 614 if( (selectedValue instanceof Integer) && 615 ((Integer)selectedValue).intValue() >= 0 ) 616 p.setPreference(ExecTool.FILTER_WARN_PREF, 617 Boolean.toString(!cb.isSelected())); 618 } 619 }); 620 } 621 } // if 622 } 623 624 public void startingTest(TestResult tr) { 625 ltrFilter.addTestURL(tr.getTestName()); 626 } 627 628 public void finishedTest(TestResult tr) { } 629 630 public void stoppingTestRun() { } 631 632 public void finishedTesting() { } 633 634 public void finishedTestRun(boolean allOK) { } 635 636 public void error(String msg) { } 637 } 638 } 639