Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java
41162 views
1
/*
2
* Copyright (c) 2002, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.management.remote.rmi;
27
28
import com.sun.jmx.remote.internal.ArrayNotificationBuffer;
29
import com.sun.jmx.remote.internal.NotificationBuffer;
30
import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
31
import com.sun.jmx.remote.util.ClassLogger;
32
33
import java.io.Closeable;
34
import java.io.IOException;
35
import java.lang.ref.WeakReference;
36
import java.rmi.Remote;
37
import java.rmi.server.RemoteServer;
38
import java.rmi.server.ServerNotActiveException;
39
import java.security.Principal;
40
import java.util.ArrayList;
41
import java.util.Collections;
42
import java.util.Iterator;
43
import java.util.List;
44
import java.util.Map;
45
import java.util.Set;
46
47
import javax.management.MBeanServer;
48
import javax.management.remote.JMXAuthenticator;
49
import javax.management.remote.JMXConnectorServer;
50
import javax.security.auth.Subject;
51
52
/**
53
* <p>An RMI object representing a connector server. Remote clients
54
* can make connections using the {@link #newClient(Object)} method. This
55
* method returns an RMI object representing the connection.</p>
56
*
57
* <p>User code does not usually reference this class directly.
58
* RMI connection servers are usually created with the class {@link
59
* RMIConnectorServer}. Remote clients usually create connections
60
* either with {@link javax.management.remote.JMXConnectorFactory}
61
* or by instantiating {@link RMIConnector}.</p>
62
*
63
* <p>This is an abstract class. Concrete subclasses define the
64
* details of the client connection objects.</p>
65
*
66
* @since 1.5
67
*/
68
public abstract class RMIServerImpl implements Closeable, RMIServer {
69
/**
70
* <p>Constructs a new <code>RMIServerImpl</code>.</p>
71
*
72
* @param env the environment containing attributes for the new
73
* <code>RMIServerImpl</code>. Can be null, which is equivalent
74
* to an empty Map.
75
*/
76
public RMIServerImpl(Map<String,?> env) {
77
this.env = (env == null) ? Collections.<String,Object>emptyMap() : env;
78
}
79
80
void setRMIConnectorServer(RMIConnectorServer connServer)
81
throws IOException {
82
this.connServer = connServer;
83
}
84
85
/**
86
* <p>Exports this RMI object.</p>
87
*
88
* @exception IOException if this RMI object cannot be exported.
89
*/
90
protected abstract void export() throws IOException;
91
92
/**
93
* Returns a remotable stub for this server object.
94
* @return a remotable stub.
95
* @exception IOException if the stub cannot be obtained - e.g the
96
* RMIServerImpl has not been exported yet.
97
**/
98
public abstract Remote toStub() throws IOException;
99
100
/**
101
* <p>Sets the default <code>ClassLoader</code> for this connector
102
* server. New client connections will use this classloader.
103
* Existing client connections are unaffected.</p>
104
*
105
* @param cl the new <code>ClassLoader</code> to be used by this
106
* connector server.
107
*
108
* @see #getDefaultClassLoader
109
*/
110
public synchronized void setDefaultClassLoader(ClassLoader cl) {
111
this.cl = cl;
112
}
113
114
/**
115
* <p>Gets the default <code>ClassLoader</code> used by this connector
116
* server.</p>
117
*
118
* @return the default <code>ClassLoader</code> used by this
119
* connector server.
120
*
121
* @see #setDefaultClassLoader
122
*/
123
public synchronized ClassLoader getDefaultClassLoader() {
124
return cl;
125
}
126
127
/**
128
* <p>Sets the <code>MBeanServer</code> to which this connector
129
* server is attached. New client connections will interact
130
* with this <code>MBeanServer</code>. Existing client connections are
131
* unaffected.</p>
132
*
133
* @param mbs the new <code>MBeanServer</code>. Can be null, but
134
* new client connections will be refused as long as it is.
135
*
136
* @see #getMBeanServer
137
*/
138
public synchronized void setMBeanServer(MBeanServer mbs) {
139
this.mbeanServer = mbs;
140
}
141
142
/**
143
* <p>The <code>MBeanServer</code> to which this connector server
144
* is attached. This is the last value passed to {@link
145
* #setMBeanServer} on this object, or null if that method has
146
* never been called.</p>
147
*
148
* @return the <code>MBeanServer</code> to which this connector
149
* is attached.
150
*
151
* @see #setMBeanServer
152
*/
153
public synchronized MBeanServer getMBeanServer() {
154
return mbeanServer;
155
}
156
157
public String getVersion() {
158
// Expected format is: "protocol-version implementation-name"
159
try {
160
return "1.0 java_runtime_" +
161
System.getProperty("java.runtime.version");
162
} catch (SecurityException e) {
163
return "1.0 ";
164
}
165
}
166
167
/**
168
* <p>Creates a new client connection. This method calls {@link
169
* #makeClient makeClient} and adds the returned client connection
170
* object to an internal list. When this
171
* <code>RMIServerImpl</code> is shut down via its {@link
172
* #close()} method, the {@link RMIConnection#close() close()}
173
* method of each object remaining in the list is called.</p>
174
*
175
* <p>The fact that a client connection object is in this internal
176
* list does not prevent it from being garbage collected.</p>
177
*
178
* @param credentials this object specifies the user-defined
179
* credentials to be passed in to the server in order to
180
* authenticate the caller before creating the
181
* <code>RMIConnection</code>. Can be null.
182
*
183
* @return the newly-created <code>RMIConnection</code>. This is
184
* usually the object created by <code>makeClient</code>, though
185
* an implementation may choose to wrap that object in another
186
* object implementing <code>RMIConnection</code>.
187
*
188
* @exception IOException if the new client object cannot be
189
* created or exported.
190
*
191
* @exception SecurityException if the given credentials do not allow
192
* the server to authenticate the user successfully.
193
*
194
* @exception IllegalStateException if {@link #getMBeanServer()}
195
* is null.
196
*/
197
public RMIConnection newClient(Object credentials) throws IOException {
198
return doNewClient(credentials);
199
}
200
201
/**
202
* This method could be overridden by subclasses defined in this package
203
* to perform additional operations specific to the underlying transport
204
* before creating the new client connection.
205
*/
206
RMIConnection doNewClient(Object credentials) throws IOException {
207
final boolean tracing = logger.traceOn();
208
209
if (tracing) logger.trace("newClient","making new client");
210
211
if (getMBeanServer() == null)
212
throw new IllegalStateException("Not attached to an MBean server");
213
214
Subject subject = null;
215
JMXAuthenticator authenticator =
216
(JMXAuthenticator) env.get(JMXConnectorServer.AUTHENTICATOR);
217
if (authenticator == null) {
218
/*
219
* Create the JAAS-based authenticator only if authentication
220
* has been enabled
221
*/
222
if (env.get("jmx.remote.x.password.file") != null ||
223
env.get("jmx.remote.x.login.config") != null) {
224
authenticator = new JMXPluggableAuthenticator(env);
225
}
226
}
227
if (authenticator != null) {
228
if (tracing) logger.trace("newClient","got authenticator: " +
229
authenticator.getClass().getName());
230
try {
231
subject = authenticator.authenticate(credentials);
232
} catch (SecurityException e) {
233
logger.trace("newClient", "Authentication failed: " + e);
234
throw e;
235
}
236
}
237
238
if (tracing) {
239
if (subject != null)
240
logger.trace("newClient","subject is not null");
241
else logger.trace("newClient","no subject");
242
}
243
244
final String connectionId = makeConnectionId(getProtocol(), subject);
245
246
if (tracing)
247
logger.trace("newClient","making new connection: " + connectionId);
248
249
RMIConnection client = makeClient(connectionId, subject);
250
251
dropDeadReferences();
252
WeakReference<RMIConnection> wr = new WeakReference<RMIConnection>(client);
253
synchronized (clientList) {
254
clientList.add(wr);
255
}
256
257
connServer.connectionOpened(connectionId, "Connection opened", null);
258
259
synchronized (clientList) {
260
if (!clientList.contains(wr)) {
261
// can be removed only by a JMXConnectionNotification listener
262
throw new IOException("The connection is refused.");
263
}
264
}
265
266
if (tracing)
267
logger.trace("newClient","new connection done: " + connectionId );
268
269
return client;
270
}
271
272
/**
273
* <p>Creates a new client connection. This method is called by
274
* the public method {@link #newClient(Object)}.</p>
275
*
276
* @param connectionId the ID of the new connection. Every
277
* connection opened by this connector server will have a
278
* different ID. The behavior is unspecified if this parameter is
279
* null.
280
*
281
* @param subject the authenticated subject. Can be null.
282
*
283
* @return the newly-created <code>RMIConnection</code>.
284
*
285
* @exception IOException if the new client object cannot be
286
* created or exported.
287
*/
288
protected abstract RMIConnection makeClient(String connectionId,
289
Subject subject)
290
throws IOException;
291
292
/**
293
* <p>Closes a client connection made by {@link #makeClient makeClient}.
294
*
295
* @param client a connection previously returned by
296
* <code>makeClient</code> on which the <code>closeClient</code>
297
* method has not previously been called. The behavior is
298
* unspecified if these conditions are violated, including the
299
* case where <code>client</code> is null.
300
*
301
* @exception IOException if the client connection cannot be
302
* closed.
303
*/
304
protected abstract void closeClient(RMIConnection client)
305
throws IOException;
306
307
/**
308
* <p>Returns the protocol string for this object. The string is
309
* <code>rmi</code> for RMI/JRMP.
310
*
311
* @return the protocol string for this object.
312
*/
313
protected abstract String getProtocol();
314
315
/**
316
* <p>Method called when a client connection created by {@link
317
* #makeClient makeClient} is closed. A subclass that defines
318
* <code>makeClient</code> must arrange for this method to be
319
* called when the resultant object's {@link RMIConnection#close()
320
* close} method is called. This enables it to be removed from
321
* the <code>RMIServerImpl</code>'s list of connections. It is
322
* not an error for <code>client</code> not to be in that
323
* list.</p>
324
*
325
* <p>After removing <code>client</code> from the list of
326
* connections, this method calls {@link #closeClient
327
* closeClient(client)}.</p>
328
*
329
* @param client the client connection that has been closed.
330
*
331
* @exception IOException if {@link #closeClient} throws this
332
* exception.
333
*
334
* @exception NullPointerException if <code>client</code> is null.
335
*/
336
protected void clientClosed(RMIConnection client) throws IOException {
337
final boolean debug = logger.debugOn();
338
339
if (debug) logger.trace("clientClosed","client="+client);
340
341
if (client == null)
342
throw new NullPointerException("Null client");
343
344
synchronized (clientList) {
345
dropDeadReferences();
346
for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
347
it.hasNext(); ) {
348
WeakReference<RMIConnection> wr = it.next();
349
if (wr.get() == client) {
350
it.remove();
351
break;
352
}
353
}
354
/* It is not a bug for this loop not to find the client. In
355
our close() method, we remove a client from the list before
356
calling its close() method. */
357
}
358
359
if (debug) logger.trace("clientClosed", "closing client.");
360
closeClient(client);
361
362
if (debug) logger.trace("clientClosed", "sending notif");
363
connServer.connectionClosed(client.getConnectionId(),
364
"Client connection closed", null);
365
366
if (debug) logger.trace("clientClosed","done");
367
}
368
369
/**
370
* <p>Closes this connection server. This method first calls the
371
* {@link #closeServer()} method so that no new client connections
372
* will be accepted. Then, for each remaining {@link
373
* RMIConnection} object returned by {@link #makeClient
374
* makeClient}, its {@link RMIConnection#close() close} method is
375
* called.</p>
376
*
377
* <p>The behavior when this method is called more than once is
378
* unspecified.</p>
379
*
380
* <p>If {@link #closeServer()} throws an
381
* <code>IOException</code>, the individual connections are
382
* nevertheless closed, and then the <code>IOException</code> is
383
* thrown from this method.</p>
384
*
385
* <p>If {@link #closeServer()} returns normally but one or more
386
* of the individual connections throws an
387
* <code>IOException</code>, then, after closing all the
388
* connections, one of those <code>IOException</code>s is thrown
389
* from this method. If more than one connection throws an
390
* <code>IOException</code>, it is unspecified which one is thrown
391
* from this method.</p>
392
*
393
* @exception IOException if {@link #closeServer()} or one of the
394
* {@link RMIConnection#close()} calls threw
395
* <code>IOException</code>.
396
*/
397
public synchronized void close() throws IOException {
398
final boolean tracing = logger.traceOn();
399
final boolean debug = logger.debugOn();
400
401
if (tracing) logger.trace("close","closing");
402
403
IOException ioException = null;
404
try {
405
if (debug) logger.debug("close","closing Server");
406
closeServer();
407
} catch (IOException e) {
408
if (tracing) logger.trace("close","Failed to close server: " + e);
409
if (debug) logger.debug("close",e);
410
ioException = e;
411
}
412
413
if (debug) logger.debug("close","closing Clients");
414
// Loop to close all clients
415
while (true) {
416
synchronized (clientList) {
417
if (debug) logger.debug("close","droping dead references");
418
dropDeadReferences();
419
420
if (debug) logger.debug("close","client count: "+clientList.size());
421
if (clientList.size() == 0)
422
break;
423
/* Loop until we find a non-null client. Because we called
424
dropDeadReferences(), this will usually be the first
425
element of the list, but a garbage collection could have
426
happened in between. */
427
for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
428
it.hasNext(); ) {
429
WeakReference<RMIConnection> wr = it.next();
430
RMIConnection client = wr.get();
431
it.remove();
432
if (client != null) {
433
try {
434
client.close();
435
} catch (IOException e) {
436
if (tracing)
437
logger.trace("close","Failed to close client: " + e);
438
if (debug) logger.debug("close",e);
439
if (ioException == null)
440
ioException = e;
441
}
442
break;
443
}
444
}
445
}
446
}
447
448
if(notifBuffer != null)
449
notifBuffer.dispose();
450
451
if (ioException != null) {
452
if (tracing) logger.trace("close","close failed.");
453
throw ioException;
454
}
455
456
if (tracing) logger.trace("close","closed.");
457
}
458
459
/**
460
* <p>Called by {@link #close()} to close the connector server.
461
* After returning from this method, the connector server must
462
* not accept any new connections.</p>
463
*
464
* @exception IOException if the attempt to close the connector
465
* server failed.
466
*/
467
protected abstract void closeServer() throws IOException;
468
469
private static synchronized String makeConnectionId(String protocol,
470
Subject subject) {
471
connectionIdNumber++;
472
473
String clientHost = "";
474
try {
475
clientHost = RemoteServer.getClientHost();
476
/*
477
* According to the rules specified in the javax.management.remote
478
* package description, a numeric IPv6 address (detected by the
479
* presence of otherwise forbidden ":" character) forming a part
480
* of the connection id must be enclosed in square brackets.
481
*/
482
if (clientHost.contains(":")) {
483
clientHost = "[" + clientHost + "]";
484
}
485
} catch (ServerNotActiveException e) {
486
logger.trace("makeConnectionId", "getClientHost", e);
487
}
488
489
final StringBuilder buf = new StringBuilder();
490
buf.append(protocol).append(":");
491
if (clientHost.length() > 0)
492
buf.append("//").append(clientHost);
493
buf.append(" ");
494
if (subject != null) {
495
Set<Principal> principals = subject.getPrincipals();
496
String sep = "";
497
for (Iterator<Principal> it = principals.iterator(); it.hasNext(); ) {
498
Principal p = it.next();
499
String name = p.getName().replace(' ', '_').replace(';', ':');
500
buf.append(sep).append(name);
501
sep = ";";
502
}
503
}
504
buf.append(" ").append(connectionIdNumber);
505
if (logger.traceOn())
506
logger.trace("newConnectionId","connectionId="+buf);
507
return buf.toString();
508
}
509
510
private void dropDeadReferences() {
511
synchronized (clientList) {
512
for (Iterator<WeakReference<RMIConnection>> it = clientList.iterator();
513
it.hasNext(); ) {
514
WeakReference<RMIConnection> wr = it.next();
515
if (wr.get() == null)
516
it.remove();
517
}
518
}
519
}
520
521
synchronized NotificationBuffer getNotifBuffer() {
522
//Notification buffer is lazily created when the first client connects
523
if(notifBuffer == null)
524
notifBuffer =
525
ArrayNotificationBuffer.getNotificationBuffer(mbeanServer,
526
env);
527
return notifBuffer;
528
}
529
530
private static final ClassLogger logger =
531
new ClassLogger("javax.management.remote.rmi", "RMIServerImpl");
532
533
/** List of WeakReference values. Each one references an
534
RMIConnection created by this object, or null if the
535
RMIConnection has been garbage-collected. */
536
private final List<WeakReference<RMIConnection>> clientList =
537
new ArrayList<WeakReference<RMIConnection>>();
538
539
private ClassLoader cl;
540
541
private MBeanServer mbeanServer;
542
543
private final Map<String, ?> env;
544
545
private RMIConnectorServer connServer;
546
547
private static int connectionIdNumber;
548
549
private NotificationBuffer notifBuffer;
550
}
551
552