1 22 package org.jboss.resource.adapter.jdbc.remote; 23 24 import java.io.ByteArrayOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.ObjectOutputStream ; 28 import java.io.Serializable ; 29 import java.lang.reflect.InvocationTargetException ; 30 import java.lang.reflect.Method ; 31 import java.lang.reflect.UndeclaredThrowableException ; 32 import java.sql.CallableStatement ; 33 import java.sql.Connection ; 34 import java.sql.DatabaseMetaData ; 35 import java.sql.ParameterMetaData ; 36 import java.sql.PreparedStatement ; 37 import java.sql.ResultSet ; 38 import java.sql.ResultSetMetaData ; 39 import java.sql.SQLException ; 40 import java.sql.Statement ; 41 import java.util.ArrayList ; 42 import java.util.HashMap ; 43 import java.util.Iterator ; 44 import java.util.Map ; 45 46 import javax.management.ObjectName ; 47 import javax.naming.BinaryRefAddr ; 48 import javax.naming.InitialContext ; 49 import javax.naming.NamingException ; 50 import javax.naming.Reference ; 51 import javax.naming.StringRefAddr ; 52 import javax.resource.Referenceable ; 53 import javax.sql.DataSource ; 54 55 import org.jboss.deployment.DeploymentException; 56 import org.jboss.invocation.Invocation; 57 import org.jboss.invocation.Invoker; 58 import org.jboss.invocation.InvokerInterceptor; 59 import org.jboss.invocation.MarshalledInvocation; 60 import org.jboss.logging.Logger; 61 import org.jboss.proxy.ClientMethodInterceptor; 62 import org.jboss.proxy.GenericProxyFactory; 63 import org.jboss.resource.connectionmanager.ConnectionFactoryBindingService; 64 import org.jboss.system.Registry; 65 import org.jboss.util.naming.NonSerializableFactory; 66 import org.jboss.util.naming.Util; 67 import org.jboss.util.Classes; 68 69 70 80 public class WrapperDataSourceService extends ConnectionFactoryBindingService implements WrapperDataSourceServiceMBean 81 { 82 private static Logger log = Logger.getLogger(WrapperDataSourceService.class); 83 84 private ObjectName jmxInvokerName; 85 private Invoker delegateInvoker; 86 private Object theProxy; 87 private HashMap marshalledInvocationMapping = new HashMap (); 88 private HashMap connectionMap = new HashMap (); 89 private HashMap statementMap = new HashMap (); 90 private HashMap resultSetMap = new HashMap (); 91 private HashMap lobMap = new HashMap (); 92 private HashMap databaseMetaDataMap = new HashMap (); 93 private boolean trace = log.isTraceEnabled(); 94 95 protected void startService() throws Exception 96 { 97 determineBindName(); 98 createConnectionFactory(); 99 if( jmxInvokerName != null ) 100 { 101 createProxy(); 102 calculateMethodHases(); 103 bindConnectionFactory(); 104 } 105 else 106 { 107 super.bindConnectionFactory(); 108 } 109 } 110 111 protected void stopService() throws Exception 112 { 113 unbindConnectionFactory(); 114 if( jmxInvokerName != null ) 115 destroyProxy(); 116 } 117 118 protected void bindConnectionFactory() throws Exception 119 { 120 InitialContext ctx = new InitialContext (); 121 try 122 { 123 log.debug("Binding object '" + cf + "' into JNDI at '" + bindName + "'"); 124 NonSerializableFactory.rebind(bindName, cf); 126 133 Referenceable referenceable = (Referenceable ) cf; 134 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 136 ObjectOutputStream oos = new ObjectOutputStream (baos); 137 oos.writeObject(theProxy); 138 oos.close(); 139 byte[] proxyBytes = baos.toByteArray(); 140 BinaryRefAddr dsAddr = new BinaryRefAddr ("ProxyData", proxyBytes); 141 String factory = DataSourceFactory.class.getName(); 142 Reference dsRef = new Reference ("javax.sql.DataSource", dsAddr, factory, null); 143 referenceable.setReference(dsRef); 144 baos.reset(); 146 ObjectOutputStream oos2 = new ObjectOutputStream (baos); 147 oos2.writeObject(DataSourceFactory.vmID); 148 oos2.close(); 149 byte[] id = baos.toByteArray(); 150 BinaryRefAddr localAddr = new BinaryRefAddr ("VMID", id); 151 dsRef.add(localAddr); 152 156 StringRefAddr jndiRef = new StringRefAddr ("JndiName", bindName); 157 dsRef.add(jndiRef); 158 Util.rebind(ctx, bindName, cf); 159 log.info("Bound ConnectionManager '" + serviceName + "' to JNDI name '" + bindName + "'"); 160 } 161 catch (NamingException ne) 162 { 163 throw new DeploymentException("Could not bind ConnectionFactory into jndi: " + bindName, ne); 164 } 165 finally 166 { 167 ctx.close(); 168 } 169 } 170 171 public ObjectName getJMXInvokerName() 172 { 173 return jmxInvokerName; 174 } 175 176 public void setJMXInvokerName(ObjectName jmxInvokerName) 177 { 178 this.jmxInvokerName = jmxInvokerName; 179 } 180 181 public Object invoke(Invocation invocation) throws Exception 182 { 183 if (invocation instanceof MarshalledInvocation) 185 { 186 MarshalledInvocation mi = (MarshalledInvocation) invocation; 187 mi.setMethodMap(marshalledInvocationMapping); 188 } 189 Method method = invocation.getMethod(); 191 Class methodClass = method.getDeclaringClass(); 192 Object [] args = invocation.getArguments(); 193 Object value = null; 194 195 try 196 { 197 if( methodClass.isAssignableFrom(DataSource .class) ) 198 { 199 InitialContext ctx = new InitialContext (); 200 DataSource ds = (DataSource ) ctx.lookup(bindName); 201 value = doDataSourceMethod(ds, method, args); 202 } 203 else if( methodClass.isAssignableFrom(Connection .class) ) 204 { 205 Integer id = (Integer ) invocation.getId(); 206 Connection conn = (Connection ) connectionMap.get(id); 207 if( conn == null ) 208 { 209 throw new IllegalAccessException ("Failed to find connection: "+id); 210 } 211 value = doConnectionMethod(conn, method, args); 212 } 213 else if( methodClass.isAssignableFrom(Statement .class) || 214 methodClass.isAssignableFrom(PreparedStatement .class) || 215 methodClass.isAssignableFrom(CallableStatement .class)) 216 { 217 Integer id = (Integer ) invocation.getId(); 218 Statement stmt = (Statement ) statementMap.get(id); 219 if( stmt == null ) 220 { 221 throw new SQLException ("Failed to find Statement: " + id); 222 } 223 value = doStatementMethod(stmt, method, args); 224 } 225 else if( methodClass.isAssignableFrom(ResultSet .class) ) 226 { 227 Integer id = (Integer ) invocation.getId(); 228 ResultSet results = (ResultSet ) resultSetMap.get(id); 229 if( results == null ) 230 { 231 throw new IllegalAccessException ("Failed to find ResultSet: "+id); 232 } 233 value = doResultSetMethod(results, method, args); 234 } 235 else if (methodClass.isAssignableFrom(DatabaseMetaData .class)) 236 { 237 Integer id = (Integer ) invocation.getId(); 238 DatabaseMetaData dbMetaData = (DatabaseMetaData ) databaseMetaDataMap.get(id); 239 if(dbMetaData == null) 240 { 241 throw new IllegalAccessException ("Failed to find DatabaseMetaData: " + id); 242 } 243 value = doDatabaseMetaDataMethod(dbMetaData, method, args); 244 } 245 else 246 { 247 throw new UnsupportedOperationException ("Do not know how to handle method="+method); 248 } 249 } 250 catch (InvocationTargetException e) 251 { 252 Throwable t = e.getTargetException(); 253 if (t instanceof Exception ) 254 throw (Exception ) t; 255 else 256 throw new UndeclaredThrowableException (t, method.toString()); 257 } 258 259 return value; 260 } 261 262 267 protected void createProxy() throws Exception 268 { 269 272 delegateInvoker = (Invoker) Registry.lookup(jmxInvokerName); 273 log.debug("Using delegate: " + delegateInvoker 274 + " for invoker=" + jmxInvokerName); 275 ObjectName targetName = getServiceName(); 276 Integer nameHash = new Integer (targetName.hashCode()); 277 Registry.bind(nameHash, targetName); 278 279 Object cacheID = null; 280 String proxyBindingName = null; 281 String jndiName = null; 282 Class [] ifaces = {javax.sql.DataSource .class}; 283 285 ArrayList interceptorClasses = new ArrayList (); 286 interceptorClasses.add(ClientMethodInterceptor.class); 287 interceptorClasses.add(InvokerInterceptor.class); 288 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 289 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 290 theProxy = proxyFactory.createProxy(cacheID, targetName, 291 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 292 loader, ifaces); 293 log.debug("Created proxy for invoker=" + jmxInvokerName 294 + ", targetName=" + targetName + ", nameHash=" + nameHash); 295 } 296 297 300 protected void destroyProxy() throws Exception 301 { 302 ObjectName name = getServiceName(); 303 Integer nameHash = new Integer (name.hashCode()); 304 Registry.unbind(nameHash); 305 } 306 307 310 protected void calculateMethodHases() throws Exception 311 { 312 Method [] methods = DataSource .class.getMethods(); 313 for(int m = 0; m < methods.length; m ++) 314 { 315 Method method = methods[m]; 316 Long hash = new Long (MarshalledInvocation.calculateHash(method)); 317 marshalledInvocationMapping.put(hash, method); 318 } 319 320 Map m = MarshalledInvocation.methodToHashesMap(Connection .class); 322 displayHashes(m); 323 marshalledInvocationMapping.putAll(m); 324 m = MarshalledInvocation.methodToHashesMap(Statement .class); 325 displayHashes(m); 326 marshalledInvocationMapping.putAll(m); 327 m = MarshalledInvocation.methodToHashesMap(CallableStatement .class); 328 displayHashes(m); 329 marshalledInvocationMapping.putAll(m); 330 m = MarshalledInvocation.methodToHashesMap(PreparedStatement .class); 331 displayHashes(m); 332 marshalledInvocationMapping.putAll(m); 333 m = MarshalledInvocation.methodToHashesMap(ResultSet .class); 334 displayHashes(m); 335 marshalledInvocationMapping.putAll(m); 336 m = MarshalledInvocation.methodToHashesMap(DatabaseMetaData .class); 337 displayHashes(m); 338 marshalledInvocationMapping.putAll(m); 339 } 340 341 private Object doDataSourceMethod(DataSource ds, Method method, Object [] args) 342 throws InvocationTargetException , IllegalAccessException 343 { 344 Object value = method.invoke(ds, args); 345 if( value instanceof Connection ) 346 { 347 value = createConnectionProxy(value); 348 } 349 else if( value != null && (value instanceof Serializable ) == false ) 350 { 351 throw new IllegalAccessException ("Method="+method+" does not return Serializable"); 352 } 353 return value; 354 } 355 356 private Object doConnectionMethod(Connection conn, Method method, Object [] args) 357 throws InvocationTargetException , IllegalAccessException , SQLException 358 { 359 if( trace ) 360 { 361 log.trace("doConnectionMethod, conn="+conn+", method="+method); 362 } 363 Object value = method.invoke(conn, args); 364 if( value instanceof Statement ) 365 { 366 value = createStatementProxy(value); 367 } 368 else if(value instanceof DatabaseMetaData ) 369 { 370 value = createDatabaseMetaData(value); 371 } 372 else if( value != null && (value instanceof Serializable ) == false ) 373 { 374 throw new IllegalAccessException ("Method="+method+" does not return Serializable"); 375 } 376 return value; 377 } 378 379 private Object doStatementMethod(Statement stmt, Method method, Object [] args) 380 throws InvocationTargetException , IllegalAccessException , SQLException 381 { 382 if( trace ) 383 { 384 log.trace("doStatementMethod, conn="+stmt+", method="+method); 385 } 386 387 if( method.getName().equals("close") ) 388 { 389 Integer id = new Integer (stmt.hashCode()); 390 statementMap.remove(id); 391 log.debug("Closed Statement="+id); 392 } 393 394 Object value = method.invoke(stmt, args); 395 if( value instanceof ResultSet ) 396 { 397 value = createResultSetProxy(value); 398 } 399 else if( value instanceof ResultSetMetaData ) 400 { 401 ResultSetMetaData rmd = (ResultSetMetaData ) value; 402 value = new SerializableResultSetMetaData(rmd); 403 } 404 else if ( value instanceof ParameterMetaData ) 405 { 406 ParameterMetaData pmd = (ParameterMetaData ) value; 407 value = new SerializableParameterMetaData(pmd); 408 } 409 else if( value != null && (value instanceof Serializable ) == false ) 410 { 411 throw new IllegalAccessException ("Method="+method+" does not return Serializable"); 412 } 413 return value; 414 } 415 416 private Object doResultSetMethod(ResultSet results, Method method, Object [] args) 417 throws InvocationTargetException , IllegalAccessException , SQLException , IOException 418 { 419 if( trace ) 420 { 421 log.trace("doStatementMethod, results="+results+", method="+method); 422 } 423 424 if( method.getName().equals("close") ) 425 { 426 Integer id = new Integer (results.hashCode()); 427 resultSetMap.remove(id); 428 log.debug("Closed ResultSet="+id); 429 } 430 431 Object value = method.invoke(results, args); 432 if( value instanceof ResultSetMetaData ) 433 { 434 ResultSetMetaData rmd = (ResultSetMetaData ) value; 435 value = new SerializableResultSetMetaData(rmd); 436 } 437 if(("getBinaryStream".equals(method.getName()) || "getAsciiStream".equals(method.getName())) && value instanceof InputStream ) 439 { 440 InputStream ins = (InputStream )value; 441 value = new SerializableInputStream(ins); 442 } 443 else if ("getCharacterStream".equals(method.getName()) && value instanceof java.io.Reader ) 444 { 445 java.io.Reader ins = (java.io.Reader )value; 446 value = new SerializableReader(ins); 447 } 448 else if("getClob".equals(method.getName()) || "getBlob".equals(method.getName())) 449 { 450 value = createLobProxy(value); 451 } 452 453 if( value != null && (value instanceof Serializable ) == false ) 454 { 455 throw new IllegalAccessException ("Method="+method+" does not return Serializable"); 456 } 457 return value; 458 } 459 460 private Object doDatabaseMetaDataMethod(DatabaseMetaData dbMetaData, Method method, Object [] args) 461 throws InvocationTargetException , IllegalAccessException 462 { 463 if( trace ) 464 { 465 log.trace("doDatabaseMetaDataMethod, dbMetaData="+dbMetaData+", method="+method); 466 } 467 468 Object value = method.invoke(dbMetaData, args); 469 if( value instanceof ResultSet ) 470 { 471 value = createResultSetProxy(value); 472 } 473 else if( value instanceof Connection ) 474 { 475 value = createConnectionProxy(value); 476 } 477 if( value != null && (value instanceof Serializable ) == false ) 478 { 479 throw new IllegalAccessException ("Method="+method+" does not return Serializable"); 480 } 481 return value; 482 } 483 484 private Object createConnectionProxy(Object conn) 485 { 486 Object cacheID = new Integer (conn.hashCode()); 487 ObjectName targetName = getServiceName(); 488 String proxyBindingName = null; 489 String jndiName = null; 490 Class [] ifaces = {java.sql.Connection .class}; 491 ArrayList interceptorClasses = new ArrayList (); 492 interceptorClasses.add(ClientMethodInterceptor.class); 493 interceptorClasses.add(InvokerInterceptor.class); 494 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 495 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 496 Object connProxy = proxyFactory.createProxy(cacheID, targetName, 497 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 498 loader, ifaces); 499 connectionMap.put(cacheID, conn); 500 log.debug("Created Connection proxy for invoker=" + jmxInvokerName 501 + ", targetName=" + targetName + ", cacheID=" + cacheID); 502 return connProxy; 503 } 504 505 private Object createStatementProxy(Object stmt) 506 { 507 Object cacheID = new Integer (stmt.hashCode()); 508 ObjectName targetName = getServiceName(); 509 String proxyBindingName = null; 510 String jndiName = null; 511 Class [] ifaces = getJavaInterfaces(stmt.getClass()); 513 ArrayList interceptorClasses = new ArrayList (); 514 interceptorClasses.add(StatementInterceptor.class); 515 interceptorClasses.add(ClientMethodInterceptor.class); 516 interceptorClasses.add(InvokerInterceptor.class); 517 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 518 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 519 Object stmtProxy = proxyFactory.createProxy(cacheID, targetName, 520 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 521 loader, ifaces); 522 statementMap.put(cacheID, stmt); 523 log.debug("Created Statement proxy for invoker=" + jmxInvokerName 524 + ", targetName=" + targetName + ", cacheID=" + cacheID); 525 return stmtProxy; 526 } 527 528 private Object createResultSetProxy(Object results) 529 { 530 Object cacheID = new Integer (results.hashCode()); 531 ObjectName targetName = getServiceName(); 532 String proxyBindingName = null; 533 String jndiName = null; 534 Class [] ifaces = getJavaInterfaces(results.getClass()); 536 537 ArrayList interceptorClasses = new ArrayList (); 538 interceptorClasses.add(ClientMethodInterceptor.class); 539 interceptorClasses.add(InvokerInterceptor.class); 540 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 541 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 542 Object resultsProxy = proxyFactory.createProxy(cacheID, targetName, 543 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 544 loader, ifaces); 545 resultSetMap.put(cacheID, results); 546 log.debug("Created ResultSet proxy for invoker=" + jmxInvokerName 547 + ", targetName=" + targetName + ", cacheID=" + cacheID); 548 return resultsProxy; 549 } 550 551 private Object createLobProxy(Object results) 552 { 553 Object cacheID = new Integer (results.hashCode()); 554 ObjectName targetName = getServiceName(); 555 String proxyBindingName = null; 556 String jndiName = null; 557 Class [] ifaces = results.getClass().getInterfaces(); 558 ArrayList interceptorClasses = new ArrayList (); 559 interceptorClasses.add(ClientMethodInterceptor.class); 560 interceptorClasses.add(InvokerInterceptor.class); 561 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 562 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 563 Object resultsProxy = proxyFactory.createProxy(cacheID, targetName, 564 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 565 loader, ifaces); 566 lobMap.put(cacheID, results); 567 log.debug("Created LOB proxy for invoker=" + jmxInvokerName 568 + ", targetName=" + targetName + ", cacheID=" + cacheID); 569 return resultsProxy; 570 } 571 572 private Object createDatabaseMetaData(Object dbMetaData) 573 { 574 Object cacheID = new Integer (dbMetaData.hashCode()); 575 ObjectName targetName = getServiceName(); 576 String proxyBindingName = null; 577 String jndiName = null; 578 Class [] ifaces = {java.sql.DatabaseMetaData .class}; 579 ArrayList interceptorClasses = new ArrayList (); 580 interceptorClasses.add(ClientMethodInterceptor.class); 581 interceptorClasses.add(InvokerInterceptor.class); 582 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 583 GenericProxyFactory proxyFactory = new GenericProxyFactory(); 584 Object dbMetaDataProxy = proxyFactory.createProxy(cacheID, targetName, 585 delegateInvoker, jndiName, proxyBindingName, interceptorClasses, 586 loader, ifaces); 587 databaseMetaDataMap.put(cacheID, dbMetaData); 588 log.debug("Created DatabaseMetadata proxy for invoker=" + jmxInvokerName 589 + ", targetName=" + targetName + ", cacheID=" + cacheID); 590 return dbMetaDataProxy; 591 592 } 593 594 private void displayHashes(Map m) 595 { 596 if( trace == false ) 597 return; 598 599 Iterator keys = m.keySet().iterator(); 600 while( keys.hasNext() ) 601 { 602 Long key = (Long ) keys.next(); 603 log.trace(key+"="+m.get(key)); 604 } 605 } 606 607 private Class [] getJavaInterfaces(Class clazz) 608 { 609 ArrayList tmp = new ArrayList (); 610 Classes.getAllInterfaces(tmp, clazz); 611 Iterator iter = tmp.iterator(); 612 while( iter.hasNext() ) 613 { 614 Class c = (Class ) iter.next(); 615 if( c.getName().startsWith("java") == false ) 616 iter.remove(); 617 } 618 Class [] ifaces = new Class [tmp.size()]; 619 return (Class []) tmp.toArray(ifaces); 620 } 621 } 622 | Popular Tags |