1 /*
   2  * Copyright (c) 2005, 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 6204469
  27  * @summary Test that Open MBean attributes and parameters cannot have
  28  * illegal constraints like min greater than max
  29  * @author Eamonn McManus
  30  * @modules java.management
  31  * @run clean BadConstraintTest
  32  * @run build BadConstraintTest
  33  * @run main BadConstraintTest
  34  */
  35 
  36 import java.io.*;
  37 import java.lang.reflect.*;
  38 import java.util.*;
  39 import javax.management.*;
  40 import javax.management.openmbean.*;
  41 
  42 public class BadConstraintTest {
  43     private static String failure;
  44 
  45     public static void main(String[] args) throws Exception {
  46         genericTests();
  47         descriptorTests();
  48 
  49         if (failure == null)
  50             System.out.println("Test passed");
  51         else
  52             throw new Exception("TEST FAILED: " + failure);
  53     }
  54 
  55     private static void genericTests() throws Exception {
  56         for (Object[] test : tests) {
  57             if (test.length != 5) {
  58                 throw new Exception("Test element has wrong length: " +
  59                                     toString(test));
  60             }
  61 
  62             OpenType<?> openType = (OpenType<?>) test[0];
  63             Object defaultValue = test[1];
  64             Comparable<?> minValue = (Comparable<?>) test[2];
  65             Comparable<?> maxValue = (Comparable<?>) test[3];
  66             Object[] legalValues = (Object[]) test[4];
  67 
  68             System.out.println("test: openType=" + openType +
  69                                "; defaultValue=" + defaultValue +
  70                                "; minValue=" + minValue +
  71                                "; maxValue=" + maxValue +
  72                                "; legalValues=" + toString(legalValues));
  73 
  74             genericTest(openType, defaultValue, minValue, maxValue,
  75                         legalValues);
  76         }
  77     }
  78 
  79     private static void descriptorTests() throws Exception {
  80         for (Object[][] test : descriptorTests) {
  81             if (test.length != 2) {
  82                 throw new Exception("Test element has wrong length: " +
  83                                     toString(test));
  84             }
  85 
  86             if (test[0].length != 1) {
  87                 throw new Exception("Test element should have one OpenType: " +
  88                                     toString(test[0]));
  89             }
  90 
  91             OpenType<?> openType = (OpenType<?>) test[0][0];
  92             Descriptor d = descriptor(test[1]);
  93 
  94             System.out.println("test: openType=" + openType +
  95                                "; descriptor=" + d);
  96 
  97             descriptorTest(openType, d);
  98         }
  99     }
 100 
 101     /* Tests that apply to both the Descriptor and the non-Descriptor
 102        constructors.  We invoke the non-Descriptor constructors by
 103        reflection, then we make the corresponding Descriptor and call
 104        the descriptorTest with it.  */
 105     private static void genericTest(OpenType<?> openType,
 106                                     Object defaultValue,
 107                                     Comparable<?> minValue,
 108                                     Comparable<?> maxValue,
 109                                     Object[] legalValues)
 110             throws Exception {
 111 
 112         if (minValue == null && maxValue == null && legalValues == null) {
 113             if (defaultValue == null)
 114                 throw new Exception("What am I testing?");
 115             Class[] params1 = new Class[] {
 116                 String.class, String.class, OpenType.class,
 117                 boolean.class, boolean.class, boolean.class,
 118                 Object.class
 119             };
 120             Constructor<OpenMBeanAttributeInfoSupport> c1 =
 121                 OpenMBeanAttributeInfoSupport.class.getConstructor(params1);
 122             Class[] params2 = new Class[] {
 123                 String.class, String.class, OpenType.class,
 124                 Object.class
 125             };
 126             Constructor<OpenMBeanParameterInfoSupport> c2 =
 127                 OpenMBeanParameterInfoSupport.class.getConstructor(params2);
 128             ode(c1, "name", "descr", openType, true, true, false, defaultValue);
 129             ode(c2, "name", "descr", openType, defaultValue);
 130             descriptorTest(openType,
 131                            descriptor("defaultValue", defaultValue));
 132             descriptorTest(openType,
 133                            descriptor("defaultValue", string(defaultValue)));
 134         }
 135 
 136         if (legalValues == null) {
 137             Class[] params1 = new Class[] {
 138                 String.class, String.class, OpenType.class,
 139                 boolean.class, boolean.class, boolean.class,
 140                 Object.class, Comparable.class, Comparable.class
 141             };
 142             Constructor<OpenMBeanAttributeInfoSupport> c1 =
 143                 OpenMBeanAttributeInfoSupport.class.getConstructor(params1);
 144             Class[] params2 = new Class[] {
 145                 String.class, String.class, OpenType.class,
 146                 Object.class, Comparable.class, Comparable.class
 147             };
 148             Constructor<OpenMBeanParameterInfoSupport> c2 =
 149                 OpenMBeanParameterInfoSupport.class.getConstructor(params2);
 150             ode(c1, "name", "descr", openType, true, true, false, defaultValue,
 151                 minValue, maxValue);
 152             ode(c2, "name", "descr", openType, defaultValue,
 153                 minValue, maxValue);
 154             descriptorTest(openType,
 155                            descriptor("defaultValue", defaultValue,
 156                                       "minValue", minValue,
 157                                       "maxValue", maxValue));
 158             descriptorTest(openType,
 159                            descriptor("defaultValue", string(defaultValue),
 160                                       "minValue", string(minValue),
 161                                       "maxValue", string(maxValue)));
 162         }
 163 
 164         if (legalValues != null) {
 165             Class[] params1 = new Class[] {
 166                 String.class, String.class, OpenType.class,
 167                 boolean.class, boolean.class, boolean.class,
 168                 Object.class, Object[].class
 169             };
 170             Constructor<OpenMBeanAttributeInfoSupport> c1 =
 171                 OpenMBeanAttributeInfoSupport.class.getConstructor(params1);
 172             Class[] params2 = new Class[] {
 173                 String.class, String.class, OpenType.class,
 174                 Object.class, Object[].class
 175             };
 176             Constructor<OpenMBeanParameterInfoSupport> c2 =
 177                 OpenMBeanParameterInfoSupport.class.getConstructor(params2);
 178             ode(c1, "name", "descr", openType, true, true, false, defaultValue,
 179                 legalValues);
 180             ode(c2, "name", "descr", openType, defaultValue,
 181                 legalValues);
 182             descriptorTest(openType,
 183                            descriptor("defaultValue", defaultValue,
 184                                       "legalValues", legalValues));
 185             descriptorTest(openType,
 186                            descriptor("defaultValue", defaultValue,
 187                                       "legalValues", arraySet(legalValues)));
 188             Set<String> strings = new HashSet<String>();
 189             for (Object x : legalValues)
 190                 strings.add(x.toString());
 191             descriptorTest(openType,
 192                            descriptor("defaultValue", defaultValue,
 193                                       "legalValues", strings));
 194             descriptorTest(openType,
 195                            descriptor("defaultValue", defaultValue,
 196                                       "legalValues",
 197                                       strings.toArray(new String[0])));
 198         }
 199     }
 200 
 201     private static void descriptorTest(OpenType<?> openType, Descriptor d)
 202             throws Exception {
 203         Class[] params1 = new Class[] {
 204             String.class, String.class, OpenType.class,
 205             boolean.class, boolean.class, boolean.class,
 206             Descriptor.class
 207         };
 208         Constructor<OpenMBeanAttributeInfoSupport> c1 =
 209             OpenMBeanAttributeInfoSupport.class.getConstructor(params1);
 210         Class[] params2 = new Class[] {
 211             String.class, String.class, OpenType.class,
 212             Descriptor.class
 213         };
 214         Constructor<OpenMBeanParameterInfoSupport> c2 =
 215             OpenMBeanParameterInfoSupport.class.getConstructor(params2);
 216         iae(c1, "name", "descr", openType, true, true, false, d);
 217         iae(c2, "name", "descr", openType, d);
 218     }
 219 
 220     /* Check that the given constructor invocation gets an
 221        IllegalArgumentException. */
 222     private static void iae(Constructor<?> con, Object... params) {
 223         checkException(IllegalArgumentException.class, con, params);
 224     }
 225 
 226     /* Check that the given constructor invocation gets an
 227        OpenDataException.  */
 228     private static void ode(Constructor<?> con, Object... params) {
 229         checkException(OpenDataException.class, con, params);
 230     }
 231 
 232     private static void checkException(Class<? extends Exception> exc,
 233                                        Constructor<?> con, Object[] params) {
 234         try {
 235             con.newInstance(params);
 236             fail("Constructor succeeded but should have got " + exc.getName() +
 237                  " with params " + Arrays.deepToString(params));
 238         } catch (InvocationTargetException e) {
 239             Throwable cause = e.getCause();
 240             if (exc.isInstance(cause))
 241                 return;
 242             StringWriter sw = new StringWriter();
 243             PrintWriter pw = new PrintWriter(sw);
 244             cause.printStackTrace(pw);
 245             pw.close();
 246             fail("Constructor should have got " + exc.getName() +
 247                  " with params " + Arrays.deepToString(params) + ": " + sw);
 248         } catch (Exception e) {
 249             throw new IllegalArgumentException("Reflection failed", e);
 250         }
 251     }
 252 
 253     private static void fail(String why) {
 254         System.out.println("FAILED: " + why);
 255         failure = why;
 256     }
 257 
 258     private static Descriptor descriptor(Object... entries) {
 259         if (entries.length % 2 != 0)
 260             throw new RuntimeException("Odd length descriptor entries");
 261         String[] names = new String[entries.length / 2];
 262         Object[] values = new Object[entries.length / 2];
 263         for (int i = 0; i < entries.length; i += 2) {
 264             names[i / 2] = (String) entries[i];
 265             values[i / 2] = entries[i + 1];
 266         }
 267         return new ImmutableDescriptor(names, values);
 268     }
 269 
 270     private static <T> Set<T> arraySet(T[] array) {
 271         return new HashSet<T>(Arrays.asList(array));
 272     }
 273 
 274     private static String toString(Object x) {
 275         if (x == null)
 276             return "null";
 277         else if (x.getClass().isArray()) {
 278             StringBuilder sb = new StringBuilder("[");
 279             int len = Array.getLength(x);
 280             for (int i = 0; i < len; i++) {
 281                 if (i > 0)
 282                     sb.append(", ");
 283                 sb.append(toString(Array.get(x, i)));
 284             }
 285             sb.append("]");
 286             return sb.toString();
 287         } else
 288             return x.toString();
 289     }
 290 
 291     private static String string(Object x) {
 292         if (x == null)
 293             return null;
 294         return toString(x);
 295     }
 296 
 297     private static final OpenType<?>
 298         ostring = SimpleType.STRING,
 299         oint = SimpleType.INTEGER,
 300         obool = SimpleType.BOOLEAN,
 301         olong = SimpleType.LONG,
 302         obyte = SimpleType.BYTE,
 303         ofloat = SimpleType.FLOAT,
 304         odouble = SimpleType.DOUBLE,
 305         ostringarray, ostringarray2;
 306     private static final CompositeType ocomposite;
 307     private static final CompositeData compositeData, compositeData2;
 308     static {
 309         try {
 310             ostringarray = new ArrayType<String[]>(1, ostring);
 311             ostringarray2 = new ArrayType<String[][]>(2, ostring);
 312             ocomposite =
 313                 new CompositeType("name", "descr",
 314                                   new String[] {"s", "i"},
 315                                   new String[] {"sdesc", "idesc"},
 316                                   new OpenType[] {ostring, oint});
 317             compositeData =
 318                 new CompositeDataSupport(ocomposite,
 319                                          new String[] {"s", "i"},
 320                                          new Object[] {"foo", 23});
 321             compositeData2 =
 322                 new CompositeDataSupport(ocomposite,
 323                                          new String[] {"s", "i"},
 324                                          new Object[] {"bar", -23});
 325         } catch (OpenDataException e) { // damn checked exceptions...
 326             throw new IllegalArgumentException(e.toString(), e);
 327         }
 328     }
 329 
 330     private static final Descriptor
 331         nullD = null,
 332         emptyD = ImmutableDescriptor.EMPTY_DESCRIPTOR;
 333 
 334     /* Each element of this array contains five Objects:
 335        - OpenType;
 336        - defaultValue;
 337        - minValue;
 338        - maxValue;
 339        - legalValues.  The objects are used to construct tests cases
 340        where all possible constructors that make sense for that
 341        combination of values are invoked, and all are checked to ensure
 342        that they throw the right exception.  */
 343     private static final Object[][] tests = {
 344 
 345         // Values must be of appropriate type
 346 
 347         {oint, "oops", null, null, null},
 348         {oint, Long.MAX_VALUE, null, null, null},
 349         {oint, null, "oops", null, null},
 350         {oint, "oops", 3, null, null},
 351         {oint, 3, "oops", null, null},
 352         {oint, null, null, "oops", null},
 353         {oint, null, 3, "oops", null},
 354         {oint, null, 3, false, null},
 355         {oint, null, null, null, new String[] {"x"}},
 356         {oint, null, null, null, new Object[] {"x"}},
 357         {oint, null, null, null, new Object[] {3, "x"}},
 358 
 359         // If defaultValue is present then it must satisfy the constraints
 360         // defined by legalValues, minValue, or maxValue when any of
 361         // these is also present
 362 
 363         {oint, 3, 4, null, null},
 364         {oint, 3, null, 2, null},
 365         {oint, 3, null, null, new Integer[] {2, 4}},
 366 
 367         // If minValue and maxValue are both present then minValue must
 368         // not be greater than maxValue
 369 
 370         {ostring, null, "z", "a", null},
 371         {oint, null, 3, 2, null},
 372 
 373         // We don't support default values or legal sets for arrays (yet)
 374 
 375         {ostringarray, new String[] {"x"}, null, null, null},
 376         {ostringarray, null, null, null, new String[][]{new String[] {"x"}}},
 377     };
 378 
 379     /* The tests here can only be expressed via Descriptors because an
 380        attempt to invoke one of the non-Descriptor constructors with
 381        the implied parameters would not compile (or would fail at the
 382        reflection stage when reflection is being used).
 383 
 384        Each element of this array contains two subarrays.  The first
 385        is an array of OpenTypes that must contain exactly one element.
 386        The second is an array of alternating field names and field
 387        values that will be used to construct a Descriptor that is supposed
 388        to fail when given to an OpenMBean*Info constructor with the given
 389        OpenType.  */
 390     private static final Object[][][] descriptorTests = {
 391 
 392         // Values must be of appropriate type
 393 
 394         {{oint},
 395          {"minValue", 25L}},
 396 
 397         {{oint},
 398          {"minValue", new Object()}}, // not even Comparable
 399         {{oint},
 400          {"maxValue", new Object()}}, // not even Comparable
 401         {{oint},
 402          {"defaultValue", 3,
 403           "minValue", new Object()}},
 404         {{oint},
 405          {"defaultValue", 3,
 406           "maxValue", new Object()}},
 407 
 408         {{oint},
 409          {"legalValues", new int[] {3}}}, // should be new Integer[] to work
 410         {{oint},
 411          {"legalValues", 3}},
 412 
 413         // If legalValues is present then neither minValue nor maxValue
 414         // must be present
 415 
 416         {{oint},
 417          {"minValue", 3, "legalValues", new Integer[] {3, 4}}},
 418         {{oint},
 419          {"maxValue", 3, "legalValues", new Integer[] {2, 3}}},
 420         {{oint},
 421          {"defaultValue", 3, "minValue", 3, "legalValues", new Integer[] {3}}},
 422 
 423         // We don't support min or max arrays (what would they mean?)
 424 
 425         {{ostringarray},
 426          {"minValue", new String[] {"x"}}},
 427         {{ostringarray},
 428          {"maxValue", new String[] {"x"}}},
 429 
 430     };
 431 }