KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mx4j > tools > remote > AbstractConnectionManager


1 /*
2  * Copyright (C) The MX4J Contributors.
3  * All rights reserved.
4  *
5  * This software is distributed under the terms of the MX4J License version 1.0.
6  * See the terms of the MX4J License in the documentation provided with this software.
7  */

8
9 package mx4j.tools.remote;
10
11 import java.io.IOException JavaDoc;
12 import java.lang.ref.WeakReference JavaDoc;
13 import java.security.AccessControlContext JavaDoc;
14 import java.security.AccessController JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import javax.management.remote.JMXAuthenticator JavaDoc;
20 import javax.management.remote.JMXConnectorServer JavaDoc;
21 import javax.security.auth.Subject JavaDoc;
22
23 import mx4j.remote.MX4JRemoteUtils;
24
25 /**
26  * Implementation of the ConnectionManager interface that implements emission of connection notifications,
27  * authentication, and proper closing of connections.
28  *
29  * @version $Revision: 1.8 $
30  */

31 public abstract class AbstractConnectionManager implements ConnectionManager
32 {
33    private AbstractJMXConnectorServer server;
34    private final Map JavaDoc environment;
35    private final AccessControlContext JavaDoc context;
36    private final Map JavaDoc connections = new HashMap JavaDoc();
37    private volatile boolean closed;
38
39    /**
40     * Called by subclasses.
41     *
42     * @param server The JMXConnectorServer that will emit connection notifications
43     * @param environment The environment passed when the JMXConnectorServer is created.
44     */

45    protected AbstractConnectionManager(AbstractJMXConnectorServer server, Map JavaDoc environment)
46    {
47       this.server = server;
48       this.environment = environment;
49       this.context = AccessController.getContext();
50    }
51
52    protected void setJMXConnectorServer(AbstractJMXConnectorServer server)
53    {
54       this.server = server;
55    }
56
57    /**
58     * Implemented using the template method pattern, it handles authentication, creation of the connection ID,
59     * emission of connection notification of type "opened".
60     *
61     * @see #doConnect
62     * @see #authenticate
63     * @see #createConnectionID
64     */

65    public synchronized Connection connect(Object JavaDoc credentials) throws IOException JavaDoc, SecurityException JavaDoc
66    {
67       if (isClosed()) throw new IOException JavaDoc("This connection manager is already closed " + this);
68
69       Subject JavaDoc subject = authenticate(credentials);
70       String JavaDoc connectionId = createConnectionID(subject);
71
72       Connection client = doConnect(connectionId, subject);
73       WeakReference JavaDoc weak = new WeakReference JavaDoc(client);
74
75       synchronized (connections)
76       {
77          connections.put(connectionId, weak);
78       }
79
80       server.connectionOpened(connectionId, "Connection opened " + client, null);
81
82       return client;
83    }
84
85    /**
86     * Returns a connection ID as specified by JSR 160.
87     *
88     * @param subject The authenticated Subject
89     */

90    protected String JavaDoc createConnectionID(Subject JavaDoc subject)
91    {
92       return MX4JRemoteUtils.createConnectionID(getProtocol(), null, -1, subject);
93    }
94
95    /**
96     * Template method to be implemented by subclasses; must return the server-side part of
97     * a connection.
98     * When an remote invocation arrives, it will lookup the corrispondent server-side part
99     * of the connection and delegate the call to it. The server-side part of the connection
100     * must then (eventually) call the MBeanServer to satisfy the request.
101     *
102     * @param connectionId The connection ID for connection that is returned
103     * @param subject The authenticated Subject
104     * @return The server-side part of a connection (with the given connection ID)
105     * @throws IOException If the connection cannot be created
106     */

107    protected abstract Connection doConnect(String JavaDoc connectionId, Subject JavaDoc subject) throws IOException JavaDoc;
108
109    /**
110     * Implemented using the template method pattern
111     *
112     * @see #doClose
113     * @see #closeConnection
114     */

115    public synchronized void close() throws IOException JavaDoc
116    {
117       if (isClosed()) return;
118       closed = true;
119       doClose();
120       closeConnections();
121    }
122
123    /**
124     * Closes this ConnectionManager but not the connections it manages
125     *
126     * @throws IOException If this ConnectionManager cannot be closed
127     */

128    protected abstract void doClose() throws IOException JavaDoc;
129
130    private void closeConnections() throws IOException JavaDoc
131    {
132       IOException JavaDoc clientException = null;
133       synchronized (connections)
134       {
135          while (!connections.isEmpty())
136          {
137             // Create the iterator every time, since closeConnection() may modify the Map
138
Iterator JavaDoc entries = connections.entrySet().iterator();
139             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)entries.next();
140             WeakReference JavaDoc weak = (WeakReference JavaDoc)entry.getValue();
141             Connection connection = (Connection)weak.get();
142             if (connection == null)
143             {
144                // Already GC'ed
145
entries.remove();
146                continue;
147             }
148             else
149             {
150                try
151                {
152                   connection.close();
153                }
154                catch (IOException JavaDoc x)
155                {
156                   if (clientException == null) clientException = x;
157                }
158             }
159          }
160       }
161       if (clientException != null) throw clientException;
162    }
163
164    /**
165     * Implemented using the template method pattern, handles the emission of the connection notification
166     * of type "closed".
167     * This method is called both when closing the connector server and when closing a connector.
168     *
169     * @see #doCloseConnection
170     */

171    public void closeConnection(Connection connection) throws IOException JavaDoc
172    {
173       String JavaDoc connectionID = connection.getConnectionId();
174       WeakReference JavaDoc weak = null;
175       synchronized (connections)
176       {
177          weak = (WeakReference JavaDoc)connections.remove(connectionID);
178       }
179       // Someone may have called stop() and closed all connections in the meanwhile
180
if (weak == null) return;
181
182       Connection client = (Connection)weak.get();
183       if (connection != client) throw new IOException JavaDoc("Could not find active connection " + connection + ", expecting " + client);
184
185       doCloseConnection(connection);
186
187       server.connectionClosed(connectionID, "Closed connection " + connection, null);
188    }
189
190    /**
191     * Closes the given Connection.
192     */

193    protected abstract void doCloseConnection(Connection connection) throws IOException JavaDoc;
194
195    /**
196     * Returns whether the {@link #close} method has been called.
197     */

198    protected boolean isClosed()
199    {
200       return closed;
201    }
202
203    /**
204     * Returns the environment passed when creating the JMXConnectorServer
205     */

206    protected Map JavaDoc getEnvironment()
207    {
208       return environment;
209    }
210
211    /**
212     * Returns a security context at the moment of creation of this ConnectionManager.
213     * This security context is the restricting context that should be used when a call
214     * from a remote client is invoked in a doPrivileged() block.
215     */

216    protected AccessControlContext JavaDoc getSecurityContext()
217    {
218       return context;
219    }
220
221    /**
222     * Authenticates a Subject with the given credentials, by looking up a JMXAuthenticator
223     * in the environment returned by {@link #getEnvironment}.
224     */

225    protected Subject JavaDoc authenticate(Object JavaDoc credentials) throws IOException JavaDoc, SecurityException JavaDoc
226    {
227       Map JavaDoc environment = getEnvironment();
228       if (environment != null)
229       {
230          JMXAuthenticator JavaDoc authenticator = (JMXAuthenticator JavaDoc)environment.get(JMXConnectorServer.AUTHENTICATOR);
231          if (authenticator != null)
232          {
233             return authenticator.authenticate(credentials);
234          }
235       }
236       return null;
237    }
238 }
239
Popular Tags