Coverage Report - org.apache.commons.workflow.web.ActivityServlet
 
Classes in this File Line Coverage Branch Coverage Complexity
ActivityServlet
0%
0/121
0%
0/32
3.9
 
 1  
 /*
 2  
  * Copyright 1999-2001,2004 The Apache Software Foundation.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */ 
 16  
 
 17  
 package org.apache.commons.workflow.web;
 18  
 
 19  
 
 20  
 import java.io.InputStream;
 21  
 import java.io.IOException;
 22  
 import javax.servlet.ServletException;
 23  
 import javax.servlet.UnavailableException;
 24  
 import javax.servlet.http.HttpServlet;
 25  
 import javax.servlet.http.HttpServletRequest;
 26  
 import javax.servlet.http.HttpServletResponse;
 27  
 import javax.servlet.http.HttpSession;
 28  
 import org.apache.commons.digester.Digester;
 29  
 import org.apache.commons.workflow.Activity;
 30  
 import org.apache.commons.workflow.Context;
 31  
 import org.apache.commons.workflow.ContextEvent;
 32  
 import org.apache.commons.workflow.ContextListener;
 33  
 import org.apache.commons.workflow.Step;
 34  
 import org.apache.commons.workflow.StepException;
 35  
 import org.apache.commons.workflow.base.BaseRuleSet;
 36  
 import org.apache.commons.workflow.core.CoreRuleSet;
 37  
 import org.apache.commons.workflow.io.IoRuleSet;
 38  
 import org.apache.commons.workflow.web.WebContext;
 39  
 import org.apache.commons.workflow.web.WebRuleSet;
 40  
 
 41  
 
 42  
 /**
 43  
  * <p>Demonstration servlet that illustrates one way that workflow support can
 44  
  * be integrated into web applications (or web services) without any
 45  
  * dependency on application frameworks.  For this implementation, a servlet
 46  
  * <em>definition</em> (plus one or more servlet <em>mappings</em>) will be
 47  
  * associated with each <code>Activity</code> supported by this web
 48  
  * application.</p>
 49  
  *
 50  
  * <p>Initialization parameters (defaults in square brackets):</p>
 51  
  * <ul>
 52  
  * <li><strong>activity</strong> - Context-relative resource path to the
 53  
  *     definition file for the Activity that is supported by this servlet.</li>
 54  
  * <li><strong>attribute</strong> - Name of the session attribute under
 55  
  *     which our current <code>Context</code> implementation is stored.
 56  
  *     [org.apache.commons.workflow.web.CONTEXT]</li>
 57  
  * <li><strong>debug</strong> - The debugging detail level for this
 58  
  *     servlet, which controls how much information is logged.  [0]</li>
 59  
  * <li><strong>detail</strong> - The debugging detail level for the Digester
 60  
  *     we utilize in <code>initMapping()</code>, which logs to System.out
 61  
  *     instead of the servlet log.  [0]</li>
 62  
  * </ul>
 63  
  *
 64  
  * @author Craig R. McClanahan
 65  
  * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
 66  
  */
 67  
 
 68  
 
 69  0
 public class ActivityServlet extends HttpServlet implements ContextListener {
 70  
 
 71  
 
 72  
     // ----------------------------------------------------- Instance Variables
 73  
 
 74  
 
 75  
     /**
 76  
      * The <code>Activity</code> that is supported by this servlet instance.
 77  
      */
 78  0
     private Activity activity = null;
 79  
 
 80  
 
 81  
     /**
 82  
      * Name of the session attribute under which our current
 83  
      * <code>Context</code> is stored.
 84  
      */
 85  0
     private String attribute = "org.apache.commons.workflow.CONTEXT";
 86  
 
 87  
 
 88  
     /**
 89  
      * The debugging detail level for this servlet.
 90  
      */
 91  0
     private int debug = 0;
 92  
 
 93  
 
 94  
     /**
 95  
      * The debugging detail level for our Digester.
 96  
      */
 97  0
     private int detail = 0;
 98  
 
 99  
 
 100  
     // --------------------------------------------------------- Public Methods
 101  
 
 102  
 
 103  
     /**
 104  
      * Perform a graceful shutdown of this servlet instance.
 105  
      */
 106  
     public void destroy() {
 107  
 
 108  
         ; // No processing required
 109  
 
 110  0
     }
 111  
 
 112  
 
 113  
     /**
 114  
      * Process a GET transaction.
 115  
      *
 116  
      * @param request The servlet request we are processing
 117  
      * @param response The servlet response we are processing
 118  
      *
 119  
      * @exception IOException if an input/output exception occurs
 120  
      * @exception ServletException if a servlet exception occurs
 121  
      */
 122  
     public void doGet(HttpServletRequest request,
 123  
                       HttpServletResponse response)
 124  
         throws IOException, ServletException {
 125  
 
 126  0
         doPost(request, response);
 127  
 
 128  0
     }
 129  
 
 130  
 
 131  
     /**
 132  
      * Process a POST transaction.
 133  
      *
 134  
      * @param request The servlet request we are processing
 135  
      * @param response The servlet response we are processing
 136  
      *
 137  
      * @exception IOException if an input/output exception occurs
 138  
      * @exception ServletException if a servlet exception occurs
 139  
      */
 140  
     public void doPost(HttpServletRequest request,
 141  
                        HttpServletResponse response)
 142  
         throws IOException, ServletException {
 143  
 
 144  
         // Acquire or create the current Context for this user
 145  0
         HttpSession session = request.getSession(true);
 146  0
         WebContext context = (WebContext)
 147  
             session.getAttribute(attribute);
 148  0
         if (context == null) {
 149  0
             if (debug >= 1)
 150  0
                 log("{" + session.getId() + "} Creating new Context");
 151  0
             context = new WebContext();
 152  0
             context.setActivity(activity);
 153  0
             context.setHttpSession(session);
 154  0
             context.setServletContext(getServletContext());
 155  0
             if (debug >= 3)
 156  0
                 context.addContextListener(this);
 157  0
             session.setAttribute(attribute, context);
 158  
         }                
 159  
 
 160  
 
 161  
         // Execute the next stage of the current Activity
 162  0
         synchronized (context) {
 163  
 
 164  
             // If we are not already executing our associated Activity, call it
 165  0
             if (!activity.equals(context.getActivity())) {
 166  0
                 if (debug >= 2)
 167  0
                     log("{" + session.getId() + "} calling Activity " +
 168  
                         activity.getId());
 169  0
                 context.call(activity);
 170  
             }
 171  
 
 172  
             // Associate our context with the current request and response
 173  0
             context.setServletRequest(request);
 174  0
             context.setServletResponse(response);
 175  
 
 176  
             // Execute our activity until suspended or ended
 177  
             try {
 178  0
                 if (debug >= 2)
 179  0
                     log("{" + session.getId() + "} executing Activity " +
 180  
                         activity.getId());
 181  0
                 context.execute();
 182  0
             } catch (StepException e) {
 183  0
                 if (e.getCause() == null)
 184  0
                     throw new ServletException(e.getMessage(), e);
 185  
                 else
 186  0
                     throw new ServletException(e.getMessage(), e.getCause());
 187  0
             }
 188  
 
 189  0
         }
 190  
 
 191  0
     }
 192  
 
 193  
 
 194  
     /**
 195  
      * Perform a graceful startup of this servlet instance.
 196  
      *
 197  
      * @exception ServletException if we cannot process the activity
 198  
      *  definition file for this activity
 199  
      */
 200  
     public void init() throws ServletException {
 201  
 
 202  
         // Record the debugging detail level settings
 203  0
         String debug = getServletConfig().getInitParameter("debug");
 204  0
         if (debug != null) {
 205  
             try {
 206  0
                 this.debug = Integer.parseInt(debug);
 207  0
             } catch (NumberFormatException e) {
 208  0
                 throw new UnavailableException
 209  
                     ("Debug initialization parameter must be an integer");
 210  0
             }
 211  
         }
 212  0
         String detail = getServletConfig().getInitParameter("detail");
 213  0
         if (detail != null) {
 214  
             try {
 215  0
                 this.detail = Integer.parseInt(detail);
 216  0
             } catch (NumberFormatException e) {
 217  0
                 throw new UnavailableException
 218  
                     ("Detail initialization parameter must be an integer");
 219  0
             }
 220  
         }
 221  
 
 222  
         // Record the attribute name for our current Context
 223  0
         String attribute = getServletConfig().getInitParameter("attribute");
 224  0
         if (attribute != null)
 225  0
             this.attribute = attribute;
 226  
 
 227  
         // Parse the activity definition file for our Activity
 228  0
         String path = getServletConfig().getInitParameter("activity");
 229  0
         if (path == null)
 230  0
             throw new UnavailableException
 231  
                 ("Must specify an 'activity' attribute");
 232  0
         parse(path);
 233  0
         if (activity == null)
 234  0
             throw new UnavailableException("No activity defined in resource "
 235  
                                            + path);
 236  
 
 237  0
     }
 238  
 
 239  
 
 240  
     /**
 241  
      * Set the <code>Activity</code> associated with this instance.
 242  
      *
 243  
      * @param activity The new associated Activity
 244  
      */
 245  
     public void setActivity(Activity activity) {
 246  
 
 247  0
         this.activity = activity;
 248  
 
 249  0
     }
 250  
 
 251  
 
 252  
     // ------------------------------------------------ ContextListener Methods
 253  
 
 254  
 
 255  
     /**
 256  
      * Invoked immediately after execution of the related Activity has
 257  
      * been completed normally, been suspended, or been aborted by
 258  
      * the throwing of a StepException.  The Step included in this event
 259  
      * will be the last one to be executed.
 260  
      *
 261  
      * @param event The <code>ContextEvent</code> that has occurred
 262  
      */
 263  
     public void afterActivity(ContextEvent event) {
 264  
 
 265  0
         WebContext context = (WebContext) event.getContext();
 266  0
         HttpSession session = context.getHttpSession();
 267  0
         StringBuffer sb = new StringBuffer("{");
 268  0
         sb.append(session.getId());
 269  0
         sb.append("} afterActivity");
 270  0
         log(sb.toString());
 271  
 
 272  0
     }
 273  
 
 274  
 
 275  
 
 276  
     /**
 277  
      * Invoked immediately after the specified Step was executed.
 278  
      *
 279  
      * @param event The <code>ContextEvent</code> that has occurred
 280  
      */
 281  
     public void afterStep(ContextEvent event) {
 282  
 
 283  0
         WebContext context = (WebContext) event.getContext();
 284  0
         HttpSession session = context.getHttpSession();
 285  0
         StringBuffer sb = new StringBuffer("{");
 286  0
         sb.append(session.getId());
 287  0
         sb.append("} afterStep ");
 288  0
         sb.append(event.getStep());
 289  0
         if (context.getSuspend())
 290  0
             sb.append(" (Suspended)");
 291  0
         if (context.getNextStep() == null)
 292  0
             sb.append(" (Finished)");
 293  0
         log(sb.toString());
 294  0
         if (event.getException() != null)
 295  0
             log("-->Step threw exception", event.getException());
 296  
 
 297  0
     }
 298  
 
 299  
 
 300  
     /**
 301  
      * Invoked immediately before execution of the related Activity has
 302  
      * started.  The Step included in this event will be the first one
 303  
      * to be executed.
 304  
      *
 305  
      * @param event The <code>ContextEvent</code> that has occurred
 306  
      */
 307  
     public void beforeActivity(ContextEvent event) {
 308  
 
 309  0
         WebContext context = (WebContext) event.getContext();
 310  0
         HttpSession session = context.getHttpSession();
 311  0
         StringBuffer sb = new StringBuffer("{");
 312  0
         sb.append(session.getId());
 313  0
         sb.append("} beforeActivity");
 314  0
         log(sb.toString());
 315  
 
 316  0
     }
 317  
 
 318  
 
 319  
     /**
 320  
      * Invoked immediately before the specified Step is executed.
 321  
      *
 322  
      * @param event The <code>ContextEvent</code> that has occurred
 323  
      */
 324  
     public void beforeStep(ContextEvent event) {
 325  
 
 326  0
         WebContext context = (WebContext) event.getContext();
 327  0
         HttpSession session = context.getHttpSession();
 328  0
         StringBuffer sb = new StringBuffer("{");
 329  0
         sb.append(session.getId());
 330  0
         sb.append("} beforeStep ");
 331  0
         sb.append(event.getStep());
 332  0
         log(sb.toString());
 333  
 
 334  0
     }
 335  
 
 336  
 
 337  
     // -------------------------------------------------------- Private Methods
 338  
 
 339  
 
 340  
     /**
 341  
      * Parse the specified activity definition file for this instance.
 342  
      *
 343  
      * @param path Context-relative resource path of the activity
 344  
      *  definition file
 345  
      *
 346  
      * @exception ServletException on any processing error in parsing
 347  
      */
 348  
     private void parse(String path) throws ServletException {
 349  
 
 350  
         // Get an input source for the specified path
 351  0
         InputStream is =
 352  
             getServletContext().getResourceAsStream(path);
 353  0
         if (is == null)
 354  0
             throw new UnavailableException("Cannot access resource " +
 355  
                                            path);
 356  
 
 357  
         // Configure a Digester instance to parse our definition file
 358  0
         Digester digester = new Digester();
 359  0
         digester.setNamespaceAware(true);
 360  0
         digester.setValidating(false);
 361  0
         digester.push(this);
 362  
 
 363  
         // Add rules to recognize the built-in steps that we know about
 364  0
         BaseRuleSet brs = new BaseRuleSet();
 365  0
         digester.addRuleSet(brs);
 366  0
         digester.addRuleSet(new CoreRuleSet());
 367  0
         digester.addRuleSet(new IoRuleSet());
 368  0
         digester.addRuleSet(new WebRuleSet());
 369  
 
 370  
         // Add a rule to register the Activity being created
 371  0
         digester.setRuleNamespaceURI(brs.getNamespaceURI());
 372  0
         digester.addSetNext("activity", "setActivity",
 373  
                             "org.apache.commons.workflow.Activity");
 374  
 
 375  
         // Parse the activity definition file
 376  
         try {
 377  0
             digester.parse(is);
 378  0
         } catch (Throwable t) {
 379  0
             log("Cannot parse resource " + path, t);
 380  0
             throw new UnavailableException("Cannot parse resource " + path);
 381  
         } finally {
 382  0
             try {
 383  0
                 is.close();
 384  0
             } catch (Throwable u) {
 385  
                 ;
 386  0
             }
 387  0
         }
 388  
 
 389  0
     }
 390  
 
 391  
 
 392  
 }