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 /** 037 * @see railo.runtime.ext.tag.BodyTagImpl#release() 038 */ 039 public void release() { 040 //hasBody=false; 041 isolation=Connection.TRANSACTION_NONE; 042 action=ACTION_NONE; 043 innerTag=false; 044 super.release(); 045 ignore=false; 046 } 047 048 /** 049 * @param action The action to set. 050 * @throws DatabaseException 051 */ 052 public void setAction(String strAction) throws DatabaseException { 053 strAction = strAction.trim().toLowerCase(); 054 if(strAction.equals("begin")) action=ACTION_BEGIN; 055 else if(strAction.equals("commit")) action=ACTION_COMMIT; 056 else if(strAction.equals("rollback")) action=ACTION_ROLLBACK; 057 else if(strAction.equals("setsavepoint")) action=ACTION_SET_SAVEPOINT; 058 else { 059 throw new DatabaseException("attribute action has a invalid value, valid values are [begin,commit,setsavepoint and rollback]",null,null,null); 060 } 061 062 063 } 064 065 /** 066 * @param isolation The isolation to set. 067 * @throws DatabaseException 068 */ 069 public void setIsolation(String isolation) throws DatabaseException { 070 isolation=isolation.trim().toLowerCase(); 071 if(isolation.equals("read_uncommitted")) this.isolation=Connection.TRANSACTION_READ_UNCOMMITTED; 072 else if(isolation.equals("read_committed")) this.isolation=Connection.TRANSACTION_READ_COMMITTED; 073 else if(isolation.equals("repeatable_read"))this.isolation=Connection.TRANSACTION_REPEATABLE_READ; 074 else if(isolation.equals("serializable")) this.isolation=Connection.TRANSACTION_SERIALIZABLE; 075 else if(isolation.equals("none")) this.isolation=Connection.TRANSACTION_NONE; 076 else throw new DatabaseException("transaction has a invalid isolation level (attribute isolation, valid values are [read_uncommitted,read_committed,repeatable_read,serializable])",null,null,null); 077 } 078 079 /** 080 * @see railo.runtime.ext.tag.TagImpl#doStartTag() 081 */ 082 public int doStartTag() throws PageException { 083 DataSourceManager manager = pageContext.getDataSourceManager(); 084 // first transaction 085 if(manager.isAutoCommit()) { 086 //if(!hasBody)throw new DatabaseException("transaction tag with no end Tag can only be used inside a transaction tag",null,null,null); 087 manager.begin(isolation); 088 return EVAL_BODY_INCLUDE; 089 } 090 // inside transaction 091 innerTag=true; 092 switch(action){ 093 /* nested transaction no longer throw a exception, they are simply ignored 094 case ACTION_NONE: 095 throw new DatabaseException("you can't have a nested transaction with no action defined",null,null,null); 096 case ACTION_BEGIN: 097 throw new DatabaseException("you can't start a transaction inside a transaction tag",null,null,null); 098 */ 099 case ACTION_NONE: 100 case ACTION_BEGIN: 101 ignore=true; 102 break; 103 104 case ACTION_COMMIT: 105 manager.commit(); 106 break; 107 case ACTION_ROLLBACK: 108 manager.rollback(); 109 break; 110 case ACTION_SET_SAVEPOINT: 111 ((DatasourceManagerImpl)manager).savepoint(); 112 break; 113 } 114 115 return EVAL_BODY_INCLUDE; 116 } 117 118 /** 119 * @see railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl#doCatch(java.lang.Throwable) 120 */ 121 public void doCatch(Throwable t) throws Throwable { 122 if(innerTag || ignore) throw t; 123 124 DataSourceManager manager = pageContext.getDataSourceManager(); 125 try { 126 manager.rollback(); 127 } catch (DatabaseException e) { 128 //print.printST(e); 129 } 130 throw t; 131 } 132 133 /** 134 * @param hasBody 135 */ 136 public void hasBody(boolean hasBody) {//print.out("hasBody"+hasBody); 137 //this.hasBody=hasBody; 138 } 139 140 /** 141 * @see railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl#doFinally() 142 */ 143 public void doFinally() { 144 if(!ignore && !innerTag) { 145 pageContext.getDataSourceManager().end(); 146 } 147 super.doFinally(); 148 } 149 150 /** 151 * @see railo.runtime.ext.tag.BodyTagImpl#doAfterBody() 152 */ 153 public int doAfterBody() throws JspException { 154 155 if(!ignore && !innerTag) { 156 pageContext.getDataSourceManager().commit(); 157 } 158 return super.doAfterBody(); 159 } 160 }