1 /* 2 * Copyright (c) 2008, 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 */ 30 31 import java.io.ByteArrayInputStream; 32 import java.io.ByteArrayOutputStream; 33 import java.io.ObjectInputStream; 34 import java.io.ObjectOutputStream; 35 import java.lang.reflect.Field; 36 import java.lang.reflect.Modifier; 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.LinkedHashMap; 40 import java.util.List; 41 import java.util.Map; 42 import javax.management.JMX; 43 import javax.management.MBeanServer; 44 import javax.management.MBeanServerFactory; 45 import javax.management.ObjectName; 46 import javax.management.openmbean.CompositeData; 47 import javax.management.openmbean.CompositeDataSupport; 48 import javax.management.openmbean.CompositeType; 49 import javax.management.openmbean.OpenDataException; 50 import javax.management.openmbean.OpenType; 51 import javax.management.openmbean.SimpleType; 52 import javax.management.openmbean.TabularData; 53 import javax.management.openmbean.TabularDataSupport; 54 import javax.management.openmbean.TabularType; 55 56 public class TabularDataOrderTest { 57 private static String failure; 58 59 private static final String COMPAT_PROP_NAME = "jmx.tabular.data.hash.map"; 60 61 private static final String[] intNames = { 62 "unus", "duo", "tres", "quatuor", "quinque", "sex", "septem", 63 "octo", "novem", "decim", 64 }; 65 private static final Map<String, Integer> stringToValue = 66 new LinkedHashMap<String, Integer>(); 67 static { 68 for (int i = 0; i < intNames.length; i++) 69 stringToValue.put(intNames[i], i + 1); 70 } 71 72 public static interface TestMXBean { 73 public Map<String, Integer> getMap(); 74 } 75 76 public static class TestImpl implements TestMXBean { 77 public Map<String, Integer> getMap() { 78 return stringToValue; 79 } 80 } 81 82 private static final CompositeType ct; 83 private static final TabularType tt; 84 static { 85 try { 86 ct = new CompositeType( 87 "a.b.c", "name and int", 88 new String[] {"name", "int"}, 89 new String[] {"name of integer", "value of integer"}, 90 new OpenType<?>[] {SimpleType.STRING, SimpleType.INTEGER}); 91 tt = new TabularType( 92 "d.e.f", "name and int indexed by name", ct, 93 new String[] {"name"}); 94 } catch (OpenDataException e) { 95 throw new AssertionError(e); 96 } 97 } 98 99 private static TabularData makeTable() throws OpenDataException { 100 TabularData td = new TabularDataSupport(tt); 101 for (Map.Entry<String, Integer> entry : stringToValue.entrySet()) { 102 CompositeData cd = new CompositeDataSupport( 103 ct, 104 new String[] {"name", "int"}, 105 new Object[] {entry.getKey(), entry.getValue()}); 106 td.put(cd); 107 } 108 return td; 109 } 110 111 public static void main(String[] args) throws Exception { 112 System.out.println("Testing standard behaviour"); 113 TabularData td = makeTable(); 114 System.out.println(td); 115 116 // Test that a default TabularData has the order keys were added in 117 int last = 0; 118 boolean ordered = true; 119 for (Object x : td.values()) { 120 CompositeData cd = (CompositeData) x; 121 String name = (String) cd.get("name"); 122 int value = (Integer) cd.get("int"); 123 System.out.println(name + " = " + value); 124 if (last + 1 != value) 125 ordered = false; 126 last = value; 127 } 128 if (!ordered) 129 fail("Order not preserved"); 130 131 // Now test the undocumented property that causes HashMap to be used 132 // instead of LinkedHashMap, in case serializing to a 1.3 client. 133 // We serialize and deserialize in case the implementation handles 134 // this at serialization time. Then we look at object fields; that's 135 // not guaranteed to work but at worst it will fail spuriously and 136 // we'll have to update the test. 137 System.out.println("Testing compatible behaviour"); 138 System.setProperty(COMPAT_PROP_NAME, "true"); 139 td = makeTable(); 140 System.out.println(td); 141 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 142 ObjectOutputStream oout = new ObjectOutputStream(bout); 143 oout.writeObject(td); 144 oout.close(); 145 byte[] bytes = bout.toByteArray(); 146 ByteArrayInputStream bin = new ByteArrayInputStream(bytes); 147 ObjectInputStream oin = new ObjectInputStream(bin); 148 td = (TabularData) oin.readObject(); 149 boolean found = false; 150 for (Field f : td.getClass().getDeclaredFields()) { 151 if (Modifier.isStatic(f.getModifiers())) 152 continue; 153 f.setAccessible(true); 154 Object x = f.get(td); 155 if (x != null && x.getClass() == HashMap.class) { 156 found = true; 157 System.out.println( 158 x.getClass().getName() + " TabularDataSupport." + 159 f.getName() + " = " + x); 160 break; 161 } 162 } 163 if (!found) { 164 fail("TabularDataSupport does not contain HashMap though " + 165 COMPAT_PROP_NAME + "=true"); 166 } 167 System.clearProperty(COMPAT_PROP_NAME); 168 169 System.out.println("Testing MXBean behaviour"); 170 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 171 ObjectName name = new ObjectName("a:b=c"); 172 mbs.registerMBean(new TestImpl(), name); 173 TestMXBean proxy = JMX.newMXBeanProxy(mbs, name, TestMXBean.class); 174 Map<String, Integer> map = proxy.getMap(); 175 List<String> origNames = new ArrayList<String>(stringToValue.keySet()); 176 List<String> proxyNames = new ArrayList<String>(map.keySet()); 177 if (!origNames.equals(proxyNames)) 178 fail("Order mangled after passage through MXBean: " + proxyNames); 179 180 if (failure == null) 181 System.out.println("TEST PASSED"); 182 else 183 throw new Exception("TEST FAILED: " + failure); 184 } 185 186 private static void fail(String why) { 187 System.out.println("FAILED: " + why); 188 failure = why; 189 } 190 }