--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/mxbean/MXBeanTest.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,707 @@
+/*
+ * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6175517 6278707 6318827 6305746 6392303
+ * @summary General MXBean test.
+ * @author Eamonn McManus
+ * @run clean MXBeanTest MerlinMXBean TigerMXBean
+ * @run build MXBeanTest MerlinMXBean TigerMXBean
+ * @run main MXBeanTest
+ */
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import javax.management.Attribute;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataInvocationHandler;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+public class MXBeanTest {
+ public static void main(String[] args) throws Exception {
+ testInterface(MerlinMXBean.class, false);
+ testInterface(TigerMXBean.class, false);
+ testInterface(MerlinMXBean.class, true);
+ testInterface(TigerMXBean.class, true);
+ testExplicitMXBean();
+ testSubclassMXBean();
+ testIndirectMXBean();
+
+ if (failures == 0)
+ System.out.println("Test passed");
+ else {
+ System.out.println("TEST FAILURES: " + failures);
+ System.exit(1);
+ }
+ }
+
+ private static int failures = 0;
+
+ public static interface ExplicitMXBean {
+ public int[] getInts();
+ }
+ public static class Explicit implements ExplicitMXBean {
+ public int[] getInts() {
+ return new int[] {1, 2, 3};
+ }
+ }
+ public static class Subclass
+ extends StandardMBean
+ implements ExplicitMXBean {
+ public Subclass() {
+ super(ExplicitMXBean.class, true);
+ }
+
+ public int[] getInts() {
+ return new int[] {1, 2, 3};
+ }
+ }
+ public static interface IndirectInterface extends ExplicitMXBean {}
+ public static class Indirect implements IndirectInterface {
+ public int[] getInts() {
+ return new int[] {1, 2, 3};
+ }
+ }
+
+ private static void testExplicitMXBean() throws Exception {
+ System.out.println("Explicit MXBean test...");
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ ObjectName on = new ObjectName("test:type=Explicit");
+ Explicit explicit = new Explicit();
+ mbs.registerMBean(explicit, on);
+ testMXBean(mbs, on);
+ }
+
+ private static void testSubclassMXBean() throws Exception {
+ System.out.println("Subclass MXBean test...");
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ ObjectName on = new ObjectName("test:type=Subclass");
+ Subclass subclass = new Subclass();
+ mbs.registerMBean(subclass, on);
+ testMXBean(mbs, on);
+ }
+
+ private static void testIndirectMXBean() throws Exception {
+ System.out.println("Indirect MXBean test...");
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+ ObjectName on = new ObjectName("test:type=Indirect");
+ Indirect indirect = new Indirect();
+ mbs.registerMBean(indirect, on);
+ testMXBean(mbs, on);
+ }
+
+ private static void testMXBean(MBeanServer mbs, ObjectName on)
+ throws Exception {
+ MBeanInfo mbi = mbs.getMBeanInfo(on);
+ MBeanAttributeInfo[] attrs = mbi.getAttributes();
+ int nattrs = attrs.length;
+ if (mbi.getAttributes().length != 1)
+ failure("wrong number of attributes: " + attrs);
+ else {
+ MBeanAttributeInfo mbai = attrs[0];
+ if (mbai.getName().equals("Ints")
+ && mbai.isReadable() && !mbai.isWritable()
+ && mbai.getDescriptor().getFieldValue("openType")
+ .equals(new ArrayType(SimpleType.INTEGER, true))
+ && attrs[0].getType().equals("[I"))
+ success("MBeanAttributeInfo");
+ else
+ failure("MBeanAttributeInfo: " + mbai);
+ }
+
+ int[] ints = (int[]) mbs.getAttribute(on, "Ints");
+ if (equal(ints, new int[] {1, 2, 3}, null))
+ success("getAttribute");
+ else
+ failure("getAttribute: " + Arrays.toString(ints));
+
+ ExplicitMXBean proxy =
+ JMX.newMXBeanProxy(mbs, on, ExplicitMXBean.class);
+ int[] pints = proxy.getInts();
+ if (equal(pints, new int[] {1, 2, 3}, null))
+ success("getAttribute through proxy");
+ else
+ failure("getAttribute through proxy: " + Arrays.toString(pints));
+ }
+
+ private static class NamedMXBeans extends HashMap<ObjectName, Object> {
+ private static final long serialVersionUID = 0;
+
+ NamedMXBeans(MBeanServerConnection mbsc) {
+ this.mbsc = mbsc;
+ }
+
+ MBeanServerConnection getMBeanServerConnection() {
+ return mbsc;
+ }
+
+ private final MBeanServerConnection mbsc;
+ }
+
+ /* This is the core of the test. Given the MXBean interface c, we
+ make an MXBean object that implements that interface by
+ constructing a dynamic proxy. If the interface defines an
+ attribute Foo (with getFoo and setFoo methods), then it must
+ also contain a field (constant) Foo of the same type, and a
+ field (constant) FooType that is an OpenType. The field Foo is
+ a reference value for this case. We check that the attribute
+ does indeed have the given OpenType. The dynamically-created
+ MXBean will return the reference value from the getFoo()
+ method, and we check that that value survives the mapping to
+ open values and back when the attribute is accessed through an
+ MXBean proxy. The MXBean will also check in its setFoo method
+ that the value being set is equal to the reference value, which
+ tests that the mapping and unmapping also works in the other
+ direction. The interface should define an operation opFoo with
+ two parameters and a return value all of the same type as the
+ attribute. The MXBean will check that the two parameters are
+ equal to the reference value, and will return that value. The
+ test checks that calling the operation through an MXBean proxy
+ returns the reference value, again after mapping to and back
+ from open values.
+
+ If any field (constant) in the MXBean interface has a name that
+ ends with ObjectName, say FooObjectName, then its value must be
+ a String containing an ObjectName value. There must be a field
+ (constant) called Foo that is a valid MXBean, and that MXBean
+ will be registered in the MBean Server with the given name before
+ the test starts. This enables us to test that inter-MXBean
+ references are correctly converted to ObjectNames and back.
+ */
+ private static <T> void testInterface(Class<T> c, boolean nullTest)
+ throws Exception {
+
+ System.out.println("Testing " + c.getName() +
+ (nullTest ? " for null values" : "") + "...");
+
+ MBeanServer mbs = MBeanServerFactory.newMBeanServer();
+
+ JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+ JMXConnectorServer cs =
+ JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
+ cs.start();
+ JMXServiceURL addr = cs.getAddress();
+ JMXConnector cc = JMXConnectorFactory.connect(addr);
+ MBeanServerConnection mbsc = cc.getMBeanServerConnection();
+
+ NamedMXBeans namedMXBeans = new NamedMXBeans(mbsc);
+ InvocationHandler ih =
+ nullTest ? new MXBeanNullImplInvocationHandler(c, namedMXBeans) :
+ new MXBeanImplInvocationHandler(c, namedMXBeans);
+ T impl = c.cast(Proxy.newProxyInstance(c.getClassLoader(),
+ new Class[] {c},
+ ih));
+ ObjectName on = new ObjectName("test:type=" + c.getName());
+ mbs.registerMBean(impl, on);
+
+ System.out.println("Register any MXBeans...");
+
+ Field[] fields = c.getFields();
+ for (Field field : fields) {
+ String n = field.getName();
+ if (n.endsWith("ObjectName")) {
+ String objectNameString = (String) field.get(null);
+ String base = n.substring(0, n.length() - 10);
+ Field f = c.getField(base);
+ Object mxbean = f.get(null);
+ ObjectName objectName =
+ ObjectName.getInstance(objectNameString);
+ mbs.registerMBean(mxbean, objectName);
+ namedMXBeans.put(objectName, mxbean);
+ }
+ }
+
+ try {
+ testInterface(c, mbsc, on, namedMXBeans, nullTest);
+ } finally {
+ try {
+ cc.close();
+ } finally {
+ cs.stop();
+ }
+ }
+ }
+
+ private static <T> void testInterface(Class<T> c,
+ MBeanServerConnection mbsc,
+ ObjectName on,
+ NamedMXBeans namedMXBeans,
+ boolean nullTest)
+ throws Exception {
+
+ System.out.println("Type check...");
+
+ MBeanInfo mbi = mbsc.getMBeanInfo(on);
+ MBeanAttributeInfo[] mbais = mbi.getAttributes();
+ for (int i = 0; i < mbais.length; i++) {
+ MBeanAttributeInfo mbai = mbais[i];
+ String name = mbai.getName();
+ Field typeField = c.getField(name + "Type");
+ OpenType typeValue = (OpenType) typeField.get(null);
+ OpenType openType =
+ (OpenType) mbai.getDescriptor().getFieldValue("openType");
+ if (typeValue.equals(openType))
+ success("attribute " + name);
+ else {
+ final String msg =
+ "Wrong type attribute " + name + ": " +
+ openType + " should be " + typeValue;
+ failure(msg);
+ }
+ }
+
+ MBeanOperationInfo[] mbois = mbi.getOperations();
+ for (int i = 0; i < mbois.length; i++) {
+ MBeanOperationInfo mboi = mbois[i];
+ String oname = mboi.getName();
+ if (!oname.startsWith("op"))
+ throw new Error();
+ OpenType retType =
+ (OpenType) mboi.getDescriptor().getFieldValue("openType");
+ MBeanParameterInfo[] params = mboi.getSignature();
+ MBeanParameterInfo p1i = params[0];
+ MBeanParameterInfo p2i = params[1];
+ OpenType p1Type =
+ (OpenType) p1i.getDescriptor().getFieldValue("openType");
+ OpenType p2Type =
+ (OpenType) p2i.getDescriptor().getFieldValue("openType");
+ if (!retType.equals(p1Type) || !p1Type.equals(p2Type)) {
+ final String msg =
+ "Parameter and return open types should all be same " +
+ "but are not: " + retType + " " + oname + "(" + p1Type +
+ ", " + p2Type + ")";
+ failure(msg);
+ continue;
+ }
+ String name = oname.substring(2);
+ Field typeField = c.getField(name + "Type");
+ OpenType typeValue = (OpenType) typeField.get(null);
+ if (typeValue.equals(retType))
+ success("operation " + oname);
+ else {
+ final String msg =
+ "Wrong type operation " + oname + ": " +
+ retType + " should be " + typeValue;
+ failure(msg);
+ }
+ }
+
+
+ System.out.println("Mapping check...");
+
+ Object proxy =
+ JMX.newMXBeanProxy(mbsc, on, c);
+
+ Method[] methods = c.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ final Method method = methods[i];
+ if (method.getDeclaringClass() != c)
+ continue; // skip hashCode() etc inherited from Object
+ final String mname = method.getName();
+ final int what = getType(method);
+ final String name = getName(method);
+ final Field refField = c.getField(name);
+ if (nullTest && refField.getType().isPrimitive())
+ continue;
+ final Field openTypeField = c.getField(name + "Type");
+ final OpenType openType = (OpenType) openTypeField.get(null);
+ final Object refValue = nullTest ? null : refField.get(null);
+ Object setValue = refValue;
+ try {
+ Field onField = c.getField(name + "ObjectName");
+ String refName = (String) onField.get(null);
+ ObjectName refObjName = ObjectName.getInstance(refName);
+ Class<?> mxbeanInterface = refField.getType();
+ setValue = nullTest ? null :
+ JMX.newMXBeanProxy(mbsc, refObjName, mxbeanInterface);
+ } catch (Exception e) {
+ // no xObjectName field, setValue == refValue
+ }
+ boolean ok = true;
+ try {
+ switch (what) {
+ case GET:
+ final Object gotOpen = mbsc.getAttribute(on, name);
+ if (nullTest) {
+ if (gotOpen != null) {
+ failure(mname + " got non-null value " +
+ gotOpen);
+ ok = false;
+ }
+ } else if (!openType.isValue(gotOpen)) {
+ if (gotOpen instanceof TabularData) {
+ // detail the mismatch
+ TabularData gotTabular = (TabularData) gotOpen;
+ compareTabularType((TabularType) openType,
+ gotTabular.getTabularType());
+ }
+ failure(mname + " got open data " + gotOpen +
+ " not valid for open type " + openType);
+ ok = false;
+ }
+ final Object got = method.invoke(proxy, (Object[]) null);
+ if (!equal(refValue, got, namedMXBeans)) {
+ failure(mname + " got " + string(got) +
+ ", should be " + string(refValue));
+ ok = false;
+ }
+ break;
+
+ case SET:
+ method.invoke(proxy, new Object[] {setValue});
+ break;
+
+ case OP:
+ final Object opped =
+ method.invoke(proxy, new Object[] {setValue, setValue});
+ if (!equal(refValue, opped, namedMXBeans)) {
+ failure(
+ mname + " got " + string(opped) +
+ ", should be " + string(refValue)
+ );
+ ok = false;
+ }
+ break;
+
+ default:
+ throw new Error();
+ }
+
+ if (ok)
+ success(mname);
+
+ } catch (Exception e) {
+ failure(mname, e);
+ }
+ }
+ }
+
+
+ private static void success(String what) {
+ System.out.println("OK: " + what);
+ }
+
+ private static void failure(String what) {
+ System.out.println("FAILED: " + what);
+ failures++;
+ }
+
+ private static void failure(String what, Exception e) {
+ System.out.println("FAILED WITH EXCEPTION: " + what);
+ e.printStackTrace(System.out);
+ failures++;
+ }
+
+ private static class MXBeanImplInvocationHandler
+ implements InvocationHandler {
+ MXBeanImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) {
+ this.intf = intf;
+ this.namedMXBeans = namedMXBeans;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ final String mname = method.getName();
+ final int what = getType(method);
+ final String name = getName(method);
+ final Field refField = intf.getField(name);
+ final Object refValue = getRefValue(refField);
+
+ switch (what) {
+ case GET:
+ assert args == null;
+ return refValue;
+
+ case SET:
+ assert args.length == 1;
+ Object setValue = args[0];
+ if (!equal(refValue, setValue, namedMXBeans)) {
+ final String msg =
+ mname + "(" + string(setValue) +
+ ") does not match ref: " + string(refValue);
+ throw new IllegalArgumentException(msg);
+ }
+ return null;
+
+ case OP:
+ assert args.length == 2;
+ Object arg1 = args[0];
+ Object arg2 = args[1];
+ if (!equal(arg1, arg2, namedMXBeans)) {
+ final String msg =
+ mname + "(" + string(arg1) + ", " + string(arg2) +
+ "): args not equal";
+ throw new IllegalArgumentException(msg);
+ }
+ if (!equal(refValue, arg1, namedMXBeans)) {
+ final String msg =
+ mname + "(" + string(arg1) + ", " + string(arg2) +
+ "): args do not match ref: " + string(refValue);
+ throw new IllegalArgumentException(msg);
+ }
+ return refValue;
+ default:
+ throw new Error();
+ }
+ }
+
+ Object getRefValue(Field refField) throws Exception {
+ return refField.get(null);
+ }
+
+ private final Class intf;
+ private final NamedMXBeans namedMXBeans;
+ }
+
+ private static class MXBeanNullImplInvocationHandler
+ extends MXBeanImplInvocationHandler {
+ MXBeanNullImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) {
+ super(intf, namedMXBeans);
+ }
+
+ @Override
+ Object getRefValue(Field refField) throws Exception {
+ Class<?> type = refField.getType();
+ if (type.isPrimitive())
+ return super.getRefValue(refField);
+ else
+ return null;
+ }
+ }
+
+
+ private static final String[] prefixes = {
+ "get", "set", "op",
+ };
+ private static final int GET = 0, SET = 1, OP = 2;
+
+ private static String getName(Method m) {
+ return getName(m.getName());
+ }
+
+ private static String getName(String n) {
+ for (int i = 0; i < prefixes.length; i++) {
+ if (n.startsWith(prefixes[i]))
+ return n.substring(prefixes[i].length());
+ }
+ throw new Error();
+ }
+
+ private static int getType(Method m) {
+ return getType(m.getName());
+ }
+
+ private static int getType(String n) {
+ for (int i = 0; i < prefixes.length; i++) {
+ if (n.startsWith(prefixes[i]))
+ return i;
+ }
+ throw new Error();
+ }
+
+ static boolean equal(Object o1, Object o2, NamedMXBeans namedMXBeans) {
+ if (o1 == o2)
+ return true;
+ if (o1 == null || o2 == null)
+ return false;
+ if (o1.getClass().isArray()) {
+ if (!o2.getClass().isArray())
+ return false;
+ return deepEqual(o1, o2, namedMXBeans);
+ }
+ if (o1 instanceof CompositeData && o2 instanceof CompositeData) {
+ return compositeDataEqual((CompositeData) o1, (CompositeData) o2,
+ namedMXBeans);
+ }
+ if (Proxy.isProxyClass(o1.getClass())) {
+ if (Proxy.isProxyClass(o2.getClass()))
+ return proxyEqual(o1, o2, namedMXBeans);
+ InvocationHandler ih = Proxy.getInvocationHandler(o1);
+// if (ih instanceof MXBeanInvocationHandler) {
+// return proxyEqualsObject((MXBeanInvocationHandler) ih,
+// o2, namedMXBeans);
+ if (ih instanceof MBeanServerInvocationHandler) {
+ return true;
+ } else if (ih instanceof CompositeDataInvocationHandler) {
+ return o2.equals(o1);
+ // We assume the other object has a reasonable equals method
+ }
+ } else if (Proxy.isProxyClass(o2.getClass()))
+ return equal(o2, o1, namedMXBeans);
+ return o1.equals(o2);
+ }
+
+ // We'd use Arrays.deepEquals except we want the test to work on 1.4
+ // Note this code assumes no selfreferential arrays
+ // (as does Arrays.deepEquals)
+ private static boolean deepEqual(Object a1, Object a2,
+ NamedMXBeans namedMXBeans) {
+ int len = Array.getLength(a1);
+ if (len != Array.getLength(a2))
+ return false;
+ for (int i = 0; i < len; i++) {
+ Object e1 = Array.get(a1, i);
+ Object e2 = Array.get(a2, i);
+ if (!equal(e1, e2, namedMXBeans))
+ return false;
+ }
+ return true;
+ }
+
+ // This is needed to work around a bug (5095277)
+ // in CompositeDataSupport.equals
+ private static boolean compositeDataEqual(CompositeData cd1,
+ CompositeData cd2,
+ NamedMXBeans namedMXBeans) {
+ if (cd1 == cd2)
+ return true;
+ if (!cd1.getCompositeType().equals(cd2.getCompositeType()))
+ return false;
+ Collection v1 = cd1.values();
+ Collection v2 = cd2.values();
+ if (v1.size() != v2.size())
+ return false; // should not happen
+ for (Iterator i1 = v1.iterator(), i2 = v2.iterator();
+ i1.hasNext(); ) {
+ if (!equal(i1.next(), i2.next(), namedMXBeans))
+ return false;
+ }
+ return true;
+ }
+
+ // Also needed for 5095277
+ private static boolean proxyEqual(Object proxy1, Object proxy2,
+ NamedMXBeans namedMXBeans) {
+ if (proxy1.getClass() != proxy2.getClass())
+ return proxy1.equals(proxy2);
+ InvocationHandler ih1 = Proxy.getInvocationHandler(proxy1);
+ InvocationHandler ih2 = Proxy.getInvocationHandler(proxy2);
+ if (!(ih1 instanceof CompositeDataInvocationHandler)
+ || !(ih2 instanceof CompositeDataInvocationHandler))
+ return proxy1.equals(proxy2);
+ CompositeData cd1 =
+ ((CompositeDataInvocationHandler) ih1).getCompositeData();
+ CompositeData cd2 =
+ ((CompositeDataInvocationHandler) ih2).getCompositeData();
+ return compositeDataEqual(cd1, cd2, namedMXBeans);
+ }
+
+// private static boolean proxyEqualsObject(MXBeanInvocationHandler ih,
+// Object o,
+// NamedMXBeans namedMXBeans) {
+// if (namedMXBeans.getMBeanServerConnection() !=
+// ih.getMBeanServerConnection())
+// return false;
+//
+// ObjectName on = ih.getObjectName();
+// Object named = namedMXBeans.get(on);
+// if (named == null)
+// return false;
+// return (o == named && ih.getMXBeanInterface().isInstance(named));
+// }
+
+ /* I wanted to call this method toString(Object), but oddly enough
+ this meant that I couldn't call it from the inner class
+ MXBeanImplInvocationHandler, because the inherited Object.toString()
+ prevented that. Surprising behaviour. */
+ static String string(Object o) {
+ if (o == null)
+ return "null";
+ if (o instanceof String)
+ return '"' + (String) o + '"';
+ if (o instanceof Collection)
+ return deepToString((Collection) o);
+ if (o.getClass().isArray())
+ return deepToString(o);
+ return o.toString();
+ }
+
+ private static String deepToString(Object o) {
+ StringBuffer buf = new StringBuffer();
+ buf.append("[");
+ int len = Array.getLength(o);
+ for (int i = 0; i < len; i++) {
+ if (i > 0)
+ buf.append(", ");
+ Object e = Array.get(o, i);
+ buf.append(string(e));
+ }
+ buf.append("]");
+ return buf.toString();
+ }
+
+ private static String deepToString(Collection c) {
+ return deepToString(c.toArray());
+ }
+
+ private static void compareTabularType(TabularType t1, TabularType t2) {
+ if (t1.equals(t2)) {
+ System.out.println("same tabular type");
+ return;
+ }
+ if (t1.getClassName().equals(t2.getClassName()))
+ System.out.println("same class name");
+ if (t1.getDescription().equals(t2.getDescription()))
+ System.out.println("same description");
+ else {
+ System.out.println("t1 description: " + t1.getDescription());
+ System.out.println("t2 description: " + t2.getDescription());
+ }
+ if (t1.getIndexNames().equals(t2.getIndexNames()))
+ System.out.println("same index names");
+ if (t1.getRowType().equals(t2.getRowType()))
+ System.out.println("same row type");
+ }
+}