1 9 package org.ozoneDB; 10 11 import java.io.IOException ; 12 import java.net.MalformedURLException ; 13 import java.net.UnknownHostException ; 14 import java.net.URISyntaxException ; 15 import java.net.URI ; 16 import java.util.Hashtable ; 17 import java.util.StringTokenizer ; 18 import javax.transaction.xa.XAResource ; 19 20 import org.ozoneDB.DxLib.*; 21 import org.ozoneDB.core.DbRemote.*; 22 import org.ozoneDB.core.Transaction; 23 import org.ozoneDB.core.TransactionID; 24 import org.ozoneDB.core.admin.Admin; 25 import org.ozoneDB.core.admin.AdminImpl; 26 import org.ozoneDB.xa.OzoneXAResource; 27 import org.ozoneDB.xml.util.SAXChunkConsumer; 28 import org.w3c.dom.Document ; 29 import org.w3c.dom.Node ; 30 import org.xml.sax.ContentHandler ; 31 32 33 52 public abstract class ExternalDatabase extends AbstractDatabase { 53 54 56 public final static String PROP_HOST = "host"; 57 58 public final static String PROP_PORT = "port"; 59 60 public final static String PROP_DIR = "dir"; 61 62 public final static String PROP_USER = "user"; 63 64 public final static String PROP_PASSWD = "passwd"; 65 66 public final static String PROP_DEBUG = "debug"; 67 68 70 75 private ExternalDatabase wrapper; 76 77 80 private DxMap txTable; 81 82 85 private DxDeque apool; 86 87 90 private DxSet upool; 91 92 95 private XAResource xares; 96 97 100 102 106 private static DxBag databases = new DxArrayBag(); 107 108 109 119 public static ExternalDatabase forThread(Thread _thread) { 120 DxIterator it = databases.iterator(); 121 ExternalDatabase db; 122 while ((db = (ExternalDatabase) it.next()) != null) { 123 DxSet threads = db.txTable.keySet(); 124 if (threads.contains(_thread)) { 125 return db; 126 } 127 } 128 return null; 129 } 130 131 132 134 public ExternalDatabase() { 135 } 136 137 138 140 144 public final XAResource getXAResource() { 145 if (xares == null) { 146 synchronized (this) { 147 if (xares == null) { 148 xares = new OzoneXAResource(this); 149 } 150 } 151 } 152 return xares; 153 } 154 155 156 158 protected final AbstractTransaction txForThread(Thread thread) { 159 return (AbstractTransaction) txTable.elementForKey(thread); 160 } 161 162 163 168 public ExternalTransaction newTransaction() { 169 return new ExternalTransaction(this); 170 } 171 172 173 182 public ExternalTransaction currentExternalTransaction() { 183 AbstractTransaction atx = txForThread(Thread.currentThread()); 184 185 if (atx instanceof ExternalTransaction) { 186 return (ExternalTransaction) atx; 187 } else { 188 return null; 189 } 190 } 191 192 193 202 public AbstractTransaction currentTransaction() { 203 return txForThread(Thread.currentThread()); 204 } 205 206 207 210 public void beginTX(AbstractTransaction tx) throws TransactionException, IOException { 211 212 if (tx.connection != null) { 214 throw new TransactionException("Transaction already started.", TransactionException.STATE); 215 } 216 217 synchronized (tx) { 218 try { 219 tx.connection = acquirePooledConnection(); 220 joinTX(tx); 221 222 TransactionID taID = (TransactionID) sendCommand(new DbTransaction(DbTransaction.MODE_BEGIN), true, tx.connection); 224 } catch (IOException e) { 225 throw e; 226 } catch (Exception e) { 227 throw new TransactionException(e.toString(), TransactionException.UNEXPECTED); 228 } 229 } 230 } 231 232 233 236 public void joinTX(AbstractTransaction tx) throws TransactionException { 237 Thread thread = Thread.currentThread(); 238 239 synchronized (txTable) { 240 AbstractTransaction txOfThread = (AbstractTransaction) txTable.elementForKey(thread); 242 if (txOfThread != null && txOfThread != tx) { 243 throw new TransactionException("Thread is already joined to a transaction.", TransactionException.STATE); 244 } 245 txTable.addForKey(tx, thread); 246 } 247 } 248 249 250 253 public boolean leaveTX(AbstractTransaction tx) { 254 return txTable.removeForKey(Thread.currentThread()) != null; 255 } 256 257 258 261 public void checkpointTX(AbstractTransaction tx) throws TransactionException, IOException { 262 commandTX(tx, new DbTransaction(DbTransaction.MODE_CHECKPOINT)); 263 } 264 265 266 269 public void prepareTX(AbstractTransaction tx) throws TransactionException, IOException { 270 if (tx.connection == null) { 271 throw new TransactionException("Illegal state.", TransactionException.STATE); 272 } 273 commandTX(tx, new DbTransaction(DbTransaction.MODE_PREPARE)); 274 } 275 276 277 280 public void commitTX(AbstractTransaction tx, boolean onePhase) throws TransactionException, IOException { 281 synchronized (tx) { 282 if (tx.connection == null) { 283 throw new TransactionException("Illegal state.", TransactionException.STATE); 284 } 285 286 if (onePhase) { 287 commandTX(tx, new DbTransaction(DbTransaction.MODE_COMMIT_ONEPHASE)); 288 } else { 289 commandTX(tx, new DbTransaction(DbTransaction.MODE_COMMIT_TWOPHASE)); 290 } 291 releasePooledConnection(tx.connection); 292 tx.connection = null; 293 } 294 295 synchronized (txTable) { 296 DxIterator it = txTable.iterator(); 298 AbstractTransaction cursorTX; 299 while ((cursorTX = (AbstractTransaction) it.next()) != null) { 300 if (cursorTX == tx) { 301 it.removeObject(); 302 } 303 } 304 } 305 } 306 307 308 311 public void rollbackTX(AbstractTransaction tx) throws TransactionException, IOException { 312 synchronized (tx) { 313 if (tx.connection == null) { 314 return; 316 } 317 commandTX(tx, new DbTransaction(DbTransaction.MODE_ABORT)); 318 releasePooledConnection(tx.connection); 319 tx.connection = null; 320 } 321 322 synchronized (txTable) { 323 DxIterator it = txTable.iterator(); 325 AbstractTransaction cursorTX; 326 while ((cursorTX = (AbstractTransaction) it.next()) != null) { 327 if (cursorTX == tx) { 328 it.removeObject(); 329 } 330 } 331 } 332 } 333 334 335 342 public final int getStatusTX(AbstractTransaction tx) throws TransactionException, IOException { 343 if (tx.connection == null) { 344 return Transaction.STATUS_NONE; 345 } else { 346 DbTransaction command = new DbTransaction(DbTransaction.MODE_STATUS); 347 commandTX(tx, command); 348 return ((Integer ) command.result).intValue(); 349 } 350 } 351 352 353 356 protected final Object commandTX(AbstractTransaction tx, DbTransaction command) throws TransactionException, IOException { 357 if (tx.connection == null) { 358 throw new TransactionException("Thread has not yet joined a transaction.", TransactionException.STATE); 359 } 360 361 try { 362 return sendCommand(command, true, tx.connection); 366 } catch (IOException e) { 367 throw e; 368 } catch (TransactionException e) { 369 throw e; 370 } catch (Exception e) { 371 throw new TransactionException(e.toString(), TransactionException.UNEXPECTED); 372 } 373 } 374 375 376 378 379 383 protected abstract DbClient newConnection() throws Exception ; 384 385 386 399 protected final DbClient acquirePooledConnection() throws Exception { 400 synchronized (apool) { 402 synchronized (upool) { 403 if (apool.isEmpty()) { 404 DbClient connection = newConnection(); 405 apool.push(connection); 406 } 407 DbClient connection = (DbClient) apool.pop(); 408 if (upool.add(connection) == false) { 409 throw new IllegalStateException ("Connection is already in use."); 410 } 411 return connection; 412 } 413 } 414 } 415 416 417 424 protected final void releasePooledConnection(DbClient connection) { 425 synchronized (apool) { 427 synchronized (upool) { 428 if (upool.remove(connection) == false) { 429 throw new IllegalStateException ("Given connection is not element of the pool of used connections."); 430 } 431 apool.push(connection); 432 } 433 } 434 } 435 436 437 442 471 472 478 protected final Object sendCommand(DbCommand command, boolean waitForResult) throws Exception ,IOException ,TransactionException,ClassNotFoundException ,org.ozoneDB.OzoneObjectException { 479 if (!isOpen()) { 480 throw new IllegalStateException ("Database is not open."); 481 } 482 Thread thread = Thread.currentThread(); 483 484 AbstractTransaction txOfThread = (AbstractTransaction) txTable.elementForKey(thread); 485 if (txOfThread != null) { 486 DbClient connection = txOfThread.connection; 487 return sendCommand(command, waitForResult, connection); 488 } else { 489 DbClient connection = null; 490 try { 491 connection = acquirePooledConnection(); 492 return sendCommand(command, waitForResult, connection); 493 } finally { 494 releasePooledConnection(connection); 495 } 496 } 497 } 498 499 500 512 protected Object sendCommand(DbCommand command,boolean waitForResult,DbClient connection) throws Exception ,IOException ,TransactionException,ClassNotFoundException ,OzoneObjectException { 513 514 Object result = null; 515 516 synchronized (connection) { 519 connection.send(command); 520 if (waitForResult) { 521 result = connection.receive(); 523 524 if (result != null) { 525 if (result instanceof Throwable ) { 527 if (result instanceof RuntimeException ) { 528 if (result instanceof OzoneObjectException) { 529 throw (OzoneObjectException) result; 530 } else { 531 ((Exception )result).fillInStackTrace(); 532 throw (RuntimeException ) result; 533 } 534 } else if (result instanceof Exception ) { 535 ((Exception )result).fillInStackTrace(); 536 throw (Exception ) result; 537 } else { 538 if (result instanceof Error ) { 539 ((Error ) result).fillInStackTrace(); 540 throw (Error ) result; 541 } 542 } 543 } 544 } 545 } 546 } 547 return result; 548 } 549 550 551 protected ExternalDatabase linkForProxy(OzoneProxy proxy) { 552 ExternalDatabase link = wrapper != null ? wrapper : this; 553 return link; 555 } 556 557 558 protected synchronized void setWrapper(ExternalDatabase _wrapper) { 559 wrapper = _wrapper; 560 } 561 562 563 565 566 public boolean isOpen() throws Exception { 567 return txTable!=null; 568 } 569 570 571 574 protected void open(Hashtable _props) throws Exception { 575 txTable = new DxHashMap(); 576 apool = new DxArrayDeque(32); 577 upool = new DxHashSet(32); 578 579 databases.add(this); 580 } 581 582 583 589 public static ExternalDatabase openDatabase(String _url, String _username, String _passwd) throws Exception { 590 591 Hashtable props = createProps(_url); 592 props.put(PROP_USER, _username); 593 props.put(PROP_PASSWD, _passwd); 594 595 if (_url.startsWith("ozonedb:remote")) { 596 RemoteDatabase db = new RemoteDatabase(); 597 db.open(props); 598 return db; 599 } else if (_url.startsWith("ozonedb:local")) { 600 LocalDatabase db = new LocalDatabase(); 601 db.open(props); 602 return db; 603 } else { 604 throw new MalformedURLException (_url); 605 } 606 } 607 608 609 613 public static ExternalDatabase openDatabase(String _url) throws Exception { 614 615 Hashtable props = createProps(_url); 616 617 if (_url.startsWith("ozonedb:remote")) { 618 RemoteDatabase db = new RemoteDatabase(); 619 db.open(props); 620 return db; 621 } else if (_url.startsWith("ozonedb:local")) { 622 LocalDatabase db = new LocalDatabase(); 623 db.open(props); 624 return db; 625 } else { 626 throw new MalformedURLException (_url); 627 } 628 } 629 630 631 635 protected static Hashtable createProps(String _url) throws URISyntaxException , UnknownHostException { 636 Hashtable props = new Hashtable (); 637 638 URI uri = new URI (_url); 639 String protocol = uri.getScheme(); 640 if (!protocol.equals("ozonedb")) { 641 throw new URISyntaxException (_url, "unknown protocol: " + protocol); 642 } 643 644 URI subUri = new URI (uri.getSchemeSpecificPart()); 645 646 String protocol2 = subUri.getScheme(); 647 if (protocol2.equals("local")) { 648 String filename = subUri.getPath(); 649 props.put(PROP_DIR, filename); 650 } else if (protocol2.equals("remote")) { 651 String hostname = subUri.getHost(); 652 if (hostname == null) throw new UnknownHostException ("host is null"); 653 int port = subUri.getPort(); 654 props.put(PROP_HOST, hostname); 655 props.put(PROP_PORT, new Integer (port)); 656 } else { 657 throw new URISyntaxException (_url, "protocol: " + protocol2); 658 } 659 660 String query = subUri.getQuery(); 661 String user = null; 664 String password = null; 665 if (query != null) { 666 for(StringTokenizer amp = new StringTokenizer (query, "&"); amp.hasMoreElements(); ) { 667 String keyWithValue = amp.nextToken(); 668 StringTokenizer eq = new StringTokenizer (keyWithValue, "="); 669 if (eq.countTokens() != 2) throw new URISyntaxException (_url, "could not parse: " + keyWithValue); 670 String key = eq.nextToken(); 671 if (key.equals("user")) { 672 if (user == null) { 673 user = eq.nextToken(); 674 } else throw new URISyntaxException (_url, "duplicate occurence of option " + key); 675 } else if (key.equals("password")) { 676 if (password == null) { 677 password = eq.nextToken(); 678 } else throw new URISyntaxException (_url, "duplicate occurence of option " + key); 679 } else throw new URISyntaxException (_url, "unknown option " + key); 680 } 681 } 682 683 if (user == null) { 684 user = System.getProperty("org.ozoneDB.user.name"); 685 if (user == null) { 686 user = System.getProperty("user.name"); 687 } 688 if (user == null) { 689 user="noname"; 690 } 691 } 692 if (password == null) { 693 password = ""; 694 } 695 props.put(PROP_USER, user); 696 props.put(PROP_PASSWD, password); 697 698 return props; 699 } 700 701 704 public synchronized void close() throws Exception { 705 if (isOpen()) { 706 databases.remove(this); 707 708 try { 710 apool.addAll(upool); 711 712 DxIterator it = apool.iterator(); 713 DbClient connection; 714 while ((connection = (DbClient) it.next()) != null) { 715 try { 716 connection.send(new DbCloseConn()); 717 }catch(java.io.IOException e){ 718 } 721 Thread.sleep(1000); 722 try { 723 connection.close(); 724 }catch(java.io.IOException e){ 725 } 728 it.removeObject(); 729 } 730 } finally { 731 apool = null; 732 upool = null; 733 txTable = null; 734 } 735 } 736 } 737 738 739 protected void finalize() throws Throwable { 740 close(); 741 } 742 743 744 public void reloadClasses() throws Exception { 745 Integer result = (Integer ) sendCommand(new DbReloadClasses(), true); 746 } 747 748 749 public OzoneProxy createObject( String className, int access, String name, String sig, Object [] args ) throws RuntimeException , OzoneObjectException { 750 try { 751 OzoneProxy proxy = (OzoneProxy) sendCommand( new DbCreateObj( className, access, name, sig, args ), true ); 752 753 if (org.ozoneDB.core.Env.selfCheck) { 754 if (proxy==null) { throw new Error ("Found during createObject(\""+className+"\","+access+","+name+",\""+sig+"\"): returned proxy is "+proxy); 756 } 757 } 758 759 return proxy; 760 } catch (OzoneObjectException e) { 761 throw e; 762 } catch (RuntimeException e) { 763 throw e; 764 } catch (Exception e) { 765 throw new RuntimeException ("Caught during createObject(\""+className+"\","+access+","+name+",\""+sig+"\"): "+e); 768 } 769 } 770 771 772 public void deleteObject( OzoneRemote obj ) throws RuntimeException ,OzoneObjectException { 773 try { 774 sendCommand( new DbDeleteObj( (OzoneProxy)obj ), true ); 775 } catch (OzoneObjectException e) { 776 throw e; 777 } catch (Exception e) { 778 throw new RuntimeException ("Caught during deleteObject()",e); 780 } 782 } 783 784 785 public OzoneProxy copyObject(OzoneRemote obj) throws Exception { 786 return (OzoneProxy) sendCommand(new DbCopyObj((OzoneProxy) obj), true); 787 } 788 789 790 public void nameObject(OzoneRemote obj, String name) throws Exception { 791 sendCommand(new DbNameObj((OzoneProxy) obj, name), true); 792 } 793 794 795 public OzoneProxy objectForName(String name) throws Exception { 796 return (OzoneProxy) sendCommand(new DbObjForName(name), true); 797 } 798 799 public String [] objectNames() throws Exception { 800 DxSet nameSet = (DxSet)sendCommand(new DbObjectNames(), true); 802 Object [] keys = nameSet.toArray(); 803 String [] names = new String [keys.length]; 804 for (int i = 0; i < keys.length; i++) { 805 names[i] = (String ) keys[i]; 806 } 807 return names; 808 } 809 810 public OzoneProxy objectForHandle(String handle) throws Exception { 811 return (OzoneProxy) sendCommand(new DbObjForHandle(handle), true); 812 } 813 814 815 public Object invoke(OzoneProxy rObj, String methodName, String sig, Object [] args, int lockLevel) 816 throws Exception { 817 Object result = sendCommand(new DbInvoke(rObj, methodName, sig, args, lockLevel), true); 819 return result; 820 } 821 822 823 public Object invoke(OzoneProxy rObj, int methodIndex, Object [] args, int lockLevel) throws Exception { 824 Object result = sendCommand(new DbInvoke(rObj, methodIndex, args, lockLevel), true); 826 return result; 827 } 828 829 830 public OzoneCompatible fetch(OzoneProxy rObj, int lockLevel) throws Exception ,org.ozoneDB.ObjectNotFoundException, java.io.IOException , java.lang.ClassNotFoundException , org.ozoneDB.TransactionException, org.ozoneDB.core.TransactionError { 831 return null; 832 } 833 834 835 public Node xmlForObject(OzoneRemote rObj, Document domFactory) throws Exception { 836 byte[] bytes = (byte[]) sendCommand(new DbXMLForObj((OzoneProxy) rObj), true); 837 838 SAXChunkConsumer consumer = new SAXChunkConsumer(domFactory, null); 839 consumer.processChunk(bytes); 840 841 return consumer.getResultNode(); 842 } 843 844 845 public void xmlForObject(OzoneRemote rObj, ContentHandler ch) throws Exception { 846 byte[] bytes = (byte[]) sendCommand(new DbXMLForObj((OzoneProxy) rObj), true); 847 848 SAXChunkConsumer consumer = new SAXChunkConsumer(ch); 849 consumer.processChunk(bytes); 850 } 851 852 853 858 public Admin admin() throws Exception { 859 Admin admin = (Admin) objectForName(AdminImpl.OBJECT_NAME); 860 return admin; 861 } 862 863 871 public void notifyProxyDeath(OzoneProxy proxy) { 872 try { 873 sendCommand(new DbProxyDeath(proxy),false); 874 } catch (Exception e) { 875 throw new RuntimeException ("Caught during notifyProxyDeath(): "+e); 878 } 879 } 880 } 881 882 | Popular Tags |