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