1 8 9 package mx4j.remote.resolver.rmi; 10 11 import java.io.IOException ; 12 import java.io.ByteArrayOutputStream ; 13 import java.io.ObjectOutputStream ; 14 import java.io.ByteArrayInputStream ; 15 import java.io.ObjectInputStream ; 16 import java.net.MalformedURLException ; 17 import java.rmi.server.RMIClientSocketFactory ; 18 import java.rmi.server.RMIServerSocketFactory ; 19 import java.rmi.Remote ; 20 import java.util.Hashtable ; 21 import java.util.Map ; 22 23 import javax.management.remote.JMXServiceURL ; 24 import javax.management.remote.rmi.RMIConnectorServer ; 25 import javax.management.remote.rmi.RMIJRMPServerImpl ; 26 import javax.management.remote.rmi.RMIServer ; 27 import javax.management.remote.rmi.RMIServerImpl ; 28 import javax.naming.InitialContext ; 29 import javax.naming.NamingException ; 30 31 import mx4j.log.Logger; 32 import mx4j.remote.ConnectionResolver; 33 import mx4j.util.Base64Codec; 34 35 41 public class RMIResolver extends ConnectionResolver 42 { 43 private static final String JNDI_CONTEXT = "/jndi/"; 44 private static final String STUB_CONTEXT = "/stub/"; 45 46 47 50 51 public Object lookupClient(JMXServiceURL url, Map environment) throws IOException 52 { 53 return lookupRMIServerStub(url, environment); 54 } 55 56 public Object bindClient(Object client, Map environment) throws IOException 57 { 58 return client; 60 } 61 62 protected RMIServer lookupRMIServerStub(JMXServiceURL url, Map environment) throws IOException 63 { 64 Logger logger = getLogger(); 65 66 String path = url.getURLPath(); 67 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("JMXServiceURL for lookup is: '" + url + "'"); 68 69 if (path != null) 70 { 71 if (path.startsWith(JNDI_CONTEXT)) 72 { 73 return lookupStubInJNDI(url, environment); 74 } 75 76 return decodeStub(url, environment); 77 } 78 79 throw new MalformedURLException ("Unsupported lookup " + url); 80 } 81 82 private RMIServer lookupStubInJNDI(JMXServiceURL url, Map environment) throws IOException 83 { 84 Logger logger = getLogger(); 85 86 String path = url.getURLPath(); 87 String name = path.substring(JNDI_CONTEXT.length()); 88 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Looking up RMI stub in JNDI under name " + name); 89 90 InitialContext ctx = null; 91 try 92 { 93 ctx = new InitialContext (new Hashtable (environment)); 94 Object stub = ctx.lookup(name); 95 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Found RMI stub in JNDI " + stub); 96 return narrowRMIServerStub(stub); 97 } 98 catch (NamingException x) 99 { 100 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot lookup RMI stub in JNDI", x); 101 throw new IOException (x.toString()); 102 } 103 finally 104 { 105 try 106 { 107 if (ctx != null) ctx.close(); 108 } 109 catch (NamingException x) 110 { 111 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot close InitialContext", x); 112 } 113 } 114 } 115 116 protected RMIServer narrowRMIServerStub(Object stub) 117 { 118 return (RMIServer )stub; 119 } 120 121 protected RMIServer decodeStub(JMXServiceURL url, Map environment) throws IOException 122 { 123 String path = url.getURLPath(); 124 if (path.startsWith(STUB_CONTEXT)) 125 { 126 byte[] encoded = path.substring(STUB_CONTEXT.length()).getBytes(); 127 if (!Base64Codec.isArrayByteBase64(encoded)) throw new IOException ("Encoded stub form is not a valid Base64 sequence: " + url); 128 byte[] decoded = Base64Codec.decodeBase64(encoded); 129 ByteArrayInputStream bais = new ByteArrayInputStream (decoded); 130 ObjectInputStream ois = null; 131 try 132 { 133 ois = new ObjectInputStream (bais); 134 return (RMIServer )ois.readObject(); 135 } 136 catch (ClassNotFoundException x) 137 { 138 throw new IOException ("Cannot decode stub from " + url + ": " + x); 139 } 140 finally 141 { 142 if (ois != null) ois.close(); 143 } 144 } 145 throw new MalformedURLException ("Unsupported binding: " + url); 146 } 147 148 149 152 153 public Object createServer(JMXServiceURL url, Map environment) throws IOException 154 { 155 return createRMIServer(url, environment); 156 } 157 158 protected RMIServerImpl createRMIServer(JMXServiceURL url, Map environment) throws IOException 159 { 160 int port = url.getPort(); 161 RMIClientSocketFactory clientFactory = (RMIClientSocketFactory )environment.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE); 162 RMIServerSocketFactory serverFactory = (RMIServerSocketFactory )environment.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE); 163 return new RMIJRMPServerImpl (port, clientFactory, serverFactory, environment); 164 } 165 166 public JMXServiceURL bindServer(Object server, JMXServiceURL url, Map environment) throws IOException 167 { 168 170 RMIServerImpl rmiServer = (RMIServerImpl )server; 171 172 Logger logger = getLogger(); 173 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("JMXServiceURL for binding is: '" + url + "'"); 174 175 if (isEncodedForm(url)) 176 { 177 String path = encodeStub(rmiServer, environment); 178 return new JMXServiceURL (url.getProtocol(), url.getHost(), url.getPort(), path); 179 } 180 181 String jndiURL = parseJNDIForm(url); 182 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("JMXServiceURL path for binding is: '" + jndiURL + "'"); 183 184 InitialContext ctx = null; 185 try 186 { 187 ctx = new InitialContext (new Hashtable (environment)); 188 boolean rebind = Boolean.valueOf((String )environment.get(RMIConnectorServer.JNDI_REBIND_ATTRIBUTE)).booleanValue(); 189 if (rebind) 190 ctx.rebind(jndiURL, rmiServer.toStub()); 191 else 192 ctx.bind(jndiURL, rmiServer.toStub()); 193 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Bound " + rmiServer + " to " + jndiURL); 194 return url; 195 } 196 catch (NamingException x) 197 { 198 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot bind server " + rmiServer + " to " + jndiURL, x); 199 throw new IOException (x.toString()); 200 } 201 finally 202 { 203 try 204 { 205 if (ctx != null) ctx.close(); 206 } 207 catch (NamingException x) 208 { 209 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot close InitialContext", x); 210 } 211 } 212 } 213 214 protected String encodeStub(RMIServerImpl rmiServer, Map environment) throws IOException 215 { 216 Remote stub = rmiServer.toStub(); 217 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 218 ObjectOutputStream oos = null; 219 try 220 { 221 oos = new ObjectOutputStream (baos); 222 oos.writeObject(stub); 223 } 224 finally 225 { 226 if (oos != null) oos.close(); 227 } 228 byte[] bytes = baos.toByteArray(); 229 byte[] encoded = Base64Codec.encodeBase64(bytes); 230 return STUB_CONTEXT + new String (encoded); 232 } 233 234 protected boolean isEncodedForm(JMXServiceURL url) 235 { 236 String path = url.getURLPath(); 237 if (path == null || path.length() == 0 || path.equals("/") || path.startsWith(STUB_CONTEXT)) return true; 238 return false; 239 } 240 241 private String parseJNDIForm(JMXServiceURL url) throws MalformedURLException 242 { 243 String path = url.getURLPath(); 244 if (path.startsWith(JNDI_CONTEXT)) 245 { 246 String jndiURL = path.substring(JNDI_CONTEXT.length()); 247 if (jndiURL == null || jndiURL.length() == 0) throw new MalformedURLException ("No JNDI URL specified: " + url); 248 return jndiURL; 249 } 250 throw new MalformedURLException ("Unsupported binding: " + url); 251 } 252 253 public void unbindServer(Object server, JMXServiceURL url, Map environment) throws IOException 254 { 255 Logger logger = getLogger(); 256 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("JMXServiceURL for unbinding is: '" + url + "'"); 257 if (isEncodedForm(url)) 259 { 260 destroyServer(server, environment); 261 return; 262 } 263 264 String jndiURL = parseJNDIForm(url); 265 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("JMXServiceURL path for binding is: '" + jndiURL + "'"); 266 267 InitialContext ctx = null; 268 try 269 { 270 ctx = new InitialContext (new Hashtable (environment)); 271 ctx.unbind(jndiURL); 272 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Unbound " + server + " from " + jndiURL); 273 } 274 catch (NamingException x) 275 { 276 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot unbind server " + server + " to " + jndiURL, x); 277 throw new IOException (x.toString()); 278 } 279 finally 280 { 281 try 282 { 283 if (ctx != null) ctx.close(); 284 } 285 catch (NamingException x) 286 { 287 if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Cannot close InitialContext", x); 288 } 289 } 290 } 291 292 protected void destroyServer(Object server, Map environment) throws IOException 293 { 294 } 295 } 296 | Popular Tags |