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