1 /* 2 * Copyright (c) 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 8041565 27 * @summary Tests the limits imposed on the domain name part of an 28 * ObjectName instance 29 * @author Jaroslav Bachorik 30 * @modules java.management/javax.management:open 31 * @run main CompressedStorageTest 32 */ 33 34 import java.lang.reflect.Field; 35 import java.lang.reflect.InvocationTargetException; 36 import java.lang.reflect.Method; 37 import java.util.function.Consumer; 38 import javax.management.MalformedObjectNameException; 39 import javax.management.ObjectName; 40 41 public class CompressedStorageTest { 42 private static Method setDomainLengthM; 43 private static Field compressedStorageFld; 44 45 private static int DOMAIN_PATTERN; 46 private static int PROPLIST_PATTERN; 47 private static int PROPVAL_PATTERN; 48 49 private static Method setDomainPattern; 50 private static Method setPropertyListPattern; 51 private static Method setPropertyValuePattern; 52 53 54 static { 55 try { 56 Class<?> clz = ObjectName.class; 57 setDomainLengthM = clz.getDeclaredMethod("setDomainLength", int.class); 58 setDomainLengthM.setAccessible(true); 59 60 compressedStorageFld = clz.getDeclaredField("_compressed_storage"); 61 compressedStorageFld.setAccessible(true); 62 63 setDomainPattern = clz.getDeclaredMethod("setDomainPattern", boolean.class); 64 setDomainPattern.setAccessible(true); 65 setPropertyListPattern = clz.getDeclaredMethod("setPropertyListPattern", boolean.class); 66 setPropertyListPattern.setAccessible(true); 67 setPropertyValuePattern = clz.getDeclaredMethod("setPropertyValuePattern", boolean.class); 68 setPropertyValuePattern.setAccessible(true); 69 70 DOMAIN_PATTERN = getStaticIntFld("DOMAIN_PATTERN"); 71 PROPLIST_PATTERN = getStaticIntFld("PROPLIST_PATTERN"); 72 PROPVAL_PATTERN = getStaticIntFld("PROPVAL_PATTERN"); 73 74 } catch (Exception e) { 75 throw new Error(e); 76 } 77 } 78 79 public static void main(String[] args) throws Exception { 80 testZeroLength(); 81 testNegativeLength(); 82 testMaxLength(); 83 84 testSetDomainPattern(); 85 testSetPropertyListPattern(); 86 testSetPropertyValuePattern(); 87 } 88 89 private static ObjectName getObjectName() 90 throws MalformedObjectNameException { 91 return new ObjectName("domain", "key", "value"); 92 } 93 94 /** 95 * Test for accepting 0 being passed as argument to 96 * {@linkplain ObjectName#setDomainLength(int)}. 97 * 98 */ 99 private static void testZeroLength() throws Exception { 100 setDomainNameLength(0); 101 } 102 103 /** 104 * Test for rejecting negative value being passed as argument to 105 * {@linkplain ObjectName#setDomainLength(int)}. 106 */ 107 private static void testNegativeLength() throws Exception { 108 try { 109 setDomainNameLength(-1); 110 } catch (MalformedObjectNameException e) { 111 return; 112 } 113 fail("Allowing negative domain name length"); 114 } 115 116 /** 117 * Test for rejecting value exceeding the maximum allowed length 118 * being passed as argument to {@linkplain ObjectName#setDomainLength(int)}. 119 */ 120 private static void testMaxLength() throws Exception { 121 try { 122 setDomainNameLength(Integer.MAX_VALUE / 4 + 1); 123 } catch (MalformedObjectNameException e) { 124 return; 125 } 126 fail("Maximum domain name length is not respected"); 127 } 128 129 /** 130 * Tests that calling {@linkplain ObjectName#setDomainPattern(boolean)} 131 * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}. 132 */ 133 private static void testSetDomainPattern() throws Exception { 134 ObjectName on = getObjectName(); 135 136 checkMask(DOMAIN_PATTERN, setDomainPattern, on); 137 } 138 139 /** 140 * Tests that calling {@linkplain ObjectName#setPropertyListPattern(boolean)} 141 * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}. 142 */ 143 private static void testSetPropertyListPattern() throws Exception { 144 ObjectName on = getObjectName(); 145 146 checkMask(PROPLIST_PATTERN, setPropertyListPattern, on); 147 } 148 149 /** 150 * Tests that calling {@linkplain ObjectName#setPropertyValuePattern(boolean)} 151 * results in setting correct bits in {@linkplain ObjectName#_compressed_storage}. 152 */ 153 private static void testSetPropertyValuePattern() throws Exception { 154 ObjectName on = getObjectName(); 155 156 checkMask(PROPVAL_PATTERN, setPropertyValuePattern, on); 157 } 158 159 /** 160 * Helper method to call {@linkplain ObjectName#setDomainLength(int)} 161 * method via reflection. 162 * @param len The domain name length 163 * @throws MalformedObjectNameException Propagated from 164 * {@linkplain ObjectName#setDomainLength(int)} invocation. 165 */ 166 private static void setDomainNameLength(int len) 167 throws MalformedObjectNameException { 168 try { 169 setDomainLengthM.invoke(getObjectName(), len); 170 } catch (InvocationTargetException e) { 171 Throwable cause = e.getCause(); 172 if (cause instanceof MalformedObjectNameException) { 173 throw (MalformedObjectNameException)cause; 174 } 175 throw new Error(cause); 176 } catch (IllegalAccessException | IllegalArgumentException e) { 177 throw new Error(e); 178 } 179 } 180 181 /** 182 * Helper method to assert that a particular boolean setter affects only 183 * a particular bit in the {@linkplain ObjectName#_compressed_storage} field. 184 * @param mask bitmask for storing the boolean value 185 * @param setter setter method reference 186 * @param on {@linkplain ObjectName} instance 187 */ 188 private static void checkMask(int mask, Method setter, ObjectName on) 189 throws Exception { 190 int valBefore = compressedStorageFld.getInt(on); 191 setter.invoke(on, true); 192 int valAfter = compressedStorageFld.getInt(on); 193 194 checkMask(mask, valAfter ^ valBefore); 195 196 valBefore = valAfter; 197 setter.invoke(on, false); 198 valAfter = compressedStorageFld.getInt(on); 199 200 checkMask(mask, valAfter ^ valBefore); 201 } 202 203 /** 204 * Compare the changed bits with the given mask. 205 * @param mask bitmask 206 * @param val the changed bits; may be 0 if there was no change 207 */ 208 private static void checkMask(int mask, int val) { 209 if (val != 0 && val != mask) { 210 fail("Invalid mask: expecting '" + 211 Integer.toBinaryString(mask) + "' , received '" + 212 Integer.toBinaryString(val) + "'"); 213 } 214 } 215 216 /** 217 * Helper method to obtain the value of a static field via reflection. 218 * @param name static field name 219 * @return static field value 220 */ 221 private static int getStaticIntFld(String name) throws Exception { 222 Field fld = ObjectName.class.getDeclaredField(name); 223 fld.setAccessible(true); 224 225 return fld.getInt(null); 226 } 227 228 private static void fail(String msg) { 229 throw new Error(msg); 230 } 231 }