cziegeler    02/04/22 08:43:36

  Modified:    src/java/org/apache/cocoon/components/treeprocessor
                        DefaultTreeBuilder.java
               src/java/org/apache/cocoon/components/treeprocessor/sitemap
                        ActTypeNode.java ActionSetNode.java MatchNode.java
                        MatchNodeBuilder.java PipelineNode.java
                        PreparableMatchNode.java SelectNode.java
                        SelectNodeBuilder.java SwitchSelectNode.java
  Log:
  Added releasing of selectors
  
  Revision  Changes    Path
  1.6       +28 -27    
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
  
  Index: DefaultTreeBuilder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- DefaultTreeBuilder.java   21 Apr 2002 17:39:16 -0000      1.5
  +++ DefaultTreeBuilder.java   22 Apr 2002 15:43:36 -0000      1.6
  @@ -93,7 +93,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: DefaultTreeBuilder.java,v 1.5 2002/04/21 17:39:16 vgritsenko 
Exp $
  + * @version CVS $Id: DefaultTreeBuilder.java,v 1.6 2002/04/22 15:43:36 cziegeler 
Exp $
    */
   
   public class DefaultTreeBuilder extends AbstractLoggable implements TreeBuilder,
  @@ -525,37 +525,38 @@
   
           String type = statement.getAttribute("type", null);
   
  -        ComponentSelector selector;
  +        ComponentSelector selector = null;
   
           try {
  -            selector = (ComponentSelector)this.manager.lookup(role);
  -        } catch(ComponentException ce) {
  -            String msg = "Cannot get component selector for '" + 
statement.getName() + "' at " +
  -                statement.getLocation();
  -            getLogger().error(msg, ce);
  -            throw new ConfigurationException(msg, ce);
  -        }
  +            try {
  +                selector = (ComponentSelector)this.manager.lookup(role);
  +            } catch(ComponentException ce) {
  +                String msg = "Cannot get component selector for '" + 
statement.getName() + "' at " +
  +                    statement.getLocation();
  +                getLogger().error(msg, ce);
  +                throw new ConfigurationException(msg, ce);
  +            }
   
  -        if (type == null && selector instanceof ExtendedComponentSelector) {
  -            type = ((ExtendedComponentSelector)selector).getDefaultHint();
  -        }
  +            if (type == null && selector instanceof ExtendedComponentSelector) {
  +                type = ((ExtendedComponentSelector)selector).getDefaultHint();
  +            }
   
  -        if (type == null) {
  -            String msg = "No default type exists for '" + statement.getName() + "' 
at " +
  -                statement.getLocation();
  -            getLogger().error(msg);
  -            throw new ConfigurationException(msg);
  -        }
  +            if (type == null) {
  +                String msg = "No default type exists for '" + statement.getName() + 
"' at " +
  +                    statement.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
  +            }
   
  -        if (!selector.hasComponent(type)) {
  -            String msg = "Type '" + type + "' is not defined for '" + 
statement.getName() + "' at " +
  -                statement.getLocation();
  -            getLogger().error(msg);
  -            throw new ConfigurationException(msg);
  +            if (!selector.hasComponent(type)) {
  +                String msg = "Type '" + type + "' is not defined for '" + 
statement.getName() + "' at " +
  +                    statement.getLocation();
  +                getLogger().error(msg);
  +                throw new ConfigurationException(msg);
  +            }
  +        } finally {
  +            this.manager.release(selector);
           }
  -
  -        this.manager.release(selector);
  -
           return type;
       }
   
  @@ -565,7 +566,7 @@
           this.linkedBuilders.clear();
           this.canGetNode = false;
           this.registeredNodes.clear();
  -        
  +
           // Don't clear disposableNodes as they're used by the Processor
           this.disposableNodes = new ArrayList();
   
  
  
  
  1.3       +5 -2      
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java
  
  Index: ActTypeNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ActTypeNode.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ActTypeNode.java  27 Mar 2002 15:13:40 -0000      1.2
  +++ ActTypeNode.java  22 Apr 2002 15:43:36 -0000      1.3
  @@ -75,7 +75,7 @@
    * Handles &lt;map:act type="..."&gt; (action-sets calls are handled by {@link 
ActSetNode}).
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: ActTypeNode.java,v 1.2 2002/03/27 15:13:40 sylvain Exp $
  + * @version CVS $Id: ActTypeNode.java,v 1.3 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class ActTypeNode extends SimpleSelectorProcessingNode
  @@ -90,6 +90,8 @@
       /** Pre-selected action, if it's ThreadSafe */
       protected Action threadSafeAction;
   
  +    protected ComponentManager manager;
  +
       public ActTypeNode(String name, String source) throws PatternException {
           super(name);
           this.source = MapStackResolver.getResolver(source);
  @@ -100,7 +102,7 @@
       }
   
       public void compose(ComponentManager manager) throws ComponentException {
  -
  +        this.manager = manager;
           setSelector((ComponentSelector)manager.lookup(Action.ROLE + "Selector"));
   
           // Get the action, if it's thread safe
  @@ -160,5 +162,6 @@
           if (this.threadSafeAction != null) {
               this.selector.release(this.threadSafeAction);
           }
  +        this.manager.release(this.selector);
       }
   }
  
  
  
  1.3       +9 -5      
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java
  
  Index: ActionSetNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/ActionSetNode.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ActionSetNode.java        27 Mar 2002 15:10:35 -0000      1.2
  +++ ActionSetNode.java        22 Apr 2002 15:43:36 -0000      1.3
  @@ -74,7 +74,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: ActionSetNode.java,v 1.2 2002/03/27 15:10:35 sylvain Exp $
  + * @version CVS $Id: ActionSetNode.java,v 1.3 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class ActionSetNode extends SimpleSelectorProcessingNode
  @@ -88,13 +88,16 @@
   
       /** The actions that are ThreadSafe, to avoid lookups */
       private Action[] threadSafeActions;
  -    
  +
       /** The src for each action */
       private MapStackResolver[] sources;
  -    
  +
       /** The parameters for each action */
       private Map[] parameters;
   
  +    /** The component manager */
  +    protected ComponentManager manager;
  +
       public ActionSetNode(
         String name, String[] types, String[] actionNames,
         MapStackResolver[] sources, Map[] parameters) {
  @@ -106,7 +109,7 @@
       }
   
       public void compose(ComponentManager manager) throws ComponentException {
  -
  +        this.manager = manager;
           setSelector((ComponentSelector)manager.lookup(Action.ROLE + "Selector"));
   
           // Get all actions that are thread safe
  @@ -151,7 +154,7 @@
               String actionName = actionNames[i];
               String source = sources[i].resolve(mapStack);
               if (actionName == null || actionName.equals(cocoonAction)) {
  -                
  +
                   Parameters actionParams = 
MapStackResolver.buildParameters(parameters[i], mapStack);
                   if (actionParams == Parameters.EMPTY_PARAMETERS) {
                       actionParams = params;
  @@ -195,6 +198,7 @@
           for (int i = 0; i < this.threadSafeActions.length; i++) {
               this.selector.release(this.threadSafeActions[i]);
           }
  +        this.manager.release(this.selector);
       }
   
       /**
  
  
  
  1.2       +15 -4     
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MatchNode.java
  
  Index: MatchNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MatchNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MatchNode.java    5 Mar 2002 08:26:23 -0000       1.1
  +++ MatchNode.java    22 Apr 2002 15:43:36 -0000      1.2
  @@ -57,6 +57,7 @@
   import org.apache.cocoon.components.treeprocessor.SimpleSelectorProcessingNode;
   import org.apache.cocoon.components.treeprocessor.MapStackResolver;
   import org.apache.cocoon.matching.Matcher;
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.parameters.Parameters;
  @@ -71,10 +72,11 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: MatchNode.java,v 1.1 2002/03/05 08:26:23 sylvain Exp $
  + * @version CVS $Id: MatchNode.java,v 1.2 2002/04/22 15:43:36 cziegeler Exp $
    */
   
  -public class MatchNode extends SimpleSelectorProcessingNode implements 
ParameterizableProcessingNode, Composable {
  +public class MatchNode extends SimpleSelectorProcessingNode
  +implements ParameterizableProcessingNode, Composable, Disposable {
   
       /** The 'pattern' attribute */
       private MapStackResolver pattern;
  @@ -84,6 +86,8 @@
   
       private Map parameters;
   
  +    private ComponentManager manager;
  +
       public MatchNode(String name, String pattern) throws PatternException {
           super(name);
           this.pattern = MapStackResolver.getResolver(pattern);
  @@ -94,8 +98,8 @@
       }
   
       public void compose(ComponentManager manager) throws ComponentException {
  -
  -        super.setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + 
"Selector"));
  +        this.manager = manager;
  +        this.setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + 
"Selector"));
   
           // Get matcher if it's ThreadSafe
           this.threadSafeMatcher = (Matcher)this.getThreadSafeComponent();
  @@ -140,5 +144,12 @@
               // Matcher failed
               return false;
           }
  +    }
  +
  +    /**
  +     * Disposable Interface
  +     */
  +    public void dispose() {
  +        this.manager.release(this.selector);
       }
   }
  
  
  
  1.4       +10 -5     
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MatchNodeBuilder.java
  
  Index: MatchNodeBuilder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MatchNodeBuilder.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- MatchNodeBuilder.java     17 Apr 2002 21:50:46 -0000      1.3
  +++ MatchNodeBuilder.java     22 Apr 2002 15:43:36 -0000      1.4
  @@ -69,7 +69,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: MatchNodeBuilder.java,v 1.3 2002/04/17 21:50:46 sylvain Exp $
  + * @version CVS $Id: MatchNodeBuilder.java,v 1.4 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class MatchNodeBuilder extends AbstractParentProcessingNodeBuilder
  @@ -96,10 +96,15 @@
           // Get the type and class for this matcher
           ComponentsSelector selector = 
(ComponentsSelector)this.manager.lookup(SELECTOR_ROLE);
   
  -        // Find matcher class
  -        Matcher matcher = (Matcher)selector.select(type);
  -        Class clazz = matcher.getClass();
  -        selector.release(matcher);
  +        Class clazz = null;
  +        try {
  +            // Find matcher class
  +            Matcher matcher = (Matcher)selector.select(type);
  +            clazz = matcher.getClass();
  +            selector.release(matcher);
  +        } finally {
  +            this.manager.release(selector);
  +        }
   
           // PreparableMatcher are only prepared if pattern doesn't need request-time 
resolution.
           boolean preparable =
  
  
  
  1.2       +7 -3      
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/PipelineNode.java
  
  Index: PipelineNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/PipelineNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PipelineNode.java 5 Mar 2002 08:26:23 -0000       1.1
  +++ PipelineNode.java 22 Apr 2002 15:43:36 -0000      1.2
  @@ -76,7 +76,7 @@
    *
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: PipelineNode.java,v 1.1 2002/03/05 08:26:23 sylvain Exp $
  + * @version CVS $Id: PipelineNode.java,v 1.2 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class PipelineNode extends AbstractParentProcessingNode implements 
Composable {
  @@ -198,8 +198,12 @@
   
               // Create a Notifying
               NotifyingBuilder notifyingBuilder= 
(NotifyingBuilder)this.manager.lookup(NotifyingBuilder.ROLE);
  -            Notifying currentNotifying = notifyingBuilder.build(this, ex);
  -            this.manager.release(notifyingBuilder);
  +            Notifying currentNotifying = null;
  +            try {
  +                currentNotifying = notifyingBuilder.build(this, ex);
  +            } finally {
  +                this.manager.release(notifyingBuilder);
  +            }
   
               // Add it to the object model
               env.getObjectModel().put(Constants.NOTIFYING_OBJECT, currentNotifying );
  
  
  
  1.2       +12 -2     
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/PreparableMatchNode.java
  
  Index: PreparableMatchNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/PreparableMatchNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PreparableMatchNode.java  5 Mar 2002 08:26:23 -0000       1.1
  +++ PreparableMatchNode.java  22 Apr 2002 15:43:36 -0000      1.2
  @@ -58,6 +58,7 @@
   import org.apache.cocoon.components.treeprocessor.MapStackResolver;
   import org.apache.cocoon.matching.Matcher;
   import org.apache.cocoon.matching.PreparableMatcher;
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.ComponentSelector;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.Composable;
  @@ -72,7 +73,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: PreparableMatchNode.java,v 1.1 2002/03/05 08:26:23 sylvain Exp 
$
  + * @version CVS $Id: PreparableMatchNode.java,v 1.2 2002/04/22 15:43:36 cziegeler 
Exp $
    */
   
   public class PreparableMatchNode extends SimpleSelectorProcessingNode implements 
ParameterizableProcessingNode, Composable {
  @@ -87,6 +88,8 @@
       /** The matcher, if it's ThreadSafe */
       private PreparableMatcher threadSafeMatcher;
   
  +    protected ComponentManager manager;
  +
       public PreparableMatchNode(String name, String pattern) throws PatternException 
{
           super(name);
           this.pattern = pattern;
  @@ -98,7 +101,7 @@
   
   
       public void compose(ComponentManager manager) throws ComponentException {
  -
  +        this.manager = manager;
           setSelector((ComponentSelector)manager.lookup(Matcher.ROLE + "Selector"));
   
           // Prepare the pattern, and keep matcher if ThreadSafe
  @@ -159,5 +162,12 @@
               // Matcher failed
               return false;
           }
  +    }
  +
  +    /**
  +     * Disposable Interface
  +     */
  +    public void dispose() {
  +        this.manager.release(this.selector);
       }
   }
  
  
  
  1.3       +5 -2      
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SelectNode.java
  
  Index: SelectNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SelectNode.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SelectNode.java   27 Mar 2002 22:20:12 -0000      1.2
  +++ SelectNode.java   22 Apr 2002 15:43:36 -0000      1.3
  @@ -77,7 +77,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: SelectNode.java,v 1.2 2002/03/27 22:20:12 sylvain Exp $
  + * @version CVS $Id: SelectNode.java,v 1.3 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class SelectNode extends SimpleSelectorProcessingNode
  @@ -95,6 +95,8 @@
   
       private ProcessingNode[] otherwhiseNodes;
   
  +    private ComponentManager manager;
  +
       public SelectNode(String name) throws PatternException {
           super(name);
       }
  @@ -110,7 +112,7 @@
       }
   
       public void compose(ComponentManager manager) throws ComponentException {
  -
  +        this.manager = manager;
           setSelector((ComponentSelector)manager.lookup(Selector.ROLE + "Selector"));
   
           // Get the selector, if it's ThreadSafe
  @@ -171,5 +173,6 @@
           if (this.threadSafeSelector != null) {
               this.selector.release(this.threadSafeSelector);
           }
  +        this.manager.release(this.selector);
       }
   }
  
  
  
  1.3       +14 -6     
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SelectNodeBuilder.java
  
  Index: SelectNodeBuilder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SelectNodeBuilder.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SelectNodeBuilder.java    17 Apr 2002 21:50:46 -0000      1.2
  +++ SelectNodeBuilder.java    22 Apr 2002 15:43:36 -0000      1.3
  @@ -70,7 +70,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: SelectNodeBuilder.java,v 1.2 2002/04/17 21:50:46 sylvain Exp $
  + * @version CVS $Id: SelectNodeBuilder.java,v 1.3 2002/04/22 15:43:36 cziegeler Exp 
$
    */
   
   public class SelectNodeBuilder extends AbstractParentProcessingNodeBuilder 
implements ThreadSafe, Recomposable {
  @@ -131,17 +131,25 @@
                   throw new ConfigurationException(msg);
               }
           }
  -        
  +
           ProcessingNode[][] whenChildrenNodes = 
(ProcessingNode[][])whenChildren.toArray(new ProcessingNode[0][0]);
           MapStackResolver[] whenResolvers = 
(MapStackResolver[])whenTests.toArray(new MapStackResolver[whenTests.size()]);
   
           // Get the type and class for this selector
           ComponentsSelector compSelector = 
(ComponentsSelector)this.manager.lookup(SELECTOR_ROLE);
   
  -        // Find selector class
  -        Selector selector = (Selector)compSelector.select(type);
  -        Class clazz = selector.getClass();
  -        compSelector.release(selector);
  +        Class clazz = null;
  +        try {
  +            // Find selector class
  +            Selector selector = (Selector)compSelector.select(type);
  +            try {
  +                clazz = selector.getClass();
  +            } finally {
  +                compSelector.release(selector);
  +            }
  +        } finally {
  +            this.manager.release(compSelector);
  +        }
   
           if (SwitchSelector.class.isAssignableFrom(clazz)) {
               SwitchSelectNode node = new SwitchSelectNode(type);
  
  
  
  1.2       +9 -4      
xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java
  
  Index: SwitchSelectNode.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SwitchSelectNode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SwitchSelectNode.java     17 Apr 2002 21:50:46 -0000      1.1
  +++ SwitchSelectNode.java     22 Apr 2002 15:43:36 -0000      1.2
  @@ -78,7 +78,7 @@
   /**
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Sylvain Wallez</a>
  - * @version CVS $Id: SwitchSelectNode.java,v 1.1 2002/04/17 21:50:46 sylvain Exp $
  + * @version CVS $Id: SwitchSelectNode.java,v 1.2 2002/04/22 15:43:36 cziegeler Exp $
    */
   
   public class SwitchSelectNode extends SimpleSelectorProcessingNode
  @@ -96,6 +96,8 @@
   
       private ProcessingNode[] otherwhiseNodes;
   
  +    private ComponentManager manager;
  +
       public SwitchSelectNode(String name) throws PatternException {
           super(name);
       }
  @@ -111,6 +113,7 @@
       }
   
       public void compose(ComponentManager manager) throws ComponentException {
  +        this.manager = manager;
   
           setSelector((ComponentSelector)manager.lookup(Selector.ROLE + "Selector"));
   
  @@ -130,7 +133,7 @@
           if (this.threadSafeSelector != null) {
   
               Object ctx = this.threadSafeSelector.getSelectorContext(objectModel, 
resolvedParams);
  -            
  +
               for (int i = 0; i < this.whenTests.length; i++) {
                   if (this.threadSafeSelector.select(whenTests[i].resolve(mapStack), 
ctx)) {
                       return invokeNodes(this.whenNodes[i], env, context);
  @@ -145,9 +148,9 @@
   
           } else {
               SwitchSelector selector = 
(SwitchSelector)this.selector.select(this.componentName);
  -            
  +
               Object ctx = selector.getSelectorContext(objectModel, resolvedParams);
  -            
  +
               try {
   
                   for (int i = 0; i < this.whenTests.length; i++) {
  @@ -171,5 +174,7 @@
           if (this.threadSafeSelector != null) {
               this.selector.release(this.threadSafeSelector);
           }
  +        this.manager.release(this.selector);
  +        this.selector = null;
       }
   }
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to