Coverage Report - org.argouml.persistence.TodoParser
 
Classes in this File Line Coverage Branch Coverage Complexity
TodoParser
0%
0/140
0%
0/84
4
 
 1  
 /* $Id: TodoParser.java 17832 2010-01-12 19:02:29Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    tfmorris
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2009 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.persistence;
 40  
 
 41  
 import java.io.Reader;
 42  
 import java.util.ArrayList;
 43  
 import java.util.List;
 44  
 
 45  
 import org.apache.log4j.Logger;
 46  
 import org.argouml.cognitive.Designer;
 47  
 import org.argouml.cognitive.ListSet;
 48  
 import org.argouml.cognitive.ResolvedCritic;
 49  
 import org.argouml.cognitive.ToDoItem;
 50  
 import org.xml.sax.InputSource;
 51  
 import org.xml.sax.SAXException;
 52  
 
 53  
 
 54  
 // TODO: Reuse the offender List.
 55  
 
 56  
 /**
 57  
  * Class that reads a todo list from a todo xml file.
 58  
  *
 59  
  * @author        Michael Stockman
 60  
  */
 61  
 class TodoParser extends SAXParserBase {
 62  
     /**
 63  
      * Logger.
 64  
      */
 65  0
     private static final Logger LOG = Logger.getLogger(TodoParser.class);
 66  
 
 67  0
     private TodoTokenTable tokens = new TodoTokenTable();
 68  
 
 69  
     /**
 70  
      * The headline of the ToDoItem currently being read.
 71  
      */
 72  
     private String headline;
 73  
 
 74  
     /**
 75  
      * The priority of the ToDoItem currently being read.
 76  
      */
 77  
     private int    priority;
 78  
 
 79  
     /**
 80  
      * The moreInfoURL of the ToDoItem currently being read.
 81  
      */
 82  
     private String moreinfourl;
 83  
 
 84  
     /**
 85  
      * The description of the ToDoItem currently being read.
 86  
      */
 87  
     private String description;
 88  
 
 89  
     /**
 90  
      * The critic String of the ResolvedCritic currently being read.
 91  
      */
 92  
     private String critic;
 93  
 
 94  
     /**
 95  
      * The offenders list of the ResolvedCritic currently being
 96  
      * read.
 97  
      */
 98  
     private List offenders;
 99  
 
 100  
     /**
 101  
      * Creates a new TodoParser.
 102  
      */
 103  0
     public TodoParser() {
 104  
         // Empty constructor
 105  0
     }
 106  
 
 107  
 
 108  
     /**
 109  
      * Read an XML todo list and enter any todo items into the current designer.
 110  
      * 
 111  
      * @param inputSource The stream containing TodoList XML data.
 112  
      * @throws SAXException on any error
 113  
      */
 114  
     public synchronized void readTodoList(
 115  
             InputSource inputSource) throws SAXException {
 116  0
         LOG.info("Reading ToDo list");
 117  0
         parse(inputSource);
 118  0
     }
 119  
     
 120  
     /**
 121  
      * Reads an XML todo list from InputStream is and enters
 122  
      * any todo items into the current designer.
 123  
      *
 124  
      * @param        is        The stream containing TodoList XML data.
 125  
      * @throws SAXException on any error
 126  
      */
 127  
     public synchronized void readTodoList(
 128  
             Reader is) throws SAXException {
 129  
 
 130  0
         LOG.info("=======================================");
 131  0
         LOG.info("== READING TO DO LIST");
 132  0
         parse(is);
 133  0
     }
 134  
 
 135  
     /**
 136  
      * Called by the XML implementation to signal the start of
 137  
      * an XML entity.
 138  
      *
 139  
      * @param        e        The entity being started.
 140  
      */
 141  
     public void handleStartElement(XMLElement e) {
 142  
         //cat.debug("NOTE: TodoParser handleStartTag:" + e.getName());
 143  
 
 144  
         try {
 145  0
             switch (tokens.toToken(e.getName(), true)) {
 146  
             case TodoTokenTable.TOKEN_HEADLINE:
 147  
             case TodoTokenTable.TOKEN_DESCRIPTION:
 148  
             case TodoTokenTable.TOKEN_PRIORITY:
 149  
             case TodoTokenTable.TOKEN_MOREINFOURL:
 150  
             case TodoTokenTable.TOKEN_POSTER:
 151  
             case TodoTokenTable.TOKEN_OFFENDER:
 152  
                 // NOP
 153  0
                 break;
 154  
 
 155  
             case TodoTokenTable.TOKEN_TO_DO:
 156  0
                 handleTodo(e);
 157  0
                 break;
 158  
 
 159  
             case TodoTokenTable.TOKEN_TO_DO_LIST:
 160  0
                 handleTodoList(e);
 161  0
                 break;
 162  
 
 163  
             case TodoTokenTable.TOKEN_TO_DO_ITEM:
 164  0
                 handleTodoItemStart(e);
 165  0
                 break;
 166  
 
 167  
             case TodoTokenTable.TOKEN_RESOLVEDCRITICS:
 168  0
                 handleResolvedCritics(e);
 169  0
                 break;
 170  
 
 171  
             case TodoTokenTable.TOKEN_ISSUE:
 172  0
                 handleIssueStart(e);
 173  0
                 break;
 174  
 
 175  
             default:
 176  0
                 LOG.warn("WARNING: unknown tag:" + e.getName());
 177  
                 break;
 178  
             }
 179  0
         } catch (Exception ex) {
 180  0
             LOG.error("Exception in startelement", ex);
 181  0
         }
 182  0
     }
 183  
 
 184  
     /**
 185  
      * Called by the XML implementation to signal the end of an XML
 186  
      * entity.
 187  
      *
 188  
      * @param        e        The XML entity that ends.
 189  
      * @throws SAXException on any error
 190  
      */
 191  
     public void handleEndElement(XMLElement e) throws SAXException {
 192  
 
 193  
         try {
 194  0
             switch (tokens.toToken(e.getName(), false)) {
 195  
             case TodoTokenTable.TOKEN_TO_DO:
 196  
             case TodoTokenTable.TOKEN_RESOLVEDCRITICS:
 197  
             case TodoTokenTable.TOKEN_TO_DO_LIST:
 198  
                 // NOP
 199  0
                 break;
 200  
 
 201  
             case TodoTokenTable.TOKEN_TO_DO_ITEM:
 202  0
                 handleTodoItemEnd(e);
 203  0
                 break;
 204  
 
 205  
             case TodoTokenTable.TOKEN_HEADLINE:
 206  0
                 handleHeadline(e);
 207  0
                 break;
 208  
 
 209  
             case TodoTokenTable.TOKEN_DESCRIPTION:
 210  0
                 handleDescription(e);
 211  0
                 break;
 212  
 
 213  
             case TodoTokenTable.TOKEN_PRIORITY:
 214  0
                 handlePriority(e);
 215  0
                 break;
 216  
 
 217  
             case TodoTokenTable.TOKEN_MOREINFOURL:
 218  0
                 handleMoreInfoURL(e);
 219  0
                 break;
 220  
 
 221  
             case TodoTokenTable.TOKEN_ISSUE:
 222  0
                 handleIssueEnd(e);
 223  0
                 break;
 224  
 
 225  
             case TodoTokenTable.TOKEN_POSTER:
 226  0
                 handlePoster(e);
 227  0
                 break;
 228  
 
 229  
             case TodoTokenTable.TOKEN_OFFENDER:
 230  0
                 handleOffender(e);
 231  0
                 break;
 232  
 
 233  
             default:
 234  0
                 LOG.warn("WARNING: unknown end tag:"
 235  
                          + e.getName());
 236  
                 break;
 237  
             }
 238  0
         } catch (Exception ex) {
 239  0
             throw new SAXException(ex);
 240  0
         }
 241  0
     }
 242  
 
 243  
     /**
 244  
      * Internal method.
 245  
      *
 246  
      * @param e the element
 247  
      */
 248  
     protected void handleTodo(XMLElement e) {
 249  
         /* do nothing */
 250  0
     }
 251  
 
 252  
     /**
 253  
      * Internal method.
 254  
      *
 255  
      * @param e the element
 256  
      */
 257  
     protected void handleTodoList(XMLElement e) {
 258  
         /* do nothing */
 259  0
     }
 260  
 
 261  
     /**
 262  
      * Internal method.
 263  
      *
 264  
      * @param e the element
 265  
      */
 266  
     protected void handleResolvedCritics(XMLElement e) {
 267  
         /* do nothing */
 268  0
     }
 269  
 
 270  
     /**
 271  
      * Internal method.
 272  
      *
 273  
      * @param e the element
 274  
      */
 275  
     protected void handleTodoItemStart(XMLElement e) {
 276  0
         headline = "";
 277  0
         priority = ToDoItem.HIGH_PRIORITY;
 278  0
         moreinfourl = "";
 279  0
         description = "";
 280  0
     }
 281  
 
 282  
     /**
 283  
      * Internal method.
 284  
      *
 285  
      * @param e the element
 286  
      */
 287  
     protected void handleTodoItemEnd(XMLElement e) {
 288  
         ToDoItem item;
 289  
         Designer dsgr;
 290  
 
 291  
         /* This is expected to be safe, don't add a try block here */
 292  
 
 293  0
         dsgr = Designer.theDesigner();
 294  0
         item =
 295  
             new ToDoItem(dsgr, headline, priority, description, moreinfourl,
 296  
                          new ListSet());
 297  0
         dsgr.getToDoList().addElement(item);
 298  
         //cat.debug("Added ToDoItem: " + _headline);
 299  0
     }
 300  
 
 301  
     /**
 302  
      * Internal method.
 303  
      *
 304  
      * @param e the element
 305  
      */
 306  
     protected void handleHeadline(XMLElement e) {
 307  0
         headline = decode(e.getText()).trim();
 308  0
     }
 309  
 
 310  
     /**
 311  
      * Internal method.
 312  
      *
 313  
      * @param e the element
 314  
      */
 315  
     protected void handlePriority(XMLElement e) {
 316  0
         String prio = decode(e.getText()).trim();
 317  
         int np;
 318  
 
 319  
         try {
 320  0
             np = Integer.parseInt(prio);
 321  0
         } catch (NumberFormatException nfe) {
 322  0
             np = ToDoItem.HIGH_PRIORITY;
 323  
 
 324  0
             if (TodoTokenTable.STRING_PRIO_HIGH.equalsIgnoreCase(prio)) {
 325  0
                 np = ToDoItem.HIGH_PRIORITY;
 326  0
             } else if (TodoTokenTable.STRING_PRIO_MED.equalsIgnoreCase(prio)) {
 327  0
                 np = ToDoItem.MED_PRIORITY;
 328  0
             } else if (TodoTokenTable.STRING_PRIO_LOW.equalsIgnoreCase(prio)) {
 329  0
                 np = ToDoItem.LOW_PRIORITY;
 330  
             }
 331  0
         }
 332  
 
 333  0
         priority = np;
 334  0
     }
 335  
 
 336  
     /**
 337  
      * Internal method.
 338  
      *
 339  
      * @param e the element
 340  
      */
 341  
     protected void handleMoreInfoURL(XMLElement e) {
 342  0
         moreinfourl = decode(e.getText()).trim();
 343  0
     }
 344  
 
 345  
     /**
 346  
      * Internal method.
 347  
      *
 348  
      * @param e the element
 349  
      */
 350  
     protected void handleDescription(XMLElement e) {
 351  0
         description = decode(e.getText()).trim();
 352  0
     }
 353  
 
 354  
     /**
 355  
      * Internal method.
 356  
      *
 357  
      * @param e the element
 358  
      */
 359  
     protected void handleIssueStart(XMLElement e) {
 360  0
         critic = null;
 361  0
         offenders = null;
 362  0
     }
 363  
 
 364  
     /**
 365  
      * Internal method.
 366  
      *
 367  
      * @param e the element
 368  
      */
 369  
     protected void handleIssueEnd(XMLElement e) {
 370  
         Designer dsgr;
 371  
         ResolvedCritic item;
 372  
 
 373  0
         if (critic == null) {
 374  0
             return;
 375  
         }
 376  
 
 377  0
         item = new ResolvedCritic(critic, offenders);
 378  0
         dsgr = Designer.theDesigner();
 379  0
         dsgr.getToDoList().addResolvedCritic(item);
 380  0
     }
 381  
 
 382  
     /**
 383  
      * Internal method.
 384  
      *
 385  
      * @param e the element
 386  
      */
 387  
     protected void handlePoster(XMLElement e) {
 388  0
         critic = decode(e.getText()).trim();
 389  0
     }
 390  
 
 391  
     /**
 392  
      * Internal method.
 393  
      *
 394  
      * @param e the element
 395  
      */
 396  
     protected void handleOffender(XMLElement e) {
 397  0
         if (offenders == null) {
 398  0
             offenders = new ArrayList();
 399  
         }
 400  0
         offenders.add(decode(e.getText()).trim());
 401  0
     }
 402  
 
 403  
     /**
 404  
      * Utility method to decode a String filtering out any noise that
 405  
      * an XML framework might have seen fit to add and thus regaining
 406  
      * the original unmodified String.
 407  
      *
 408  
      * @param        str        The String to decode.
 409  
      * @return        A copy of the original String.
 410  
      */
 411  
     public static String decode(String str) {
 412  0
         if (str == null) {
 413  0
             return null;
 414  
         }
 415  
 
 416  
         StringBuffer sb;
 417  
         int i1, i2;
 418  
         char c;
 419  
 
 420  0
         sb = new StringBuffer();
 421  0
         for (i1 = 0, i2 = 0; i2 < str.length(); i2++) {
 422  0
             c = str.charAt(i2);
 423  0
             if (c == '%') {
 424  0
                 if (i2 > i1) {
 425  0
                     sb.append(str.substring(i1, i2));
 426  
                 }
 427  0
                 for (i1 = ++i2; i2 < str.length(); i2++) {
 428  0
                     if (str.charAt(i2) == ';') {
 429  0
                         break;
 430  
                     }
 431  
                 }
 432  0
                 if (i2 >= str.length()) {
 433  0
                     i1 = i2;
 434  0
                     break;
 435  
                 }
 436  
 
 437  0
                 if (i2 > i1) {
 438  0
                     String ent = str.substring(i1, i2);
 439  0
                     if ("proc".equals(ent)) {
 440  0
                         sb.append('%');
 441  
                     } else {
 442  
                         try {
 443  0
                             sb.append((char) Integer.parseInt(ent));
 444  0
                         } catch (NumberFormatException nfe) {
 445  
                             // TODO: handle parse error
 446  0
                         }
 447  
                     }
 448  
                 }
 449  0
                 i1 = i2 + 1;
 450  
             }
 451  
         }
 452  0
         if (i2 > i1) {
 453  0
             sb.append(str.substring(i1, i2));
 454  
         }
 455  0
         return sb.toString();
 456  
     }
 457  
 
 458  
     /**
 459  
      * Utility method to encode a String in a way that allows it to be
 460  
      * saved properly in an XML file and regained filtering out any noice
 461  
      * that an XML framework might have seen fit to add.
 462  
      *
 463  
      * TODO: Why are we doing this ourselves?  Surely encoding information
 464  
      * for XML serialization is a well known task - tfm
 465  
      * I have never understood why this is being done. I think we should remove
 466  
      * any usage - bob
 467  
      * 
 468  
      * @param        str        The String to encode.
 469  
      * @return        The encoded String.
 470  
      */
 471  
     public static String encode(String str) {
 472  
         StringBuffer sb;
 473  
         int i1, i2;
 474  
         char c;
 475  
 
 476  0
         if (str == null) {
 477  0
             return null;
 478  
         }
 479  0
         sb = new StringBuffer();
 480  0
         for (i1 = 0, i2 = 0; i2 < str.length(); i2++) {
 481  0
             c = str.charAt(i2);
 482  0
             if (c == '%') {
 483  0
                 if (i2 > i1) {
 484  0
                     sb.append(str.substring(i1, i2));
 485  
                 }
 486  0
                 sb.append("%proc;");
 487  0
                 i1 = i2 + 1;
 488  0
             } else if (c < 0x28
 489  
                 ||  (c >= 0x3C && c <= 0x40 && c != 0x3D && c != 0x3F)
 490  
                 ||  (c >= 0x5E && c <= 0x60 && c != 0x5F)
 491  
                 ||   c >= 0x7B) {
 492  0
                 if (i2 > i1) {
 493  0
                     sb.append(str.substring(i1, i2));
 494  
                 }
 495  0
                 sb.append("%" + Integer.toString(c) + ";");
 496  0
                 i1 = i2 + 1;
 497  
             }
 498  
         }
 499  0
         if (i2 > i1) {
 500  0
             sb.append(str.substring(i1, i2));
 501  
         }
 502  
 
 503  
         //cat.debug("encode:\n" + str + "\n -> " + sb.toString());
 504  0
         return sb.toString();
 505  
     }
 506  
 }
 507