1 29 30 package com.caucho.amber.manager; 31 32 import com.caucho.amber.AmberException; 33 import com.caucho.amber.AmberObjectNotFoundException; 34 import com.caucho.amber.AmberQuery; 35 import com.caucho.amber.AmberRuntimeException; 36 import com.caucho.amber.cfg.EntityResultConfig; 37 import com.caucho.amber.cfg.NamedNativeQueryConfig; 38 import com.caucho.amber.cfg.SqlResultSetMappingConfig; 39 import com.caucho.amber.collection.AmberCollection; 40 import com.caucho.amber.entity.*; 41 import com.caucho.amber.query.AbstractQuery; 42 import com.caucho.amber.query.QueryCacheKey; 43 import com.caucho.amber.query.QueryParser; 44 import com.caucho.amber.query.ResultSetCacheChunk; 45 import com.caucho.amber.query.UserQuery; 46 import com.caucho.amber.table.Table; 47 import com.caucho.amber.type.EntityType; 48 import com.caucho.config.ConfigException; 49 import com.caucho.ejb.EJBExceptionWrapper; 50 import com.caucho.jca.BeginResource; 51 import com.caucho.jca.CloseResource; 52 import com.caucho.jca.UserTransactionProxy; 53 import com.caucho.util.L10N; 54 import com.caucho.util.LruCache; 55 56 import javax.persistence.EntityNotFoundException; 57 import javax.persistence.EntityTransaction; 58 import javax.persistence.FlushModeType; 59 import javax.persistence.LockModeType; 60 import javax.persistence.Query; 61 import javax.persistence.PersistenceException; 62 import javax.persistence.EntityExistsException; 63 import javax.persistence.TransactionRequiredException; 64 import javax.sql.DataSource ; 65 import javax.transaction.Status ; 66 import javax.transaction.Synchronization ; 67 import javax.transaction.Transaction ; 68 import java.sql.Connection ; 69 import java.sql.PreparedStatement ; 70 import java.sql.ResultSet ; 71 import java.sql.ResultSetMetaData ; 72 import java.sql.SQLException ; 73 import java.sql.Statement ; 74 import java.util.ArrayList ; 75 import java.util.List ; 76 import java.util.Map ; 77 import java.util.logging.Level ; 78 import java.util.logging.Logger ; 79 80 83 public class AmberConnection 84 implements BeginResource, CloseResource, Synchronization 85 { 86 private static final L10N L = new L10N(AmberConnection.class); 87 private static final Logger log 88 = Logger.getLogger(AmberConnection.class.getName()); 89 90 private AmberPersistenceUnit _persistenceUnit; 91 92 private boolean _isRegistered; 93 private boolean _isThreadConnection; 94 95 private ArrayList <Entity> _entities = new ArrayList <Entity>(); 96 97 private ArrayList <Entity> _txEntities = new ArrayList <Entity>(); 98 99 private ArrayList <AmberCompletion> _completionList 100 = new ArrayList <AmberCompletion>(); 101 102 private ArrayList <AmberCollection> _queries 103 = new ArrayList <AmberCollection>(); 104 105 private EntityTransaction _trans; 106 107 private long _xid; 108 private boolean _isInTransaction; 109 private boolean _isXA; 110 111 private Connection _conn; 112 private Connection _readConn; 113 114 private boolean _isAutoCommit = true; 115 116 private int _depth; 117 118 private LruCache<String ,PreparedStatement > _preparedStatementMap 119 = new LruCache<String ,PreparedStatement >(32); 120 121 private ArrayList <Statement > _statements = new ArrayList <Statement >(); 122 123 private QueryCacheKey _queryKey = new QueryCacheKey(); 124 125 128 AmberConnection(AmberPersistenceUnit persistenceUnit) 129 { 130 _persistenceUnit = persistenceUnit; 131 } 132 133 136 public AmberPersistenceUnit getPersistenceUnit() 137 { 138 return _persistenceUnit; 139 } 140 141 144 public void initThreadConnection() 145 { 146 _isThreadConnection = true; 147 148 register(); 149 } 150 151 155 public void prePersist(Entity entity) 156 { 157 try { 158 _persistenceUnit.callListeners(Listener.PRE_PERSIST, entity); 159 } catch (RuntimeException e) { 160 throw e; 161 } catch (Exception e) { 162 throw new EJBExceptionWrapper(e); 163 } 164 } 165 166 170 public void postPersist(Entity entity) 171 { 172 try { 173 _persistenceUnit.callListeners(Listener.POST_PERSIST, entity); 174 } catch (RuntimeException e) { 175 throw e; 176 } catch (Exception e) { 177 throw new EJBExceptionWrapper(e); 178 } 179 } 180 181 185 public void preRemove(Entity entity) 186 { 187 try { 188 _persistenceUnit.callListeners(Listener.PRE_REMOVE, entity); 189 } catch (RuntimeException e) { 190 throw e; 191 } catch (Exception e) { 192 throw new EJBExceptionWrapper(e); 193 } 194 } 195 196 200 public void postRemove(Entity entity) 201 { 202 try { 203 _persistenceUnit.callListeners(Listener.POST_REMOVE, entity); 204 } catch (RuntimeException e) { 205 throw e; 206 } catch (Exception e) { 207 throw new EJBExceptionWrapper(e); 208 } 209 } 210 211 215 public void preUpdate(Entity entity) 216 { 217 try { 218 _persistenceUnit.callListeners(Listener.PRE_UPDATE, entity); 219 } catch (RuntimeException e) { 220 throw e; 221 } catch (Exception e) { 222 throw new EJBExceptionWrapper(e); 223 } 224 } 225 226 230 public void postUpdate(Entity entity) 231 { 232 try { 233 _persistenceUnit.callListeners(Listener.POST_UPDATE, entity); 234 } catch (RuntimeException e) { 235 throw e; 236 } catch (Exception e) { 237 throw new EJBExceptionWrapper(e); 238 } 239 } 240 241 245 public void postLoad(Entity entity) 246 { 247 try { 248 _persistenceUnit.callListeners(Listener.POST_LOAD, entity); 249 } catch (RuntimeException e) { 250 throw e; 251 } catch (Exception e) { 252 throw new EJBExceptionWrapper(e); 253 } 254 } 255 256 259 public void persist(Object entity) 260 { 261 try { 262 if (entity == null) 263 return; 264 265 if (! (entity instanceof Entity)) 266 throw new IllegalArgumentException (L.l("persist() operation can only be applied to an entity instance. If the argument is an entity, the corresponding class must be specified in the scope of a persistence unit.")); 267 268 checkTransactionRequired("persist"); 269 270 persistInternal(entity); 271 272 } catch (RuntimeException e) { 273 throw e; 274 } catch (SQLException e) { 275 throw new IllegalStateException (e); 276 } catch (Exception e) { 277 throw new EJBExceptionWrapper(e); 278 } 279 } 280 281 285 public void persistNoChecks(Object entity) 286 { 287 try { 288 if (entity == null) 289 return; 290 291 persistInternal(entity); 292 293 } catch (EntityExistsException e) { 294 } catch (RuntimeException e) { 298 throw e; 299 } catch (SQLException e) { 300 throw new IllegalStateException (e); 301 } catch (Exception e) { 302 throw new EJBExceptionWrapper(e); 303 } 304 } 305 306 309 public <T> T merge(T entityT) 310 { 311 try { 312 313 if (! (entityT instanceof Entity)) 314 throw new IllegalArgumentException (L.l("merge() operation can only be applied to an entity instance. If the argument is an entity, the corresponding class must be specified in the scope of a persistence unit.")); 315 316 flushInternal(); 317 318 Entity entity = (Entity) entityT; 319 320 int state = entity.__caucho_getEntityState(); 321 322 if (state == com.caucho.amber.entity.Entity.TRANSIENT) { 323 if (contains(entity)) { 324 throw new UnsupportedOperationException (L.l("Merge operation for detached instances is not supported")); 326 } 327 else { 328 persist(entity); 330 } 331 } 332 else if (state >= com.caucho.amber.entity.Entity.P_DELETING) { 333 throw new IllegalArgumentException (L.l("Merge operation cannot be applied to a removed entity instance")); 335 } 336 else { 337 339 entity.__caucho_cascadePrePersist(this); 341 342 entity.__caucho_cascadePostPersist(this); 344 } 345 346 349 return entityT; 350 351 } catch (RuntimeException e) { 352 throw e; 353 } catch (Exception e) { 354 throw new EJBExceptionWrapper(e); 355 } 356 } 357 358 361 public void remove(Object entity) 362 { 363 try { 364 if (entity == null) 365 return; 366 367 if (! (entity instanceof Entity)) 368 throw new IllegalArgumentException (L.l("remove() operation can only be applied to an entity instance. If the argument is an entity, the corresponding class must be specified in the scope of a persistence unit.")); 369 370 checkTransactionRequired("remove"); 371 372 Entity instance = (Entity) entity; 373 374 if (instance.__caucho_getConnection() == null) 376 throw new IllegalArgumentException (L.l("remove() operation can only be applied to a managed entity. This entity instance is detached which means it was probably removed or needs to be merged.")); 377 378 int state = instance.__caucho_getEntityState(); 379 380 if (state >= com.caucho.amber.entity.Entity.P_DELETING) 381 return; 382 383 Object oldEntity = getEntity(instance.getClass().getName(), 384 instance.__caucho_getPrimaryKey()); 385 386 if (oldEntity == null) 388 throw new IllegalArgumentException (L.l("remove() operation can only be applied to a managed entity instance.")); 389 390 instance.__caucho_cascadePreRemove(this); 392 393 delete(instance); 394 395 instance.__caucho_cascadePostRemove(this); 398 399 } catch (RuntimeException e) { 400 throw e; 401 } catch (Exception e) { 402 throw new EJBExceptionWrapper(e); 403 } 404 } 405 406 409 421 422 425 public <T> T find(Class <T> entityClass, 426 Object primaryKey) 427 { 428 return find(entityClass, primaryKey, null); 429 } 430 431 434 public <T> T find(Class <T> entityClass, 435 Object primaryKey, 436 Map preloadedProperties) 437 { 438 try { 439 AmberEntityHome entityHome 440 = _persistenceUnit.getEntityHome(entityClass.getName()); 441 442 if (entityHome == null) { 443 throw new IllegalArgumentException (L.l("find() operation can only be applied if the entity class is specified in the scope of a persistence unit.")); 444 } 445 446 return (T) load(entityClass, primaryKey, preloadedProperties); 447 } catch (AmberObjectNotFoundException e) { 448 451 return null; 452 } catch (RuntimeException e) { 453 throw e; 454 } catch (Exception e) { 455 throw new EJBExceptionWrapper(e); 456 } 457 } 458 459 462 public <T> T getReference(Class <T> entityClass, Object primaryKey) 463 throws EntityNotFoundException, IllegalArgumentException 464 { 465 T reference = null; 466 467 try { 468 470 reference = find(entityClass, primaryKey); 471 472 if (reference == null) 473 throw new EntityNotFoundException(L.l("entity with primary key {0} not found in getReference()", primaryKey)); 474 475 if (! (entityClass.isAssignableFrom(Entity.class))) 476 throw new IllegalArgumentException (L.l("getReference() operation can only be applied to an entity class")); 477 478 return reference; 479 480 } catch (EntityNotFoundException e) { 481 throw e; 482 } catch (RuntimeException e) { 483 throw new IllegalArgumentException (e); 484 } catch (Exception e) { 485 throw new EJBExceptionWrapper(e); 486 } 487 } 488 489 492 public void clear() 493 { 494 _entities.clear(); 495 _txEntities.clear(); 496 } 497 498 501 public Query createQuery(String sql) 502 { 503 try { 504 AbstractQuery queryProgram = parseQuery(sql, false); 505 506 return new QueryImpl(queryProgram, this); 507 } catch (RuntimeException e) { 508 throw new IllegalArgumentException (e); 509 } catch (Exception e) { 510 throw new EJBExceptionWrapper(e); 511 } 512 } 513 514 517 public Query createNamedQuery(String name) 518 { 519 String sql = _persistenceUnit.getNamedQuery(name); 520 521 if (sql != null) 522 return createQuery(sql); 523 524 NamedNativeQueryConfig nativeQuery 525 = _persistenceUnit.getNamedNativeQuery(name); 526 527 sql = nativeQuery.getQuery(); 528 529 String resultSetMapping = nativeQuery.getResultSetMapping(); 530 531 if (! ((resultSetMapping == null) || "".equals(resultSetMapping))) 532 return createNativeQuery(sql, resultSetMapping); 533 534 String resultClass = nativeQuery.getResultClass(); 535 536 AmberEntityHome entityHome 537 = _persistenceUnit.getEntityHome(resultClass); 538 539 EntityType entityType = entityHome.getEntityType(); 540 541 try { 542 return createNativeQuery(sql, entityType.getInstanceClass()); 543 } catch (Exception e) { 544 throw new IllegalArgumentException (e); 545 } 546 } 547 548 551 public Query createNativeQuery(String sql) 552 { 553 try { 554 QueryImpl query = new QueryImpl(this); 555 556 query.setNativeSql(sql); 557 558 return query; 559 } catch (RuntimeException e) { 560 throw new IllegalArgumentException (e); 561 } catch (Exception e) { 562 throw new EJBExceptionWrapper(e); 563 } 564 } 565 566 569 public Query createNativeQuery(String sql, String map) 570 { 571 573 SqlResultSetMappingConfig resultSet; 574 575 resultSet = _persistenceUnit.getSqlResultSetMapping(map); 576 577 if (resultSet == null) 578 throw new IllegalArgumentException (L.l("createNativeQuery() cannot create a native query for a result set named '{0}'", map)); 579 580 return createInternalNativeQuery(sql, resultSet); 581 } 582 583 586 public Query createNativeQuery(String sql, Class type) 587 { 588 SqlResultSetMappingConfig resultSet 589 = new SqlResultSetMappingConfig(); 590 591 EntityResultConfig entityResult 592 = new EntityResultConfig(); 593 594 entityResult.setEntityClass(type.getName()); 595 596 resultSet.addEntityResult(entityResult); 597 598 return createInternalNativeQuery(sql, resultSet); 599 } 600 601 604 public void refresh(Object entity) 605 { 606 try { 607 if (entity == null) 608 return; 609 610 if (! (entity instanceof Entity)) 611 throw new IllegalArgumentException (L.l("refresh() operation can only be applied to an entity instance.")); 612 613 checkTransactionRequired("refresh"); 614 615 Entity instance = (Entity) entity; 616 617 Object oldEntity = getEntity(instance.getClass().getName(), 618 instance.__caucho_getPrimaryKey()); 619 620 if (oldEntity != null) { 621 int state = instance.__caucho_getEntityState(); 622 623 if (state <= Entity.TRANSIENT || state >= Entity.P_DELETING) 624 oldEntity = null; 625 } 626 627 if (oldEntity == null) 628 throw new IllegalArgumentException (L.l("refresh() operation can only be applied to a managed entity instance.")); 629 630 instance.__caucho_expire(); 632 instance.__caucho_makePersistent(this, (EntityType) null); 633 instance.__caucho_retrieve(this); 634 } catch (SQLException e) { 635 throw new AmberRuntimeException(e); 636 } 637 } 638 639 642 public FlushModeType getFlushMode() 643 { 644 return FlushModeType.AUTO; 645 } 646 647 650 public void setFlushMode(FlushModeType mode) 651 { 652 throw new UnsupportedOperationException (); 653 } 654 655 658 public void lock(Object entity, LockModeType lockMode) 659 { 660 throw new UnsupportedOperationException (); 661 } 662 663 666 public EntityTransaction getTransaction() 667 { 668 if (_trans == null) 669 _trans = new EntityTransactionImpl(); 670 671 return _trans; 672 } 673 674 677 public boolean isOpen() 678 { 679 return _persistenceUnit != null; 680 } 681 682 685 void register() 686 { 687 if (! _isRegistered) { 688 UserTransactionProxy.getInstance().enlistCloseResource(this); 689 UserTransactionProxy.getInstance().enlistBeginResource(this); 690 } 691 692 _isRegistered = true; 693 } 694 695 698 public void joinTransaction() 699 { 700 throw new UnsupportedOperationException (); 701 } 702 703 706 public Object getDelegate() 707 { 708 throw new UnsupportedOperationException (); 709 } 710 711 714 public void close() 715 { 716 if (_persistenceUnit == null) 717 return; 718 719 try { 720 if (_isThreadConnection) 721 _persistenceUnit.removeThreadConnection(); 722 723 _isRegistered = false; 724 725 cleanup(); 726 } finally { 727 _persistenceUnit = null; 728 } 729 } 730 731 734 public AmberPersistenceUnit getAmberManager() 735 { 736 return _persistenceUnit; 737 } 738 739 742 public void register(AmberCollection query) 743 { 744 _queries.add(query); 745 } 746 747 750 public void addCompletion(AmberCompletion completion) 751 { 752 if (! _completionList.contains(completion)) 753 _completionList.add(completion); 754 } 755 756 759 public boolean isInTransaction() 760 { 761 return _isInTransaction; 762 } 763 764 767 public int getCacheChunkSize() 768 { 769 return 25; 770 } 771 772 775 public Object load(Class cl, 776 Object key) 777 throws AmberException 778 { 779 return load(cl, key, null); 780 } 781 782 785 public Object load(Class cl, 786 Object key, 787 Map preloadedProperties) 788 throws AmberException 789 { 790 Entity entity = null; 791 792 if (key == null) 793 return null; 794 795 entity = getEntity(cl.getName(), key); 798 799 if (entity != null) 800 return entity; 801 802 AmberEntityHome entityHome = _persistenceUnit.getEntityHome(cl.getName()); 803 804 if (entityHome == null) 805 return null; 806 else { 807 try { 808 entityHome.init(); 809 } catch (ConfigException e) { 810 throw new AmberException(e); 811 } 812 813 entity = entityHome.load(this, key, preloadedProperties); 814 815 if (entity == null) 816 return null; 817 818 addEntity(entity); 819 820 return entity; 821 } 822 } 823 824 827 public Object load(String entityName, 828 Object key) 829 throws AmberException 830 { 831 AmberEntityHome entityHome = _persistenceUnit.getEntityHome(entityName); 832 833 if (entityHome == null) 834 return null; 835 836 Entity entity = null; 837 838 entity = getEntity(entityName, key); 841 842 if (entity != null) 843 return entity; 844 845 try { 846 entityHome.init(); 847 } catch (ConfigException e) { 848 throw new AmberException(e); 849 } 850 851 entity = entityHome.load(this, key); 852 853 addEntity(entity); 854 855 return entity; 856 } 857 858 861 public Entity getEntity(EntityItem item) 862 { 863 return getEntity(item, null); 864 } 865 866 869 public Entity getEntity(EntityItem item, Map preloadedProperties) 870 { 871 Entity itemEntity = item.getEntity(); 872 EntityType entityType = itemEntity.__caucho_getEntityType(); 873 874 Entity entity = getEntity(entityType.getBeanClass().getName(), 875 itemEntity.__caucho_getPrimaryKey()); 876 877 if (entity != null) 878 return entity; 879 else { 880 entity = item.copy(this); 881 882 addEntity(entity); 883 884 return entity; 885 } 886 } 887 888 891 public Object makePersistent(Object obj) 892 throws SQLException 893 { 894 Entity entity = (Entity) obj; 895 896 898 if (entity == null) 899 throw new NullPointerException (); 900 901 Class cl = entity.getClass(); 902 903 905 AmberEntityHome entityHome; 906 entityHome = _persistenceUnit.getEntityHome(entity.getClass().getName()); 907 908 if (entityHome == null) 909 throw new AmberException(L.l("entity has no matching home")); 910 911 entityHome.makePersistent(entity, this, false); 912 913 return entity; 914 } 915 916 919 public Entity loadLazy(Class cl, String name, Object key) 920 { 921 return loadLazy(cl.getName(), name, key); 922 } 923 924 927 public Entity loadLazy(String className, String name, Object key) 928 { 929 if (key == null) 930 return null; 931 932 Entity entity = null; 933 934 entity = getEntity(className, key); 937 938 try { 939 AmberEntityHome home = _persistenceUnit.getEntityHome(name); 940 941 if (home == null) 942 throw new RuntimeException (L.l("no matching home for {0}", className)); 943 944 home.init(); 945 946 Object obj = home.loadLazy(this, key); 947 948 entity = (Entity) obj; 949 950 addEntity(entity); 951 952 return entity; 953 } catch (SQLException e) { 954 log.log(Level.WARNING, e.toString(), e); 955 956 return null; 957 } catch (ConfigException e) { 958 throw new AmberRuntimeException(e); 959 } 960 } 961 962 965 public EntityItem findEntityItem(String name, Object key) 966 { 967 try { 968 AmberEntityHome home = _persistenceUnit.getEntityHome(name); 969 970 if (home == null) 971 throw new RuntimeException (L.l("no matching home for {0}", name)); 972 973 home.init(); 974 975 return home.findEntityItem(_persistenceUnit.getCacheConnection(), key, false); 976 } catch (RuntimeException e) { 977 throw e; 978 } catch (Exception e) { 979 throw new AmberRuntimeException(e); 980 } 981 } 982 983 986 public EntityItem setEntityItem(String name, Object key, EntityItem item) 987 { 988 try { 989 AmberEntityHome home = _persistenceUnit.getEntityHome(name); 990 991 if (home == null) 992 throw new RuntimeException (L.l("no matching home for {0}", name)); 993 994 home.init(); 995 996 return home.setEntityItem(key, item); 997 } catch (RuntimeException e) { 998 throw e; 999 } catch (Exception e) { 1000 throw new AmberRuntimeException(e); 1001 } 1002 } 1003 1004 1007 public Object loadProxy(String name, Object key) 1008 { 1009 return loadProxy(name, key, null); 1010 } 1011 1012 1015 public Object loadProxy(String name, 1016 Object key, 1017 Map preloadedProperties) 1018 { 1019 if (key == null) 1020 return null; 1021 1022 AmberEntityHome home = _persistenceUnit.getEntityHome(name); 1023 1024 if (home == null) 1025 throw new RuntimeException (L.l("no matching home for {0}", name)); 1026 1027 return loadProxy(home.getEntityType(), key, preloadedProperties); 1028 } 1029 1030 1033 public Object loadProxy(EntityType type, 1034 Object key) 1035 { 1036 return loadProxy(type, key, null); 1037 } 1038 1039 1042 public Object loadProxy(EntityType type, 1043 Object key, 1044 Map preloadedProperties) 1045 { 1046 if (key == null) 1047 return null; 1048 1049 try { 1050 AmberEntityHome home = type.getHome(); 1051 1052 EntityItem item = home.findEntityItem(this, key, false, preloadedProperties); 1053 1054 if (item == null) 1055 return null; 1056 1057 EntityFactory factory = home.getEntityFactory(); 1058 1059 Object entity = factory.getEntity(this, item, preloadedProperties); 1060 1061 return entity; 1062 } catch (SQLException e) { 1063 log.log(Level.WARNING, e.toString(), e); 1064 1065 return null; 1066 } 1067 } 1068 1069 1070 1073 public Object load(Class cl, long intKey) 1074 throws AmberException 1075 { 1076 AmberEntityHome entityHome = _persistenceUnit.getEntityHome(cl.getName()); 1077 1078 if (entityHome == null) 1079 return null; 1080 1081 Object key = entityHome.toObjectKey(intKey); 1082 1083 return load(cl, key); 1084 } 1085 1086 1089 public Object loadLazy(Class cl, long intKey) 1090 throws AmberException 1091 { 1092 AmberEntityHome entityHome = _persistenceUnit.getEntityHome(cl.getName()); 1093 1094 if (entityHome == null) 1095 return null; 1096 1097 Object key = entityHome.toObjectKey(intKey); 1098 1099 return loadLazy(cl, cl.getName(), key); 1100 } 1101 1102 1105 public Entity getEntity(String className, Object key) 1106 { 1107 for (int i = _entities.size() - 1; i >= 0; i--) { 1108 Entity entity = _entities.get(i); 1109 1110 if (entity.__caucho_match(className, key)) { 1111 return entity; 1112 } 1113 } 1114 1115 return null; 1116 } 1117 1118 private Entity getTransactionEntity(String className, Object key) 1119 { 1120 for (int i = _txEntities.size() - 1; i >= 0; i--) { 1121 Entity entity = _txEntities.get(i); 1122 1123 if (entity.__caucho_match(className, key)) { 1124 return entity; 1125 } 1126 } 1127 1128 return null; 1129 } 1130 1131 1134 public boolean addEntity(Entity entity) 1135 { 1136 boolean added = false; 1137 1138 Entity oldEntity = getEntity(entity.getClass().getName(), 1139 entity.__caucho_getPrimaryKey()); 1140 1141 if (oldEntity == null) { 1143 _entities.add(entity); 1144 added = true; 1145 } 1146 1147 if (_isInTransaction) { 1149 oldEntity = getTransactionEntity(entity.getClass().getName(), 1150 entity.__caucho_getPrimaryKey()); 1151 1152 if (oldEntity == null) { 1154 _txEntities.add(entity); 1155 added = true; 1156 } 1157 } 1158 1159 return added; 1160 } 1161 1162 1165 public boolean removeEntity(Entity entity) 1166 { 1167 _entities.remove(entity); 1168 1169 if (_isInTransaction) 1170 _txEntities.remove(entity); 1171 1172 return true; 1173 } 1174 1175 1178 public boolean contains(Object obj) 1179 { 1180 if (obj == null) 1181 return false; 1182 1183 if (! (obj instanceof Entity)) 1184 throw new IllegalArgumentException (L.l("contains() operation can only be applied to an entity instance.")); 1185 1186 Entity entity = (Entity) obj; 1187 1188 entity = getEntity(entity.getClass().getName(), 1189 entity.__caucho_getPrimaryKey()); 1190 1191 if (entity == null) 1192 return false; 1193 1194 if (entity.__caucho_getEntityState() >= Entity.P_DELETING) 1195 return false; 1196 1197 return true; 1198 } 1199 1200 1203 public void begin(Transaction xa) 1204 { 1205 try { 1206 xa.registerSynchronization(this); 1207 1208 _isInTransaction = true; 1209 _isXA = true; 1210 } catch (Throwable e) { 1211 log.log(Level.WARNING, e.toString(), e); 1212 } 1213 } 1214 1215 1218 public void beginTransaction() 1219 throws SQLException 1220 { 1221 _isInTransaction = true; 1222 1223 if (_conn != null && _isAutoCommit) { 1224 _isAutoCommit = false; 1225 _conn.setAutoCommit(false); 1226 } 1227 1228 } 1230 1231 1234 public void setXA(boolean isXA) 1235 { 1236 _isXA = isXA; 1237 _isInTransaction = isXA; 1238 } 1239 1240 1243 public void commit() 1244 throws SQLException 1245 { 1246 try { 1247 flushInternal(); 1248 1249 _xid = 0; 1250 if (_conn != null) { 1251 _conn.commit(); 1252 } 1253 } 1254 catch (RuntimeException e) { 1255 throw e; 1256 } 1257 catch (SQLException e) { 1258 throw new IllegalStateException (e); 1259 } 1260 catch (Exception e) { 1261 throw new EJBExceptionWrapper(e); 1262 } 1263 finally { 1264 if (! _isXA) 1265 _isInTransaction = false; 1266 1267 for (int i = 0; i < _txEntities.size(); i++) { 1268 Entity entity = _txEntities.get(i); 1269 1270 entity.__caucho_afterCommit(); 1271 } 1272 1273 _txEntities.clear(); 1274 } 1275 } 1276 1277 1280 public void beforeCompletion() 1281 { 1282 try { 1283 beforeCommit(); 1284 } catch (Exception e) { 1285 log.log(Level.WARNING, e.toString(), e); 1286 } 1287 } 1288 1289 1292 public void afterCompletion(int status) 1293 { 1294 afterCommit(status == Status.STATUS_COMMITTED); 1295 _isXA = false; 1296 _isInTransaction = false; 1297 } 1298 1299 1302 public void beforeCommit() 1303 throws SQLException 1304 { 1305 for (int i = _txEntities.size() - 1; i >= 0; i--) { 1307 Entity entity = _txEntities.get(i); 1308 1309 entity.__caucho_flush(); 1310 } 1311 } 1312 1313 1316 public void afterCommit(boolean isCommit) 1317 { 1318 if (! _isXA) 1319 _isInTransaction = false; 1320 1321 if (isCommit) { 1322 if (_completionList.size() > 0) { 1323 _persistenceUnit.complete(_completionList); 1324 } 1325 } 1326 _completionList.clear(); 1327 1328 for (int i = 0; i < _txEntities.size(); i++) { 1329 Entity entity = _txEntities.get(i); 1330 1331 try { 1332 if (isCommit) 1333 entity.__caucho_afterCommit(); 1334 else 1335 entity.__caucho_afterRollback(); 1336 } catch (Throwable e) { 1337 log.log(Level.WARNING, e.toString(), e); 1338 } 1339 } 1340 1341 _txEntities.clear(); 1342 1343 if (! isCommit) { 1344 _entities.clear(); 1346 1347 try { 1348 if (_conn != null) 1349 _conn.rollback(); 1350 } catch (SQLException e) { 1351 throw new IllegalStateException (e); 1352 } 1353 } 1354 } 1355 1356 1359 public void rollback() 1360 throws SQLException 1361 { 1362 try { 1363 flushInternal(); 1364 1365 _xid = 0; 1366 if (_conn != null) { 1367 _conn.rollback(); 1368 } 1369 } 1370 catch (RuntimeException e) { 1371 throw e; 1372 } 1373 catch (SQLException e) { 1374 throw new IllegalStateException (e); 1375 } 1376 catch (Exception e) { 1377 throw new EJBExceptionWrapper(e); 1378 } 1379 finally { 1380 if (! _isXA) 1381 _isInTransaction = false; 1382 1383 _completionList.clear(); 1384 1385 for (int i = 0; i < _txEntities.size(); i++) { 1386 Entity entity = _txEntities.get(i); 1387 1388 entity.__caucho_afterRollback(); 1389 } 1390 1391 _txEntities.clear(); 1392 } 1393 } 1394 1395 1398 public void flush() 1399 { 1400 try { 1401 checkTransactionRequired("flush"); 1402 1403 flushInternal(); 1404 1405 } catch (RuntimeException e) { 1406 throw e; 1407 } catch (SQLException e) { 1408 throw new IllegalStateException (e); 1409 } catch (Exception e) { 1410 throw new EJBExceptionWrapper(e); 1411 } 1412 } 1413 1414 1417 public void flushNoChecks() 1418 { 1419 try { 1420 flushInternal(); 1421 1422 } catch (RuntimeException e) { 1423 throw e; 1424 } catch (SQLException e) { 1425 throw new IllegalStateException (e); 1426 } catch (Exception e) { 1427 throw new EJBExceptionWrapper(e); 1428 } 1429 } 1430 1431 1434 public void expire() 1435 throws SQLException 1436 { 1437 for (int i = 0; i < _entities.size(); i++) { 1438 Entity entity = _entities.get(i); 1439 1440 entity.__caucho_expire(); 1441 } 1442 } 1443 1444 1447 public Connection getConnection() 1448 throws SQLException 1449 { 1450 DataSource readDataSource = _persistenceUnit.getReadDataSource(); 1451 1452 if (! _isXA && ! _isInTransaction && readDataSource != null) { 1453 if (_readConn == null) { 1454 _readConn = readDataSource.getConnection(); 1455 } 1456 else if (_readConn.isClosed()) { 1457 closeConnectionImpl(); 1458 _readConn = _persistenceUnit.getDataSource().getConnection(); 1459 } 1460 1461 return _readConn; 1462 } 1463 1464 if (_conn == null) { 1465 _conn = _persistenceUnit.getDataSource().getConnection(); 1466 _isAutoCommit = true; 1467 } 1468 else if (_conn.isClosed()) { 1469 closeConnectionImpl(); 1470 _conn = _persistenceUnit.getDataSource().getConnection(); 1471 _isAutoCommit = true; 1472 } 1473 1474 if (_isXA) { 1475 } 1476 else if (_isInTransaction && _isAutoCommit) { 1477 _isAutoCommit = false; 1478 _conn.setAutoCommit(false); 1479 } 1480 else if (! _isInTransaction && ! _isAutoCommit) { 1481 _isAutoCommit = true; 1482 _conn.setAutoCommit(true); 1483 } 1484 1485 return _conn; 1486 } 1487 1488 1491 public PreparedStatement prepareStatement(String sql) 1492 throws SQLException 1493 { 1494 try { 1495 Connection conn = getConnection(); 1496 1497 PreparedStatement pstmt = _preparedStatementMap.get(sql); 1498 1499 if (pstmt == null) { 1500 pstmt = conn.prepareStatement(sql); 1501 1502 _statements.add(pstmt); 1503 1504 _preparedStatementMap.put(sql, pstmt); 1505 } 1506 1507 return pstmt; 1508 } catch (SQLException e) { 1509 closeConnectionImpl(); 1510 1511 throw e; 1512 } 1513 } 1514 1515 1518 public PreparedStatement prepareInsertStatement(String sql) 1519 throws SQLException 1520 { 1521 PreparedStatement pstmt = _preparedStatementMap.get(sql); 1522 1523 if (pstmt == null) { 1524 Connection conn = getConnection(); 1525 1526 if (_persistenceUnit.hasReturnGeneratedKeys()) 1527 pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 1528 else 1529 pstmt = conn.prepareStatement(sql); 1530 1531 _statements.add(pstmt); 1532 1533 _preparedStatementMap.put(sql, pstmt); 1534 } 1535 1536 return pstmt; 1537 } 1538 1539 1546 public void makeTransactional(Entity entity) 1547 { 1548 if (! _persistenceUnit.isJPA()) 1550 return; 1551 1552 int state = entity.__caucho_getEntityState(); 1553 1554 if (state > Entity.TRANSIENT && state < Entity.P_DELETING) { 1555 addEntity(entity); 1557 } 1558 1559 1568 } 1569 1570 1576 public void update(Object obj) 1577 { 1578 1589 1590 1612 } 1613 1614 1619 public void create(Object obj) 1620 throws SQLException 1621 { 1622 try { 1624 1625 createInternal(obj); 1626 1627 } catch (RuntimeException e) { 1628 throw e; 1629 } catch (Exception e) { 1630 throw new EJBExceptionWrapper(e); 1631 } 1632 } 1633 1634 1639 public void create(String homeName, Object obj) 1640 throws SQLException 1641 { 1642 try { 1644 1645 createInternal(homeName, obj); 1646 1647 } catch (RuntimeException e) { 1648 throw e; 1649 } catch (Exception e) { 1650 throw new EJBExceptionWrapper(e); 1651 } 1652 } 1653 1654 1659 public void create(AmberEntityHome home, Object obj) 1660 throws SQLException 1661 { 1662 try { 1664 1665 createInternal(home, obj); 1666 1667 } catch (RuntimeException e) { 1668 throw e; 1669 } catch (Exception e) { 1670 throw new EJBExceptionWrapper(e); 1671 } 1672 } 1673 1674 1677 public void update(Entity entity) 1678 { 1679 if (entity == null) 1680 return; 1681 1682 if (entity.__caucho_getEntityType() == null) 1684 return; 1685 1686 Table table = entity.__caucho_getEntityType().getTable(); 1687 1688 Object key = entity.__caucho_getPrimaryKey(); 1689 1690 addCompletion(new RowInvalidateCompletion(table.getName(), key)); 1691 1692 if (! _txEntities.contains(entity)) 1693 _txEntities.add(entity); 1694 } 1695 1696 1701 public void delete(Entity entity) 1702 throws SQLException 1703 { 1704 Entity oldEntity = getEntity(entity.getClass().getName(), 1705 entity.__caucho_getPrimaryKey()); 1706 1707 if (oldEntity == null) { 1708 1709 EntityType entityType = entity.__caucho_getEntityType(); 1710 1711 if (entityType == null) 1712 return; 1713 1715 AmberEntityHome entityHome = entityType.getHome(); 1716 1718 if (entityHome == null) 1719 throw new AmberException(L.l("entity has no matching home")); 1720 1721 entityHome.makePersistent(entity, this, true); 1722 1723 addEntity(entity); 1724 } 1725 else { 1726 oldEntity.__caucho_setConnection(this); 1728 1729 entity = oldEntity; 1730 } 1731 1732 entity.__caucho_delete(); 1733 } 1734 1735 1740 public AmberQuery prepareQuery(String queryString) 1741 throws AmberException 1742 { 1743 return prepareQuery(queryString, false); 1744 } 1745 1746 1751 public AmberQuery prepareLazyQuery(String queryString) 1752 throws AmberException 1753 { 1754 return prepareQuery(queryString, true); 1755 } 1756 1757 1762 public AmberQuery prepareUpdate(String queryString) 1763 throws AmberException 1764 { 1765 return prepareQuery(queryString, true); 1766 } 1767 1768 1773 private AmberQuery prepareQuery(String queryString, boolean isLazy) 1774 throws AmberException 1775 { 1776 AbstractQuery queryProgram = parseQuery(queryString, isLazy); 1777 1778 UserQuery query = new UserQuery(queryProgram); 1779 1780 query.setSession(this); 1781 1782 return query; 1783 } 1784 1785 1790 public AbstractQuery parseQuery(String queryString, boolean isLazy) 1791 throws AmberException 1792 { 1793 try { 1794 _persistenceUnit.initEntityHomes(); 1795 } catch (Exception e) { 1796 throw AmberRuntimeException.create(e); 1797 } 1798 1799 QueryParser parser = new QueryParser(queryString); 1800 1801 parser.setAmberManager(_persistenceUnit); 1802 parser.setLazyResult(isLazy); 1803 1804 return parser.parse(); 1805 } 1806 1807 1814 public ResultSet query(String hsql) 1815 throws SQLException 1816 { 1817 AmberQuery query = prepareQuery(hsql); 1818 1819 return query.executeQuery(); 1820 } 1821 1822 1829 public ResultSetCacheChunk getQueryCacheChunk(String sql, 1830 Object []args, 1831 int startRow) 1832 { 1833 _queryKey.init(sql, args, startRow); 1834 1835 return _persistenceUnit.getQueryChunk(_queryKey); 1836 } 1837 1838 1841 public ResultSetMetaData getQueryMetaData() 1842 { 1843 return _persistenceUnit.getQueryMetaData(_queryKey); 1844 } 1845 1846 1854 public void putQueryCacheChunk(String sql, 1855 Object []args, 1856 int startRow, 1857 ResultSetCacheChunk cacheChunk, 1858 ResultSetMetaData cacheMetaData) 1859 { 1860 QueryCacheKey key = new QueryCacheKey(); 1861 Object []newArgs = new Object [args.length]; 1862 1863 System.arraycopy(args, 0, newArgs, 0, args.length); 1864 1865 key.init(sql, newArgs, startRow); 1866 1867 _persistenceUnit.putQueryChunk(key, cacheChunk); 1868 _persistenceUnit.putQueryMetaData(key, cacheMetaData); 1869 } 1870 1871 1878 public int update(String hsql) 1879 throws SQLException 1880 { 1881 AmberQuery query = prepareUpdate(hsql); 1882 1883 return query.executeUpdate(); 1884 } 1885 1886 1893 public List find(String hsql) 1894 throws SQLException 1895 { 1896 AmberQuery query = prepareQuery(hsql); 1897 1898 return query.list(); 1899 } 1900 1901 1904 public void cleanup() 1905 { 1906 try { 1907 flushInternal(); 1908 } 1909 catch (RuntimeException e) { 1910 throw e; 1911 } 1912 catch (SQLException e) { 1913 throw new IllegalStateException (e); 1914 } 1915 catch (Exception e) { 1916 throw new EJBExceptionWrapper(e); 1917 } 1918 finally { 1919 _depth = 0; 1920 1921 for (int i = _entities.size() - 1; i >= 0; i--) { 1922 _entities.get(i).__caucho_detach(); 1923 } 1924 1925 _entities.clear(); 1926 _txEntities.clear(); 1927 _completionList.clear(); 1928 1929 freeConnection(); 1930 } 1931 } 1932 1933 1936 public void pushDepth() 1937 { 1938 } 1941 1942 1945 public void popDepth() 1946 { 1947 } 1948 1949 1952 public void freeConnection() 1953 { 1954 closeConnectionImpl(); 1955 } 1956 1957 1960 private void closeConnectionImpl() 1961 { 1962 Connection conn = _conn; 1963 _conn = null; 1964 1965 Connection readConn = _readConn; 1966 _readConn = null; 1967 1968 boolean isAutoCommit = _isAutoCommit; 1969 _isAutoCommit = true; 1970 1971 try { 1972 if (conn != null && ! isAutoCommit) 1973 conn.setAutoCommit(true); 1974 } catch (SQLException e) { 1975 } 1976 1977 try { 1978 _preparedStatementMap.clear(); 1979 _statements.clear(); 1980 1981 if (conn != null) 1982 conn.close(); 1983 1984 if (readConn != null) 1985 readConn.close(); 1986 } catch (Exception e) { 1987 log.log(Level.WARNING, e.toString(), e); 1988 } 1989 } 1990 1991 public String toString() 1992 { 1993 if (_persistenceUnit != null) 1994 return "AmberConnection[" + _persistenceUnit.getName() + "]"; 1995 else 1996 return "AmberConnection[closed]"; 1997 } 1998 1999 2002 public void finalize() 2003 { 2004 cleanup(); 2005 } 2006 2007 2010 public boolean shouldRetrieveFromCache() 2011 { 2012 return (! isInTransaction()); 2014 } 2015 2016 2024 2029 private void createInternal(Object obj) 2030 throws Exception 2031 { 2032 AmberEntityHome home = null; 2033 2034 Class cl = obj.getClass(); 2035 2036 for (; home == null && cl != null; cl = cl.getSuperclass()) { 2037 home = _persistenceUnit.getHome(cl); 2038 } 2039 2040 if (home == null) 2041 throw new AmberException(L.l("`{0}' is not a known entity class.", 2042 obj.getClass().getName())); 2043 2044 createInternal(home, obj); 2045 } 2046 2047 2052 private void createInternal(String homeName, Object obj) 2053 throws Exception 2054 { 2055 AmberEntityHome home = _persistenceUnit.getEntityHome(homeName); 2056 2057 if (home == null) 2058 throw new AmberException(L.l("`{0}' is not a known entity class.", 2059 obj.getClass().getName())); 2060 2061 createInternal(home, obj); 2062 } 2063 2064 2069 private void createInternal(AmberEntityHome home, Object obj) 2070 throws Exception 2071 { 2072 2077 if (contains(obj)) 2078 return; 2079 2080 Entity entity = (Entity) obj; 2081 2082 if (_persistenceUnit.isJPA()) 2084 entity.__caucho_create(this, home.getEntityType()); 2085 else 2086 home.save(this, entity); 2087 2088 addEntity(entity); 2089 2090 Table table = home.getEntityType().getTable(); 2091 addCompletion(new TableInvalidateCompletion(table.getName())); 2092 } 2093 2094 private void checkTransactionRequired(String operation) 2095 throws TransactionRequiredException 2096 { 2097 2099 if (! (_isXA || _isInTransaction)) 2100 throw new TransactionRequiredException(L.l("{0}() operation can only be executed in the scope of a transaction.", operation)); 2101 } 2102 2103 2106 private void flushInternal() 2107 throws Exception 2108 { 2109 for (int i = _txEntities.size() - 1; i >= 0; i--) { 2110 Entity entity = _txEntities.get(i); 2111 2112 int state = entity.__caucho_getEntityState(); 2113 2114 if (state < Entity.P_DELETING) { 2121 entity.__caucho_cascadePrePersist(this); 2122 } 2124 } 2125 2126 for (int i = _txEntities.size() - 1; i >= 0; i--) { 2127 Entity entity = _txEntities.get(i); 2128 2129 entity.__caucho_flush(); 2130 } 2131 2132 if (! isInTransaction()) { 2133 if (_completionList.size() > 0) { 2134 _persistenceUnit.complete(_completionList); 2135 } 2136 _completionList.clear(); 2137 2138 for (int i = 0; i < _txEntities.size(); i++) { 2139 Entity entity = _txEntities.get(i); 2140 2141 entity.__caucho_afterCommit(); 2142 } 2143 2144 _txEntities.clear(); 2145 } 2146 } 2147 2148 2151 public void persistInternal(Object entity) 2152 throws Exception 2153 { 2154 Entity instance = (Entity) entity; 2155 2156 instance.__caucho_cascadePrePersist(this); 2159 2160 int state = instance.__caucho_getEntityState(); 2161 2162 if (state == Entity.TRANSIENT) { 2163 createInternal(instance); 2164 } 2165 else if (state >= Entity.P_DELETING) { 2166 instance.__caucho_makePersistent(null, (EntityType) null); 2168 createInternal(instance); 2169 } 2170 else throw new EntityExistsException(L.l("Trying to persist an entity that is detached or already exists. Entity state '{0}'", state)); 2172 2173 instance.__caucho_cascadePostPersist(this); 2176 } 2177 2178 2181 private Query createInternalNativeQuery(String sql, 2182 SqlResultSetMappingConfig map) 2183 { 2184 Query query = createNativeQuery(sql); 2185 2186 QueryImpl queryImpl = (QueryImpl) query; 2187 2188 queryImpl.setSqlResultSetMapping(map); 2189 2190 return query; 2191 } 2192 2193 private class EntityTransactionImpl implements EntityTransaction { 2194 2197 public void begin() 2198 { 2199 try { 2200 AmberConnection.this.beginTransaction(); 2201 } catch (SQLException e) { 2202 throw new PersistenceException(e); 2203 } 2204 } 2205 2206 2209 public void commit() 2210 { 2211 try { 2212 AmberConnection.this.commit(); 2213 } catch (SQLException e) { 2214 throw new PersistenceException(e); 2215 } 2216 } 2217 2218 2221 public void rollback() 2222 { 2223 try { 2224 AmberConnection.this.rollback(); 2225 } catch (SQLException e) { 2226 throw new PersistenceException(e); 2227 } 2228 } 2229 2230 2233 public void setRollbackOnly() 2234 { 2235 } 2236 2237 2240 public boolean getRollbackOnly() 2241 { 2242 return false; 2243 } 2244 2245 2248 public boolean isActive() 2249 { 2250 return _isInTransaction; 2251 } 2252 } 2253} 2254 | Popular Tags |