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