1 30 package com.genimen.djeneric.repository.rdbms; 31 32 import java.io.IOException ; 33 import java.sql.Connection ; 34 import java.sql.DriverManager ; 35 import java.sql.ResultSet ; 36 import java.sql.SQLException ; 37 import java.text.SimpleDateFormat ; 38 import java.util.ArrayList ; 39 import java.util.EmptyStackException ; 40 import java.util.HashMap ; 41 import java.util.Stack ; 42 43 import javax.naming.Context ; 44 import javax.naming.InitialContext ; 45 import javax.sql.DataSource ; 46 47 import com.genimen.djeneric.language.Messages; 48 import com.genimen.djeneric.repository.DjContextManager; 49 import com.genimen.djeneric.repository.DjExtent; 50 import com.genimen.djeneric.repository.DjIdProvider; 51 import com.genimen.djeneric.repository.DjMessenger; 52 import com.genimen.djeneric.repository.DjModelView; 53 import com.genimen.djeneric.repository.DjPersistenceManager; 54 import com.genimen.djeneric.repository.DjProperty; 55 import com.genimen.djeneric.repository.DjRelation; 56 import com.genimen.djeneric.repository.DjRepositoryDescriptor; 57 import com.genimen.djeneric.repository.DjSession; 58 import com.genimen.djeneric.repository.exceptions.CatalogException; 59 import com.genimen.djeneric.repository.exceptions.DjenericException; 60 import com.genimen.djeneric.repository.exceptions.LoadModelException; 61 import com.genimen.djeneric.util.DjLogger; 62 63 68 public class RdbmsPersistenceManager extends DjPersistenceManager 69 { 70 private int _maxConnectionPoolSize = 20; 71 72 public final static String OBJECT_TYPE_COLUMN = "_OBJTYPE"; 73 74 77 public final static String CONTEXT_TABLE = "dj_contexts"; 78 81 public final static String USER_TABLE = "dj_users"; 82 85 public final static String USER_CTX_TABLE = "dj_usr_ctx"; 86 89 public final static String USER_VWS_TABLE = "dj_usr_vws"; 90 93 public final static String VIEW_TABLE = "dj_views"; 94 97 public final static String MODEL_TABLE = "dj_model"; 98 101 public final static String POLYMORPH_TABLE = "dj_polymorph"; 102 105 public final static String INTERNAL_IDS_TABLE = "dj_ids"; 106 107 110 public final static String INTERNAL_TYPE_COLUMN = "table_alias"; 111 114 public final static String INTERNAL_CONTEXT_COLUMN = "context_id"; 115 116 119 public final static String CONTEXT_PARAM_NAME = "_dj_context_id_"; 120 123 public final static int LOCK_STRING_MAX_LENGTH = 50; 124 125 private int _sqlTranslationMode; 126 HashMap _cachedStatements = new HashMap (); 127 128 private String _modelLockTag = null; 131 132 Stack _connectionPool = new Stack (); 133 134 144 public RdbmsPersistenceManager(DjMessenger messenger, DjRepositoryDescriptor rdesc) throws DjenericException 145 { 146 super(messenger, rdesc); 147 sharedInit(); 148 construct(); 149 } 150 151 protected void sharedInit() 152 { 153 setTranslationMode(SqlXlator.TRANSLATE_TO_MAPPING); 154 } 155 156 169 public RdbmsPersistenceManager(DjMessenger messenger, DjRepositoryDescriptor rdesc, String repositoryUser, 170 String repositoryPassword) throws DjenericException 171 { 172 super(messenger, rdesc); 173 sharedInit(); 174 if (repositoryUser != null) setRepositoryUser(repositoryUser); 175 if (repositoryPassword != null) setRepositoryPassword(repositoryPassword); 176 construct(); 177 } 178 179 protected void construct() throws DjenericException 180 { 181 loadModel(); 182 } 183 184 189 public boolean isInPolymorphMode() 190 { 191 return (getTranslationMode() == SqlXlator.TRANSLATE_TO_MAPPING); 192 } 193 194 200 public void setTranslationMode(int tp) 201 { 202 _sqlTranslationMode = tp; 203 } 204 205 210 public int getTranslationMode() 211 { 212 return _sqlTranslationMode; 213 } 214 215 227 protected String retrieveModelXml() throws DjenericException 228 { 229 Connection conn = getConnection(); 230 String result = ""; 231 try 232 { 233 SqlStatement stmt = new SqlStatement(conn, "select metamodel from " + MODEL_TABLE); 234 ResultSet rs = stmt.executeQuery(); 235 if (rs.next()) 236 { 237 result = new String (SqlStatement.getBlob(rs, "metamodel")); 238 } 239 rs.close(); 240 stmt.close(); 241 } 242 catch (SQLException sqe) 243 { 244 throw new LoadModelException(sqe); 245 } 246 catch (IOException iox) 247 { 248 throw new CatalogException(iox); 249 } 250 finally 251 { 252 try 253 { 254 releaseToPool(conn); 255 } 256 catch (SQLException se) 257 { 258 throw new CatalogException(se); 259 } 260 if (shouldTrace(TRACE_INTERNAL)) trace("Model retrieved"); 261 } 262 return result; 263 } 264 265 public void loadModel() throws DjenericException 266 { 267 super.loadModel(); 268 269 _cachedStatements = new HashMap (); 271 } 272 273 281 protected void storeModelXml(String xml) throws DjenericException 282 { 283 try 284 { 285 RdbmsSession session = (RdbmsSession) createSession(); 286 try 287 { 288 SqlStatement stmt = session.getInternalSqlStatement("delete from " + MODEL_TABLE); 289 stmt.executeUpdate(); 290 291 stmt = session.getInternalSqlStatement("insert into " + MODEL_TABLE 292 + "(metamodel, locked_by) values(:metamodel, :lockedBy)"); 293 stmt.setBlob("metamodel", xml, DjPersistenceManager.ENCODING_METHOD); 294 stmt.setString("lockedBy", _modelLockTag); 295 stmt.executeUpdate(); 296 session.commit(); 297 if (shouldTrace(TRACE_INTERNAL)) trace("Model stored"); 298 } 299 finally 300 { 301 session.close(); 302 } 303 } 304 catch (SQLException x) 305 { 306 throw new DjenericException(x); 307 } 308 } 309 310 317 public DjModelView[] getViews() throws DjenericException 318 { 319 try 320 { 321 RdbmsSession session = (RdbmsSession) createSession(); 322 ArrayList result = new ArrayList (); 323 324 try 325 { 326 SqlStatement stmt = ((RdbmsSession) session).getInternalSqlStatement("select id, code, metaview " + "from " 327 + VIEW_TABLE + " mvw " 328 + "order by mvw.code "); 329 ResultSet rs = stmt.executeQuery(); 330 while (rs.next()) 331 { 332 DjModelView vw = new RdbmsModelView(this, rs.getLong("id"), rs.getString("code"), new String (SqlStatement 333 .getBlob(rs, "metaview"))); 334 result.add(vw); 335 } 336 rs.close(); 337 stmt.close(); 338 if (shouldTrace(TRACE_INTERNAL)) trace("Views retrieved"); 339 } 340 finally 341 { 342 session.close(); 343 } 344 345 return (DjModelView[]) result.toArray(new DjModelView[0]); 346 } 347 catch (SQLException x) 348 { 349 throw new DjenericException(x); 350 } 351 catch (IOException x) 352 { 353 throw new DjenericException(x); 354 } 355 } 356 357 363 public void login() throws DjenericException 364 { 365 super.login(); 366 367 clearConnectionPool(); 371 } 372 373 376 public void clearConnectionPool() 377 { 378 while (_connectionPool.size() > 0) 379 { 380 try 381 { 382 ((Connection ) _connectionPool.pop()).close(); 383 } 384 catch (EmptyStackException esx) 385 { 386 } 389 catch (SQLException x) 390 { 391 DjLogger.log(x); 392 } 393 } 394 } 395 396 399 public void close() 400 { 401 try 402 { 403 if (isModelLocked()) unlockModel(); 404 if (shouldTrace(TRACE_INTERNAL)) trace("Persistence manager closed"); 405 } 406 catch (CatalogException x) 407 { 408 DjLogger.log(x); 409 } 410 clearConnectionPool(); 411 } 412 413 private boolean _isolationProblemEncountered = false; 414 415 422 protected Connection getConnection() throws DjenericException 423 { 424 try 425 { 426 if (!isRepositoryUserKnown()) 427 { 428 login(); 429 } 430 431 435 try 436 { 437 Connection conn = (Connection ) _connectionPool.pop(); 438 if (shouldTrace(TRACE_INTERNAL)) trace("Connection fetched from connection pool"); 439 return conn; 440 } 441 catch (EmptyStackException esx) 442 { 443 } 445 446 Connection conn; 447 if (getCurrentRepository().isDatasource()) 448 { 449 Context initContext = new InitialContext (); 450 Context envContext = (Context ) initContext.lookup("java:comp/env"); 451 DataSource ds = (DataSource ) envContext.lookup(getCurrentRepository().getUrl()); 452 conn = ds.getConnection(); 453 } 454 else 455 { 456 Class.forName(getCurrentRepository().getDriver()); 457 conn = DriverManager.getConnection(getCurrentRepository().getUrl(), getRepositoryUser(), 458 getRepositoryPassword()); 459 } 460 conn.setAutoCommit(false); 461 try 462 { 463 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); 464 } 465 catch (SQLException x) 466 { 467 if (!_isolationProblemEncountered) DjLogger.log(Messages.getString("RdbmsPersistenceManager.IsolationLevel", x 468 .getMessage())); 469 _isolationProblemEncountered = true; 470 } 471 if (shouldTrace(TRACE_INTERNAL)) trace("New connection created"); 472 return conn; 473 } 474 catch (Exception x) 475 { 476 throw new DjenericException(x); 477 } 478 } 479 480 488 protected void releaseToPool(Connection conn) throws SQLException 489 { 490 if (conn == null) return; 491 if (_connectionPool.size() < _maxConnectionPoolSize) 492 { 493 conn.rollback(); 496 _connectionPool.push(conn); 497 if (shouldTrace(TRACE_INTERNAL)) trace("Connection released to pool (poolsize = " + _connectionPool.size() + ")"); 498 } 499 else 500 { 501 conn.close(); 503 if (shouldTrace(TRACE_INTERNAL)) trace("Connection discarded (poolsize = " + _connectionPool.size() + ")"); 504 } 505 } 506 507 514 public DjSession createSession() throws DjenericException 515 { 516 RdbmsSession ses = new RdbmsSession(this); 517 ses.setCommitAllowed(isCommitAllowed()); 518 return ses; 519 } 520 521 530 public String external2internalStatement(String sql) throws DjenericException 531 { 532 try 533 { 534 String prevOne = (String ) _cachedStatements.get(sql); 535 if (prevOne != null) return prevOne; 536 537 SqlXlator xlator = new SqlXlator(this, getCurrentContext()); 538 xlator.setTranslationMode(_sqlTranslationMode); 539 String result = xlator.translate(sql); 540 _cachedStatements.put(sql, result); 541 return result; 542 } 543 catch (Throwable x) 544 { 545 System.err.println(sql); 546 throw new DjenericException(x); 547 } 548 } 549 550 561 public String external2internalStatement(String sql, ArrayList metaDataColumnUsages) throws DjenericException 562 { 563 try 564 { 565 SqlXlator xlator = new SqlXlator(this, getCurrentContext()); 566 xlator.setTranslationMode(_sqlTranslationMode); 567 xlator.setGatherMetaData(true); 568 569 metaDataColumnUsages.clear(); 570 String result = xlator.translate(sql); 571 metaDataColumnUsages.addAll(xlator.getMetaData()); 572 573 return result; 574 } 575 catch (Exception x) 576 { 577 System.err.println(sql); 578 throw new DjenericException(x); 579 } 580 } 581 582 589 public DjModelView createModelView() 590 { 591 return new RdbmsModelView(this); 592 } 593 594 601 public DjContextManager createContextManager(DjPersistenceManager mgr) 602 { 603 return new RdbmsContextManager(mgr); 604 } 605 606 625 public DjExtent createExtent(String objectType, String name, String alias, String internalCode, String title, 626 String nameSingular, String namePlural) 627 { 628 return new RdbmsExtent(objectType, name, alias, internalCode, title, nameSingular, namePlural); 629 } 630 631 636 public DjIdProvider createIdProvider() 637 { 638 return new RdbmsIdProvider(); 639 } 640 641 648 public DjIdProvider createIdProvider(int cacheSize) 649 { 650 return new RdbmsIdProvider(cacheSize); 651 } 652 653 670 public DjRelation createRelation(String name, DjExtent masterExtent, DjExtent detailExtent, 671 DjProperty detailProperty, boolean isContainedRelation, String description) 672 { 673 return new DjRelation(name, masterExtent, detailExtent, detailProperty, isContainedRelation, description); 674 } 675 676 681 public boolean isModelLocked() 682 { 683 return _modelLockTag != null; 684 } 685 686 693 public String getCurrentLockTag() throws CatalogException 694 { 695 try 696 { 697 RdbmsSession session = (RdbmsSession) createSession(); 698 try 699 { 700 SqlStatement stmt = session.getInternalSqlStatement("select locked_by from " + MODEL_TABLE); 701 702 String lockString = null; 703 ResultSet rs = stmt.executeQuery(); 704 if (rs.next()) lockString = rs.getString("locked_by"); 705 rs.close(); 706 stmt.close(); 707 return lockString; 708 } 709 finally 710 { 711 session.close(); 712 } 713 } 714 catch (Exception x) 715 { 716 throw new CatalogException(x); 717 } 718 } 719 720 726 public void lockModel() throws CatalogException 727 { 728 boolean lockFailed = false; 729 String msg = null; 730 try 731 { 732 RdbmsSession session = (RdbmsSession) createSession(); 733 try 734 { 735 SqlStatement stmt = session.getInternalSqlStatement("update " + MODEL_TABLE + " set locked_by = :lockedBy " 736 + " where (locked_by is null or locked_by = :lockedBy)"); 737 738 String lockString; 739 if (_modelLockTag != null) lockString = _modelLockTag; 740 else 741 { 742 SimpleDateFormat sf = new SimpleDateFormat ("dd-MM-yyyy HH:mm:ss"); 743 String ts = sf.format(new java.util.Date (System.currentTimeMillis())); 744 lockString = System.getProperty("user.name", "anonymous") + " at " + ts; 745 if (lockString.length() > LOCK_STRING_MAX_LENGTH) lockString = lockString 746 .substring(0, LOCK_STRING_MAX_LENGTH); 747 } 748 749 stmt.setString("lockedBy", lockString); 750 int recsHit = stmt.executeUpdate(); 751 stmt.close(); 752 753 if (recsHit == 0) 762 { 763 stmt = session.getInternalSqlStatement("select count(*) as cnt from " + MODEL_TABLE); 764 ResultSet rs = stmt.executeQuery(); 765 if (rs.next()) 766 { 767 if (rs.getInt("cnt") != 0) lockFailed = true; 768 } 769 rs.close(); 770 stmt.close(); 771 if (!lockFailed) 773 { 774 _modelLockTag = lockString; 776 storeModelXml(EMPTY_MODEL_XML_DOC); 777 } 778 } 779 780 if (!lockFailed) 781 { 782 stmt = session.getInternalSqlStatement("select metamodel from " + MODEL_TABLE); 785 ResultSet rs = stmt.executeQuery(); 786 String modelInDB = EMPTY_MODEL_XML_DOC; 787 if (rs.next()) 788 { 789 modelInDB = new String (SqlStatement.getBlob(rs, "metamodel")); 790 } 791 rs.close(); 792 stmt.close(); 793 if (!modelInDB.equals(getOriginalModel())) 794 { 795 lockFailed = true; 796 session.rollback(); 797 msg = Messages.getString("RdbmsPersistenceManager.ModelUpdated"); 798 } 799 else _modelLockTag = lockString; 800 } 801 session.commit(); 802 } 803 finally 804 { 805 session.close(); 806 } 807 } 808 catch (Exception x) 809 { 810 throw new CatalogException(x); 811 } 812 if (lockFailed) 813 { 814 if (shouldTrace(TRACE_INTERNAL)) trace("Lock failed"); 815 if (msg == null) msg = Messages.getString("RdbmsPersistenceManager.locked", getCurrentLockTag()); 816 throw new CatalogException(Messages.getString("RdbmsPersistenceManager.CouldNotLockModel", msg)); 817 } 818 else if (shouldTrace(TRACE_INTERNAL)) trace("Model lock aquired"); 819 820 } 821 822 828 public void unlockModel() throws CatalogException 829 { 830 try 831 { 832 if (_modelLockTag == null) throw new CatalogException(Messages.getString("RdbmsPersistenceManager.NoLockAquired")); 833 RdbmsSession session = (RdbmsSession) createSession(); 834 try 835 { 836 SqlStatement stmt = session.getInternalSqlStatement("update " + MODEL_TABLE + " set locked_by = null " 837 + " where (locked_by is null or locked_by = :lockedBy)"); 838 839 stmt.setString("lockedBy", _modelLockTag); 840 int recsHit = stmt.executeUpdate(); 841 stmt.close(); 842 session.commit(); 843 _modelLockTag = null; 844 if (shouldTrace(TRACE_INTERNAL)) trace("Model unlocked"); 845 if (recsHit == 0) throw new CatalogException(Messages.getString("RdbmsPersistenceManager.LockInvalidated")); 846 } 847 finally 848 { 849 session.close(); 850 } 851 } 852 catch (Exception x) 853 { 854 throw new CatalogException(x); 855 } 856 } 857 858 864 public void forceUnlockModel() throws CatalogException 865 { 866 try 867 { 868 RdbmsSession session = (RdbmsSession) createSession(); 869 try 870 { 871 SqlStatement stmt = session.getInternalSqlStatement("update " + MODEL_TABLE + " set locked_by = null "); 872 873 stmt.executeUpdate(); 874 stmt.close(); 875 session.commit(); 876 } 877 finally 878 { 879 session.close(); 880 } 881 } 882 catch (Exception x) 883 { 884 throw new CatalogException(x); 885 } 886 } 887 888 894 public void setEstimatedConcurrentSessions(int estimate) 895 { 896 _maxConnectionPoolSize = estimate; 897 } 898 } | Popular Tags |