Coverage Report - net.sf.jolene.dom.Document
 
Classes in this File Line Coverage Branch Coverage Complexity
Document
65%
145/222
65%
60/92
0
 
 1  
 /**
 2  
  * This package is DOMLET!!!
 3  
  */
 4  
 package net.sf.jolene.dom;
 5  
 
 6  
 import net.sf.jolene.constants.Prefs;
 7  
 import net.sf.jolene.constants.Tags;
 8  
 import net.sf.jolene.html.Attributes;
 9  
 import net.sf.jolene.html.IAttributes;
 10  
 import org.apache.log4j.LogManager;
 11  
 import org.apache.log4j.Logger;
 12  
 
 13  
 import java.io.*;
 14  
 import java.util.*;
 15  
 
 16  
 /**
 17  
  * HTML Document object.
 18  
  *
 19  
  * @author Dan Howard
 20  
  * @since Sep 21, 2003 5:22:33 PM
 21  
  */
 22  0
 public final class Document {
 23  
 
 24  
     // todo modifiy file constructor to use File object - add constructor passing in the content of the document
 25  
 
 26  1
     private static final Logger log = LogManager.getLogger(Document.class);
 27  
 
 28  
     // These are default protection so they are available to the Parser. The Parser's job is
 29  
     // to initialize and define these objects.
 30  
     String title;
 31  
     List<Header> head;
 32  
     String doctype;     // Store the text before the start of HTML - usually !DOCTYPE
 33  
     String bodyText;    // Body text string.
 34  
 
 35  
     List<Form> forms;
 36  
     IAttributes body;
 37  
 
 38  
     private String fileName;
 39  
     private String contextPath;
 40  
     private String uri;
 41  
 
 42  
     /**
 43  
      * Indicator for labels being translated.  We do not do the translations here.
 44  
      * We expect that the translation is done at the application level. This can
 45  
      * therefore be used to decide if the document is already translated (so you
 46  
      * don't need to do it over again.
 47  
      * <p/>
 48  
      * see net.sf.jolene.struts.DomletAction for the struts implementation
 49  
      */
 50  
     private boolean translated;
 51  
 
 52  
     /**
 53  
      * @param fileName
 54  
      * @param contextPath
 55  
      * @param uri
 56  
      * @throws IOException
 57  
      * @throws MalformedHTMLException - runtime exception
 58  
      */
 59  
     public Document(String fileName, String contextPath, String uri) throws IOException, MalformedHTMLException {
 60  1
         this(fileName);
 61  1
         this.contextPath = contextPath;
 62  1
         this.uri = uri;
 63  1
         translatePaths();
 64  1
     }
 65  
 
 66  
     /**
 67  
      * @param fileName - file name of the document.
 68  
      * @throws IOException            - if an IOException occurs
 69  
      * @throws MalformedHTMLException - runtime exception
 70  
      */
 71  
     public Document(String fileName) throws IOException, MalformedHTMLException {
 72  34
         this();
 73  34
         this.fileName = fileName;
 74  34
         open();
 75  33
     }
 76  
 
 77  
     /**
 78  
      * For clone only.
 79  
      */
 80  35
     Document() {
 81  35
         title = "";
 82  35
         head = new ArrayList<Header>(4);
 83  35
         doctype = "";
 84  35
         bodyText = "";
 85  35
         contextPath = "";
 86  35
         uri = "";
 87  35
         body = new Attributes();
 88  35
         forms = new ArrayList<Form>(4);
 89  35
         uri = "";
 90  35
     }
 91  
 
 92  
 
 93  
     /**
 94  
      * Adds a header element to the document.
 95  
      *
 96  
      * @param header a Header object.
 97  
      * @return boolean to indicate success.
 98  
      */
 99  
     public boolean addHeader(Header header) {
 100  1
         return head.add(header);
 101  
     }
 102  
 
 103  
     /**
 104  
      * This is a custom clone implementation which ensures the document
 105  
      * is cleanly and safely cloned. Used by the DocumentFactory.
 106  
      *
 107  
      * @return Document
 108  
      */
 109  
     @Override
 110  
     public Document clone() {
 111  1
         Document doc = new Document();
 112  1
         doc.bodyText = bodyText;
 113  1
         doc.fileName = fileName;
 114  1
         doc.uri = uri;
 115  1
         doc.doctype = doctype;
 116  1
         doc.title = title;
 117  
 
 118  
         Iterator<Header> ith;
 119  1
         ith = head.iterator();
 120  2
         while (ith.hasNext()) {
 121  1
             doc.head.add(ith.next().clone());
 122  
         }
 123  
 
 124  
         Iterator it;
 125  1
         doc.body = new Attributes();
 126  1
         it = body.keySet().iterator();
 127  2
         while (it.hasNext()) {
 128  
             Object key;
 129  
             Object value;
 130  1
             key = it.next();
 131  1
             value = body.getAttribute(key.toString());
 132  1
             doc.body.setAttribute(key.toString(), value.toString());
 133  1
         }
 134  
 
 135  1
         doc.forms = new ArrayList<Form>(forms.size());
 136  2
         for (int i = 0; i < forms.size(); i++) {
 137  1
             doc.forms.add(forms.get(i).clone());
 138  
         }
 139  
 
 140  1
         return doc;
 141  
     }
 142  
 
 143  
     /**
 144  
      * Returns a object by searching all forms in the document.
 145  
      *
 146  
      * @param id The id of the element.
 147  
      * @return HTMLElement
 148  
      */
 149  
     public HTMLElement elements(String id) {
 150  23
         HTMLElement element = null;
 151  
 
 152  23
         if (forms != null && forms.size() > 0) {
 153  26
             for (int j = 0; j < forms.size(); j++) {
 154  23
                 element = forms.get(j).elements(id);
 155  23
                 if (element != null) {
 156  20
                     return element;
 157  
                 }
 158  
             }
 159  
         }
 160  
 
 161  3
         return element;
 162  
     }
 163  
 
 164  
     /**
 165  
      * Returns the form object specified by the number.
 166  
      *
 167  
      * @param index form number (starting with 0)
 168  
      * @return Form a Form object
 169  
      * @throws IndexOutOfBoundsException - if the index is out of range (index < 0 || index >= size()).
 170  
      */
 171  
     public Form forms(int index) {
 172  754
         return forms.get(index);
 173  
     }
 174  
 
 175  
     /**
 176  
      * Returns a form object specified by name. For the form to be found it will require a 'name' attribute.
 177  
      * @param name name of the form in the document (case insensitive).
 178  
      * @return Form a Form object or null if not found.
 179  
      */
 180  
     public Form forms(String name) {
 181  2
         for (Form form: forms) {
 182  2
             if (name.equalsIgnoreCase(form.getName())) {
 183  1
                 return form;
 184  
             }
 185  
         }
 186  1
         return null;
 187  
     }
 188  
 
 189  
     /**
 190  
      * Retrives the body attributes.
 191  
      *
 192  
      * @return IAttributes
 193  
      */
 194  
     public IAttributes getBody() {
 195  0
         return body;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Gets the doc type of the document.
 200  
      *
 201  
      * @return String
 202  
      */
 203  
     public String getDoctype() {
 204  0
         return doctype;
 205  
     }
 206  
 
 207  
 
 208  
     /**
 209  
      * @return Number of forms in the document.
 210  
      */
 211  
     public int getFormCount() {
 212  0
         return forms.size();
 213  
     }
 214  
 
 215  
     /**
 216  
      * Returns the number of Header elements in the document.
 217  
      *
 218  
      * @return int number of Header elements.
 219  
      */
 220  
     public int getHeaderCount() {
 221  0
         return head.size();
 222  
     }
 223  
 
 224  
     /**
 225  
      * Gets the document title.
 226  
      *
 227  
      * @return title
 228  
      */
 229  
     public String getTitle() {
 230  23
         return title;
 231  
     }
 232  
 
 233  
     /**
 234  
      * @return uri string for this document.
 235  
      */
 236  
     public String getUri() {
 237  0
         return uri;
 238  
     }
 239  
 
 240  
     /**
 241  
      * Return the Header element specified by the index based on document order.
 242  
      *
 243  
      * @param header to the Header (starting with 0).
 244  
      * @return Header element.
 245  
      */
 246  
     public Header headers(int header) {
 247  0
         return head.get(header);
 248  
     }
 249  
 
 250  
     /**
 251  
      * Indicator for labels being translated.  We do not do the translations here.
 252  
      * We expect that the translation is done at the application level. This can
 253  
      * therefore be used to decide if the document is already translated (so you
 254  
      * don't need to do it over again.
 255  
      * <p/>
 256  
      * see net.sf.jolene.struts.DomletAction for the struts implementation
 257  
      *
 258  
      * @return true if this document is translated
 259  
      */
 260  
     public boolean isTranslated() {
 261  0
         return translated;
 262  
     }
 263  
 
 264  
     /**
 265  
      * Remove the headers
 266  
      * @param index to the header in the document. Zero based in document order.
 267  
      * @return The removed header object.
 268  
      */
 269  
     public Header removeHeader(int index) {
 270  1
         return head.remove(index);
 271  
     }
 272  
 
 273  
     /**
 274  
      * Sets the doc type of the document.
 275  
      *
 276  
      * @param doctype The HTML doctype string.
 277  
      */
 278  
     public void setDoctype(String doctype) {
 279  0
         this.doctype = doctype;
 280  0
     }
 281  
 
 282  
     /**
 283  
      * Set the document title.
 284  
      *
 285  
      * @param string The document title.
 286  
      */
 287  
     public void setTitle(String string) {
 288  34
         title = string;
 289  34
     }
 290  
 
 291  
     /**
 292  
      * Indicator for labels being translated.  We do not do the translations here.
 293  
      * We expect that the translation is done at the application level. This can
 294  
      * therefore be used to decide if the document is already translated (so you
 295  
      * don't need to do it over again.
 296  
      * see net.sf.jolene.struts.DomletAction for the struts implementation
 297  
      *
 298  
      * @param translated set to true if the doc has been translated.
 299  
      */
 300  
     public void setTranslated(boolean translated) {
 301  0
         this.translated = translated;
 302  0
     }
 303  
 
 304  
     /**
 305  
      * Writes the document to the specified fileName.
 306  
      *
 307  
      * @param filename The filename to write to.
 308  
      * @throws java.io.IOException if there's an IOException
 309  
      */
 310  
     public void stream(String filename) throws IOException {
 311  19
         BufferedWriter out = null;
 312  
         try {
 313  19
             out = new BufferedWriter(new FileWriter(filename));
 314  19
             stream(out);
 315  
         } finally {
 316  19
             if (out != null) {
 317  
                 try {
 318  19
                     out.close();
 319  0
                 } catch (IOException e) {
 320  19
                 }
 321  
             }
 322  
         }
 323  19
     }
 324  
 
 325  
     /**
 326  
      * Writes the document to the specified Writer object and closes the Writer.
 327  
      *
 328  
      * @param out an output Writer to write to.
 329  
      * @throws java.io.IOException it there's an IOException
 330  
      */
 331  
     public void stream(Writer out) throws IOException {
 332  
         try {
 333  23
             String ls = System.getProperty("line.separator");
 334  
 
 335  23
             if (doctype != null && doctype.trim().length() > 0) {
 336  6
                 out.write(doctype + ls);
 337  
             }
 338  23
             out.write("<html>" + ls);
 339  23
             out.write("<head>" + ls);
 340  23
             for (Header aHead : head) {
 341  61
                 out.write(aHead.getBeforeText() + aHead + aHead.getAfterText() + ls);
 342  
             }
 343  23
             out.write("<title>" + getTitle() + "</title>" + ls);
 344  23
             out.write("</head>" + ls);
 345  
 
 346  23
             out.write("<body ");
 347  23
             for (String s : body.keySet()) {
 348  3
                 out.write(s + "=\"" + body.getAttribute(s) + "\" ");
 349  
             }
 350  23
             out.write(">" + ls);
 351  
 
 352  
             // For each form, put the text from the start of the body text to
 353  
             // the startpoint of the form.
 354  
             int offset;
 355  23
             offset = 0;
 356  
             Form form;
 357  
 
 358  53
             for (int j = 0; j < forms.size(); j++) {
 359  30
                 form = (Form) forms(j);
 360  
                 // Write whatever text exist between previous form (or start of doc) and current form.
 361  30
                 out.write(bodyText.substring(offset, form.getStartPoint()));
 362  30
                 out.write(form.getBeforeText() + form + form.getAfterText());
 363  30
                 offset = form.getEndPoint() + 1;
 364  
 
 365  213
                 for (int k = 0; k < form.elements.size(); k++) {
 366  
                     //System.out.print("k = " + k + " " + form.elements(k).startPoint + " " + form.elements(k).endPoint + " " + offset);
 367  
                     //System.out.println(" ID: " + form.elements(k).getAttribute("id"));
 368  
 
 369  183
                     out.write(bodyText.substring(offset, form.elements(k).getStartPoint()));
 370  183
                     out.write(form.elements(k).getBeforeText() + form.elements(k) + form.elements(k).getAfterText());
 371  183
                     offset = form.elements(k).getEndPoint() + 1;
 372  
                 }
 373  
 
 374  
                 // if this is the last form write the remaining text.
 375  30
                 if (j == forms.size() - 1) {
 376  23
                     out.write(bodyText.substring(offset, bodyText.length()));
 377  
                 }
 378  
             }
 379  
 
 380  23
             out.write(ls);
 381  23
             out.write("</body>" + ls);
 382  23
             out.write("</html>");
 383  23
             out.flush();
 384  
         } finally {
 385  0
             try {
 386  23
                 out.close();
 387  0
             } catch (IOException e) {
 388  23
             }
 389  0
         }
 390  23
     }
 391  
 
 392  
     /**
 393  
      * Returns the document file name.
 394  
      *
 395  
      * @return String
 396  
      */
 397  
     public String toString() {
 398  33
         return fileName;
 399  
     }
 400  
 
 401  
     //================================================
 402  
 
 403  
     void open() throws IOException, MalformedHTMLException {
 404  34
         long starttime = System.currentTimeMillis();
 405  34
         long fileSize = new File(fileName).length();
 406  
 
 407  34
         log.debug("FileName:" + fileName + " fileSize: " + fileSize);
 408  34
         BufferedReader reader = new BufferedReader(new FileReader(fileName));
 409  34
         char[] buff = new char[(int) fileSize];
 410  
 
 411  34
         String fileBuffer = "";
 412  
         try {
 413  34
             int n = reader.read(buff, 0, (int) fileSize);
 414  
 
 415  
             // Convert char array to StringBuffer
 416  34
             fileBuffer = new String(buff, 0, n);
 417  
         }
 418  
 
 419  
         finally {
 420  0
             try {
 421  34
                 reader.close();
 422  0
             } catch (IOException e) {
 423  34
             }
 424  0
         }
 425  
 
 426  34
         String workBuffer = new String(fileBuffer);
 427  
 
 428  34
         new Parser(workBuffer, this);
 429  
 
 430  33
         if ("true".equalsIgnoreCase(Prefs.GenerateLocaleStrings.getValue())) {
 431  0
             generateLocaleStrings();
 432  
         }
 433  
 
 434  33
         log.info("Time to open doc: " + (System.currentTimeMillis() - starttime));
 435  33
     }
 436  
 
 437  
     private void generateLocaleStrings() throws IOException {
 438  0
         Properties properties = new Properties();
 439  
 //@todo - so many issues here. Null pointer possibility, What value for objects? Which objects? Should they include html? NO! Wrong place for the code. Where to create the file?
 440  
 
 441  0
         FileOutputStream out = null;
 442  0
         FileInputStream in = null;
 443  
         try {
 444  0
             File f = new File("resources/application.properties");
 445  0
             f.createNewFile();
 446  0
             in = new FileInputStream(f);
 447  0
             properties.load(in);
 448  0
             out = new FileOutputStream(f);
 449  
 
 450  
             Form ff;
 451  
             StringBuilder objectName;
 452  
 
 453  0
             log.info("FILENAME: " + this.fileName);
 454  
             String docName;
 455  0
             docName = this.fileName.substring(this.fileName.lastIndexOf("/") + 1);
 456  0
             docName = docName.substring(0, docName.indexOf("."));
 457  0
             log.info("DOC NAME: " + docName);
 458  0
             for (int j = 0; j < forms.size(); j++) {
 459  0
                 objectName = new StringBuilder();
 460  0
                 objectName.append(docName).append('.');
 461  
 
 462  0
                 ff = (Form) forms(j);
 463  0
                 if (ff.getName().trim().length() > 0) {
 464  0
                     objectName.append(ff.getName()).append('.');
 465  
                 } else {
 466  0
                     objectName.append("form").append(j + 1).append('.');
 467  
                 }
 468  
 
 469  
                 String elementName;
 470  
                 HTMLElement element;
 471  0
                 for (int k = 0; k < ff.elements.size(); k++) {
 472  0
                     element = ff.elements(k);
 473  0
                     if (element.hasAttribute("name")) {
 474  0
                         elementName = element.getAttribute("name");
 475  0
                     } else if (element.hasAttribute("id")) {
 476  0
                         elementName = element.getAttribute("id");
 477  
                     } else {
 478  0
                         elementName = element.getTag().toString() + k;
 479  
                     }
 480  0
                     if (element.getValue() != null) {
 481  0
                         properties.put(objectName + elementName, element.getValue());
 482  
                     }
 483  
                 }
 484  
             }
 485  0
             properties.store(out, "---Locale strings written by jolene---");
 486  0
             out.close();
 487  0
             in.close();
 488  
         } finally {
 489  0
             if (out != null) {
 490  
                 try {
 491  0
                     out.close();
 492  0
                 } catch (IOException e) {
 493  0
                     log.warn(e.getMessage(), e);
 494  0
                 }
 495  
                 try {
 496  0
                     in.close();
 497  0
                 } catch (IOException e) {
 498  0
                     log.warn(e.getMessage(), e);
 499  0
                 }
 500  
             }
 501  
         }
 502  0
     }
 503  
 
 504  
     //--------------------------------------------------------
 505  
 
 506  
     //@TODO Add call for JUnit tests
 507  
 
 508  
     void streamObjects() {
 509  
         Form ff;
 510  
 
 511  0
         for (int j = 0; j < forms.size(); j++) {
 512  0
             ff = (Form) forms(j);
 513  
 
 514  0
             System.out.println("FORM: " + j + ff);
 515  0
             for (int k = 0; k < ff.elements.size(); k++) {
 516  0
                 System.out.print("" + ff.elements(k));
 517  0
                 if (ff.elements(k).hasAttribute("name")) {
 518  0
                     System.out.println("NAME: " + ff.elements(k).getAttribute("name"));
 519  
                 } else {
 520  0
                     if (ff.elements(k).hasAttribute("id")) {
 521  0
                         System.out.println("ID: " + ff.elements(k).getAttribute("ID"));
 522  
                     } else {
 523  0
                         System.out.println();
 524  
                     }
 525  
                 }
 526  
             }
 527  
         }
 528  0
     }
 529  
 
 530  
     /**
 531  
      * For JUnit
 532  
      */
 533  
     void streamResults(Writer writer) throws IOException {
 534  19
         for (int j = 0; j < forms.size(); j++) {
 535  11
             writer.write("form : " + j + " " + forms(j) + "\n");
 536  136
             for (int k = 0; k < forms(j).elements.size(); k++) {
 537  125
                 writer.write("element : " + k + "\n" + forms(j).elements(k) + "\n");
 538  
             }
 539  
         }
 540  8
     }
 541  
 
 542  
     private void translatePaths() {
 543  
         HTMLElement element;
 544  
         String src;
 545  
 
 546  3
         for (int j = 0; j < this.forms.size(); j++) {
 547  17
             for (int k = 0; k < this.forms.get(j).getElementCount(); k++) {
 548  15
                 element = this.forms.get(j).elements(k);
 549  15
                 if (element.getTag().equals(Tags.img) && element.hasAttribute("src")) {
 550  2
                     src = translatePath(element.getAttribute("src"));
 551  2
                     element.setAttribute("src", src);
 552  
                 }
 553  
             }
 554  
         }
 555  
 
 556  15
         for (int j = 0; j < this.head.size(); j++) {
 557  14
             element = this.head.get(j);
 558  
 
 559  14
             if (element.tag == Tags.script && element.hasAttribute("src")) {
 560  0
                 src = translatePath(element.getAttribute("src"));
 561  0
                 element.setAttribute("src", src);
 562  14
             } else if (element.tag == Tags.link) {
 563  6
                 if (element.hasAttribute("href")) {
 564  6
                     src = translatePath(element.getAttribute("href"));
 565  6
                     element.setAttribute("href", src);
 566  
                 }
 567  
 
 568  6
                 if (element.hasAttribute("src")) {
 569  0
                     src = translatePath(element.getAttribute("srg"));
 570  0
                     element.setAttribute("src", src);
 571  
                 }
 572  
             }
 573  
         }
 574  1
     }
 575  
 
 576  
     private String translatePath(String path) {
 577  8
         if (path == null) {
 578  
             // If an element does not have a src or href attribute then it will be assigned blank
 579  0
             return "";
 580  
         }
 581  8
         if (path.toLowerCase().startsWith("http")) {
 582  
             // leave it alone, the path exists on some other server.
 583  1
             return path;
 584  
         }
 585  7
         path = path.replace('\\', '/');
 586  7
         StringTokenizer st = new StringTokenizer(path, "/");
 587  7
         StringBuffer endPath = new StringBuffer("");
 588  
         String pathElement;
 589  40
         while (st.hasMoreElements()) {
 590  33
             pathElement = st.nextElement().toString();
 591  33
             if (pathElement.equals(".") || pathElement.equals("..")) {
 592  
             } else {
 593  13
                 endPath.append('/').append(pathElement);
 594  
             }
 595  
         }
 596  
 
 597  7
         path = contextPath + endPath;
 598  
 
 599  7
         return path;
 600  
     }
 601  
 }