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 8058865
  27  * @summary Checks that a serialized instance is not transmitted from an MXBean.
  28  * All the communication should be done via Open Types
  29  * @author Olivier Lagneau
  30  *
  31  * @library /lib/testlibrary
  32  * @modules java.management.rmi
  33  *
  34  * @compile Basic.java
  35  * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanWeirdParamTest
  36  */
  37 
  38 import java.util.Map;
  39 import java.util.List;
  40 import java.util.ArrayList;
  41 import java.util.Arrays;
  42 
  43 import java.lang.Process;
  44 import java.lang.management.ManagementFactory;
  45 
  46 import javax.management.MBeanServer;
  47 import javax.management.MBeanServerConnection;
  48 import javax.management.remote.JMXConnector;
  49 import javax.management.remote.JMXConnectorFactory;
  50 import javax.management.remote.JMXConnectorServer;
  51 import javax.management.remote.JMXConnectorServerFactory;
  52 import javax.management.remote.JMXServiceURL;
  53 
  54 import javax.management.ObjectName;
  55 import javax.management.openmbean.CompositeType;
  56 import javax.management.openmbean.CompositeData;
  57 import javax.management.openmbean.CompositeDataSupport;
  58 import javax.management.openmbean.OpenType;
  59 import javax.management.openmbean.SimpleType;
  60 import javax.management.openmbean.TabularDataSupport;
  61 import javax.management.openmbean.TabularType;
  62 
  63 import jdk.testlibrary.ProcessTools;
  64 import jdk.testlibrary.JDKToolFinder;
  65 
  66 public class MXBeanWeirdParamTest {
  67 
  68     private static String BASIC_MXBEAN_CLASS_NAME = "Basic";
  69 
  70     private static final String CLIENT_CLASS_MAIN =
  71         "MXBeanWeirdParamTest$ClientSide";
  72 
  73     private JMXConnectorServer cs;
  74 
  75     /*
  76      * First Debug properties and arguments are collect in expected
  77      * map  (argName, value) format, then calls original test's run method.
  78      */
  79     public static void main(String args[]) throws Exception {
  80 
  81         System.out.println("=================================================");
  82 
  83         // Parses parameters
  84         Utils.parseDebugProperties();
  85         Map<String, Object> map = Utils.parseParameters(args) ;
  86 
  87         // Run test
  88         MXBeanWeirdParamTest test = new MXBeanWeirdParamTest();
  89         test.run(map);
  90 
  91     }
  92 
  93     /*
  94      * Create the MBeansServe side of the test and returns its address
  95      */
  96     private JMXServiceURL createServerSide() throws Exception {
  97         final int NINETY_SECONDS = 90;
  98 
  99         // We will use the platform mbean server
 100         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
 101 
 102         JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
 103         cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
 104         cs.start();
 105 
 106         Utils.waitReady(cs, NINETY_SECONDS);
 107 
 108         JMXServiceURL addr = cs.getAddress();
 109         return addr;
 110     }
 111 
 112 
 113     /*
 114      * Creating command-line for running subprocess JVM:
 115      *
 116      * JVM command line is like:
 117      * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main
 118      *
 119      * {defaultopts} are the default java options set by the framework.
 120      *
 121      */
 122     private List<String> buildCommandLine() {
 123         List<String> opts = new ArrayList<>();
 124         opts.add(JDKToolFinder.getJDKTool("java"));
 125         opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts()));
 126         // We need to set WEIRD_PARAM propertty on the client-side
 127         opts.add("-DWEIRD_PARAM");
 128         opts.add("-cp");
 129         opts.add(System.getProperty("test.class.path", "test.class.path"));
 130         opts.add(CLIENT_CLASS_MAIN);
 131 
 132         return opts;
 133     }
 134 
 135     /**
 136      * Runs MXBeanWeirdParamTest$ClientSide with the passed options and redirects
 137      * subprocess standard I/O to the current (parent) process. This provides a
 138      * trace of what happens in the subprocess while it is runnning (and before
 139      * it terminates).
 140      *
 141      * @param serviceUrlStr string representing the JMX service Url to connect to.
 142      */
 143     private int runClientSide(String serviceUrlStr) throws Exception {
 144 
 145         // Building command-line
 146         List<String> opts = buildCommandLine();
 147         opts.add(serviceUrlStr);
 148 
 149         // Launch separate JVM subprocess
 150         int exitCode = 0;
 151         String[] optsArray = opts.toArray(new String[0]);
 152         ProcessBuilder pb = new ProcessBuilder(optsArray);
 153         Process p = ProcessTools.startProcess("MXBeanWeirdParamTest$ClientSide", pb);
 154 
 155         // Handling end of subprocess
 156         try {
 157             exitCode = p.waitFor();
 158             if (exitCode != 0) {
 159                 System.out.println(
 160                     "Subprocess unexpected exit value of [" + exitCode +
 161                     "]. Expected 0.\n");
 162             }
 163         } catch (InterruptedException e) {
 164             System.out.println("Parent process interrupted with exception : \n " + e + " :" );
 165 
 166             // Parent thread unknown state, killing subprocess.
 167             p.destroyForcibly();
 168 
 169             throw new RuntimeException(
 170                 "Parent process interrupted with exception : \n " + e + " :" );
 171         } finally {
 172             return exitCode;
 173         }
 174 
 175      }
 176 
 177     public void run(Map<String, Object> args) throws Exception {
 178 
 179         System.out.println("MXBeanWeirdParamTest::run: Start") ;
 180         int errorCount = 0;
 181 
 182         try {
 183             // Initialise the server side
 184             JMXServiceURL urlToUse = createServerSide();
 185 
 186             // Run client side
 187             errorCount = runClientSide(urlToUse.toString());
 188 
 189             if ( errorCount == 0 ) {
 190                 System.out.println("MXBeanWeirdParamTest::run: Done without any error") ;
 191             } else {
 192                 System.out.println("MXBeanWeirdParamTest::run: Done with "
 193                         + errorCount
 194                         + " error(s)") ;
 195                 throw new RuntimeException("errorCount = " + errorCount);
 196             }
 197 
 198             cs.stop();
 199 
 200         } catch(Exception e) {
 201             throw new RuntimeException(e);
 202         }
 203 
 204     }
 205 
 206     private static class ClientSide {
 207         public static void main(String args[]) throws Exception {
 208 
 209             int errorCount = 0 ;
 210             String msgTag = "ClientSide::main: ";
 211 
 212             try {
 213 
 214                 // Get a connection to remote mbean server
 215                 JMXServiceURL addr = new JMXServiceURL(args[0]);
 216                 JMXConnector cc = JMXConnectorFactory.connect(addr);
 217                 MBeanServerConnection mbsc = cc.getMBeanServerConnection();
 218 
 219                 // ----
 220                 System.out.println(msgTag + "Create and register the MBean");
 221                 ObjectName objName = new ObjectName("sqe:type=Basic,protocol=rmi") ;
 222                 mbsc.createMBean(BASIC_MXBEAN_CLASS_NAME, objName);
 223                 System.out.println(msgTag +"---- OK\n") ;
 224 
 225                 // ----
 226                 System.out.println(msgTag +"Get attribute SqeParameterAtt on our MXBean");
 227                 Object result = mbsc.getAttribute(objName, "SqeParameterAtt");
 228                 System.out.println(msgTag +"(OK) Got result of class "
 229                         + result.getClass().getName());
 230                 System.out.println(msgTag +"Received CompositeData is " + result);
 231                 System.out.println(msgTag +"---- OK\n") ;
 232 
 233                 // ----
 234                 // We use the value returned by getAttribute to perform the invoke.
 235                 System.out.println(msgTag +"Call operation doWeird on our MXBean [1]");
 236                 mbsc.invoke(objName, "doWeird",
 237                         new Object[]{result},
 238                         new String[]{"javax.management.openmbean.CompositeData"});
 239                 System.out.println(msgTag +"---- OK\n") ;
 240 
 241                 // ----
 242                 // We build the CompositeData ourselves that time.
 243                 System.out.println(msgTag +"Call operation doWeird on our MXBean [2]");
 244                 String typeName = "SqeParameter";
 245                 String[] itemNames = new String[] {"glop"};
 246                 OpenType<?>[] openTypes = new OpenType<?>[] {SimpleType.STRING};
 247                 CompositeType rowType = new CompositeType(typeName, typeName,
 248                         itemNames, itemNames, openTypes);
 249                 Object[] itemValues = {"HECTOR"};
 250                 CompositeData data =
 251                         new CompositeDataSupport(rowType, itemNames, itemValues);
 252                 TabularType tabType = new TabularType(typeName, typeName,
 253                         rowType, new String[]{"glop"});
 254                 TabularDataSupport tds = new TabularDataSupport(tabType);
 255                 tds.put(data);
 256                 System.out.println(msgTag +"Source CompositeData is " + data);
 257                 mbsc.invoke(objName, "doWeird",
 258                         new Object[]{data},
 259                         new String[]{"javax.management.openmbean.CompositeData"});
 260                 System.out.println(msgTag +"---- OK\n") ;
 261 
 262                 // ----
 263                 System.out.println(msgTag +"Unregister the MBean");
 264                 mbsc.unregisterMBean(objName);
 265                 System.out.println(msgTag +"---- OK\n") ;
 266 
 267                 // Terminate the JMX Client
 268                 cc.close();
 269 
 270             } catch(Exception e) {
 271                 Utils.printThrowable(e, true) ;
 272                 errorCount++;
 273                 throw new RuntimeException(e);
 274             } finally {
 275                 System.exit(errorCount);
 276             }
 277         }
 278     }
 279 }