aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/javax/management/namespace/JMXDomain.java
blob: bff3c1370624db19ab97825f470253407c1d00c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/*
 * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package javax.management.namespace;

import java.io.IOException;
import javax.management.ListenerNotFoundException;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;


import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

/**
 * A special {@link JMXNamespace} that can handle part of
 * the MBeanServer local name space.
 * <p>
 * A {@code JMXDomain} makes a domain <i>X</i> of a
 * {@linkplain #getSourceServer() source MBean server} appear in the same domain
 * <i>X</i> of a containing {@code MBeanServer} in which the
 * {@code JMXDomain} MBean {@linkplain #getMBeanServer() is registered}.
 * </p>
 * <p>
 * The JMX infrastructure of the containing {@code MBeanServer} takes care of
 * routing all calls to MBeans whose names have domain <i>X</i> to the
 * {@linkplain #getSourceServer() source MBean server} exported by the
 * {@code JMXDomain} MBean in charge of domain <i>X</i>.
 * </p>
 * <p>
 * The {@linkplain #getSourceServer() source MBean server} of a {@code JMXDomain}
 * can, but need not be a regular {@code MBeanServer} created through
 * the {@link javax.management.MBeanServerFactory}. It could also be,
 * for instance, an instance of a subclass of {@link MBeanServerSupport},
 * or a custom object implementing the {@link MBeanServer} interface.
 * </p>
 *
 * <h4>Differences between {@code JMXNamespace} and {@code JMXDomain}</h4>
 *
 * <p>
 * A {@code JMXDomain} is a special kind of {@code JMXNamespace}.
 * A {@code JMXNamespace} such as {@code foo//} is triggered by an
 * {@code ObjectName} that begins with the string {@code foo//}, for example
 * {@code foo//bar:type=Baz}.  A {@code JMXDomain} such as {@code foo} is
 * triggered by an {@code ObjectName} with that exact domain, for example
 * {@code foo:type=Baz}.  A client can immediately see that an MBean is
 * handled by a {@code JMXNamespace} because of the {@code //} in the name.
 * A client cannot see whether a name such as {@code foo:type=Baz} is an
 * ordinary MBean or is handled by a {@code JMXDomain}.
 * </p>
 *
 * <p>
 * A {@linkplain MBeanServer#queryNames query} on the containing {@code
 * MBeanserver} will return all MBeans from the {@code JMXDomain} that match
 * the query.  In particular, {@code queryNames(null, null)} will return all
 * MBeans including those from {@code JMXDomain} domains.  On the other hand,
 * a query will not include MBeans from a {@code JMXNamespace} unless the
 * {@code ObjectName} pattern in the query starts with the name of that
 * namespace.
 * </p>
 *
 * <h4 id="security">Permission checks</h4>
 *
 * <p>
 * When a JMXDomain MBean is registered in a containing
 * MBean server created through the default {@link
 * javax.management.MBeanServerBuilder}, and if a {@link
 * SecurityManager SecurityManager} is
 * {@linkplain System#getSecurityManager() present}, the containing MBeanServer will
 * check an {@link javax.management.MBeanPermission} before invoking
 * any method on the {@linkplain #getSourceServer() source MBeanServer} of the
 * JMXDomain.
 * </p>
 *
 * <p>First, if there is no security manager ({@link
 * System#getSecurityManager()} is null), that containing
 * {@code MBeanServer} is free not to make any checks.
 * </p>
 *
 * <p>
 * Assuming that there is a security manager, or that the
 * implementation chooses to make checks anyway, the containing
 * {@code MBeanServer} will perform
 * {@link javax.management.MBeanPermission MBeanPermission} checks
 * for access to the MBeans in domain <i>X</i> handled by a {@code JMXDomain}
 * in the same way that it would do for MBeans registered in its own local
 * repository, and as <a href="../MBeanServer.html#security">described in
 * the MBeanServer interface</a>, with the following exceptions:
 * </p>
 *
 * <p>
 * For those permissions that require a {@code className}, the
 * <code>className</code> is the
 * string returned by {@link #getSourceServer() getSourceServer()}.
 * {@link MBeanServer#getObjectInstance(ObjectName)
 * getObjectInstance(mbeanName)}.
 * {@link javax.management.ObjectInstance#getClassName() getClassName()},
 * except for {@code createMBean} and {@code registerMBean} operations,
 * for which the permission checks are performed as follows:
 * </p>
 * <ul>
 * <li><p>For {@code createMBean} operations, the {@code className} of the
 * permission you need is the {@code className} passed as first parameter
 * to {@code createMBean}.</p>
 *
 * <li><p>For {@code registerMBean} operations, the {@code className} of the
 * permission you need is the name of the class of the mbean object, as
 * returned by {@code mbean.getClass().getClassName()}, where
 * {@code mbean} is the mbean reference passed as first parameter
 * to {@code registerMBean}.</p>
 *
 * <li><p>In addition, for {@code createMBean} and {@code registerMBean}, the
 * permission you need is checked with the {@linkplain ObjectName object name} of
 * the mbean that is passed as second parameter to the {@code createMBean} or
 * {@code registerMBean} operation.
 * </p>
 *
 * <li><p>Contrarily to what is done for regular MBeans registered in the
 *     MBeanServer local repository, the containing MBeanServer will not
 *     check the {@link javax.management.MBeanTrustPermission#MBeanTrustPermission(String)
 *     MBeanTrustPermission("register")} against the protection domain
 *     of the MBean's class. This check can be performed by the
 *     {@linkplain #getSourceServer source MBean server} implementation,
 *     if necessary.
 * </p>
 * </ul>
 *
 * <p>If a security check fails, the method throws {@link
 * SecurityException}.</p>
 *
 * <p>For methods that can throw {@link InstanceNotFoundException},
 * this exception is thrown for a non-existent MBean, regardless of
 * permissions.  This is because a non-existent MBean has no
 * <code>className</code>.</p>
 *
 * All these checks are performed by the containing {@code MBeanServer},
 * before accessing the JMXDomain {@linkplain #getSourceServer source MBean server}.
 * The implementation of the JMXDomain {@linkplain #getSourceServer source MBean
 * server} is free to make any additional checks. In fact, if the JMXDomain
 * {@linkplain #getSourceServer source MBean server} is an {@code MBeanServer}
 * obtained through the {@link javax.management.MBeanServerFactory}, it will
 * again make permission checks as described in the
 * <a href="../MBeanServer.html#security">MBeanServer</a> interface.
 *
 * <p>See the <a href="../MBeanServer.html#security">MBeanServer</a> interface
 * for more details on permission checks.</p>
 *
 * @since 1.7
 */
public class JMXDomain extends JMXNamespace {


    /**
     * This constant contains the value of the {@code type}
     * key used in defining a standard JMXDomain MBean object name.
     * By definition, a standard JMXDomain MBean object name must be of
     * the form:
     * <pre>
     * {@code "<domain>:"}+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
     * </pre>
     */
    public static final String TYPE = "JMXDomain";

    /**
     * This constant contains the value of the standard
     * {@linkplain javax.management.ObjectName#getKeyPropertyListString() key
     * property list string} for JMXDomain MBean object names.
     * By definition, a standard JMXDomain MBean object name must be of
     * the form:
     * <pre>
     * {@code <domain>}+":"+{@value javax.management.namespace.JMXDomain#TYPE_ASSIGNMENT}
     * </pre>
     */
    public static final String TYPE_ASSIGNMENT = "type="+TYPE;



    /**
     * Creates a new instance of JMXDomain. The MBeans contained in this
     * domain are handled by the {@code virtualServer} object given to
     * this constructor. Frequently, this will be an instance of
     * {@link MBeanServerSupport}.
     * @param virtualServer The virtual server that acts as a container for
     *        the MBeans handled by this JMXDomain object. Frequently, this will
     *        be an instance of {@link MBeanServerSupport}
     * @see JMXNamespace#JMXNamespace(MBeanServer)
     */
    public JMXDomain(MBeanServer virtualServer) {
        super(virtualServer);
    }

    /**
     * Return the name of domain handled by this JMXDomain.
     * @return the domain handled by this JMXDomain.
     * @throws IOException - if the domain cannot be determined,
     *         for instance, if the MBean is not registered yet.
     */
    @Override
    public final String getDefaultDomain() {
        final ObjectName name = getObjectName();
        if (name == null)
            throw new IllegalStateException("DefaultDomain is not yet known");
        final String dom = name.getDomain();
        return dom;
    }

    /**
     * Returns a singleton array, containing the only domain handled by
     * this JMXDomain object. This is
     * {@code new String[] {getDefaultDomain()}}.
     * @return the only domain handled by this JMXDomain.
     * @throws IOException if the domain cannot be determined,
     *         for instance, if the MBean is not registered yet.
     * @see #getDefaultDomain()
     */
    @Override
    public final String[] getDomains() {
        return new String[] {getDefaultDomain()};
    }

    /**
     * This method returns the number of MBeans in the domain handled
     * by this JMXDomain object. The default implementation is:
     * <pre>
     *    getSourceServer().queryNames(
     *        new ObjectName(getObjectName().getDomain()+":*"), null).size();
     * </pre>
     * If this JMXDomain is not yet registered, this method returns 0.
     * Subclasses can override the above behavior and provide a better
     * implementation.
     * <p>
     * The getMBeanCount() method is called when computing the number
     * of MBeans in the {@linkplain #getMBeanServer() containing MBeanServer}.
     * @return the number of MBeans in this domain, or 0.
     */
    @Override
    public Integer getMBeanCount()  {
        final ObjectName name = getObjectName();
        if (name == null) return 0;
        try {
            return getSourceServer().
               queryNames(ObjectName.WILDCARD.withDomain(name.getDomain()),
               null).size();
        } catch (RuntimeException x) {
            throw x;
        } catch (Exception x) {
            throw new RuntimeException("Unexpected exception: "+x,x);
        }
    }



    /**
     * Return a canonical handler name for the provided local
     * <var>domain</var> name, or null if the provided domain name is
     * {@code null}.
     * If not null, the handler name returned will be
     * {@code domain+":type="+}{@link #TYPE TYPE}, for example
     * {@code foo:type=JMXDomain}.
     * @param domain A domain name
     * @return a canonical ObjectName for a domain handler.
     * @throws IllegalArgumentException if the provided
     *         <var>domain</var> is not valid - e.g it contains "//".
     */
    public static ObjectName getDomainObjectName(String domain) {
        if (domain == null) return null;
        if (domain.contains(NAMESPACE_SEPARATOR))
            throw new IllegalArgumentException(domain);
        try {
            return ObjectName.getInstance(domain, "type", TYPE);
        } catch (MalformedObjectNameException x) {
            throw new IllegalArgumentException(domain,x);
        }
    }


    /**
     * Validate the ObjectName supplied to preRegister.
     * This method is introduced to allow standard subclasses to use
     * an alternate naming scheme. For instance - if we want to
     * reuse JMXNamespace in order to implement sessions...
     * It is however only available for subclasses in this package.
     **/
    @Override
    ObjectName validateHandlerName(ObjectName suppliedName) {
        if (suppliedName == null)
            throw new IllegalArgumentException("Must supply a valid name");
        final String dirName = JMXNamespaces.
                normalizeNamespaceName(suppliedName.getDomain());
        final ObjectName handlerName = getDomainObjectName(dirName);
        if (!suppliedName.equals(handlerName))
            throw new IllegalArgumentException("invalid name space name: "+
                        suppliedName);

        return suppliedName;
    }

    /**
     * This method is called by the JMX framework to register a
     * NotificationListener that will forward {@linkplain
     * javax.management.MBeanServerNotification mbean server notifications}
     * through the delegate of the {@linkplain #getMBeanServer()
     * containing MBeanServer}.
     * The default implementation of this method is to call
     * <pre>
     *    getSourceServer().addNotificationListener(
     *           MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
     * </pre>
     * Subclasses can redefine this behavior if needed. In particular,
     * subclasses can send their own instances of {@link
     * javax.management.MBeanServerNotification} by calling
     * {@code listener.handleNotification()}.
     *
     * @param listener The MBeanServerNotification listener for this domain.
     * @param filter   A notification filter.
     */
    public void addMBeanServerNotificationListener(
            NotificationListener listener, NotificationFilter filter) {
        try {
            getSourceServer().addNotificationListener(
                MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
        } catch(InstanceNotFoundException x) {
            throw new UnsupportedOperationException(
                    "Unexpected exception: " +
                    "Emission of MBeanServerNotification disabled.", x);
        }
    }

    /**
     * This method is called by the JMX framework to remove the
     * NotificationListener that was added with {@link
     * #addMBeanServerNotificationListener addMBeanServerNotificationListener}.
     * The default implementation of this method is to call
     * <pre>
     *    getSourceServer().removeNotificationListener(
     *           MBeanServerDelegate.DELEGATE_NAME, listener);
     * </pre>
     * Subclasses can redefine this behavior if needed.
     *
     * @param listener The MBeanServerNotification listener for this domain.
     * @throws ListenerNotFoundException if the listener is not found.
     */
    public void removeMBeanServerNotificationListener(
            NotificationListener listener)
            throws ListenerNotFoundException {
        try {
            getSourceServer().removeNotificationListener(
                MBeanServerDelegate.DELEGATE_NAME, listener);
        } catch(InstanceNotFoundException x) {
            throw new UnsupportedOperationException(
                    "Unexpected exception: " +
                    "Emission of MBeanServerNotification disabled.", x);
        }
    }

}