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      */
main(String args[])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      */
createServerSide()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      */
buildCommandLine()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      */
runClientSide(String serviceUrlStr)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 
run(Map<String, Object> args)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 {
main(String args[])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 }
278