1 /* 2 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6334663 27 * @summary Test that TabularDataSupport preserves the order elements were added 28 * @author Eamonn McManus 29 * @modules java.management 30 */ 31 32 import java.io.ByteArrayInputStream; 33 import java.io.ByteArrayOutputStream; 34 import java.io.ObjectInputStream; 35 import java.io.ObjectOutputStream; 36 import java.lang.reflect.Field; 37 import java.lang.reflect.Modifier; 38 import java.util.ArrayList; 39 import java.util.HashMap; 40 import java.util.LinkedHashMap; 41 import java.util.List; 42 import java.util.Map; 43 import javax.management.JMX; 44 import javax.management.MBeanServer; 45 import javax.management.MBeanServerFactory; 46 import javax.management.ObjectName; 47 import javax.management.openmbean.CompositeData; 48 import javax.management.openmbean.CompositeDataSupport; 49 import javax.management.openmbean.CompositeType; 50 import javax.management.openmbean.OpenDataException; 51 import javax.management.openmbean.OpenType; 52 import javax.management.openmbean.SimpleType; 53 import javax.management.openmbean.TabularData; 54 import javax.management.openmbean.TabularDataSupport; 55 import javax.management.openmbean.TabularType; 56 57 public class TabularDataOrderTest { 58 private static String failure; 59 60 private static final String COMPAT_PROP_NAME = "jmx.tabular.data.hash.map"; 61 62 private static final String[] intNames = { 63 "unus", "duo", "tres", "quatuor", "quinque", "sex", "septem", 64 "octo", "novem", "decim", 65 }; 66 private static final Map<String, Integer> stringToValue = 67 new LinkedHashMap<String, Integer>(); 68 static { 69 for (int i = 0; i < intNames.length; i++) 70 stringToValue.put(intNames[i], i + 1); 71 } 72 73 public static interface TestMXBean { 74 public Map<String, Integer> getMap(); 75 } 76 77 public static class TestImpl implements TestMXBean { 78 public Map<String, Integer> getMap() { 79 return stringToValue; 80 } 81 } 82 83 private static final CompositeType ct; 84 private static final TabularType tt; 85 static { 86 try { 87 ct = new CompositeType( 88 "a.b.c", "name and int", 89 new String[] {"name", "int"}, 90 new String[] {"name of integer", "value of integer"}, 91 new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER}); 92 tt = new TabularType( 93 "d.e.f", "name and int indexed by name", ct, 94 new String[] {"name"}); 95 } catch (OpenDataException e) { 96 throw new AssertionError(e); 97 } 98 } 99 100 private static TabularData makeTable() throws OpenDataException { 101 TabularData td = new TabularDataSupport(tt); 102 for (Map.Entry<String, Integer> entry : stringToValue.entrySet()) { 103 CompositeData cd = new CompositeDataSupport( 104 ct, 105 new String[] {"name", "int"}, 106 new Object[] {entry.getKey(), entry.getValue()}); 107 td.put(cd); 108 } 109 return td; 110 } 111 112 public static void main(String[] args) throws Exception { 113 System.out.println("Testing standard behaviour"); 114 TabularData td = makeTable(); 115 System.out.println(td); 116 117 // Test that a default TabularData has the order keys were added in 118 int last = 0; 119 boolean ordered = true; 120 for (Object x : td.values()) { 121 CompositeData cd = (CompositeData) x; 122 String name = (String) cd.get("name"); 123 int value = (Integer) cd.get("int"); 124 System.out.println(name + " = " + value); 125 if (last + 1 != value) 126 ordered = false; 127 last = value; 128 } 129 if (!ordered) 130 fail("Order not preserved"); 131 132 // Now test the undocumented property that causes HashMap to be used 133 // instead of LinkedHashMap, in case serializing to a 1.3 client. 134 // We serialize and deserialize in case the implementation handles 135 // this at serialization time. Then we look at object fields; that's 136 // not guaranteed to work but at worst it will fail spuriously and 137 // we'll have to update the test. 138 System.out.println("Testing compatible behaviour"); 139 System.setProperty(COMPAT_PROP_NAME, "true"); 140 td = makeTable(); 141 System.out.println(td); 142 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 143 ObjectOutputStream oout = new ObjectOutputStream(bout); 144 oout.writeObject(td); 145 oout.close(); 146 byte[] bytes = bout.toByteArray(); 147 ByteArrayInputStream bin = new ByteArrayInputStream(bytes); 148 ObjectInputStream oin = new ObjectInputStream(bin); 149 td = (TabularData) oin.readObject(); 150 boolean found = false; 151 for (Field f : td.getClass().getDeclaredFields()) { 152 if (Modifier.isStatic(f.getModifiers())) 153 continue; 154 f.setAccessible(true); 155 Object x = f.get(td); 156 if (x != null && x.getClass() == HashMap.class) { 157 found = true; 158 System.out.println( 159 x.getClass().getName() + " TabularDataSupport." + 160 f.getName() + " = " + x); 161 break; 162 } 163 } 164 if (!found) { 165 fail("TabularDataSupport does not contain HashMap though " + 166 COMPAT_PROP_NAME + "=true"); 167 } 168 System.clearProperty(COMPAT_PROP_NAME); 169 170 System.out.println("Testing MXBean behaviour"); 171 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 172 ObjectName name = new ObjectName("a:b=c"); 173 mbs.registerMBean(new TestImpl(), name); 174 TestMXBean proxy = JMX.newMXBeanProxy(mbs, name, TestMXBean.class); 175 Map<String, Integer> map = proxy.getMap(); 176 List<String> origNames = new ArrayList<String>(stringToValue.keySet()); 177 List<String> proxyNames = new ArrayList<String>(map.keySet()); 178 if (!origNames.equals(proxyNames)) 179 fail("Order mangled after passage through MXBean: " + proxyNames); 180 181 if (failure == null) 182 System.out.println("TEST PASSED"); 183 else 184 throw new Exception("TEST FAILED: " + failure); 185 } 186 187 private static void fail(String why) { 188 System.out.println("FAILED: " + why); 189 failure = why; 190 } 191 }