You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by ta...@apache.org on 2006/02/10 20:52:08 UTC

svn commit: r376821 - in /portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors: MethodReplayDecisionMaker.java MethodReplayInterceptor.java TransactionalMethodReplayDecisionMaker.java

Author: taylor
Date: Fri Feb 10 11:52:07 2006
New Revision: 376821

URL: http://svn.apache.org/viewcvs?rev=376821&view=rev
Log:
transactional interceptors to playback failed DAO DML operations
useful for databases such as Oracle TAF for failover of client connections

Added:
    portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayDecisionMaker.java
    portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayInterceptor.java
    portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/TransactionalMethodReplayDecisionMaker.java

Added: portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayDecisionMaker.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayDecisionMaker.java?rev=376821&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayDecisionMaker.java (added)
+++ portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayDecisionMaker.java Fri Feb 10 11:52:07 2006
@@ -0,0 +1,22 @@
+package org.apache.jetspeed.util.interceptors;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * A interface which is akin to a <B>gateway</B>
+ * in BPMN notation. Concrete implementations can make a decision
+ * as to whether or not a method invocation should be replayed.
+ * 
+ * @author a336317
+ */
+public interface MethodReplayDecisionMaker {
+	
+	/**
+	 * 
+	 * @param invocation The MethodInvocation object
+	 * @param exception Exception thrown on previous invocation attempt
+	 * @return True if we should replay the method, false otherwise
+	 */
+	public boolean shouldReplay(MethodInvocation invocation, Exception exception);
+	
+}

Added: portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayInterceptor.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayInterceptor.java?rev=376821&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayInterceptor.java (added)
+++ portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/MethodReplayInterceptor.java Fri Feb 10 11:52:07 2006
@@ -0,0 +1,126 @@
+package org.apache.jetspeed.util.interceptors;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Generic aspect that will attempt to replay a method invocation
+ * if one of a set of specified exceptions is thrown from its execution.
+ * 
+ * @author a336317
+ */
+public class MethodReplayInterceptor implements MethodInterceptor {
+	
+	/** Log reference */
+	private Log log = LogFactory.getLog(MethodReplayInterceptor.class);
+	
+	/** Serialization version identifier */
+	private static final long serialVersionUID = -1316279974504594833L;
+
+	/** How many times we should attempt to retry the method invocation if it fails */
+	private int retryCount;
+	
+	/** How long we should wait before retrying - specified in milliseconds **/
+	private int retryInterval;
+	
+	/** Object which decides whether or not a method invocation should be replayed */
+	private TransactionalMethodReplayDecisionMaker replayDecisionMaker;
+	
+	/**
+	 * Encloses <code>super.invoke()</code> in a try/catch block, where the
+	 * catch block contains additional retry logic.
+	 */
+	public Object invoke(MethodInvocation invocation) throws Throwable {
+		//TODO Make this more elegant - this logic can be simpler
+		try{
+			return invocation.proceed();
+		}
+		catch(Exception exp){
+			
+			//determine whether to retry or just throw the exception back up
+			if(!this.isReplayable(invocation,exp)){
+				throw exp;
+			}
+			
+			//TODO should this be at level WARN/ERROR?
+			if(log.isDebugEnabled()){
+				log.debug("Invocation for method ["+ invocation.getMethod().toString() 
+						+"] failed. Will attempt to replay method invocation ["+ retryCount +"] times with an interval of ["+ retryInterval +"] milliseconds");
+			}
+			
+			int retryCounter = 1;
+			Exception lastExp = null;
+			
+			while((retryCounter<retryCount)){
+				
+				try{
+					if(log.isDebugEnabled()){
+						log.debug("Sleeping for ["+ retryInterval +"] milliseconds before replaying invocation for method ["+ invocation.getMethod().toString() +"].");
+					}
+					Thread.sleep(this.retryInterval);
+					
+					if(log.isDebugEnabled()){
+						log.debug("Attempt invocation ["+ retryCounter +"] for method ["+ invocation.getMethod().toString() +"].");
+					}
+					//returning from a finally block will discard the
+					//exception
+					return invocation.proceed();
+				}
+				catch(Exception exp2){
+					//determine whether to retry or just throw the exception back up
+					if(!this.isReplayable(invocation,exp)){
+						throw exp;
+					}
+					
+					if(log.isDebugEnabled()){
+						log.debug("Attempt ["+ retryCounter +"] to replay invocation for method ["+ invocation.getMethod().toString() 
+								+"] failed. ["+ (retryCount - retryCounter) +"] attempts left.");
+					}
+					
+					lastExp = exp2;
+					retryCounter++;
+				}
+			}
+			if(log.isDebugEnabled()){
+				log.debug("["+ retryCounter +"] attempts to replay invocation for method ["+ invocation.getMethod().toString() 
+						+"] failed. Throwing exception ["+ lastExp.getClass().getName() +"]");
+			}
+			throw lastExp;
+		}
+		
+	}
+
+	public int getRetryCount() {
+		return retryCount;
+	}
+
+	public void setRetryCount(int retryCount) {
+		this.retryCount = retryCount;
+	}
+
+	public int getRetryInterval() {
+		return retryInterval;
+	}
+
+	public void setRetryInterval(int retryInterval) {
+		this.retryInterval = retryInterval;
+	}
+	
+	/**
+	 * Determine if we should attempt to replay the method given that the previous
+	 * invocation returned the passed exception.
+	 * @param exp
+	 * @return True if we should replay the method.
+	 */
+	private boolean isReplayable(MethodInvocation invocation, Exception exp){
+		return replayDecisionMaker.shouldReplay(invocation,exp);
+	}
+
+	public void setReplayDecisionMaker(
+			TransactionalMethodReplayDecisionMaker replayDecisionMaker) {
+		this.replayDecisionMaker = replayDecisionMaker;
+	}
+
+}

Added: portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/TransactionalMethodReplayDecisionMaker.java
URL: http://svn.apache.org/viewcvs/portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/TransactionalMethodReplayDecisionMaker.java?rev=376821&view=auto
==============================================================================
--- portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/TransactionalMethodReplayDecisionMaker.java (added)
+++ portals/jetspeed-2/trunk/components/page-manager/src/java/org/apache/jetspeed/util/interceptors/TransactionalMethodReplayDecisionMaker.java Fri Feb 10 11:52:07 2006
@@ -0,0 +1,82 @@
+package org.apache.jetspeed.util.interceptors;
+
+import java.sql.SQLException;
+import java.util.StringTokenizer;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * MethodReplayDecisionMaker intended for use with methods marked as transactional,
+ * where the decision to replay the method is based on the content of the underlying
+ * exception from the resource.
+ * 
+ * @author a336317
+ */
+public class TransactionalMethodReplayDecisionMaker implements
+		MethodReplayDecisionMaker {
+	
+	private int[] sqlErrorCodes;
+
+	public boolean shouldReplay(MethodInvocation invocation, Exception exception) {
+		
+		//TODO This needs to be a lot more elegant than it currently is - see Spring code
+		//for exception translators to see what we can do here.
+		
+		//exception must be of type SQLException and have an error code value, else we keep
+		//walking down the root cause tree to a maximum depth of 3
+		if(exception.getCause() instanceof SQLException){
+			SQLException sqlExp = (SQLException)exception.getCause();
+			int errorCode = sqlExp.getErrorCode();
+			
+			if(errorCode!=0){
+				return isErrorCodeListed(errorCode);
+			}
+		}
+		
+		if(exception.getCause().getCause() instanceof SQLException){
+			
+			SQLException sqlExp = (SQLException)exception.getCause().getCause();
+			int errorCode = sqlExp.getErrorCode();
+			
+			
+			if(errorCode!=0){
+				return isErrorCodeListed(errorCode);
+			}
+		}
+		
+		if(exception.getCause().getCause().getCause() instanceof SQLException){
+			SQLException sqlExp = (SQLException)exception.getCause().getCause().getCause();
+			int errorCode = sqlExp.getErrorCode();
+			
+			
+			if(errorCode!=0){
+				return isErrorCodeListed(errorCode);
+			}
+		}
+		
+		
+		return false;
+	}
+
+
+	public void setSqlErrorCodes(String sqlErrorCodesString) {
+		StringTokenizer tokenizer = new StringTokenizer(sqlErrorCodesString,",");
+		
+		this.sqlErrorCodes = new int[tokenizer.countTokens()];
+		
+		for(int i=0;tokenizer.hasMoreTokens();i++){
+			this.sqlErrorCodes[i] = new Integer(tokenizer.nextToken()).intValue();			
+		}
+	}
+	
+	
+	private boolean isErrorCodeListed(int errorCode){
+		for(int i=0;i<this.sqlErrorCodes.length;i++){
+			
+			if(this.sqlErrorCodes[i]==errorCode) return true;
+			
+		}
+		return false;
+	}
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org