langtools/test/tools/javac/diags/HTMLWriter.java
changeset 6149 48de3564aa13
child 34752 9c262a013456
equal deleted inserted replaced
6148:3a8158299c51 6149:48de3564aa13
       
     1 /*
       
     2  * Copyright (c) 1996,2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 
       
    25 
       
    26 import java.io.BufferedWriter;
       
    27 import java.io.File;
       
    28 import java.io.IOException;
       
    29 import java.io.Writer;
       
    30 import java.net.URL;
       
    31 import java.text.MessageFormat;
       
    32 import java.util.ResourceBundle;
       
    33 
       
    34 /**
       
    35  * A class to facilitate writing HTML via a stream.
       
    36  */
       
    37 public class HTMLWriter
       
    38 {
       
    39     /**
       
    40      * Create an HTMLWriter object, using a default doctype for HTML 3.2.
       
    41      * @param out a Writer to which to write the generated HTML
       
    42      * @throws IOException if there is a problem writing to the underlying stream
       
    43      */
       
    44     public HTMLWriter(Writer out) throws IOException {
       
    45         this(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">");
       
    46     }
       
    47 
       
    48     /**
       
    49      * Create an HTMLWriter object, using a specifed doctype header.
       
    50      * @param out a Writer to which to write the generated HTML
       
    51      * @param docType a string containing a doctype header for the HTML to be generetaed
       
    52      * @throws IOException if there is a problem writing to the underlying stream
       
    53      */
       
    54     public HTMLWriter(Writer out, String docType) throws IOException {
       
    55         if (out instanceof BufferedWriter)
       
    56             this.out = (BufferedWriter) out;
       
    57         else
       
    58             this.out = new BufferedWriter(out);
       
    59         this.out.write(docType);
       
    60         this.out.newLine();
       
    61     }
       
    62 
       
    63     /**
       
    64      * Create an HTMLWriter object, using a specified bundle for localizing messages.
       
    65      * @param out a Writer to which to write the generated HTML
       
    66      * @param i18n a resource bundle to use to localize messages
       
    67      * @throws IOException if there is a problem writing to the underlying stream
       
    68      */
       
    69     public HTMLWriter(Writer out, ResourceBundle i18n) throws IOException {
       
    70         this(out);
       
    71         this.i18n = i18n;
       
    72     }
       
    73 
       
    74 
       
    75     /**
       
    76      * Create an HTMLWriter object, using a specifed doctype header and
       
    77      * using a specified bundle for l0calizing messages.
       
    78      * @param out a Writer to which to write the generated HTML
       
    79      * @param docType a string containing a doctype header for the HTML to be generetaed
       
    80      * @param i18n a resource bundle to use to localize messages
       
    81      * @throws IOException if there is a problem writing to the underlying stream
       
    82      */
       
    83     public HTMLWriter(Writer out, String docType, ResourceBundle i18n) throws IOException {
       
    84         this(out, docType);
       
    85         this.i18n = i18n;
       
    86     }
       
    87 
       
    88     /**
       
    89      * Set the reource bundle to be used for localizing messages.
       
    90      * @param i18n the resource bundle to be used for localizing messages
       
    91      */
       
    92     public void setResourceBundle(ResourceBundle i18n) {
       
    93         this.i18n = i18n;
       
    94     }
       
    95 
       
    96     /**
       
    97      * Flush the stream, and the underlying output stream.
       
    98      * @throws IOException if there is a problem writing to the underlying stream
       
    99      */
       
   100     public void flush() throws IOException {
       
   101         out.flush();
       
   102     }
       
   103 
       
   104     /**
       
   105      * Close the stream, and the underlying output stream.
       
   106      * @throws IOException if there is a problem closing the underlying stream
       
   107      */
       
   108     public void close() throws IOException {
       
   109         out.close();
       
   110     }
       
   111 
       
   112     /**
       
   113      * Write a newline to the underlying output stream.
       
   114      * @throws IOException if there is a problem writing to the underlying stream
       
   115      */
       
   116     public void newLine() throws IOException {
       
   117         out.newLine();
       
   118     }
       
   119 
       
   120     /**
       
   121      * Start an HTML tag.  If a prior tag has been started, it will
       
   122      * be closed first. Once a tag has been opened, attributes for the
       
   123      * tag may be written out, followed by body content before finally
       
   124      * ending the tag.
       
   125      * @param tag the tag to be started
       
   126      * @throws IOException if there is a problem writing to the underlying stream
       
   127      * @see #writeAttr
       
   128      * @see #write
       
   129      * @see #endTag
       
   130      */
       
   131     public void startTag(String tag) throws IOException {
       
   132         if (state == IN_TAG) {
       
   133             out.write(">");
       
   134             state = IN_BODY;
       
   135         }
       
   136         //newLine();
       
   137         out.write("<");
       
   138         out.write(tag);
       
   139         state = IN_TAG;
       
   140     }
       
   141 
       
   142     /**
       
   143      * Finish an HTML tag. It is expected that a call to endTag will match
       
   144      * a corresponding earlier call to startTag, but there is no formal check
       
   145      * for this.
       
   146      * @param tag the tag to be closed.
       
   147      * @throws IOException if there is a problem writing to the underlying stream
       
   148      */
       
   149     public void endTag(String tag) throws IOException {
       
   150         if (state == IN_TAG) {
       
   151             out.write(">");
       
   152             state = IN_BODY;
       
   153             out.newLine();
       
   154         }
       
   155         out.write("</");
       
   156         out.write(tag);
       
   157         out.write(">");
       
   158         //out.newLine();   // PATCHED, jjg
       
   159         state = IN_BODY;
       
   160     }
       
   161 
       
   162     /**
       
   163      * Finish an empty element tag, such as a META, BASE or LINK tag.
       
   164      * This is expected to correspond with a startTag.
       
   165      * @param tag the tag which is being closed.  this is only useful for
       
   166      *        validation, it is not written out
       
   167      * @throws IllegalStateException if this call does not follow startTag
       
   168      *         (stream is not currently inside a tag)
       
   169      * @throws IOException if there is a problem writing to the underlying stream
       
   170      */
       
   171     public void endEmptyTag(String tag) throws IOException {
       
   172         if (state != IN_TAG)
       
   173             throw new IllegalStateException();
       
   174 
       
   175         out.write(">");
       
   176         state = IN_BODY;
       
   177         out.newLine();
       
   178     }
       
   179 
       
   180     /**
       
   181      * Write an attribute for a tag. A tag must previously have been started.
       
   182      * All tag attributes must be written before any body text is written.
       
   183      * The value will be quoted if necessary when writing it to the underlying
       
   184      * stream. No check is made that the attribute is valid for the current tag.
       
   185      * @param name the name of the attribute to be written
       
   186      * @param value the value of the attribute to be written
       
   187      * @throws IllegalStateException if the stream is not in a state to
       
   188      * write attributes -- e.g. if this call does not follow startTag or other
       
   189      * calls of writteAttr
       
   190      * @throws IOException if there is a problem writing to the underlying stream
       
   191      */
       
   192     public void writeAttr(String name, String value) throws IOException {
       
   193         if (state != IN_TAG)
       
   194             throw new IllegalStateException();
       
   195 
       
   196         out.write(" ");
       
   197         out.write(name);
       
   198         out.write("=");
       
   199         boolean alpha = true;
       
   200         for (int i = 0; i < value.length() && alpha; i++)
       
   201             alpha = Character.isLetter(value.charAt(i));
       
   202         if (!alpha)
       
   203             out.write("\"");
       
   204         out.write(value);
       
   205         if (!alpha)
       
   206             out.write("\"");
       
   207     }
       
   208 
       
   209     /**
       
   210      * Write an attribute for a tag. A tag must previously have been started.
       
   211      * All tag attributes must be written before any body text is written.
       
   212      * The value will be quoted if necessary when writing it to the underlying
       
   213      * stream. No check is made that the attribute is valid for the current tag.
       
   214      * @param name the name of the attribute to be written
       
   215      * @param value the value of the attribute to be written
       
   216      * @throws IllegalStateException if the stream is not in a state to
       
   217      * write attributes -- e.g. if this call does not follow startTag or other
       
   218      * calls of writteAttr
       
   219      * @throws IOException if there is a problem writing to the underlying stream
       
   220      */
       
   221     public void writeAttr(String name, int value) throws IOException {
       
   222         writeAttr(name, Integer.toString(value));
       
   223     }
       
   224 
       
   225     /**
       
   226      * Write a line of text, followed by a newline.
       
   227      * The text will be escaped as necessary.
       
   228      * @param text the text to be written.
       
   229      * @throws IOException if there is a problem closing the underlying stream
       
   230      */
       
   231     public void writeLine(String text) throws IOException {
       
   232         write(text);
       
   233         out.newLine();
       
   234     }
       
   235 
       
   236     /**
       
   237      * Write body text, escaping it as necessary.
       
   238      * If this call follows a call of startTag, the open tag will be
       
   239      * closed -- meaning that no more attributes can be written until another
       
   240      * tag is started.  If the text value is null, the current tag will still
       
   241      * be closed, but no other text will be written.
       
   242      * @param text the text to be written, may be null or zero length.
       
   243      * @throws IOException if there is a problem writing to the underlying stream
       
   244      */
       
   245     public void write(String text) throws IOException {
       
   246         if (state == IN_TAG) {
       
   247             out.write(">");
       
   248             state = IN_BODY;
       
   249         }
       
   250 
       
   251         if (text == null)
       
   252             return;
       
   253 
       
   254         // check to see if there are any special characters
       
   255         boolean specialChars = false;
       
   256         for (int i = 0; i < text.length() && !specialChars; i++) {
       
   257             switch (text.charAt(i)) {
       
   258             case '<': case '>': case '&':
       
   259                 specialChars = true;
       
   260             }
       
   261         }
       
   262 
       
   263         // if there are special characters write the string character at a time;
       
   264         // otherwise, write it out as is
       
   265         if (specialChars) {
       
   266             for (int i = 0; i < text.length(); i++) {
       
   267                 char c = text.charAt(i);
       
   268                 switch (c) {
       
   269                 case '<': out.write("&lt;"); break;
       
   270                 case '>': out.write("&gt;"); break;
       
   271                 case '&': out.write("&amp;"); break;
       
   272                 default: out.write(c);
       
   273                 }
       
   274             }
       
   275         }
       
   276         else
       
   277             out.write(text);
       
   278     }
       
   279 
       
   280     /**
       
   281      * Write a basic HTML entity, such as &nbsp; or &#123; .
       
   282      * @param entity the entity to write
       
   283      * @throws IOException if there is a problem writing to the underlying stream
       
   284      */
       
   285     public void writeEntity(String entity) throws IOException {
       
   286         if (state == IN_TAG) {
       
   287             out.write(">");
       
   288             state = IN_BODY;
       
   289         }
       
   290         out.write(entity);
       
   291     }
       
   292 
       
   293     /**
       
   294      * Write an image tag, using a specified path for the image source attribute.
       
   295      * @param imagePath the path for the image source
       
   296      * @throws IOException if there is a problem closing the underlying stream
       
   297      */
       
   298     public void writeImage(String imagePath) throws IOException {
       
   299         startTag(IMAGE);
       
   300         writeAttr(SRC, imagePath);
       
   301     }
       
   302 
       
   303     /**
       
   304      * Write an image tag, using a specified path for the image source attribute.
       
   305      * @param imageURL the url for the image source
       
   306      * @throws IOException if there is a problem closing the underlying stream
       
   307      */
       
   308     public void writeImage(URL imageURL) throws IOException {
       
   309         writeImage(imageURL.toString());
       
   310     }
       
   311 
       
   312     /**
       
   313      * Write a hypertext link.
       
   314      * @param anchor the target for the link
       
   315      * @param body the body text for the link
       
   316      * @throws IOException if there is a problem closing the underlying stream
       
   317      */
       
   318     public void writeLink(String anchor, String body) throws IOException {
       
   319         startTag(A);
       
   320         writeAttr(HREF, anchor);
       
   321         write(body);
       
   322         endTag(A);
       
   323     }
       
   324 
       
   325     /**
       
   326      * Write a hypertext link.
       
   327      * @param file the target for the link
       
   328      * @param body the body text for the link
       
   329      * @throws IOException if there is a problem closing the underlying stream
       
   330      */
       
   331     public void writeLink(File file, String body) throws IOException {
       
   332         startTag(A);
       
   333         StringBuffer sb = new StringBuffer();
       
   334         String path = file.getPath().replace(File.separatorChar, '/');
       
   335         if (file.isAbsolute() && !path.startsWith("/"))
       
   336             sb.append('/');
       
   337         sb.append(path);
       
   338         writeAttr(HREF, sb.toString());
       
   339         write(body);
       
   340         endTag(A);
       
   341     }
       
   342 
       
   343     /**
       
   344      * Write a hypertext link.
       
   345      * @param file the target and body for the link
       
   346      * @throws IOException if there is a problem closing the underlying stream
       
   347      */
       
   348     public void writeLink(File file) throws IOException {
       
   349         writeLink(file, file.getPath());
       
   350     }
       
   351 
       
   352     /**
       
   353      * Write a hypertext link.
       
   354      * @param url the target for the link
       
   355      * @param body the body text for the link
       
   356      * @throws IOException if there is a problem closing the underlying stream
       
   357      */
       
   358     public void writeLink(URL url, String body) throws IOException {
       
   359         startTag(A);
       
   360         writeAttr(HREF, url.toString());
       
   361         write(body);
       
   362         endTag(A);
       
   363     }
       
   364 
       
   365     /**
       
   366      * Write the destination marker for a hypertext link.
       
   367      * @param anchor the destination marker for hypertext links
       
   368      * @param body the body text for the marker
       
   369      * @throws IOException if there is a problem closing the underlying stream
       
   370      */
       
   371     public void writeLinkDestination(String anchor, String body) throws IOException {
       
   372         startTag(A);
       
   373         writeAttr(NAME, anchor);
       
   374         write(body);
       
   375         endTag(A);
       
   376     }
       
   377 
       
   378     /**
       
   379      * Write a parameter tag.
       
   380      * @param name the name of the parameter
       
   381      * @param value the value of the parameter
       
   382      * @throws IOException if there is a problem closing the underlying stream
       
   383      */
       
   384     public void writeParam(String name, String value) throws IOException {
       
   385         startTag(PARAM);
       
   386         writeAttr(NAME, name);
       
   387         writeAttr(VALUE, value);
       
   388     }
       
   389 
       
   390     /**
       
   391      * Write a style attribute.
       
   392      * @param value the value for the style atrtribute
       
   393      * @throws IOException if there is a problem closing the underlying stream
       
   394      */
       
   395     public void writeStyleAttr(String value) throws IOException {
       
   396         writeAttr(STYLE, value);
       
   397     }
       
   398 
       
   399     /**
       
   400      * Write a localized message, using a specified resource bundle.
       
   401      * @param i18n the resource bundle used to localize the message
       
   402      * @param key the key for the message to be localized
       
   403      * @throws IOException if there is a problem closing the underlying stream
       
   404      */
       
   405     public void write(ResourceBundle i18n, String key) throws IOException {
       
   406         write(getString(i18n, key));
       
   407     }
       
   408 
       
   409     /**
       
   410      * Write a localized message, using a specified resource bundle.
       
   411      * @param i18n the resource bundle used to localize the message
       
   412      * @param key the key for the message to be localized
       
   413      * @param arg an argument to be formatted into the localized message
       
   414      * @throws IOException if there is a problem closing the underlying stream
       
   415      */
       
   416     public void write(ResourceBundle i18n, String key, Object arg) throws IOException {
       
   417         write(getString(i18n, key, arg));
       
   418     }
       
   419 
       
   420     /**
       
   421      * Write a localized message, using a specified resource bundle.
       
   422      * @param i18n the resource bundle used to localize the message
       
   423      * @param key the key for the message to be localized
       
   424      * @param args arguments to be formatted into the localized message
       
   425      * @throws IOException if there is a problem closing the underlying stream
       
   426      */
       
   427     public void write(ResourceBundle i18n, String key, Object[] args) throws IOException {
       
   428         write(getString(i18n, key, args));
       
   429     }
       
   430 
       
   431     /**
       
   432      * Write a localized message, using the default resource bundle.
       
   433      * @param key the key for the message to be localized
       
   434      * @throws IOException if there is a problem closing the underlying stream
       
   435      */
       
   436     public void writeI18N(String key) throws IOException {
       
   437         write(getString(i18n, key));
       
   438     }
       
   439 
       
   440     /**
       
   441      * Write a localized message, using the default resource bundle.
       
   442      * @param key the key for the message to be localized
       
   443      * @param arg an argument to be formatted into the localized message
       
   444      * @throws IOException if there is a problem closing the underlying stream
       
   445      */
       
   446     public void writeI18N(String key, Object arg) throws IOException {
       
   447         write(getString(i18n, key, arg));
       
   448     }
       
   449 
       
   450     /**
       
   451      * Write a localized message, using the default resource bundle.
       
   452      * @param key the key for the message to be localized
       
   453      * @param args arguments to be formatted into the localized message
       
   454      * @throws IOException if there is a problem closing the underlying stream
       
   455      */
       
   456     public void writeI18N(String key, Object[] args) throws IOException {
       
   457         write(getString(i18n, key, args));
       
   458     }
       
   459 
       
   460     private String getString(ResourceBundle rb, String key, Object... args) {
       
   461         String s = rb.getString(key);
       
   462         return MessageFormat.format(s, args);
       
   463     }
       
   464 
       
   465     /** The HTML "a" tag. */
       
   466     public static final String A = "a";
       
   467     /** The HTML "align" attribute. */
       
   468     public static final String ALIGN = "align";
       
   469     /** The HTML "b" tag. */
       
   470     public static final String B = "b";
       
   471     /** The HTML "body" tag. */
       
   472     public static final String BODY = "body";
       
   473     /** The HTML "border" attribute. */
       
   474     public static final String BORDER = "border";
       
   475     /** The HTML "br" tag. */
       
   476     public static final String BR = "br";
       
   477     /** The HTML "class" attribute. */
       
   478     public static final String CLASS  = "class";
       
   479     /** The HTML "classid" attribute. */
       
   480     public static final String CLASSID  = "classid";
       
   481     /** The HTML "code" tag. */
       
   482     public static final String CODE  = "code";
       
   483     /** The HTML "color" attribte. */
       
   484     public static final String COLOR  = "color";
       
   485     /** The HTML "col" attribute value. */
       
   486     public static final String COL = "col";
       
   487     /** The HTML "dd" tag. */
       
   488     public static final String DD = "dd";
       
   489     /** The HTML "div" tag. */
       
   490     public static final String DIV = "div";
       
   491     /** The HTML "dl" tag. */
       
   492     public static final String DL = "dl";
       
   493     /** The HTML "dt" tag. */
       
   494     public static final String DT = "dt";
       
   495     /** The HTML "font" tag. */
       
   496     public static final String FONT = "font";
       
   497     /** The HTML "h1" tag. */
       
   498     public static final String H1 = "h1";
       
   499     /** The HTML "h2" tag. */
       
   500     public static final String H2 = "h2";
       
   501     /** The HTML "h3" tag. */
       
   502     public static final String H3 = "h3";
       
   503     /** The HTML "h4" tag. */
       
   504     public static final String H4 = "h4";
       
   505     /** The HTML "h5" tag. */
       
   506     public static final String H5 = "h5";
       
   507     /** The HTML "head" tag. */
       
   508     public static final String HEAD = "head";
       
   509     /** The HTML "href" attribute. */
       
   510     public static final String HREF = "href";
       
   511     /** The HTML "html" tag. */
       
   512     public static final String HTML = "html";
       
   513     /** The HTML "hr" tag. */
       
   514     public static final String HR = "hr";
       
   515     /** The HTML "i" tag. */
       
   516     public static final String I = "i";
       
   517     /** The HTML "id" tag. */
       
   518     public static final String ID = "id";
       
   519     /** The HTML "image" tag. */
       
   520     public static final String IMAGE = "image";
       
   521     /** The HTML "left" attribute value. */
       
   522     public static final String LEFT = "left";
       
   523     /** The HTML "li" tag. */
       
   524     public static final String LI = "li";
       
   525     /** The HTML "link" tag. */
       
   526     public static final String LINK = "link";
       
   527     /** The HTML "name" attribute. */
       
   528     public static final String NAME = "name";
       
   529     /** The HTML "object" tag. */
       
   530     public static final String OBJECT = "object";
       
   531     /** The HTML "p" tag. */
       
   532     public static final String PARAM = "param";
       
   533     /** The HTML "param" tag. */
       
   534     public static final String P = "p";
       
   535     /** The HTML "rel" attribute value. */
       
   536     public static final String REL = "rel";
       
   537     /** The HTML "right" attribute value. */
       
   538     public static final String RIGHT = "right";
       
   539     /** The HTML "row" attribute value. */
       
   540     public static final String ROW = "row";
       
   541     /** The HTML "script" tag. */
       
   542     public static final String SCRIPT = "script";
       
   543     /** The HTML "small" tag. */
       
   544     public static final String SMALL = "small";
       
   545     /** The HTML "span" tag. */
       
   546     public static final String SPAN = "span";
       
   547     /** The HTML "src" attribute. */
       
   548     public static final String SRC = "src";
       
   549     /** The HTML "scope" attribute. */
       
   550     public static final String SCOPE = "scope";
       
   551     /** The HTML "style" attribute. */
       
   552     public static final String STYLE = "style";
       
   553     /** The HTML "table" tag. */
       
   554     public static final String TABLE = "table";
       
   555     /** The HTML "td" tag. */
       
   556     public static final String TD = "td";
       
   557     /** The HTML type for JavaScript. */
       
   558     public static final String TEXT_JAVASCRIPT = "text/javascript";
       
   559     /** The HTML "title"attribute. */
       
   560     public static final String TITLE = "title";
       
   561     /** The HTML "th" tag. */
       
   562     public static final String TH = "th";
       
   563     /** The HTML "top" attribute value. */
       
   564     public static final String TOP = "top";
       
   565     /** The HTML "tr" tag. */
       
   566     public static final String TR = "tr";
       
   567     /** The HTML "type" attribute. */
       
   568     public static final String TYPE = "type";
       
   569     /** The HTML "ul" tag. */
       
   570     public static final String UL = "ul";
       
   571     /** The HTML "valign" attribute. */
       
   572     public static final String VALIGN = "valign";
       
   573     /** The HTML "value" attribute. */
       
   574     public static final String VALUE = "value";
       
   575 
       
   576 
       
   577     private BufferedWriter out;
       
   578     private int state;
       
   579     private ResourceBundle i18n;
       
   580     private static final int IN_TAG = 1;
       
   581     private static final int IN_BODY = 2;
       
   582 }