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