001 package railo.runtime.tag; 002 003 004 import java.sql.Connection; 005 006 import javax.servlet.jsp.JspException; 007 008 import railo.runtime.db.DataSourceManager; 009 import railo.runtime.db.DatasourceManagerImpl; 010 import railo.runtime.exp.DatabaseException; 011 import railo.runtime.exp.PageException; 012 import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl; 013 014 /** 015 * Transaction class 016 */ 017 public final class Transaction extends BodyTagTryCatchFinallyImpl { 018 019 private static final int ACTION_NONE = 0; 020 021 private static final int ACTION_BEGIN = 1; 022 023 private static final int ACTION_COMMIT = 2; 024 025 private static final int ACTION_ROLLBACK = 4; 026 027 private static final int ACTION_SET_SAVEPOINT = 8; 028 029 //private boolean hasBody; 030 private int isolation=Connection.TRANSACTION_NONE; 031 private int action=ACTION_NONE; 032 private boolean innerTag=false; 033 034 private boolean ignore=false; 035 036 @Override 037 public void release() { 038 //hasBody=false; 039 isolation=Connection.TRANSACTION_NONE; 040 action=ACTION_NONE; 041 innerTag=false; 042 super.release(); 043 ignore=false; 044 } 045 046 /** 047 * @param action The action to set. 048 * @throws DatabaseException 049 */ 050 public void setAction(String strAction) throws DatabaseException { 051 strAction = strAction.trim().toLowerCase(); 052 if(strAction.equals("begin")) action=ACTION_BEGIN; 053 else if(strAction.equals("commit")) action=ACTION_COMMIT; 054 else if(strAction.equals("rollback")) action=ACTION_ROLLBACK; 055 else if(strAction.equals("setsavepoint")) action=ACTION_SET_SAVEPOINT; 056 else { 057 throw new DatabaseException("attribute action has an invalid value, valid values are [begin,commit,setsavepoint and rollback]",null,null,null); 058 } 059 060 061 } 062 063 /** 064 * @param isolation The isolation to set. 065 * @throws DatabaseException 066 */ 067 public void setIsolation(String isolation) throws DatabaseException { 068 isolation=isolation.trim().toLowerCase(); 069 if(isolation.equals("read_uncommitted")) this.isolation=Connection.TRANSACTION_READ_UNCOMMITTED; 070 else if(isolation.equals("read_committed")) this.isolation=Connection.TRANSACTION_READ_COMMITTED; 071 else if(isolation.equals("repeatable_read"))this.isolation=Connection.TRANSACTION_REPEATABLE_READ; 072 else if(isolation.equals("serializable")) this.isolation=Connection.TRANSACTION_SERIALIZABLE; 073 else if(isolation.equals("none")) this.isolation=Connection.TRANSACTION_NONE; 074 else throw new DatabaseException("transaction has an invalid isolation level (attribute isolation, valid values are [read_uncommitted,read_committed,repeatable_read,serializable])",null,null,null); 075 } 076 077 @Override 078 public int doStartTag() throws PageException { 079 DataSourceManager manager = pageContext.getDataSourceManager(); 080 // first transaction 081 if(manager.isAutoCommit()) { 082 //if(!hasBody)throw new DatabaseException("transaction tag with no end Tag can only be used inside a transaction tag",null,null,null); 083 manager.begin(isolation); 084 return EVAL_BODY_INCLUDE; 085 } 086 // inside transaction 087 innerTag=true; 088 switch(action){ 089 /* nested transaction no longer throw a exception, they are simply ignored 090 case ACTION_NONE: 091 throw new DatabaseException("you can't have a nested transaction with no action defined",null,null,null); 092 case ACTION_BEGIN: 093 throw new DatabaseException("you can't start a transaction inside a transaction tag",null,null,null); 094 */ 095 case ACTION_NONE: 096 case ACTION_BEGIN: 097 ignore=true; 098 break; 099 100 case ACTION_COMMIT: 101 manager.commit(); 102 break; 103 case ACTION_ROLLBACK: 104 manager.rollback(); 105 break; 106 case ACTION_SET_SAVEPOINT: 107 ((DatasourceManagerImpl)manager).savepoint(); 108 break; 109 } 110 111 return EVAL_BODY_INCLUDE; 112 } 113 114 @Override 115 public void doCatch(Throwable t) throws Throwable { 116 if(innerTag || ignore) throw t; 117 118 DataSourceManager manager = pageContext.getDataSourceManager(); 119 try { 120 manager.rollback(); 121 } catch (DatabaseException e) { 122 //print.printST(e); 123 } 124 throw t; 125 } 126 127 /** 128 * @param hasBody 129 */ 130 public void hasBody(boolean hasBody) {//print.out("hasBody"+hasBody); 131 //this.hasBody=hasBody; 132 } 133 134 @Override 135 public void doFinally() { 136 if(!ignore && !innerTag) { 137 pageContext.getDataSourceManager().end(); 138 } 139 super.doFinally(); 140 } 141 142 @Override 143 public int doAfterBody() throws JspException { 144 145 if(!ignore && !innerTag) { 146 pageContext.getDataSourceManager().commit(); 147 } 148 return super.doAfterBody(); 149 } 150 }