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