1 2 import java.awt.*; 3 import java.awt.event.KeyEvent; 4 import java.util.ArrayList; 5 import java.util.List; 6 import javax.accessibility.Accessible; 7 import javax.accessibility.AccessibleContext; 8 import javax.accessibility.AccessibleState; 9 import javax.accessibility.AccessibleStateSet; 10 import javax.swing.*; 11 import javax.swing.plaf.nimbus.NimbusLookAndFeel; 12 13 /* 14 * @test 15 * @key headful 16 * @bug 8134116 17 * @summary JTabbedPane$Page.getBounds throws IndexOutOfBoundsException 18 * @run main Bug8134116 19 */ 20 public class Bug8134116 { 21 22 private static volatile Exception exception = null; 23 24 public static void main(String args[]) throws Exception { 25 26 try { 27 UIManager.setLookAndFeel(new NimbusLookAndFeel()); 28 } catch (Exception e) { 29 throw new RuntimeException(e); 30 } 31 32 SwingUtilities.invokeAndWait(() -> { 33 JPanel panel0 = new JPanel(); 34 JPanel panel2 = new JPanel(); 35 BadPane badPane = new BadPane(); 36 badPane.add("zero", panel0); 37 badPane.add("one", null); // no component 38 badPane.add("", panel2); // no title 39 badPane.add("", null); // no component, no title 40 // but give it that via a tabComponent 41 JPanel tabComponent = new JPanel(); 42 JLabel tabComponentLabel = new JLabel("three"); 43 tabComponent.add(tabComponentLabel); 44 badPane.setTabComponentAt(3, tabComponent); 45 JFrame frame = new JFrame(); 46 frame.add(badPane); 47 frame.setSize(300, 300); 48 frame.setVisible(true); 49 50 try { 51 AccessibleContext ac = badPane.getAccessibleContext(); 52 Accessible page0 = ac.getAccessibleChild(0); 53 if (page0 == null) { 54 // Not something being tested, but checking anyway 55 throw new RuntimeException("getAccessibleChild(0) is null"); 56 } 57 Accessible page1 = ac.getAccessibleChild(1); 58 if (page1 == null) { 59 // Not something being tested, but checking anyway 60 throw new RuntimeException("getAccessibleChild(1) is null"); 61 } 62 Accessible page2 = ac.getAccessibleChild(2); 63 Accessible page3 = ac.getAccessibleChild(3); 64 // page0 - page3 are JTabbedPane.Page, a private inner class 65 // and is an AccessibleContext 66 // and implements Accessible and AccessibleComponent 67 AccessibleContext pac0 = page0.getAccessibleContext(); 68 AccessibleContext pac1 = page1.getAccessibleContext(); 69 AccessibleContext pac2 = page2.getAccessibleContext(); 70 AccessibleContext pac3 = page3.getAccessibleContext(); 71 72 // test Page.getBounds 73 // ensure no IndexOutOfBoundsException 74 Rectangle r0 = pac0.getAccessibleComponent().getBounds(); 75 // make sure second Bounds is different than first 76 Rectangle r1 = pac1.getAccessibleComponent().getBounds(); 77 if (r1.equals(r0)) { 78 String msg = "Second tab should not have same bounds as first tab"; 79 throw new RuntimeException(msg); 80 } 81 82 // test Page.getAccessibleStateSet 83 // At this point page 0 is selected 84 AccessibleStateSet accSS0 = pac0.getAccessibleStateSet(); 85 if (!accSS0.contains(AccessibleState.SELECTED)) { 86 String msg = "Empty title -> AccessibleState.SELECTED not set"; 87 throw new RuntimeException(msg); 88 } 89 // select second tab 90 badPane.setSelectedIndex(1); 91 AccessibleStateSet accSS1 = pac1.getAccessibleStateSet(); 92 if (!accSS1.contains(AccessibleState.SELECTED)) { 93 String msg = "Second tab selected but AccessibleState.SELECTED not set"; 94 throw new RuntimeException(msg); 95 } 96 // select third tab 97 badPane.setSelectedIndex(2); 98 AccessibleStateSet accSS2 = pac2.getAccessibleStateSet(); 99 if (!accSS1.contains(AccessibleState.SELECTED)) { 100 String msg = "Third tab selected but AccessibleState.SELECTED not set"; 101 throw new RuntimeException(msg); 102 } 103 // select fourth tab 104 badPane.setSelectedIndex(3); 105 AccessibleStateSet accSS3 = pac3.getAccessibleStateSet(); 106 if (!accSS1.contains(AccessibleState.SELECTED)) { 107 String msg = "Fourth tab selected but AccessibleState.SELECTED not set"; 108 throw new RuntimeException(msg); 109 } 110 111 // test Page.getAccessibleIndexInParent 112 if (pac0.getAccessibleIndexInParent() == -1) { 113 String msg = "Empty title -> negative AccessibleIndexInParent"; 114 throw new RuntimeException(msg); 115 } 116 if (pac0.getAccessibleIndexInParent() != 0) { 117 String msg = "first tab is not at index 0 in parent"; 118 throw new RuntimeException(msg); 119 } 120 if (pac1.getAccessibleIndexInParent() != 1) { 121 String msg = "second tab (null component) is not at index 1 in parent"; 122 throw new RuntimeException(msg); 123 } 124 if (pac2.getAccessibleIndexInParent() != 2) { 125 String msg = "third tab (empty title) string is not at index 2 in parent"; 126 throw new RuntimeException(msg); 127 } 128 if (pac3.getAccessibleIndexInParent() != 3) { 129 String msg = "fourth tab (empty title, null component, has tabComponent) string is not at index 3 in parent"; 130 throw new RuntimeException(msg); 131 } 132 133 // test Page.getAccessibleName 134 String accName = pac0.getAccessibleName(); 135 if (!accName.equals("zero")) { 136 String msg = "Empty title -> empty AccessibleName"; 137 throw new RuntimeException(msg); 138 } 139 // test Page.getAccessibleName when component is null 140 accName = pac1.getAccessibleName(); 141 if (!accName.equals("one")) { 142 String msg = "AccessibleName of null panel not 'one'"; 143 throw new RuntimeException(msg); 144 } 145 146 // test Page.setDisplayedMnemonicIndex 147 // Empty title -> IllegalArgumnetException 148 badPane.setDisplayedMnemonicIndexAt(0, 1); 149 150 // test Page.updateDisplayedMnemonicIndex 151 badPane.setMnemonicAt(0, KeyEvent.VK_Z); 152 if (badPane.getDisplayedMnemonicIndexAt(0) == -1) { 153 String msg="Empty title -> getDisplayedMnemonicIndexAt failure"; 154 throw new RuntimeException(msg); 155 } 156 } catch (Exception e) { 157 exception = e; 158 } 159 }); 160 if (exception != null) { 161 System.out.println("Test failed: " + exception.getMessage()); 162 throw exception; 163 } else { 164 System.out.println("Test passed."); 165 } 166 } 167 168 // The following is likely what is being done in Burp Suite 169 // https://portswigger.net/burp/ which fails in the same way, i.e. the 170 // pages List in JTabbedPane is not being managed properly and thus 171 // Page.title is "" for each page. The overridden insertTab manages titles 172 // in the subclass passing a "" title to the superclass JTabbedPane through 173 // its insertTab. Later an overridden getTitleAt returns the titles as 174 // managed by the subclass. 175 static class BadPane extends JTabbedPane { 176 private List<String> titles; 177 178 BadPane() { 179 titles = new ArrayList<String>(1); 180 } 181 182 @Override 183 public void insertTab( String title, Icon icon, Component component, 184 String tip, int index ) { 185 titles.add(index, title); 186 super.insertTab("", icon, component, tip, index); 187 } 188 189 @Override 190 public String getTitleAt(int i) { 191 return titles.get(i); 192 } 193 } 194 195 }