• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / elemental / 982

29 Apr 2025 08:34PM UTC coverage: 56.409% (+0.007%) from 56.402%
982

push

circleci

adamretter
[feature] Improve README.md badges

28451 of 55847 branches covered (50.94%)

Branch coverage included in aggregate %.

77468 of 131924 relevant lines covered (58.72%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.84
/exist-core/src/main/java/org/exist/management/client/JMXtoXML.java
1
/*
2
 * Elemental
3
 * Copyright (C) 2024, Evolved Binary Ltd
4
 *
5
 * admin@evolvedbinary.com
6
 * https://www.evolvedbinary.com | https://www.elemental.xyz
7
 *
8
 * Use of this software is governed by the Business Source License 1.1
9
 * included in the LICENSE file and at www.mariadb.com/bsl11.
10
 *
11
 * Change Date: 2028-04-27
12
 *
13
 * On the date above, in accordance with the Business Source License, use
14
 * of this software will be governed by the Apache License, Version 2.0.
15
 *
16
 * Additional Use Grant: Production use of the Licensed Work for a permitted
17
 * purpose. A Permitted Purpose is any purpose other than a Competing Use.
18
 * A Competing Use means making the Software available to others in a commercial
19
 * product or service that: substitutes for the Software; substitutes for any
20
 * other product or service we offer using the Software that exists as of the
21
 * date we make the Software available; or offers the same or substantially
22
 * similar functionality as the Software.
23
 *
24
 * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25
 *       The original license header is included below.
26
 *
27
 * =====================================================================
28
 *
29
 * eXist-db Open Source Native XML Database
30
 * Copyright (C) 2001 The eXist-db Authors
31
 *
32
 * info@exist-db.org
33
 * http://www.exist-db.org
34
 *
35
 * This library is free software; you can redistribute it and/or
36
 * modify it under the terms of the GNU Lesser General Public
37
 * License as published by the Free Software Foundation; either
38
 * version 2.1 of the License, or (at your option) any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43
 * Lesser General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU Lesser General Public
46
 * License along with this library; if not, write to the Free Software
47
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
48
 */
49
package org.exist.management.client;
50

51
import java.io.IOException;
52
import java.io.StringWriter;
53

54
import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple;
55
import static java.lang.management.ManagementFactory.CLASS_LOADING_MXBEAN_NAME;
56
import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME;
57
import static java.lang.management.ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME;
58
import static java.lang.management.ManagementFactory.RUNTIME_MXBEAN_NAME;
59
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
60

61
import java.net.MalformedURLException;
62
import java.util.*;
63
import java.util.concurrent.*;
64
import javax.annotation.Nullable;
65
import javax.management.*;
66
import javax.management.openmbean.CompositeData;
67
import javax.management.openmbean.CompositeType;
68
import javax.management.openmbean.TabularData;
69
import javax.management.remote.JMXConnector;
70
import javax.management.remote.JMXConnectorFactory;
71
import javax.management.remote.JMXServiceURL;
72
import javax.xml.XMLConstants;
73
import javax.xml.transform.OutputKeys;
74
import javax.xml.transform.TransformerException;
75

76
import com.evolvedbinary.j8fu.tuple.Tuple2;
77
import org.apache.logging.log4j.LogManager;
78
import org.apache.logging.log4j.Logger;
79
import org.exist.dom.QName;
80
import org.exist.management.Cache;
81
import org.exist.management.CacheManager;
82
import org.exist.management.impl.*;
83
import org.exist.dom.memtree.MemTreeBuilder;
84
import org.exist.start.CompatibleJavaVersionCheck;
85
import org.exist.start.StartException;
86
import org.exist.util.NamedThreadFactory;
87
import org.exist.util.serializer.DOMSerializer;
88
import org.exist.xquery.Expression;
89
import org.w3c.dom.Element;
90
import org.xml.sax.SAXException;
91

92
/**
93
 * Utility class to output database status information from eXist's JMX interface as XML.
94
 *
95
 * @author wolf
96
 */
97
public class JMXtoXML {
1✔
98

99
    private final static Logger LOG = LogManager.getLogger(JMXtoXML.class);
1✔
100

101
    private final static Map<String, ObjectName[]> CATEGORIES = new TreeMap<>();
1✔
102

103
    private static void putCategory(final String categoryName, final String... objectNames) {
104
        final ObjectName[] aryObjectNames = new ObjectName[objectNames.length];
1✔
105
        try {
106
            for (int i = 0; i < aryObjectNames.length; i++) {
1✔
107
                aryObjectNames[i] = new ObjectName(objectNames[i]);
1✔
108
            }
109
        } catch (final MalformedObjectNameException | NullPointerException e) {
1✔
110
            LOG.warn("Error in initialization: {}", e.getMessage(), e);
×
111
        }
112

113
        CATEGORIES.put(categoryName, aryObjectNames);
1✔
114
    }
1✔
115
    static {
116
        // Java
117
        putCategory("memory", MEMORY_MXBEAN_NAME);
1✔
118
        putCategory("runtime", RUNTIME_MXBEAN_NAME);
1✔
119
        putCategory("operatingsystem", OPERATING_SYSTEM_MXBEAN_NAME);
1✔
120
        putCategory("thread", THREAD_MXBEAN_NAME);
1✔
121
        putCategory("classloading", CLASS_LOADING_MXBEAN_NAME);
1✔
122

123
        // eXist cross-instance
124
        putCategory("system", SystemInfo.OBJECT_NAME);
1✔
125

126
        // eXist per-instance
127
        putCategory("instances", Database.getAllInstancesQuery());
1✔
128
        putCategory("locking", LockTable.getAllInstancesQuery());
1✔
129
        putCategory("disk", DiskUsage.getAllInstancesQuery());
1✔
130
        putCategory("collectioncaches", CollectionCache.getAllInstancesQuery());
1✔
131
        putCategory("caches",
1✔
132
                CacheManager.getAllInstancesQuery(),
1✔
133
                Cache.getAllInstancesQuery()
1✔
134
        );
135
        putCategory("binarystreamcaches", BinaryValues.getAllInstancesQuery());
1✔
136
        putCategory("processes", ProcessReport.getAllInstancesQuery());
1✔
137
        putCategory("sanity", SanityReport.getAllInstancesQuery());
1✔
138

139
        // Jetty
140
        putCategory("jetty.threads", "org.eclipse.jetty.util.thread:type=queuedthreadpool,*");
1✔
141
        putCategory("jetty.nio", "org.eclipse.jetty.server.nio:type=selectchannelconnector,id=0");
1✔
142

143
        // Special case: all data
144
        putCategory("all", "org.exist.*:*", "java.lang:*");
1✔
145
    }
146

147
    private static final Properties defaultProperties = new Properties();
1✔
148

149
    static {
150
        defaultProperties.setProperty(OutputKeys.INDENT, "yes");
1✔
151
        defaultProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
1✔
152
    }
153

154
    public static final String JMX_NAMESPACE = "http://exist-db.org/jmx";
155
    public static final String JMX_PREFIX = "jmx";
156

157
    private static final QName ROW_ELEMENT = new QName("row", JMX_NAMESPACE, JMX_PREFIX);
1✔
158
    private static final QName JMX_ELEMENT = new QName("jmx", JMX_NAMESPACE, JMX_PREFIX);
1✔
159
    private static final QName JMX_RESULT = new QName("result", JMX_NAMESPACE, JMX_PREFIX);
1✔
160
    private static final QName JMX_RESULT_TYPE_ATTR = new QName("class", JMX_NAMESPACE, JMX_PREFIX);
1✔
161
    private static final QName JMX_CONNECTION_ATTR = new QName("connection", XMLConstants.NULL_NS_URI);
1✔
162
    private static final QName JMX_ERROR = new QName("error", JMX_NAMESPACE, JMX_PREFIX);
1✔
163
    private static final QName VERSION_ATTR = new QName("version", XMLConstants.NULL_NS_URI);
1✔
164

165
    public static final long PING_TIMEOUT = -99;
166

167
    public static final int VERSION = 1;
1✔
168

169
    private @Nullable List<MBeanServerConnection> connections;
170
    private JMXServiceURL url;
171

172
    /**
173
     * Connect to the local JMX instance.
174
     */
175
    public void connect() {
176
        final List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
1✔
177
        if (!servers.isEmpty()) {
1!
178
            this.connections = new ArrayList<>(servers);
1✔
179
        }
180
    }
1✔
181

182
    /**
183
     * Connect to a remote JMX instance using address and port.
184
     *
185
     * @param address The remote address
186
     * @param port    The report port
187
     * @throws MalformedURLException The RMI url could not be constructed
188
     * @throws IOException           An IO error occurred
189
     */
190
    public void connect(final String address, final int port) throws MalformedURLException, IOException {
191
        this.url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + address + ":" + port + "/jmxrmi");
×
192
        final Map<String, String[]> env = new HashMap<>();
×
193
        final String[] creds = {"guest", "guest"};
×
194
        env.put(JMXConnector.CREDENTIALS, creds);
×
195

196
        final JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
×
197
        this.connections = Collections.singletonList(jmxc.getMBeanServerConnection());
×
198

199
        if (LOG.isDebugEnabled()) {
×
200
            LOG.debug("Connected to JMX server at {}", url.toString());
×
201
        }
202
    }
×
203

204
    /**
205
     * Retrieve JMX output for the given categories and return a string of XML. Valid categories are "memory",
206
     * "instances", "disk", "system", "caches", "locking", "processes", "sanity", "all".
207
     *
208
     * @param categories array of categories to include in the report
209
     * @throws TransformerException in case of serialization errors
210
     * @return string containing an XML report
211
     */
212
    public String generateReport(final String categories[]) throws TransformerException {
213
        final Element root = generateXMLReport(null, categories);
×
214
        final StringWriter writer = new StringWriter();
×
215
        final DOMSerializer streamer = new DOMSerializer(writer, defaultProperties);
×
216
        streamer.serialize(root);
×
217
        return writer.toString();
×
218
    }
219

220
    /**
221
     * Ping the database to see if it is still responsive. This will first try to get a database broker object and if it
222
     * succeeds, run a simple query. If the server does not respond within the given timeout, the method will return an
223
     * error code -99 ({@link JMXtoXML#PING_TIMEOUT}). If there's an error on the server, the return value will be less
224
     * than 0. Otherwise the return value is the response time in milliseconds.
225
     *
226
     * @param instance the name of the database instance (default instance is "exist")
227
     * @param timeout  a timeout in milliseconds
228
     * @return Response time in msec, less than 0 in case of an error on server or PING_TIMEOUT when server does not
229
     * respond in time
230
     */
231
    public long ping(final String instance, final long timeout) {
232
        final long start = System.currentTimeMillis();
×
233
        final ThreadFactory jmxPingFactory = new NamedThreadFactory(instance, "jmx.ping");
×
234
        final ExecutorService executorService = Executors.newSingleThreadExecutor(jmxPingFactory);
×
235

236
        // find the connection and MBean name for the ping
237
        final ObjectName name;
238
        final MBeanServerConnection connection;
239
        try {
240
            name = SanityReport.getName(instance);
×
241
            final List<Tuple2<MBeanServerConnection, Set<ObjectName>>> matches = queryNames(name);
×
242
            if (matches.isEmpty()) {
×
243
                LOG.warn("Unable to locate MBean connection for ping destination");
×
244
                return SanityReport.PING_ERROR;
×
245
            }
246
            connection = matches.get(0)._1;
×
247
        } catch (final MalformedObjectNameException | IOException e) {
×
248
            LOG.warn("Unable to locate MBean connection for ping destination: " + e.getMessage(), e);
×
249
            return SanityReport.PING_ERROR;
×
250
        }
251

252
        final Future<Long> futurePing = executorService.submit(new Ping(connection, name));
×
253

254
        while (true) {
255
            try {
256
                return futurePing.get(timeout, TimeUnit.MILLISECONDS);
×
257
            } catch (final ExecutionException e) {
×
258
                LOG.error(e);
×
259
                return PING_TIMEOUT;
×
260
            } catch (final TimeoutException e) {
×
261
                return PING_TIMEOUT;
×
262
            } catch (final InterruptedException e) {
×
263
                if ((System.currentTimeMillis() - start) >= timeout) {
×
264
                    return PING_TIMEOUT;
×
265
                }
266
                // else will retry in loop
267
            }
268
        }
269
    }
270

271
    private static class Ping implements Callable<Long> {
272
        private final MBeanServerConnection connection;
273
        private final ObjectName name;
274

275
        public Ping(final MBeanServerConnection connection, final ObjectName name) {
×
276
            this.connection = connection;
×
277
            this.name = name;
×
278
        }
×
279

280
        @Override
281
        public Long call() {
282
            try {
283
                return (Long) connection.invoke(name, "ping", new Object[]{Boolean.TRUE}, new String[]{boolean.class.getName()});
×
284
            } catch (final Exception e) {
×
285
                LOG.warn(e.getMessage(), e);
×
286
                return (long) SanityReport.PING_ERROR;
×
287
            }
288
        }
289
    }
290

291
    /**
292
     * Retrieve JMX output for the given categories and return it as an XML DOM. Valid categories are "memory",
293
     * "instances", "disk", "system", "caches", "locking", "processes", "sanity", "all".
294
     *
295
     * @param errcode    an optional error description
296
     * @param categories the categories to generate the report for
297
     * @return xml report
298
     */
299
    public Element generateXMLReport(final String errcode, final String categories[]) {
300
        final MemTreeBuilder builder = new MemTreeBuilder((Expression) null);
1✔
301

302
        try {
303
            builder.startDocument();
1✔
304

305
            builder.startElement(JMX_ELEMENT, null);
1✔
306
            builder.addAttribute(VERSION_ATTR, Integer.toString(VERSION));
1✔
307
            if (url != null) {
1!
308
                builder.addAttribute(JMX_CONNECTION_ATTR, url.toString());
×
309
            }
310

311
            if (errcode != null) {
1!
312
                builder.startElement(JMX_ERROR, null);
×
313
                builder.characters(errcode);
×
314
                builder.endElement();
×
315
            }
316

317
            for (final String category : categories) {
1✔
318
                final ObjectName[] names = CATEGORIES.get(category);
1✔
319
                for (final ObjectName name : names) {
1✔
320
                    queryMBeans(builder, name);
1✔
321
                }
322
            }
323

324
            builder.endElement();
1✔
325

326
            builder.endDocument();
1✔
327

328
        } catch (final Exception e) {
1✔
329
            e.printStackTrace();
×
330
            LOG.warn("Could not generate XML report from JMX: {}", e.getMessage());
×
331
        }
332
        return (Element) builder.getDocument().getNode(1);
1✔
333
    }
334

335
    public String getDataDir() {
336
        try {
337
            final List<Tuple2<MBeanServerConnection, Object>> attributeValues = getAttribute(new ObjectName("org.exist.management.exist:type=DiskUsage"), "DataDirectory");
1✔
338
            if (attributeValues.isEmpty()) {
1!
339
                return null;
×
340
            }
341
            final Object dir = attributeValues.get(0)._2;
1✔
342
            return dir == null ? null : dir.toString();
1!
343
        } catch (final MalformedObjectNameException | IOException e) {
×
344
            return null;
×
345
        }
346
    }
347

348
    public Element invoke(final String name, final String operation, final String[] args) throws InstanceNotFoundException, MalformedObjectNameException, MBeanException, IOException, ReflectionException, IntrospectionException {
349
        final ObjectName objectName = new ObjectName(name);
×
350
        final List<Tuple2<MBeanServerConnection, MBeanInfo>> mbeanInfos = getMBeanInfo(objectName);
×
351
        if (mbeanInfos.isEmpty()) {
×
352
            return null;
×
353
        }
354

355
        final MBeanServerConnection conn = mbeanInfos.get(0)._1;
×
356
        final MBeanInfo info = mbeanInfos.get(0)._2;
×
357

358
        final MBeanOperationInfo[] operations = info.getOperations();
×
359
        for (final MBeanOperationInfo op : operations) {
×
360
            if (operation.equals(op.getName())) {
×
361
                final MBeanParameterInfo[] sig = op.getSignature();
×
362
                final Object[] params = new Object[sig.length];
×
363
                final String[] types = new String[sig.length];
×
364
                for (int i = 0; i < sig.length; i++) {
×
365
                    String type = sig[i].getType();
×
366
                    types[i] = type;
×
367
                    params[i] = mapParameter(type, args[i]);
×
368
                }
369
                final Object result = conn.invoke(objectName, operation, params, types);
×
370

371
                final MemTreeBuilder builder = new MemTreeBuilder((Expression) null);
×
372

373
                try {
374
                    builder.startDocument();
×
375

376
                    builder.startElement(JMX_ELEMENT, null);
×
377
                    builder.addAttribute(VERSION_ATTR, Integer.toString(VERSION));
×
378
                    if (url != null) {
×
379
                        builder.addAttribute(JMX_CONNECTION_ATTR, url.toString());
×
380
                    }
381

382
                    builder.startElement(JMX_RESULT, null);
×
383
                    builder.addAttribute(JMX_RESULT_TYPE_ATTR, op.getReturnType());
×
384
                    serializeObject(builder, result);
×
385
                    builder.endElement();
×
386

387
                    builder.endElement();
×
388

389
                    builder.endDocument();
×
390

391
                } catch (final Exception e) {
×
392
                    e.printStackTrace();
×
393
                    LOG.warn("Could not generate XML report from JMX: {}", e.getMessage());
×
394
                }
395
                return (Element) builder.getDocument().getNode(1);
×
396
            }
397
        }
398
        return null;
×
399
    }
400

401
    private List<Tuple2<MBeanServerConnection, Set<ObjectName>>> queryNames(final ObjectName nameQuery) throws IOException {
402
        final List<Tuple2<MBeanServerConnection, Set<ObjectName>>> matchedNames = new ArrayList<>();
1✔
403
        if (connections != null ) {
1!
404
            for (final MBeanServerConnection connection : connections) {
1✔
405
                final Set<ObjectName> matches = connection.queryNames(nameQuery, null);
1✔
406
                if (!matches.isEmpty()) {
1!
407
                    matchedNames.add(Tuple(connection, matches));
1✔
408
                }
409
            }
410
        }
411
        return matchedNames;
1✔
412
    }
413

414
    private List<Tuple2<MBeanServerConnection, Object>> getAttribute(final ObjectName objectName, final String attributeName) throws IOException {
415
        final List<Tuple2<MBeanServerConnection, Object>> attributeValues = new ArrayList<>();
1✔
416
        if (connections != null ) {
1!
417
            for (final MBeanServerConnection connection : connections) {
1✔
418
                try {
419
                    attributeValues.add(Tuple(connection, connection.getAttribute(objectName, attributeName)));
1✔
420
                } catch (final AttributeNotFoundException | MBeanException | InstanceNotFoundException | ReflectionException e) {
1✔
421
                    // no-op
422
                }
423
            }
424
        }
425
        return attributeValues;
1✔
426
    }
427

428
    private List<Tuple2<MBeanServerConnection, MBeanInfo>> getMBeanInfo(final ObjectName objectName) throws IOException {
429
        final List<Tuple2<MBeanServerConnection, MBeanInfo>> mbeanInfos = new ArrayList<>();
×
430
        if (connections != null ) {
×
431
            for (final MBeanServerConnection connection : connections) {
×
432
                try {
433
                    mbeanInfos.add(Tuple(connection, connection.getMBeanInfo(objectName)));
×
434
                } catch (final IntrospectionException | InstanceNotFoundException | ReflectionException e) {
×
435
                    // no-op
436
                }
437
            }
438
        }
439
        return mbeanInfos;
×
440
    }
441

442
    private void queryMBeans(final MemTreeBuilder builder, final ObjectName nameQuery)
443
            throws IOException, InstanceNotFoundException, IntrospectionException, ReflectionException, NullPointerException {
444

445
        final List<Tuple2<MBeanServerConnection, Set<ObjectName>>> matchedNames = queryNames(nameQuery);
1✔
446

447
        for (final Tuple2<MBeanServerConnection, Set<ObjectName>> matchedName : matchedNames) {
1✔
448
            final MBeanServerConnection connection = matchedName._1;
1✔
449
            for (final ObjectName name : matchedName._2) {
1✔
450
                final MBeanInfo info = connection.getMBeanInfo(name);
1✔
451
                String className = info.getClassName().replace('$', '.');
1✔
452
                final int p = className.lastIndexOf('.');
1✔
453
                if (p > -1 && p + 1 < className.length()) {
1!
454
                    className = className.substring(p + 1);
1✔
455
                }
456

457
                final QName qname = new QName(className, JMX_NAMESPACE, JMX_PREFIX);
1✔
458
                builder.startElement(qname, null);
1✔
459
                builder.addAttribute(new QName("name", XMLConstants.NULL_NS_URI), name.toString());
1✔
460

461
                final MBeanAttributeInfo[] beanAttribs = info.getAttributes();
1✔
462
                for (MBeanAttributeInfo beanAttrib : beanAttribs) {
1✔
463
                    if (beanAttrib.isReadable()) {
1!
464
                        try {
465
                            final QName attrQName = new QName(beanAttrib.getName(), JMX_NAMESPACE, JMX_PREFIX);
1✔
466
                            final Object attrib = connection.getAttribute(name, beanAttrib.getName());
1✔
467

468
                            builder.startElement(attrQName, null);
1✔
469
                            serializeObject(builder, attrib);
1✔
470
                            builder.endElement();
1✔
471
                        } catch (final Exception e) {
1✔
472
                            LOG.debug("exception caught: {}", e.getMessage(), e);
1✔
473
                        }
474
                    }
475
                }
476
                builder.endElement();
1✔
477
            }
478
        }
479
    }
1✔
480

481
    private void serializeObject(final MemTreeBuilder builder, final Object object) throws SAXException {
482
        if (object == null) {
1✔
483
            return;
1✔
484
        }
485

486
        if (object instanceof TabularData) {
1✔
487
            serialize(builder, (TabularData) object);
1✔
488

489
        } else if (object instanceof CompositeData[]) {
1✔
490
            serialize(builder, (CompositeData[]) object);
1✔
491
        } else if (object instanceof CompositeData) {
1✔
492
            serialize(builder, (CompositeData) object);
1✔
493

494
        } else if (object instanceof Object[]) {
1✔
495
            serialize(builder, (Object[]) object);
1✔
496

497
        } else {
1✔
498
            builder.characters(object.toString());
1✔
499
        }
500
    }
1✔
501

502
    private void serialize(final MemTreeBuilder builder, final Object[] data) throws SAXException {
503
        for (final Object o : data) {
1✔
504
            serializeObject(builder, o);
1✔
505
        }
506
    }
1✔
507

508
    private void serialize(final MemTreeBuilder builder, final CompositeData data) throws SAXException {
509
        final CompositeType type = data.getCompositeType();
1✔
510
        for (final String key : type.keySet()) {
1✔
511
            final QName qname = new QName(key, JMX_NAMESPACE, JMX_PREFIX);
1✔
512
            builder.startElement(qname, null);
1✔
513
            serializeObject(builder, data.get(key));
1✔
514
            builder.endElement();
1✔
515
        }
516
    }
1✔
517

518
    private void serialize(final MemTreeBuilder builder, final TabularData data) throws SAXException {
519
        final CompositeType rowType = data.getTabularType().getRowType();
1✔
520
        for (final Object rowObj : data.values()) {
1✔
521
            final CompositeData row = (CompositeData) rowObj;
1✔
522
            builder.startElement(ROW_ELEMENT, null);
1✔
523
            for (final String key : rowType.keySet()) {
1✔
524
                final Object columnData = row.get(key);
1✔
525
                final QName columnQName = new QName(key, JMX_NAMESPACE, JMX_PREFIX);
1✔
526
                builder.startElement(columnQName, null);
1✔
527
                serializeObject(builder, columnData);
1✔
528
                builder.endElement();
1✔
529
            }
530
            builder.endElement();
1✔
531
        }
532
    }
1✔
533

534
    private void serialize(final MemTreeBuilder builder, final CompositeData[] array) throws SAXException {
535
        for (final CompositeData data : array) {
1!
536
            builder.startElement(ROW_ELEMENT, null);
×
537
            serialize(builder, data);
×
538
            builder.endElement();
×
539
        }
540
    }
1✔
541

542
    private Object mapParameter(final String type, final String value) {
543
        if (type.equals("int") || type.equals(Integer.class.getName())) {
×
544
            return Integer.parseInt(value);
×
545
        } else if (type.equals("long") || type.equals(Long.class.getName())) {
×
546
            return Long.parseLong(value);
×
547
        } else if (type.equals("float") || type.equals(Float.class.getName())) {
×
548
            return Float.parseFloat(value);
×
549
        } else if (type.equals("double") || type.equals(Double.class.getName())) {
×
550
            return Double.parseDouble(value);
×
551
        } else if (type.equals("boolean") || type.equals(Boolean.class.getName())) {
×
552
            return Boolean.parseBoolean(value);
×
553
        } else {
554
            return value;
×
555
        }
556
    }
557

558
    /**
559
     * @param args program arguments
560
     */
561
    public static void main(final String[] args) {
562
        try {
563
            CompatibleJavaVersionCheck.checkForCompatibleJavaVersion();
×
564
        } catch (final StartException e) {
×
565
            if (e.getMessage() != null && !e.getMessage().isEmpty()) {
×
566
                System.err.println(e.getMessage());
×
567
            }
568
            System.exit(e.getErrorCode());
×
569
        }
570

571
        final JMXtoXML client = new JMXtoXML();
×
572
        try {
573
            client.connect("localhost", 1099);
×
574
            System.out.println(client.generateReport(args));
×
575
        } catch (final IOException | TransformerException e) {
×
576
            e.printStackTrace();
×
577
        }
578
    }
×
579
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc