0N/A/*
2362N/A * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 6204469
0N/A * @summary Test that Open MBean attributes and parameters check constraints
0N/A * @author Eamonn McManus
0N/A * @run clean ConstraintTest
0N/A * @run build ConstraintTest
0N/A * @run main ConstraintTest
0N/A */
0N/A
0N/Aimport java.util.*;
0N/Aimport javax.management.*;
0N/Aimport javax.management.openmbean.*;
0N/A
0N/Apublic class ConstraintTest {
0N/A private static String failure;
0N/A
0N/A public static void main(String[] args) throws Exception {
0N/A for (Object[][] test : tests) {
0N/A if (test.length != 4) {
0N/A throw new Exception("Test element has wrong length: " +
0N/A Arrays.deepToString(test));
0N/A }
0N/A
0N/A if (test[0].length != 4) {
0N/A throw new Exception("Test constraints should have size 4: " +
0N/A Arrays.deepToString(test[0]));
0N/A }
0N/A Object defaultValue = test[0][0];
0N/A Comparable<?> minValue = (Comparable<?>) test[0][1];
0N/A Comparable<?> maxValue = (Comparable<?>) test[0][2];
0N/A Object[] legalValues = (Object[]) test[0][3];
0N/A System.out.println("test: defaultValue=" + defaultValue +
0N/A "; minValue=" + minValue +
0N/A "; maxValue=" + maxValue +
0N/A "; legalValues=" +
0N/A Arrays.deepToString(legalValues));
0N/A
0N/A if (test[1].length != 1) {
0N/A throw new Exception("OpenType list should have size 1: " +
0N/A Arrays.deepToString(test[1]));
0N/A }
0N/A OpenType<?> openType = (OpenType<?>) test[1][0];
0N/A
0N/A Object[] valid = test[2];
0N/A Object[] invalid = test[3];
0N/A
0N/A System.out.println("...valid=" + Arrays.deepToString(valid));
0N/A System.out.println("...invalid=" + Arrays.deepToString(invalid));
0N/A
0N/A test(openType, defaultValue, minValue, maxValue, legalValues,
0N/A valid, invalid);
0N/A }
0N/A
0N/A if (failure == null)
0N/A System.out.println("Test passed");
0N/A else
0N/A throw new Exception("TEST FAILED: " + failure);
0N/A }
0N/A
0N/A private static <T> void test(OpenType<T> openType, Object defaultValue,
0N/A Comparable<?> minValue,
0N/A Comparable<?> maxValue, Object[] legalValues,
0N/A Object[] valid, Object[] invalid)
0N/A throws Exception {
0N/A /* This hack is needed to avoid grief from the parameter checking
0N/A in the OpenMBean*InfoSupport constructors. Since they are defined
0N/A to check that the defaultValue etc are of the same type as the
0N/A OpenType<T>, there is no way to pass a defaultValue etc when
0N/A the type is OpenType<?>. So either you have to write plain
0N/A OpenType, and get unchecked warnings for every constructor
0N/A invocation, or you do this, and get the unchecked warnings just
0N/A here. */
0N/A test1(openType, (T) defaultValue, (Comparable<T>) minValue,
0N/A (Comparable<T>) maxValue, (T[]) legalValues, valid, invalid);
0N/A }
0N/A
0N/A private static <T> void test1(OpenType<T> openType, T defaultValue,
0N/A Comparable<T> minValue,
0N/A Comparable<T> maxValue, T[] legalValues,
0N/A Object[] valid, Object[] invalid)
0N/A throws Exception {
0N/A
0N/A if (legalValues != null && (minValue != null || maxValue != null))
0N/A throw new Exception("Test case has both legals and min/max");
0N/A
0N/A if (defaultValue == null && minValue == null && maxValue == null &&
0N/A legalValues == null) {
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false, nullD),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false, emptyD),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A nullD),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A emptyD),
0N/A valid, invalid);
0N/A }
0N/A
0N/A if (minValue == null && maxValue == null && legalValues == null) {
0N/A Descriptor d = descriptor("defaultValue", defaultValue);
0N/A test(new OpenMBeanAttributeInfoSupport("blah", "descr", openType,
0N/A true, true, false, d),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("blah", "descr",
0N/A openType, true, true,
0N/A false, defaultValue),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("blah", "descr", openType,
0N/A d),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("blah", "descr", openType,
0N/A defaultValue),
0N/A valid, invalid);
0N/A }
0N/A
0N/A if (legalValues == null) {
0N/A Descriptor d = descriptor("defaultValue", defaultValue,
0N/A "minValue", minValue,
0N/A "maxValue", maxValue);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false, d),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false,
0N/A defaultValue,
0N/A minValue, maxValue),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A d),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A defaultValue,
0N/A minValue, maxValue),
0N/A valid, invalid);
0N/A }
0N/A
0N/A if (minValue == null && maxValue == null) {
0N/A // Legal values in descriptor can be either an array or a set
0N/A Descriptor d1 = descriptor("defaultValue", defaultValue,
0N/A "legalValues", legalValues);
0N/A Descriptor d2;
0N/A if (legalValues == null)
0N/A d2 = d1;
0N/A else {
0N/A d2 = descriptor("defaultValue", defaultValue,
0N/A "legalValues", arraySet(legalValues));
0N/A }
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false, d1),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false, d2),
0N/A valid, invalid);
0N/A test(new OpenMBeanAttributeInfoSupport("name", "descr", openType,
0N/A true, true, false,
0N/A defaultValue, legalValues),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A d1),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A d2),
0N/A valid, invalid);
0N/A test(new OpenMBeanParameterInfoSupport("name", "descr", openType,
0N/A defaultValue, legalValues),
0N/A valid, invalid);
0N/A }
0N/A }
0N/A
0N/A /* Test one of the objects. Note that OpenMBeanAttributeInfo
0N/A extends OpenMBeanParameterInfo, so OpenMBeanAttributeInfoSupport
0N/A is-an OpenMBeanParameterInfo. */
0N/A private static void test(OpenMBeanParameterInfo info,
0N/A Object[] valid, Object[] invalid) {
0N/A test1(info, valid, invalid);
0N/A
0N/A // Check that the constraints can be specified as strings
0N/A // rather than objects
0N/A if (info.getOpenType() instanceof SimpleType<?>) {
0N/A Descriptor d = ((DescriptorRead) info).getDescriptor();
0N/A String[] names = d.getFieldNames();
0N/A Object[] values = d.getFieldValues(names);
0N/A for (int i = 0; i < values.length; i++) {
0N/A if (values[i] == null)
0N/A continue;
0N/A if (names[i].equals("legalValues")) {
0N/A Collection<?> legals;
0N/A if (values[i] instanceof Collection<?>)
0N/A legals = (Collection<?>) values[i];
0N/A else
0N/A legals = Arrays.asList((Object[]) values[i]);
0N/A List<String> strings = new ArrayList<String>();
0N/A for (Object legal : legals)
0N/A strings.add(legal.toString());
0N/A values[i] = strings.toArray(new String[0]);
0N/A } else if (!(values[i] instanceof OpenType<?>))
0N/A values[i] = values[i].toString();
0N/A }
0N/A d = new ImmutableDescriptor(names, values);
0N/A OpenType<?> ot = info.getOpenType();
0N/A if (info instanceof OpenMBeanAttributeInfo) {
0N/A OpenMBeanAttributeInfo ai = (OpenMBeanAttributeInfo) info;
0N/A info = new OpenMBeanAttributeInfoSupport(info.getName(),
0N/A info.getDescription(),
0N/A info.getOpenType(),
0N/A ai.isReadable(),
0N/A ai.isWritable(),
0N/A ai.isIs(),
0N/A d);
0N/A } else {
0N/A info = new OpenMBeanParameterInfoSupport(info.getName(),
0N/A info.getDescription(),
0N/A info.getOpenType(),
0N/A d);
0N/A }
0N/A test1(info, valid, invalid);
0N/A }
0N/A }
0N/A
0N/A private static void test1(OpenMBeanParameterInfo info,
0N/A Object[] valid, Object[] invalid) {
0N/A
0N/A for (Object x : valid) {
0N/A if (!info.isValue(x)) {
0N/A fail("Object should be valid but is not: " + x + " for: " +
0N/A info);
0N/A }
0N/A }
0N/A
0N/A for (Object x : invalid) {
0N/A if (info.isValue(x)) {
0N/A fail("Object should not be valid but is: " + x + " for: " +
0N/A info);
0N/A }
0N/A }
0N/A
0N/A /* If you specify e.g. minValue in a descriptor, then we arrange
0N/A for getMinValue() to return the same value, and if you specify
0N/A a minValue as a constructor parameter then we arrange for the
0N/A descriptor to have a minValue entry. Check that these values
0N/A do in fact match. */
0N/A
0N/A Descriptor d = ((DescriptorRead) info).getDescriptor();
0N/A
0N/A checkSameValue("defaultValue", info.getDefaultValue(),
0N/A d.getFieldValue("defaultValue"));
0N/A checkSameValue("minValue", info.getMinValue(),
0N/A d.getFieldValue("minValue"));
0N/A checkSameValue("maxValue", info.getMaxValue(),
0N/A d.getFieldValue("maxValue"));
0N/A checkSameValues("legalValues", info.getLegalValues(),
0N/A d.getFieldValue("legalValues"));
0N/A }
0N/A
0N/A private static void checkSameValue(String what, Object getterValue,
0N/A Object descriptorValue) {
0N/A if (getterValue == null) {
0N/A if (descriptorValue != null) {
0N/A fail("Getter returned null but descriptor has entry for " +
0N/A what + ": " + descriptorValue);
0N/A }
0N/A } else if (descriptorValue == null) {
0N/A fail("Getter returned value but descriptor has no entry for " +
0N/A what + ": " + getterValue);
0N/A } else if (!getterValue.equals(descriptorValue) &&
0N/A !getterValue.toString().equals(descriptorValue)) {
0N/A fail("For " + what + " getter returned " + getterValue +
0N/A " but descriptor entry is " + descriptorValue);
0N/A }
0N/A }
0N/A
0N/A private static void checkSameValues(String what, Set<?> getterValues,
0N/A Object descriptorValues) {
0N/A if (getterValues == null) {
0N/A if (descriptorValues != null) {
0N/A fail("Getter returned null but descriptor has entry for " +
0N/A what + ": " + descriptorValues);
0N/A }
0N/A } else if (descriptorValues == null) {
0N/A fail("Getter returned value but descriptor has no entry for " +
0N/A what + ": " + getterValues);
0N/A } else {
0N/A Set<?> descriptorValueSet;
0N/A if (descriptorValues instanceof Set<?>)
0N/A descriptorValueSet = (Set<?>) descriptorValues;
0N/A else
0N/A descriptorValueSet = arraySet((Object[]) descriptorValues);
0N/A boolean same = true;
0N/A if (getterValues.size() != descriptorValueSet.size())
0N/A same = false;
0N/A else {
0N/A for (Object x : getterValues) {
0N/A if (!descriptorValueSet.contains(x)
0N/A && !descriptorValueSet.contains(x.toString())) {
0N/A same = false;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A if (!same) {
0N/A fail("For " + what + " getter returned " + getterValues +
0N/A " but descriptor entry is " + descriptorValueSet);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private static void fail(String why) {
0N/A System.out.println("FAILED: " + why);
0N/A failure = why;
0N/A }
0N/A
0N/A private static Descriptor descriptor(Object... entries) {
0N/A if (entries.length % 2 != 0)
0N/A throw new RuntimeException("Odd length descriptor entries");
0N/A String[] names = new String[entries.length / 2];
0N/A Object[] values = new Object[entries.length / 2];
0N/A for (int i = 0; i < entries.length; i += 2) {
0N/A names[i / 2] = (String) entries[i];
0N/A values[i / 2] = entries[i + 1];
0N/A }
0N/A return new ImmutableDescriptor(names, values);
0N/A }
0N/A
0N/A private static <T> Set<T> arraySet(T[] array) {
0N/A return new HashSet<T>(Arrays.asList(array));
0N/A }
0N/A
0N/A private static final OpenType<?>
0N/A ostring = SimpleType.STRING,
0N/A oint = SimpleType.INTEGER,
0N/A obool = SimpleType.BOOLEAN,
0N/A olong = SimpleType.LONG,
0N/A obyte = SimpleType.BYTE,
0N/A ofloat = SimpleType.FLOAT,
0N/A odouble = SimpleType.DOUBLE,
0N/A ostringarray, ostringarray2;
0N/A private static final CompositeType ocomposite;
0N/A private static final CompositeData compositeData, compositeData2;
0N/A static {
0N/A try {
0N/A ostringarray = new ArrayType<String[]>(1, ostring);
0N/A ostringarray2 = new ArrayType<String[][]>(2, ostring);
0N/A ocomposite =
0N/A new CompositeType("name", "descr",
0N/A new String[] {"s", "i"},
0N/A new String[] {"sdesc", "idesc"},
0N/A new OpenType[] {ostring, oint});
0N/A compositeData =
0N/A new CompositeDataSupport(ocomposite,
0N/A new String[] {"s", "i"},
0N/A new Object[] {"foo", 23});
0N/A compositeData2 =
0N/A new CompositeDataSupport(ocomposite,
0N/A new String[] {"s", "i"},
0N/A new Object[] {"bar", -23});
0N/A } catch (OpenDataException e) { // damn checked exceptions...
0N/A throw new IllegalArgumentException(e.toString(), e);
0N/A }
0N/A }
0N/A
0N/A private static final Descriptor
0N/A nullD = null,
0N/A emptyD = ImmutableDescriptor.EMPTY_DESCRIPTOR;
0N/A
0N/A /* The elements of this array are grouped as follows. Each
0N/A element contains four Object[]s. The first one is a set of
0N/A four values: default value, min value, max value, legal values
0N/A (an Object[]), some of which can be null. These will be used
0N/A to derive the OpenMBean*Info values to be tested. The second
0N/A is an array with one element that is the OpenType that will be
0N/A given to the constructors of the OpenMBean*Infos. The third
0N/A element is a set of values that should be valid according to
0N/A the constraints in the OpenMBean*Info. The fourth is a set of
0N/A values that should be invalid according to those
0N/A constraints. */
0N/A private static final Object[][][] tests = {
0N/A
0N/A // Test cases when there are no constraints
0N/A // Validity checking is limited to type of object
0N/A
0N/A {{null, null, null, null},
0N/A {oint},
0N/A {-1, 0, 1, Integer.MAX_VALUE, Integer.MIN_VALUE},
0N/A {null, "noddy", 1.3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {obool},
0N/A {true, false},
0N/A {null, "noddy", 1.3, 3, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {ostring},
0N/A {"", "yes!"},
0N/A {null, 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {obyte},
0N/A {Byte.MIN_VALUE, Byte.MAX_VALUE, (byte) 0},
0N/A {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {ostringarray},
0N/A {new String[0], new String[] {"hello", "world"}},
0N/A {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {ostringarray2},
0N/A {new String[0][0], new String[][] {{"hello", "world"},
0N/A {"goodbye", "cruel", "world"}}},
0N/A {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{null, null, null, null},
0N/A {ocomposite},
0N/A {compositeData, compositeData2},
0N/A {null, "noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A // Test cases where there is a default value, so null is allowed
0N/A
0N/A {{23, null, null, null},
0N/A {oint},
0N/A {null, -1, 0, 1, Integer.MAX_VALUE, Integer.MIN_VALUE},
0N/A {"noddy", 1.3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{true, null, null, null},
0N/A {obool},
0N/A {null, true, false},
0N/A {"noddy", 1.3, 3, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{"foo", null, null, null},
0N/A {ostring},
0N/A {null, "", "yes!"},
0N/A {1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{(byte) 23, null, null, null},
0N/A {obyte},
0N/A {null, Byte.MIN_VALUE, Byte.MAX_VALUE, (byte) 0},
0N/A {"noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A {{compositeData, null, null, null},
0N/A {ocomposite},
0N/A {null, compositeData, compositeData2},
0N/A {"noddy", 1.3, 3, false, 3L, Long.MAX_VALUE, emptyD,
0N/A new int[2], new Integer[2], new Integer[] {3}, new Integer[0]}},
0N/A
0N/A // Test cases where there is a min and/or max, with or without default
0N/A
0N/A {{23, 0, 50, null},
0N/A {oint},
0N/A {null, 0, 25, 50},
0N/A {"noddy", -1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
0N/A
0N/A {{null, 0, 50, null},
0N/A {oint},
0N/A {0, 25, 50},
0N/A {null, "noddy", -1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
0N/A
0N/A {{null, 0, null, null},
0N/A {oint},
0N/A {0, 25, 50, Integer.MAX_VALUE},
0N/A {null, "noddy", -1, Integer.MIN_VALUE, 25L}},
0N/A
0N/A {{null, null, 50, null},
0N/A {oint},
0N/A {Integer.MIN_VALUE, -1, 0, 25, 50},
0N/A {null, "noddy", 51, Integer.MAX_VALUE, 25L}},
0N/A
0N/A {{"go", "a", "z~", null},
0N/A {ostring},
0N/A {null, "a", "z~", "zzzz", "z!"},
0N/A {"A", "~", "", -1}},
0N/A
0N/A // Test cases where there is a set of legal values
0N/A
0N/A {{23, null, null, new Integer[] {2, 3, 5, 7, 11, 13, 17, 23}},
0N/A {oint},
0N/A {null, 2, 11, 23},
0N/A {"noddy", -1, 1, 51, Integer.MIN_VALUE, Integer.MAX_VALUE, 25L}},
0N/A
0N/A {{null, null, null, new CompositeData[] {compositeData}},
0N/A {ocomposite},
0N/A {compositeData},
0N/A {null, compositeData2, "noddy"}},
0N/A
0N/A {{null, null, null, new Long[0]},
0N/A {olong},
0N/A {}, // constraint is impossible to satisfy!
0N/A {null, 23L, "x", 23}},
0N/A };
0N/A}