Coverage Report - org.paneris.melati.shopping.Trolley
 
Classes in this File Line Coverage Branch Coverage Complexity
Trolley
0%
0/139
0%
0/66
3.611
 
 1  
 /*
 2  
  * $Source: /usr/cvsroot/MelatiShopping/src/main/java/org/paneris/melati/shopping/Trolley.java,v $
 3  
  * $Revision: 1.25 $
 4  
  *
 5  
  * Copyright (C) 2000 Tim Joyce
 6  
  *
 7  
  * Part of Melati (http://melati.org/ ), a framework for the rapid
 8  
  * development of clean, maintainable web applications.
 9  
  *
 10  
  * Melati is free software; Permission is granted to copy, distribute
 11  
  * and/or modify this software under the terms either:
 12  
  *
 13  
  * a) the GNU General Public License as published by the Free Software
 14  
  *    Foundation; either version 2 of the License, or (at your option)
 15  
  *    any later version,
 16  
  *
 17  
  *    or
 18  
  *
 19  
  * b) any version of the Melati Software License, as published
 20  
  *    at http://melati.org
 21  
  *
 22  
  * You should have received a copy of the GNU General Public License and
 23  
  * the Melati Software License along with this program;
 24  
  * if not, write to the Free Software Foundation, Inc.,
 25  
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
 26  
  * GNU General Public License and visit http://melati.org to obtain the
 27  
  * Melati Software License.
 28  
  *
 29  
  * Feel free to contact the Developers of Melati if you would like 
 30  
  * to work out a different arrangement than the options
 31  
  * outlined here.  It is our intention to allow Melati to be used by as
 32  
  * wide an audience as possible.
 33  
  *
 34  
  * This program is distributed in the hope that it will be useful,
 35  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 36  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 37  
  * GNU General Public License for more details.
 38  
  *
 39  
  * Contact details for copyright holder:
 40  
  *
 41  
  *     Tim Joyce <timj@paneris.org>
 42  
  *     http://paneris.org/~timj/
 43  
  *     68 Sandbanks Rd, Poole, Dorset. BH14 8BY. UK
 44  
  */
 45  
 
 46  
 package org.paneris.melati.shopping;
 47  
 
 48  
 import org.melati.Melati;
 49  
 import org.melati.servlet.Form;
 50  
 import org.melati.util.MelatiException;
 51  
 import org.melati.util.InstantiationPropertyException;
 52  
 import org.melati.template.ServletTemplateContext;
 53  
 import org.melati.servlet.TemplateServlet;
 54  
 import org.melati.PoemContext;
 55  
 import org.melati.servlet.PathInfoException;
 56  
 import org.melati.servlet.InvalidUsageException;
 57  
 import java.util.Enumeration;
 58  
 import javax.servlet.ServletConfig;
 59  
 import javax.servlet.ServletException;
 60  
 
 61  
 
 62  
 /** 
 63  
  * A servlet that handles the user's interaction with 
 64  
  * the Shopping Trolley.
 65  
  *
 66  
  * @see org.paneris.melati.shopping.ShoppingTrolley
 67  
  * @see org.paneris.melati.shopping.ShoppingTrolleyItem
 68  
  * @see org.paneris.melati.shopping.DefaultShoppingTrolley
 69  
  * @see org.paneris.melati.shopping.DefaultShoppingTrolleyItem
 70  
  *
 71  
  **/
 72  
 
 73  0
 public class Trolley extends TemplateServlet {
 74  
   private static final long serialVersionUID = 1L;
 75  
 
 76  
   public MelatiShoppingConfig config;
 77  
    
 78  
   /**
 79  
    * Inititialise the Shopping Trolley Engine.  This will load a file called
 80  
    * org.paneris.melati.shopping.ShoppingTrolley.properties in order to 
 81  
    * find the classes that implement this shopping implementation.
 82  
    *
 83  
    * @param conf - the Servlet's config parameters
 84  
    * @see org.paneris.melati.shopping.MelatiShoppingConfig
 85  
    **/
 86  
   public void init(ServletConfig conf) throws ServletException {
 87  0
     super.init(conf);
 88  
     try {
 89  0
       config = new MelatiShoppingConfig();
 90  0
     } catch (MelatiException e) {
 91  0
       throw new ServletException(e.toString());
 92  0
     }
 93  0
   }
 94  
 
 95  
   /**
 96  
    * Main entry point for this servlet.
 97  
    *
 98  
    * @param melati - the melati for this request
 99  
    * @param context - the Template Context for this request
 100  
    *
 101  
    * @return - the name of the template to be returned to the user
 102  
    *
 103  
    * @throws InvalidUsageException - if this request has an invalid form
 104  
    */
 105  
   protected String 
 106  
       doTemplateRequest(Melati melati, ServletTemplateContext context)
 107  
       throws Exception {
 108  
 
 109  0
     if (config==null) 
 110  0
        throw new ShoppingConfigException("Shopping Trolley not Configured");
 111  
     // at any point, the user can be forced to login, 
 112  
     // by simply appending "?login"
 113  
     // to the url
 114  0
     if (Form.getFormNulled(context,"login") != null) assertLogin(melati);
 115  0
     ShoppingContext shoppingContext = (ShoppingContext)melati.getPoemContext();
 116  0
     if (shoppingContext.getMethod().equals("Load")) 
 117  0
       return Load(melati, shoppingContext.stid);
 118  0
     if (shoppingContext.getMethod().equals("View")) return View(melati);
 119  0
     if (shoppingContext.getMethod().equals("Update")) return Update(melati);
 120  0
     if (shoppingContext.getMethod().equals("Add")) 
 121  0
       return Add(melati, shoppingContext.stid, shoppingContext.quantity);
 122  0
     if (shoppingContext.getMethod().equals("MultipleAdd")) 
 123  0
       return MultipleAdd(melati);
 124  0
     if (shoppingContext.getMethod().equals("Remove")) 
 125  0
       return Remove(melati, shoppingContext.stid);
 126  0
     if (shoppingContext.getMethod().equals("Set")) 
 127  0
       return Set(melati, shoppingContext.stid, shoppingContext.quantity);
 128  0
     if (shoppingContext.getMethod().equals("Details")) return Details(melati);
 129  0
     if (shoppingContext.getMethod().equals("Confirm")) return Confirm(melati);
 130  0
     if (shoppingContext.getMethod().equals("Paid")) return Paid(melati);
 131  0
     if (shoppingContext.getMethod().equals("Abandon")) return Abandon(melati);
 132  0
     throw new InvalidUsageException(this, shoppingContext);
 133  
   }
 134  
 
 135  
   /** 
 136  
    * Load the trolley from something persistent.
 137  
    *
 138  
    * @param melati - the melati for this request
 139  
    * @param id - an id that can be used to identify the trolley to be loaded
 140  
    *
 141  
    * @return - "Trolley" - the page where users manipulate their 
 142  
    *           Shopping Trolley
 143  
    *
 144  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 145  
    */
 146  
   protected String Load(Melati melati, Integer id)
 147  
       throws InstantiationPropertyException {
 148  0
     ShoppingTrolley trolley = ShoppingTrolley.newTrolley(config);
 149  0
     trolley.initialise(melati,config,id);
 150  0
     melati.getTemplateContext().put("trolley", trolley);
 151  0
     return shoppingTemplate(melati, "Trolley");
 152  
   }
 153  
 
 154  
 
 155  
   /** 
 156  
    * Load the trolley from something persistent.
 157  
    *
 158  
    * @param melati - the melati for this request
 159  
    *
 160  
    * @return - "Trolley" - the page where users manipulate their 
 161  
    *           Shopping Trolley
 162  
    *
 163  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 164  
    **/
 165  
   protected String Save(Melati melati)
 166  
       throws InstantiationPropertyException {
 167  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 168  0
     trolley.save();
 169  0
     melati.getTemplateContext().put("trolley", trolley);
 170  0
     return shoppingTemplate(melati, "Trolley");
 171  
   }
 172  
 
 173  
   /** 
 174  
    * View the trolley.
 175  
    *
 176  
    * @param melati - the melati for this request
 177  
    *
 178  
    * @return - "Trolley" - the page where users manipulate their 
 179  
    *           Shopping Trolley
 180  
    *
 181  
    * @throws InstantiationPropertyException if we cannot construct the trolley
 182  
    */
 183  
   protected String View(Melati melati)
 184  
       throws InstantiationPropertyException {
 185  0
     melati.getTemplateContext().put("trolley", 
 186  
         ShoppingTrolley.getInstance(melati,config));
 187  0
     return shoppingTemplate(melati, "Trolley");
 188  
   }
 189  
 
 190  
   /** 
 191  
    * Update the entire trolley, changing quantities
 192  
    * and removing items.  The POSTed form is analysed for fields with names of 
 193  
    * the form:
 194  
    *
 195  
    * trolleyitem_<item id>_quantity - the new quantity of the item (if set)
 196  
    * trolleyitem_<item id>_deleted - remove this item from the trolley (if set)
 197  
    *
 198  
    * items will also be deleted if the quantity is set to 0
 199  
    *
 200  
    * @param melati - the melati for this request
 201  
    *
 202  
    * @return - "Trolley" - the page where users manipulate their 
 203  
    *           Shopping Trolley
 204  
    *
 205  
    * @throws InstantiationPropertyException if we cannot construct the trolley
 206  
    */
 207  
   protected String Update(Melati melati) 
 208  
       throws InstantiationPropertyException {
 209  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 210  0
     for (Enumeration c = trolley.getItems(); c.hasMoreElements();) {
 211  0
       ShoppingTrolleyItem item = (ShoppingTrolleyItem)c.nextElement();
 212  0
       String formName = "trolleyitem_" + item.getId();
 213  0
       String formQuantity = formName + "_quantity";
 214  0
       String formDeleted = formName + "_deleted";
 215  0
       String deleted = 
 216  
              Form.getFormNulled(melati.getServletTemplateContext(),
 217  
                                       formDeleted);
 218  0
       String quantity = 
 219  
              Form.getFormNulled(melati.getServletTemplateContext(),
 220  
                                       formQuantity);
 221  0
       System.err.println(deleted + " " + quantity);
 222  0
       if (deleted != null || quantity == null || quantity.equals("0")) {
 223  0
         trolley.removeItem(item);
 224  
       } else {
 225  0
         item.setQuantity(new Double(quantity).doubleValue());
 226  
       }
 227  0
     }
 228  0
     melati.getTemplateContext().put("trolley",trolley);
 229  0
     return shoppingTemplate(melati, "Trolley");
 230  
   }
 231  
 
 232  
   /** 
 233  
    * Add multiple items to the trolley, 
 234  
    * or add to the quantities already in the 
 235  
    * trolley.  
 236  
    * The POSTed form is analysed for fields with names of 
 237  
    * the form:
 238  
    *
 239  
    * product_<item id> - the id of the item to be added
 240  
    * quantity_<item id> - the quantity to add
 241  
    *
 242  
    * If no quantity is set, a single item will be added.
 243  
    *
 244  
    * @param melati - the melati for this request
 245  
    *
 246  
    * @return - "Trolley" - the page where users manipulate their 
 247  
    *           Shopping Trolley
 248  
    *
 249  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 250  
    */
 251  
   protected String MultipleAdd(Melati melati)
 252  
       throws InstantiationPropertyException {
 253  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 254  0
     for (Enumeration e = melati.getRequest().getParameterNames(); 
 255  0
                      e.hasMoreElements();) {
 256  0
       String name = (String)e.nextElement();
 257  0
       if (name.length() > 8) {
 258  0
         String p = name.substring(0,7);
 259  0
         if (p.equals("product")) {
 260  0
           String id = name.substring(8);
 261  0
           Integer idInt = new Integer(id);
 262  0
           ShoppingTrolleyItem item = trolley.getItem(idInt);
 263  0
           String quantityName = "quantity_" + id;
 264  0
           String priceName = "price_" + id;
 265  0
           String descriptionName = "description_" + id;
 266  0
           double quantity = 1;
 267  0
           Double price = null;
 268  0
           String quantitySring = 
 269  
                  Form.getFormNulled
 270  
                  (melati.getServletTemplateContext(), quantityName);
 271  0
           String priceString = 
 272  
                  Form.getFormNulled
 273  
                  (melati.getServletTemplateContext(), priceName);
 274  0
           String description = 
 275  
                  Form.getFormNulled
 276  
                  (melati.getServletTemplateContext(), descriptionName);
 277  0
           if (quantitySring != null) 
 278  0
             quantity = (new Double(quantitySring)).doubleValue();
 279  0
           if (priceString != null) price = new Double(priceString);
 280  0
           if (item == null) {
 281  0
             item = newItem(trolley,idInt,price,description);
 282  
           }
 283  0
           item.setQuantity(item.getQuantity() + quantity);
 284  
         }
 285  
       }
 286  0
     }
 287  0
     melati.getTemplateContext().put("trolley",trolley);
 288  0
     return shoppingTemplate(melati, "Trolley");
 289  
   }
 290  
 
 291  
   /** 
 292  
    * Add a single item to the trolley, or add to the quantity already in the 
 293  
    * trolley.  The product is specified on the pathinfo which should be of the
 294  
    * form:
 295  
    *
 296  
    * /<logicaldatabase>/<id>/<quantity>/Add/
 297  
    *
 298  
    * if no quantity is set, a single item will be added.  The form parmaeters
 299  
    * will be parsed to see if they contain "price" and/or "description" fields.
 300  
    * if they are present, they will be used to set up the item
 301  
    *
 302  
    * @param melati - the melati for this request
 303  
    * @param id - the id of the item to be added
 304  
    *
 305  
    * @return - "Trolley" - the page where users manipulate their 
 306  
    *           Shopping Trolley
 307  
    *
 308  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 309  
    **/
 310  
   protected String Add(Melati melati, Integer id, double quantity)
 311  
       throws InstantiationPropertyException {
 312  0
      System.err.println("Adding");
 313  
     // the quantity is defaulted to 1, so if you don't set it you will get one
 314  0
     if (quantity == 0) quantity = 1;
 315  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 316  0
     ShoppingTrolleyItem item = trolley.getItem(id);
 317  0
     if (item == null) {
 318  0
       Double price = null;
 319  0
       String priceString = 
 320  
              Form.getFormNulled(melati.getServletTemplateContext(), 
 321  
                                       "price");
 322  0
       if (priceString != null) price = new Double(priceString);
 323  0
       item = newItem(trolley,id,price,
 324  
           Form.getFormNulled(melati.getServletTemplateContext(), 
 325  
                                    "description"));
 326  
     }    
 327  0
     item.setQuantity(item.getQuantity() + quantity);
 328  0
     melati.getTemplateContext().put("trolley",trolley);
 329  0
     return shoppingTemplate(melati, "Trolley");
 330  
   }
 331  
 
 332  
   /** 
 333  
    * Remove a single item from the trolley, the product is specified on the 
 334  
    * pathinfo which should be of the form:
 335  
    *
 336  
    * /<logicaldatabase>/<id>/Remove/
 337  
    *
 338  
    * @param melati - the melati for this request
 339  
    *
 340  
    * @return - "Trolley" - the page where users manipulate their 
 341  
    *           Shopping Trolley
 342  
    *
 343  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 344  
    */
 345  
   protected String Remove(Melati melati, Integer id)
 346  
       throws InstantiationPropertyException {
 347  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati, config);
 348  0
     ShoppingTrolleyItem item = trolley.getItem(id);
 349  0
     trolley.removeItem(item);
 350  0
     melati.getTemplateContext().put("trolley", trolley);
 351  0
     return shoppingTemplate(melati, "Trolley");
 352  
   }
 353  
 
 354  
   /** 
 355  
    * Set the quantity of an item in the trolley, 
 356  
    * the product and new quantity is
 357  
    * specified on the pathinfo which should be of the form:
 358  
    *
 359  
    * /<logicaldatabase>/<id>/<quantity>/Set/
 360  
    *
 361  
    * @param melati - the melati for this request
 362  
    * @param id - the id of the item to be removed
 363  
    *
 364  
    * @return - "Trolley" - the page where users manipulate their 
 365  
    *           Shopping Trolley
 366  
    *
 367  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 368  
    */
 369  
   protected String Set(Melati melati, Integer id, double quantity)
 370  
       throws InstantiationPropertyException {
 371  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 372  0
     ShoppingTrolleyItem item = trolley.getItem(id);
 373  0
     if (item == null) item = newItem(trolley,id, null, null);
 374  0
     item.setQuantity(quantity);
 375  0
     melati.getTemplateContext().put("trolley",trolley);
 376  0
     return shoppingTemplate(melati, "Trolley");
 377  
   }
 378  
   
 379  
   /** 
 380  
    * Return the page where the user enters their details.
 381  
    *
 382  
    * @param melati - the melati for this request
 383  
    *
 384  
    * @return - "Details" - the page where users enter their details
 385  
    *
 386  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 387  
    */
 388  
   protected String Details(Melati melati)
 389  
       throws InstantiationPropertyException {
 390  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 391  0
     trolley.setDefaultDetails(melati);
 392  0
     melati.getTemplateContext().put("trolley",trolley);
 393  0
     return shoppingTemplate(melati, "Details");
 394  
   }
 395  
   
 396  
   /** 
 397  
    * Update the user's information and return the
 398  
    * confirmation page.
 399  
    *
 400  
    * @param melati - the melati for this request
 401  
    *
 402  
    * @return - "Confirm" - the page where users confirm their order
 403  
    *
 404  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 405  
    */
 406  
   protected String Confirm(Melati melati)
 407  
       throws InstantiationPropertyException {
 408  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati,config);
 409  0
     if (Form.getFormNulled(melati.getServletTemplateContext(),
 410  
                                  "submittoken") != null) 
 411  0
       trolley.setFromForm(melati);
 412  0
     trolley.save();
 413  0
     melati.getTemplateContext().put("trolley",trolley);
 414  0
     return shoppingTemplate(melati, "Confirm");
 415  
   }
 416  
   
 417  
   /** 
 418  
    * Complete the user's shopping experience, and remove their Shopping Trolley
 419  
    * from the Session.
 420  
    *
 421  
    * If you need to do something (like send an email) following confirmation 
 422  
    * of payment, define the method in <Your>ShoppingTrolley.java:
 423  
    * 
 424  
    *  public void confirmPayment(Melati melati) {}
 425  
    *
 426  
    * Because the callback request (typically) comes from the Payment Server, 
 427  
    * you will not have the user's shoping trolley (Session) available to them.
 428  
    * You will therefore need to get whatever information you require from 
 429  
    * something persistent.
 430  
    *
 431  
    * The alternative is to get the Payment Server to generate the emails (or 
 432  
    * whatever) for you.  Most Payment Servers offer this facility. 
 433  
    *
 434  
    * @param melati - the melati for this request
 435  
    *
 436  
    * @return - "Paid" - a message thanking the user for their order
 437  
    *
 438  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 439  
    */
 440  
   protected String Paid(Melati melati) 
 441  
       throws InstantiationPropertyException {
 442  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati, config);
 443  0
     trolley.confirmPayment(melati);
 444  
     // and get rid of it
 445  0
     trolley.remove(melati);
 446  0
     return shoppingTemplate(melati, "Paid");
 447  
   }
 448  
   
 449  
   /** 
 450  
    * Abandon a trolley. 
 451  
    *
 452  
    * @param melati - the melati for this request
 453  
    *
 454  
    * @return - "Trolley" - the initial trolley page
 455  
    *
 456  
    * @throws InstantiationPropertyException - if we cannot construct trolley
 457  
    */
 458  
   protected String Abandon(Melati melati) 
 459  
       throws InstantiationPropertyException {
 460  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati, config);
 461  
     // and get rid of it
 462  0
     trolley.remove(melati);
 463  0
     return shoppingTemplate(melati, "Trolley");
 464  
   }
 465  
   
 466  
   /** 
 467  
    * Force a user to login.
 468  
    *
 469  
    * @param melati - the melati for this request
 470  
    */
 471  
   protected void assertLogin(Melati melati) 
 472  
       throws InstantiationPropertyException {
 473  0
     ShoppingTrolley trolley = ShoppingTrolley.getInstance(melati, config);
 474  
     // deligate to your trolley
 475  0
     trolley.assertLogin(melati);
 476  0
   }
 477  
 
 478  
   /** 
 479  
    * Create the full name of the template to be returned.
 480  
    *
 481  
    * @param melati - the melati for this request (not used)
 482  
    * @param name - the name of the template
 483  
    *
 484  
    * @return - the full path to the template
 485  
    */
 486  
   protected String shoppingTemplate(Melati melati, String name) {
 487  0
     return "shopping/" + name;
 488  
   }
 489  
 
 490  
   /** 
 491  
    * Create a new item and add it to the ShoppingTrolley 
 492  
    * if a non null price is passed in.
 493  
    *
 494  
    * @param trolley - the trolley to add the item to 
 495  
    * @param id - the id of the item to be added
 496  
    *
 497  
    * @return - the new shopping trolley item
 498  
    */
 499  
   private ShoppingTrolleyItem newItem(ShoppingTrolley trolley, Integer id,
 500  
                                       Double price, String description)
 501  
       throws InstantiationPropertyException {
 502  0
     return trolley.newItem(id, description, price);
 503  
   }
 504  
 
 505  
   /** 
 506  
    * Override the building of the PoemContext in order to glean the 
 507  
    * additional information required for the Shopping Trolley system.
 508  
    *
 509  
    * @param melati - the melati for this request
 510  
    *
 511  
    * @return - the ShoppingContext with as many bits set up as possible
 512  
    *
 513  
    * @throws PathInfoException - if we don't understand the PathInfo
 514  
    */
 515  
   protected PoemContext poemContext(Melati melati)
 516  
       throws PathInfoException {
 517  0
     ShoppingContext it = new ShoppingContext();
 518  0
     String[] parts = melati.getPathInfoParts();
 519  0
     if (parts.length < 2) 
 520  0
       throw new PathInfoException(
 521  
           "The servlet expects to see pathinfo in the form " +
 522  
           "/db/method/ or /db/method/troid or /db/method/troid/quantity");
 523  0
     it.setLogicalDatabase(parts[0]);
 524  0
     it.setMethod(parts[1]);
 525  
     try {
 526  0
       if (parts.length > 2 && !parts[2].equals("")) 
 527  0
         it.stid = new Integer(parts[2]);
 528  0
       if (parts.length > 3 && !parts[3].equals(""))
 529  0
         it.quantity = (new Double(parts[3])).doubleValue();
 530  0
     } catch (NumberFormatException e) {
 531  0
       throw new PathInfoException(
 532  
           "The servlet expects to see pathinfo in the form " +
 533  
           "/db/method/ or /db/troid/method/ or /db/troid/quantity/method/ " +
 534  
           "where the troid is an integer and the quantity is a number");
 535  0
     }
 536  0
     return it;
 537  
   }
 538  
 
 539  
 }