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.rmi
31 * @library /lib/testlibrary
32 * @compile Basic.java
33 * @run main/othervm/timeout=300 -DDEBUG_STANDARD MXBeanWeirdParamTest
34 */
35
36import java.util.Map;
37import java.util.List;
38import java.util.ArrayList;
39import java.util.Arrays;
40
41import java.lang.Process;
42import java.lang.management.ManagementFactory;
43
44import javax.management.MBeanServer;
45import javax.management.MBeanServerConnection;
46import javax.management.remote.JMXConnector;
47import javax.management.remote.JMXConnectorFactory;
48import javax.management.remote.JMXConnectorServer;
49import javax.management.remote.JMXConnectorServerFactory;
50import javax.management.remote.JMXServiceURL;
51
52import javax.management.ObjectName;
53import javax.management.openmbean.CompositeType;
54import javax.management.openmbean.CompositeData;
55import javax.management.openmbean.CompositeDataSupport;
56import javax.management.openmbean.OpenType;
57import javax.management.openmbean.SimpleType;
58import javax.management.openmbean.TabularDataSupport;
59import javax.management.openmbean.TabularType;
60
61import jdk.testlibrary.ProcessTools;
62import jdk.testlibrary.JDKToolFinder;
63
64public 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}
278