1 /*
   2  * Copyright (c) 2015, 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 package jdk.test.failurehandler;
  25 
  26 import java.io.FilterWriter;
  27 import java.io.IOException;
  28 import java.io.PrintWriter;
  29 
  30 public class HtmlSection {
  31     protected final HtmlSection rootSection;
  32     protected final String id;
  33     protected final String name;
  34 
  35     public PrintWriter getWriter() {
  36         return textWriter;
  37     }
  38 
  39     protected final PrintWriter pw;
  40     protected final PrintWriter textWriter;
  41     protected boolean closed;
  42 
  43     private HtmlSection child;
  44 
  45 
  46     public HtmlSection(PrintWriter pw) {
  47         this(pw, "", null, null);
  48     }
  49 
  50     private HtmlSection(PrintWriter pw, String id, String name, HtmlSection rootSection) {
  51         this.pw = pw;
  52         textWriter = new PrintWriter(new HtmlFilterWriter(pw));
  53         this.id = id;
  54         this.name = name;
  55         child = null;
  56         // main
  57         if (rootSection == null) {
  58             this.rootSection = this;
  59             this.pw.println("<html>");
  60             this.pw.println("<style>\n"
  61                     + "div { display:none;}\n"
  62                     + "</style>\n"
  63                     + "\n"
  64                     + "<script>\n"
  65                     + "function show(e) {\n"
  66                     + "  while (e != null) {\n"
  67                     + "    if (e.tagName == 'DIV') {\n"
  68                     + "      e.style.display = 'block';\n"
  69                     + "    }\n"
  70                     + "    e = e.parentNode;\n"
  71                     + "  }\n"
  72                     + "}\n"
  73                     + "\n"
  74                     + "function toggle(id) {\n"
  75                     + "  e = document.getElementById(id);\n"
  76                     + "  d = e.style.display;\n"
  77                     + "  if (d == 'block') {\n"
  78                     + "    e.style.display = 'none';\n"
  79                     + "  } else {\n"
  80                     + "    show(e);\n"
  81                     + "  }\n"
  82                     + "}\n"
  83                     + "\n"
  84                     + "function main() {\n"
  85                     + "  index = location.href.indexOf(\"#\");"
  86                     + "  if (index != -1) {\n"
  87                     + "    show(document.getElementById(location.href.substring(index + 1)));\n"
  88                     + "  }\n"
  89                     + "}\n"
  90                     + "\n"
  91                     + "</script>\n"
  92                     + "</head>");
  93 
  94             this.pw.println("<body onload='main()'>");
  95         } else {
  96             this.rootSection = rootSection;
  97             this.pw.print("<ul>");
  98         }
  99     }
 100 
 101     public HtmlSection createChildren(String section) {
 102         if (child != null) {
 103             if (child.name.equals(section)) {
 104                 return child;
 105             }
 106             child.close();
 107         }
 108         child = new SubSection(this, section, rootSection);
 109         return child;
 110     }
 111 
 112     protected final void removeChild(HtmlSection child) {
 113         if (this.child == child) {
 114             this.child = null;
 115         }
 116     }
 117 
 118     public void close() {
 119         closeChild();
 120         if (closed) {
 121             return;
 122         }
 123         closed = true;
 124 
 125         if (rootSection == this) {
 126             pw.println("</body>");
 127             pw.println("</html>");
 128             pw.close();
 129         } else {
 130             pw.println("</ul>");
 131         }
 132 
 133     }
 134 
 135     protected final void closeChild() {
 136         if (child != null) {
 137             child.close();
 138             child = null;
 139         }
 140     }
 141 
 142     public void link(HtmlSection section, String child, String name) {
 143         String path = section.id;
 144         if (path.isEmpty()) {
 145             path = child;
 146         } else if (child != null) {
 147             path = String.format("%s.%s", path, child);
 148         }
 149         pw.printf("<a href=\"#%1$s\" onclick=\"show(document.getElementById('%1$s')); return true;\">%2$s</a>%n",
 150                 path, name);
 151     }
 152 
 153     public HtmlSection createChildren(String[] sections) {
 154         int i = 0;
 155         int n = sections.length;
 156         HtmlSection current = rootSection;
 157         if (current != null) {
 158             for (; i < n && current.child != null;
 159                     ++i, current = current.child) {
 160                 if (!sections[i].equals(current.child.name)) {
 161                     break;
 162                 }
 163             }
 164         }
 165         for (; i < n; ++i) {
 166             current = current.createChildren(sections[i]);
 167         }
 168         return current;
 169     }
 170 
 171     private static class SubSection extends HtmlSection {
 172         private final HtmlSection parent;
 173 
 174         public SubSection(HtmlSection parent, String name,
 175                           HtmlSection rootSection) {
 176             super(parent.pw,
 177                     parent.id.isEmpty()
 178                             ? name
 179                             : String.format("%s.%s", parent.id, name),
 180                     name, rootSection);
 181             this.parent = parent;
 182             pw.printf("<li><a name='%1$s'/><a href='#%1$s' onclick=\"toggle('%1$s'); return false;\">%2$s</a><div id='%1$s'><code><pre>",
 183                     id, name);
 184         }
 185 
 186         @Override
 187         public void close() {
 188             closeChild();
 189             if (closed) {
 190                 return;
 191             }
 192             pw.print("</pre></code></div></li><!-- " + id + "-->");
 193             parent.removeChild(this);
 194             super.close();
 195         }
 196     }
 197 
 198     private static class HtmlFilterWriter extends FilterWriter {
 199         public HtmlFilterWriter(PrintWriter pw) {
 200             super(pw);
 201         }
 202 
 203         @Override
 204         public void write(int c) throws IOException {
 205             switch (c) {
 206                 case '<':
 207                     super.write("&lt;", 0, 4);
 208                     break;
 209                 case '>':
 210                     super.write("&gt;", 0, 4);
 211                     break;
 212                 case '"':
 213                     super.write("&quot;", 0, 5);
 214                     break;
 215                 case '&':
 216                     super.write("&amp;", 0, 4);
 217                     break;
 218                 default:
 219                     super.write(c);
 220             }
 221         }
 222 
 223         @Override
 224         public void write(char[] cbuf, int off, int len) throws IOException {
 225             for (int i = off; i < len; ++i){
 226                 write(cbuf[i]);
 227             }
 228         }
 229 
 230         @Override
 231         public void write(String str, int off, int len) throws IOException {
 232             for (int i = off; i < len; ++i){
 233                 write(str.charAt(i));
 234             }
 235         }
 236     }
 237 }