001    /*
002     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003     *
004     * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
005     *
006     * The contents of this file are subject to the terms of either the GNU
007     * General Public License Version 2 only ("GPL") or the Common Development
008     * and Distribution License("CDDL") (collectively, the "License").  You
009     * may not use this file except in compliance with the License.  You can
010     * obtain a copy of the License at
011     * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
012     * or packager/legal/LICENSE.txt.  See the License for the specific
013     * language governing permissions and limitations under the License.
014     *
015     * When distributing the software, include this License Header Notice in each
016     * file and include the License file at packager/legal/LICENSE.txt.
017     *
018     * GPL Classpath Exception:
019     * Oracle designates this particular file as subject to the "Classpath"
020     * exception as provided by Oracle in the GPL Version 2 section of the License
021     * file that accompanied this code.
022     *
023     * Modifications:
024     * If applicable, add the following below the License Header, with the fields
025     * enclosed by brackets [] replaced by your own identifying information:
026     * "Portions Copyright [year] [name of copyright owner]"
027     *
028     * Contributor(s):
029     * If you wish your version of this file to be governed by only the CDDL or
030     * only the GPL Version 2, indicate your decision by adding "[Contributor]
031     * elects to include this software in this distribution under the [CDDL or GPL
032     * Version 2] license."  If you don't indicate a single choice of license, a
033     * recipient has the option to distribute your version of this file under
034     * either the CDDL, the GPL Version 2 or to extend the choice of license to
035     * its licensees as provided above.  However, if you add GPL Version 2 code
036     * and therefore, elected the GPL Version 2 license, then the option applies
037     * only if the new code is made subject to such option by the copyright
038     * holder.
039     */
040    
041    package com.sun.enterprise.admin.cli.schemadoc;
042    
043    import java.io.File;
044    import java.io.FileWriter;
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.io.InputStreamReader;
048    import java.io.PrintWriter;
049    import java.lang.reflect.InvocationTargetException;
050    import java.util.Arrays;
051    import java.util.HashSet;
052    import java.util.Map;
053    import java.util.Map.Entry;
054    import java.util.Set;
055    
056    import org.glassfish.api.admin.config.PropertyDesc;
057    import org.jvnet.hk2.annotations.Service;
058    import org.jvnet.hk2.config.Attribute;
059    import org.jvnet.hk2.config.types.Property;
060    
061    @Service(name = "html")
062    public class HtmlFormat implements SchemaOutputFormat {
063        private PrintWriter tocWriter;
064        private PrintWriter detail;
065        private Set<ClassDef> toc = new HashSet<ClassDef>();
066        private File dir;
067        private Map<String, ClassDef> defs;
068    
069        @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"})
070        @Override
071        public void output(Context context) {
072            dir = context.getDocDir();
073            defs = context.getClassDefs();
074            try {
075                try {
076                    tocWriter = new PrintWriter(new FileWriter(new File(dir, "toc.HTML")));
077                    detail = new PrintWriter(new FileWriter(new File(dir, "detail.HTML")));
078                } catch (IOException e) {
079                    e.printStackTrace();
080                    throw new RuntimeException(e.getMessage());
081                }
082                println(tocWriter,
083                    "<HTML><head><link rel=\"stylesheet\" type=\"text/css\" href=\"schemadoc.css\"><style>body{margin-left:-1em;}</style></head><body>");
084                println(detail,
085                    "<HTML><head><link rel=\"stylesheet\" type=\"text/css\" href=\"schemadoc.css\"></head><body>");
086                copyResources();
087                buildToc(defs.get(context.getRootClassName()));
088            } catch (Exception e) {
089                e.printStackTrace();
090                throw new RuntimeException(e);
091            } finally {
092                println(tocWriter, "</ul>");
093                footer(tocWriter);
094                footer(detail);
095                if (tocWriter != null) {
096                    tocWriter.close();
097                }
098                if (detail != null) {
099                    detail.close();
100                }
101            }
102        }
103    
104        private void buildDetail(ClassDef def) {
105            println(detail, "<p><table><tr>");
106            println(detail, "<a name=\"" + def.getXmlName() + "\">");
107            println(detail, String.format("<th colspan=\"4\" class=\"TableHeadingColor entity %s\">%s%s",
108                def.isDeprecated() ? "deprecated" : "",
109                def.getXmlName(), def.isDeprecated() ? " - DEPRECATED" : ""));
110            println(detail, "</th></tr>");
111            println(detail, "<colgroup><col width=\"35%\"></colgroup>");
112            printHeaderRow(detail, "attribute", "type", "default", "required");
113            final Map<String, Attribute> map = def.getAttributes();
114            if (map != null) {
115                for (Entry<String, Attribute> entry : map.entrySet()) {
116                    println(detail, String.format("<tr><td class=\"TableSubHeadingColor\">%s</td>", entry.getKey()));
117                    printAttributeData(entry.getValue());
118                }
119            }
120            println(detail, "</table>");
121            printPropertyData(def);
122        }
123    
124        private void println(final PrintWriter writer, final String text) {
125            writer.println(text);
126            writer.flush();
127        }
128    
129        private void printAttributeData(final Attribute annotation) {
130            printKeyValue(detail, annotation != null ? annotation.dataType().getName() : null);
131            printKeyValue(detail, annotation != null ? annotation.defaultValue() : null);
132            printKeyValue(detail, annotation != null && annotation.required());
133        }
134    
135        private void printPropertyData(final ClassDef def) {
136            final Set<PropertyDesc> properties = def.getProperties();
137            if (properties != null && !properties.isEmpty()) {
138                println(detail, "<tr><td colspan=\"2\">");
139                println(detail, "<table>");
140                println(detail, "<tr class=\"TableHeadingColor\">");
141                println(detail, "<th colspan=\"4\">Properties</th>");
142                println(detail, "</tr>");
143                println(detail, "<tr class=\"TableHeadingColor\">");
144                println(detail, "<th>name</th>");
145                println(detail, "<th>default</th>");
146                println(detail, "<th>values</th>");
147                println(detail, "<th>description</th>");
148                println(detail, "</tr>");
149                for (PropertyDesc property : properties) {
150                    println(detail, "<tr>");
151                    println(detail, String.format("<td class=\"TableSubHeadingColor\">%s</td>", property.name()));
152                    println(detail, String.format("<td class=\"nobreak\">%s</td>", property.defaultValue()));
153                    println(detail, String.format("<td>%s</td>",
154                        property.values().length == 0 ? "" : Arrays.toString(property.values())));
155                    println(detail, String.format("<td>%s</td>", property.description()));
156                    println(detail, "</tr>");
157                }
158                println(detail, "</table>");
159                println(detail, "</td></tr>");
160            }
161        }
162    
163        private void buildToc(final ClassDef def)
164            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
165            if (def != null/* && !"Named".equals(def.getSimpleName())*/) {
166                if (!toc.contains(def)) {
167                    buildDetail(def);
168                }
169                toc.add(def);
170                println(tocWriter, "<ul>");
171                println(tocWriter, "<li>" + link(def));
172                for (Entry<String, String> aggType : def.getAggregatedTypes().entrySet()) {
173                    if (!Property.class.getName().equals(aggType.getValue())) {
174                        buildToc(defs.get(aggType.getValue()));
175                    }
176                }
177                for (ClassDef subclass : def.getSubclasses()) {
178                    buildToc(subclass);
179                }
180                println(tocWriter, "</ul>");
181            }
182        }
183    
184        private String link(final ClassDef def) {
185            return String.format("<a %s target=\"detail\" href=\"detail.html#%s\">%s</a>",
186                def.isDeprecated() ? "class=\"deprecated\"" : "", def.getXmlName(), def.getXmlName());
187        }
188    
189        private void footer(final PrintWriter writer) {
190            writer.println("</body></HTML>");
191            writer.flush();
192            writer.close();
193        }
194    
195        private void copyResources() throws IOException {
196            copy("/schemadoc.css");
197            copy("/index.html");
198        }
199    
200        @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"})
201        private void copy(final String resource) throws IOException {
202            InputStreamReader reader = null;
203            PrintWriter writer = null;
204            try {
205                InputStream stream = getClass().getResourceAsStream(resource);
206                reader = new InputStreamReader(stream);
207                writer = new PrintWriter(new File(dir, resource));
208                char[] bytes = new char[8192];
209                int read;
210                while ((read = reader.read(bytes)) != -1) {
211                    writer.write(bytes, 0, read);
212                }
213            } finally {
214                if (reader != null) {
215                    reader.close();
216                }
217                if (writer != null) {
218                    writer.close();
219                }
220            }
221        }
222    
223        private void printKeyValue(final PrintWriter writer, Object value) {
224            println(writer, "<td>");
225            if (value != null) {
226                if (value instanceof Class) {
227                    println(writer, ((Class) value).getSimpleName());
228                } else {
229                    println(writer, value.toString().trim());
230                }
231            }
232            println(writer, "</td>");
233        }
234    
235        private void printHeaderRow(final PrintWriter writer, final String... values) {
236            writer.println("<tr class=\"TableHeadingColor\">");
237            for (String value : values) {
238                writer.println(String.format("<th>%s</th>", value != null ? value.trim() : " "));
239            }
240            writer.println("</tr>");
241        }
242    }