Commits

Anonymous committed 44492da

Move Rife continuations support out of xwork 2, but provide hooks to plug it in as necessary
XW-453

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@1269e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits 8f1aaa9

Comments (0)

Files changed (10)

             <artifactId>commons-logging</artifactId>
             <version>1.0.4</version>
         </dependency>
-        <dependency>
-            <groupId>org.rifers</groupId>
-            <artifactId>rife-continuations</artifactId>
-            <version>0.0.2</version>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
+       <dependency>
             <groupId>ognl</groupId>
             <artifactId>ognl</artifactId>
             <version>2.6.9</version>

src/java/com/opensymphony/xwork2/ActionEventListener.java

+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2;
+
+import com.opensymphony.xwork2.util.ValueStack;
+
+/**
+ * Provides hooks for handling key action events
+ */
+public interface ActionEventListener {
+    /**
+     * Called after an action has been created. 
+     * 
+     * @param action The action
+     * @param stack The current value stack
+     * @return The action to use
+     */
+    public Object prepare(Object action, ValueStack stack);
+    
+    /**
+     * Called when an exception is thrown by the action
+     * 
+     * @param t The exception/error that was thrown
+     * @param stack The current value stack
+     * @return A result code to execute, can be null
+     */
+    public String handleException(Throwable t, ValueStack stack);
+}

src/java/com/opensymphony/xwork2/ActionInvocation.java

      * with the interceptor/action/result workflow is being manipulated for certain functionality. 
      */
     String invokeActionOnly() throws Exception;
+
+    /**
+     * Sets the action event listener to respond to key action events
+     */
+    void setActionEventListener(ActionEventListener listener);
 }

src/java/com/opensymphony/xwork2/DefaultActionInvocation.java

 import com.opensymphony.xwork2.interceptor.PreResultListener;
 import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.ValueStackFactory;
-import com.opensymphony.xwork2.util.XWorkContinuationConfig;
 import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
-import com.uwyn.rife.continuations.ContinuableObject;
-import com.uwyn.rife.continuations.ContinuationConfig;
-import com.uwyn.rife.continuations.ContinuationContext;
-import com.uwyn.rife.continuations.ContinuationManager;
-import com.uwyn.rife.continuations.exceptions.PauseException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
     
 	private static final long serialVersionUID = -585293628862447329L;
 
-	public static ContinuationHandler continuationHandler;
-
     //static {
     //    if (ObjectFactory.getContinuationPackage() != null) {
     //        continuationHandler = new ContinuationHandler();
     protected boolean executed = false;
     protected boolean pushAction = true;
     protected ObjectFactory objectFactory;
+    protected ActionEventListener actionEventListener;
 
     protected UnknownHandler unknownHandler;
 
 					}
     			});
     }
+    
+    public void setActionEventListener(ActionEventListener listener) {
+        this.actionEventListener = listener;
+    }
 
     public Object getAction() {
         return action;
             UtilTimerStack.pop(timerKey);
         }
 
-        if (continuationHandler != null) {
-            continuationHandler.prepareContinuation(action, stack);
+        if (actionEventListener != null) {
+            action = actionEventListener.prepare(action, stack);
         }
     }
 
             // We try to return the source exception.
             Throwable t = e.getTargetException();
 
-            if (continuationHandler != null) {
-                String result = continuationHandler.handleException(t, getStack());
+            if (actionEventListener != null) {
+                String result = actionEventListener.handleException(t, getStack());
                 if (result != null) {
                     return result;
                 }
         }
     }
     
-    static class ContinuationHandler {
-        ContinuationManager cm;
-        
-        public ContinuationHandler() {
-            if (ContinuationConfig.getInstance() != null) {
-                cm = new ContinuationManager();
-            }
-        }
-        
-        public void prepareContinuation(Object action, ValueStack stack) {
-            if (action instanceof ContinuableObject) {
-                ContinuationContext ctx = ContinuationContext.createInstance((ContinuableObject) action);
-                if (action instanceof NonCloningContinuableObject) {
-                    ctx.setShouldClone(false);
-                }
-            }
-
-            try {
-                String id = (String) stack.getContext().get(XWorkContinuationConfig.CONTINUE_KEY);
-                stack.getContext().remove(XWorkContinuationConfig.CONTINUE_KEY);
-                if (id != null) {
-                    ContinuationContext context = cm.getContext(id);
-                    if (context != null) {
-                        ContinuationContext.setContext(context);
-                        // use the original action instead
-                        Object original = context.getContinuable();
-                        action = original;
-                    }
-                }
-            } catch (CloneNotSupportedException e) {
-                e.printStackTrace();
-            }
-
-        }
-        
-        public String handleException(Throwable t, ValueStack stack) {
-            if (t instanceof PauseException) {
-                // continuations in effect!
-                PauseException pe = ((PauseException) t);
-                ContinuationContext context = pe.getContext();
-                String result = (String) pe.getParameters();
-                stack.getContext().put(XWorkContinuationConfig.CONTINUE_KEY, context.getId());
-                cm.addContext(context);
-
-                return result;
-            }
-            return null;
-        }
-            
-    }
+    
+    
 }

src/java/com/opensymphony/xwork2/DefaultActionProxy.java

 
     protected ObjectFactory objectFactory;
 
+    protected ActionEventListener actionEventListener;
+
     /**
      * This constructor is private so the builder methods (create*) should be used to create an DefaultActionProxy.
      * <p/>
     public void setUnknownHandler(UnknownHandler handler) {
         this.unknownHandler = handler;
     }
+    
+    @Inject(required=false) 
+    public void setActionEventListener(ActionEventListener listener) {
+        this.actionEventListener = listener;
+    }
 
     public Object getAction() {
         return invocation.getAction();
             }
             
             invocation = new DefaultActionInvocation(objectFactory, unknownHandler, this, extraContext);
+            if (actionEventListener != null) {
+                invocation.setActionEventListener(actionEventListener);
+            }
             resolveMethod();
         } finally {
             UtilTimerStack.pop(profileKey);

src/java/com/opensymphony/xwork2/NonCloningContinuableObject.java

-/*
- * Copyright (c) 2002-2006 by OpenSymphony
- * All rights reserved.
- */
-
-package com.opensymphony.xwork2;
-
-import com.uwyn.rife.continuations.ContinuableObject;
-
-/**
- * Implementing this interface indicates that the action should not be cloned, but instead should be re-used. This is
- * needed when you are using objects, fields, and method variables that cannot be cloned. The downside to using this is
- * that the advanced forward/backward historical support that normally automatically comes with continuations is no
- * longer available.
- */
-public interface NonCloningContinuableObject extends ContinuableObject {
-}

src/java/com/opensymphony/xwork2/ObjectFactory.java

 import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.interceptor.Interceptor;
 import com.opensymphony.xwork2.util.OgnlUtil;
-import com.opensymphony.xwork2.util.XWorkContinuationConfig;
 import com.opensymphony.xwork2.validator.Validator;
 
 import java.io.IOException;
     private static final Log LOG = LogFactory.getLog(ObjectFactory.class);
 
     private ClassLoader ccl;
-    private static ObjectFactory self = new ObjectFactory();
-    private String continuationPackage;
+    private static ThreadLocal<ObjectFactory> thSelf = new ThreadLocal<ObjectFactory>();
     private Container container;
 
-    @Inject(value="continuations.package", required=false)
-    public void setContinuationPackage(String continuationPackage) {
-        
-        // This reflection silliness is to ensure Rife is optional
-        Class contConfig = null;
-        try {
-            contConfig = Class.forName("com.uwyn.rife.continuations.ContinuationConfig");
-        } catch (ClassNotFoundException ex) {
-            throw new XWorkException("Unable to use continuations package, as the Rife " +
-                    "continuations jar is missing", ex);
-        }
-        try {
-            Method m = contConfig.getMethod("setInstance", contConfig);
-            m.invoke(contConfig, new XWorkContinuationConfig());
-        } catch (NoSuchMethodException ex) {
-            throw new XWorkException("Incorrect version of the Rife continuation library", ex);
-        } catch (IllegalAccessException ex) {
-            throw new XWorkException("Incorrect version of the Rife continuation library", ex);
-        } catch (InvocationTargetException ex) {
-            throw new XWorkException("Unable to initialize the Rife continuation library", ex);
-        }
-        this.continuationPackage = continuationPackage;
-        this.ccl = new ContinuationsClassLoader(continuationPackage, Thread.currentThread().getContextClassLoader());
-    }
-
-    public String getContinuationPackage() {
-        return continuationPackage;
+    @Inject(value="objectFactory.classloader", required=false)
+    public void setClassLoader(ClassLoader cl) {
+        this.ccl = cl;
     }
 
     public ObjectFactory() {
 
     @Inject
     public static void setObjectFactory(ObjectFactory factory) {
-        self = factory;
+        thSelf.set(factory);
     }
 
     public static ObjectFactory getObjectFactory() {
-        return self;
+        return thSelf.get();
     }
 
     /**
     }
 
     static class ContinuationsClassLoader extends ClassLoader {
-        private String base;
-        private ClassLoader parent;
-
-        public ContinuationsClassLoader(String base, ClassLoader parent) {
-            super(parent);
-            this.base = base;
-            this.parent = parent;
-        }
-
-        public Class loadClass(String name) throws ClassNotFoundException {
-            if (validName(name)) {
-                Class clazz = findLoadedClass(name);
-                if (clazz == null) {
-                    try {
-                        byte[] bytes = com.uwyn.rife.continuations.util.ClassByteUtil.getBytes(name, parent);
-                        if (bytes == null) {
-                            throw new ClassNotFoundException(name);
-                        }
-
-                        byte[] resume_bytes = null;
-                        try {
-                            resume_bytes = com.uwyn.rife.continuations.ContinuationInstrumentor.instrument(bytes, name, false);
-                        } catch (ClassNotFoundException e) {
-                            // this can happen when the Rife Continuations code gets broken (there are bugs in it still, ya know!)
-                            // rather than making a big deal, we'll quietly log this and move on
-                            // when more people are using continuations, perhaps we'll raise the log level
-                            LOG.debug("Error instrumenting with RIFE/Continuations, " +
-                                    "loading class normally without continuation support", e);
-                        }
-
-                        if (resume_bytes == null) {
-                            return parent.loadClass(name);
-                        } else {
-                            return defineClass(name, resume_bytes, 0, resume_bytes.length);
-                        }
-                    } catch (IOException e) {
-                        throw new XWorkException("Continuation error", e);
-                    }
-                } else {
-                    return clazz;
-                }
-            } else {
-                return parent.loadClass(name);
-            }
-        }
-
-        private boolean validName(String name) {
-            return name.startsWith(base + ".");
-        }
+        
     }
 }

src/java/com/opensymphony/xwork2/mock/MockActionInvocation.java

 import java.util.Iterator;
 import java.util.List;
 
+import com.opensymphony.xwork2.ActionEventListener;
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionProxy;
 
     private Object action;
     private ActionContext invocationContext;
+    private ActionEventListener actionEventListener;
     private ActionProxy proxy;
     private Result result;
     private String resultCode;
         return resultCode;
     }
 
+    public void setActionEventListener(ActionEventListener listener) {
+        this.actionEventListener = listener;
+    }
+    
+    public ActionEventListener getActionEventListener() {
+        return this.actionEventListener;
+    }
+
 }

src/java/com/opensymphony/xwork2/util/XWorkContinuationConfig.java

-/*
- * Copyright (c) 2002-2006 by OpenSymphony
- * All rights reserved.
- */
-
-package com.opensymphony.xwork2.util;
-
-import com.uwyn.rife.continuations.ContinuationConfig;
-
-/**
- * RIFE Continuation configuration.
- *
- * @author patrick
- */
-public class XWorkContinuationConfig extends ContinuationConfig {
-    public static final String CONTINUE_PARAM = "__continue";
-    public static final String CONTINUE_KEY = "__continue";
-
-    public String getContinuableClassInternalName() {
-        return "com.opensymphony.xwork2.ActionSupport";
-    }
-
-    public String getContinuableInterfaceInternalName() {
-        return "com.opensymphony.xwork2.Action";
-    }
-
-    public String getEntryMethod() {
-        return "execute()Ljava/lang/String;";
-    }
-
-    public String getContinuableClassOrInterfaceName() {
-        return "com.opensymphony.xwork2.ActionSupport";
-    }
-
-    public String getPauseSignature() {
-        return "(Ljava/lang/String;)V";
-    }
-}

src/test/com/opensymphony/xwork2/spring/interceptor/TestActionInvocation.java

 package com.opensymphony.xwork2.spring.interceptor;
 
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionEventListener;
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.ActionProxy;
 import com.opensymphony.xwork2.Result;
         Method method = action.getClass().getMethod("execute", new Class[0]);
         return (String) method.invoke(action, new Object[0]);
     }
+
+    public void setActionEventListener(ActionEventListener listener) {
+    }
 }