/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.faces.generate;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import com.sun.faces.config.beans.AttributeBean;
import com.sun.faces.config.beans.DescriptionBean;
import com.sun.faces.config.beans.FacesConfigBean;
import com.sun.faces.config.beans.RenderKitBean;
import com.sun.faces.config.beans.RendererBean;
import java.util.Locale;
/**
* <p>Generate javadoc style documenation about the render-kits defined in a
* faces-config.xml file.</p>
* <p/>
*/
public class RenderKitSpecificationGenerator implements Generator {
public static String DOCTYPE =
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\"http://www.w3.org/TR/REC-html40/loose.dtd\">";
// -------------------------------------------------------- Static Variables
// The directory into which the HTML will be generated
private File baseDirectory;
// The directory into which the individual Renderer HTML will be generated
private File renderKitDirectory;
private String renderKitId;
private FacesConfigBean configBean;
// ------------------------------------------------------------ Constructors
public RenderKitSpecificationGenerator(PropertyManager propManager) {
this.renderKitId =
propManager.getProperty(PropertyManager.RENDERKIT_ID);
baseDirectory =
new File(System.getProperty("user.dir") +
File.separatorChar +
propManager.getProperty(PropertyManager.BASE_OUTPUT_DIR) +
File.separatorChar + "facesdoc");
if (!baseDirectory.exists()) {
baseDirectory.mkdirs();
}
renderKitDirectory = new File(baseDirectory, renderKitId);
if (!renderKitDirectory.exists()) {
renderKitDirectory.mkdirs();
}
} // END RenderKitSpecificationGenerator
// ---------------------------------------------------------- Public Methods
public void generate(FacesConfigBean configBean) {
this.configBean = configBean;
try {
// copy the static files to the output area
copyResourceToFile("com/sun/faces/generate/facesdoc/index.html",
new File(baseDirectory, "index.html"));
copyResourceToFile("com/sun/faces/generate/facesdoc/stylesheet.css",
new File(baseDirectory, "stylesheet.css"));
generateAllRenderersFrame();
generateRenderKitSummary();
generateRenderersDocs();
} catch (Exception e) {
throw new RuntimeException(e);
}
} // END generate
// --------------------------------------------------------- Private Methods
private static String getFirstSentance(String para) throws Exception {
int dot = para.indexOf('.');
return para.substring(0, dot + 1);
}
private static void copyResourceToFile(String resourceName, File file)
throws Exception {
byte[] bytes = new byte[1024];
FileOutputStream fos = new FileOutputStream(file);
URL url = getCurrentLoader(fos).getResource(resourceName);
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
BufferedInputStream bis =
new BufferedInputStream(conn.getInputStream());
for (int len = bis.read(bytes, 0, 1024); len != -1;
len = bis.read(bytes, 0, 1024)) {
fos.write(bytes, 0, len);
}
fos.close();
bis.close();
}
private static void writeStringToFile(String toWrite,
File file) throws Exception {
FileOutputStream fos = new FileOutputStream(file);
byte[] bytes = toWrite.getBytes();
fos.write(bytes);
fos.close();
}
private static void appendResourceToStringBuffer(String resourceName,
StringBuffer sb)
throws Exception {
char[] chars = new char[1024];
URL url = getCurrentLoader(sb).getResource(resourceName);
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
InputStreamReader isr = new InputStreamReader(conn.getInputStream());
for (int len = isr.read(chars, 0, 1024); len != -1;
len = isr.read(chars, 0, 1024)) {
sb.append(chars, 0, len);
}
isr.close();
}
private void generateAllRenderersFrame() throws Exception {
// generate the allrenderers-frame.html
StringBuffer sb = new StringBuffer(2048);
appendResourceToStringBuffer(
"com/sun/faces/generate/facesdoc/allrenderers-frame.top",
sb);
sb.append("<FONT size=\"+1\" CLASS=\"FrameHeadingFont\">\n");
sb.append("<B>" + renderKitId + " RenderKit ");
String implVersionNumber = System.getProperty("impl.version.number");
if (null != implVersionNumber) {
sb.append("(" + implVersionNumber + ")");
}
sb.append("</B></FONT>\n");
sb.append("<BR>\n\n");
sb.append("<DL CLASS=\"FrameItemFont\">\n\n");
Map<String, ArrayList<RendererBean>> renderersByComponentFamily =
GeneratorUtil.getComponentFamilyRendererMap(configBean, renderKitId);
for (Map.Entry entry : renderersByComponentFamily.entrySet()) {
String curFamily = (String)entry.getKey();
sb.append(" <DT>" + curFamily + "</DT>\n");
List<RendererBean> renderers = (List<RendererBean>)entry.getValue();
for (Iterator<RendererBean> rendererIter = renderers.iterator();
rendererIter.hasNext(); ) {
RendererBean renderer = rendererIter.next();
String curType = renderer.getRendererType();
DescriptionBean[] descriptions = renderer.getDescriptions();
String
enclosingDiv = null,
enclosingSpan = null;
int [] divStart = new int[1];
int [] spanStart = new int[1];
if (null != descriptions) {
// Get the current operating locale
String localeStr = Locale.getDefault().getCountry().toLowerCase();
// iterate over the descriptions and try to find one that matches
// the country of the current locale
for (DescriptionBean cur : descriptions) {
if (null != cur.getLang() &&
(-1 != localeStr.indexOf(cur.getLang().toLowerCase()))) {
enclosingDiv =
GeneratorUtil.getFirstDivFromString(renderer.getDescription(cur.getLang()).getDescription(), divStart);
enclosingSpan = GeneratorUtil.getFirstSpanFromString(renderer.getDescription(cur.getLang()).getDescription(), spanStart);
break;
}
}
}
if (null != enclosingDiv || null != enclosingSpan) {
String divOrSpan = (null != enclosingDiv ? enclosingDiv : enclosingSpan);
// If there is a div and a span, take which ever comes first
if (null != enclosingDiv && null != enclosingSpan) {
divOrSpan = (spanStart[0] < divStart[0] ? enclosingSpan : enclosingDiv);
}
sb.append(" <DD>" + divOrSpan);
sb.append("<A HREF=\"" + renderKitId + "/" +
curFamily + curType +
".html\" TARGET=\"rendererFrame\">" + curType +
"</A>");
sb.append((null != enclosingDiv ? "</div>" : "</span>") +
"</DD>\n");
}
else {
sb.append(" <DD><A HREF=\"" + renderKitId + "/" +
curFamily + curType +
".html\" TARGET=\"rendererFrame\">" + curType +
"</A></DD>\n");
}
}
}
sb.append("</dl>\n");
appendResourceToStringBuffer(
"com/sun/faces/generate/facesdoc/allrenderers-frame.bottom",
sb);
writeStringToFile(sb.toString(),
new File(baseDirectory,
"allrenderers-frame.html"));
}
private void generateRenderKitSummary() throws Exception {
// generate the renderkit-summary.html
StringBuffer sb = new StringBuffer(2048);
appendResourceToStringBuffer(
"com/sun/faces/generate/facesdoc/renderkit-summary.top",
sb);
sb.append("<H2>" + renderKitId + " RenderKit ");
String implVersionNumber = System.getProperty("impl.version.number");
if (null != implVersionNumber) {
sb.append("(" + implVersionNumber + ")");
}
sb.append("</H2>");
sb.append("<BR>\n\n");
RenderKitBean renderKit = configBean.getRenderKit(renderKitId);
if (renderKit == null) {
RenderKitBean[] kits = configBean.getRenderKits();
if (kits == null) {
throw new IllegalStateException("no RenderKits");
}
renderKit = kits[0];
if (renderKit == null) {
throw new IllegalStateException("no RenderKits");
}
}
DescriptionBean descBean = renderKit.getDescription("");
String description = (null == descBean) ?
"" : descBean.getDescription();
sb.append("<P>" + description + "</P>\n");
sb.append("<P />");
sb.append(
"<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" WIDTH=\"100%\">");
sb.append("<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n");
sb.append("<TD COLSPAN=\"3\"><FONT SIZE=\"+2\">\n");
sb.append("<B>Renderer Summary</B></FONT></TD>\n");
sb.append("\n");
sb.append("<TR>\n");
sb.append("<TH>component-family</TH>\n");
sb.append("<TH>renderer-type</TH>\n");
sb.append("<TH>description</TH>\n");
sb.append("</TR>\n");
Map<String,ArrayList<RendererBean>> renderersByComponentFamily =
GeneratorUtil.getComponentFamilyRendererMap(configBean, renderKitId);
for (Map.Entry entry : renderersByComponentFamily.entrySet()) {
String curFamily = (String)entry.getKey();
List<RendererBean> renderers = (List<RendererBean>) entry.getValue();
sb.append(" <TR>\n");
sb.append(" <TD rowspan=\"" + renderers.size() + "\">" +
curFamily + "</TD>\n");
for (Iterator<RendererBean> rendererIter = renderers.iterator();
rendererIter.hasNext(); ) {
RendererBean renderer = rendererIter.next();
String curType = renderer.getRendererType();
sb.append(" <TD><A HREF=\"" + curFamily + curType +
".html\" TARGET=\"rendererFrame\">" + curType +
"</A></TD>\n");
descBean = renderer.getDescription("");
description = (null == descBean) ?
"" : descBean.getDescription();
sb.append(" <TD>" + getFirstSentance(description) +
"</TD>");
if (rendererIter.hasNext()) {
sb.append(" </TR>\n");
sb.append(" <TR>\n");
}
}
sb.append(" </TR>\n");
}
sb.append("</TABLE>\n\n");
appendResourceToStringBuffer(
"com/sun/faces/generate/facesdoc/renderkit-summary.bottom",
sb);
writeStringToFile(sb.toString(),
new File(renderKitDirectory,
"renderkit-summary.html"));
}
private void generateRenderersDocs() throws Exception {
StringBuffer sb;
RenderKitBean renderKit;
DescriptionBean descBean;
String description;
String rendererType;
String componentFamily;
String defaultValue;
String title;
// generate the docus for each renderer
if (null == (renderKit = configBean.getRenderKit(renderKitId))) {
RenderKitBean[] kits = configBean.getRenderKits();
if (kits == null) {
throw new IllegalStateException("no RenderKits");
}
renderKit = kits[0];
if (renderKit == null) {
throw new IllegalStateException("no RenderKits");
}
}
RendererBean[] renderers = renderKit.getRenderers();
AttributeBean[] attributes;
sb = new StringBuffer(2048);
for (int i = 0, len = renderers.length; i < len; i++) {
if (null == renderers[i]) {
throw new IllegalStateException("null Renderer at index: " + i);
}
attributes = renderers[i].getAttributes();
sb.append(DOCTYPE + "\n");
sb.append("<html>\n");
sb.append("<head>\n");
// PENDING timestamp
sb.append("<title>\n");
title = "<font size=\"-1\">component-family:</font> " +
(componentFamily = renderers[i].getComponentFamily()) +
" <font size=\"-1\">renderer-type:</font> " +
(rendererType = renderers[i].getRendererType());
sb.append(title + "\n");
sb.append("</title>\n");
// PENDING META tag
sb.append(
"<link REL =\"stylesheet\" TYPE=\"text/css\" HREF=\"../stylesheet.css\" TITLE=\"Style\">\n");
sb.append("</head>\n");
sb.append("<script>\n");
sb.append("function asd()\n");
sb.append("{\n");
sb.append(" parent.document.title=" + title + "\n");
sb.append("}\n");
sb.append("</SCRIPT>\n");
sb.append("<body BGCOLOR=\"white\" onload=\"asd();\">\n");
sb.append("\n");
sb.append("<H2><font size=\"-1\">" + renderKitId +
" render-kit</font>\n");
sb.append("<br />\n");
sb.append(title + "\n");
sb.append("</H2>\n");
sb.append("<HR />\n");
descBean = renderers[i].getDescription("");
description = (null == descBean) ? "" : descBean.getDescription();
sb.append("<P>" + description + "</P>\n");
// render our renders children status
if (renderers[i].isRendersChildren()) {
sb.append(
"<P>This renderer is responsible for rendering its children.</P>");
} else {
sb.append(
"<P>This renderer is not responsible for rendering its children.</P>");
}
// if we have attributes
if ((null == attributes) || (0 < attributes.length)) {
sb.append("<HR />\n");
sb.append("<a NAME=\"attributes\"><!-- --></a>\n");
sb.append("\n");
sb.append("<h3>Note:</h3>\n");
sb.append("\n");
sb.append(
"<p>Attributes with a <code class=\"changed_modified_2_2\">ignored-by-renderer</code> value of\n");
sb.append(
"<code>true</code> are not interpreted by the renderer and are conveyed\n");
sb.append(
"straight to the rendered markup, without checking for validity. Attributes with a\n");
sb.append(
"<code class=\"changed_modified_2_2\">ignored-by-renderer</code> value of <code>false</code> are interpreted\n");
sb.append(
"by the renderer, and may or may not be checked for validity by the renderer.</p>\n");
sb.append("\n");
sb.append(
"<table BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" WIDTH=\"100%\">\n");
sb.append(
"<tr BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n");
sb.append("<td COLSPAN=\"5\"><font SIZE=\"+2\">\n");
sb.append("<b>Attributes</b></font></td>\n");
sb.append("</tr>\n");
sb.append(
"<tr BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">\n");
sb.append("<th><b>attribute-name</b></th>\n");
sb.append("<th><b class=\"changed_modified_2_2\">ignored-by-renderer</b></th>\n");
sb.append("<th><b>attribute-class</b></th>\n");
sb.append("<th><b>description</b></th>\n");
sb.append("<th><b>default-value</b></th>\n");
sb.append("</tr>\n");
sb.append(" \n");
// output each attribute
if (attributes != null) {
for (int j = 0, attrLen = attributes.length; j < attrLen; j++) {
if (attributes[j].isAttributeIgnoredForRenderer()) {
continue;
}
sb.append(
"<tr BGCOLOR=\"white\" CLASS=\"TableRowColor\">\n");
sb.append(
"<td ALIGN=\"right\" VALIGN=\"top\" WIDTH=\"1%\"><code>\n");
sb.append(
" " + attributes[j].getAttributeName() + "\n");
sb.append("</td>\n");
sb.append("<td ALIGN=\"right\" VALIGN=\"top\">" +
attributes[j].isPassThrough() + "</td>\n");
sb.append("<td><code>" + attributes[j].getAttributeClass() +
"</code></td>\n");
descBean = attributes[j].getDescription("");
description = (null == descBean) ?
"" : descBean.getDescription();
sb.append("<td>" + description + "</td>\n");
if (null ==
(defaultValue = attributes[j].getDefaultValue())) {
defaultValue = "undefined";
}
sb.append("<td>" + defaultValue + "<td>\n");
sb.append("</tr>\n");
}
}
sb.append("</table>\n");
} else {
sb.append("<p>This renderer-type has no attributes</p>\n");
}
sb.append("<hr>\n");
sb.append(
"Copyright (c) 2003-2017 Oracle America, Inc. All Rights Reserved.\n");
sb.append("</body>\n");
sb.append("</html>\n");
writeStringToFile(sb.toString(),
new File(renderKitDirectory,
componentFamily + rendererType +
".html"));
sb.delete(0, sb.length());
}
}
private static ClassLoader getCurrentLoader(Object fallbackClass) {
ClassLoader loader =
Thread.currentThread().getContextClassLoader();
if (loader == null) {
loader = fallbackClass.getClass().getClassLoader();
}
return loader;
}
// ------------------------------------------------------------- Main Method
public static void main(String[] args) throws Exception {
PropertyManager propManager = PropertyManager.newInstance(args[0]);
Generator generator =
new RenderKitSpecificationGenerator(propManager);
generator.generate(GeneratorUtil.getConfigBean(args[1]));
}
}