/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 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.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.Arrays;
import com.sun.faces.config.beans.FacesConfigBean;
import com.sun.faces.config.beans.RendererBean;
/**
* <p>Base class for JSP TLD generation.</p>
*/
public abstract class JspTLDGenerator implements Generator {
// Defaults
private static final String DEFAULT_BODY_CONTENT = "JSP";
private static final String DEFAULT_RTEXPRVALUE = "false";
protected XMLWriter writer;
protected FacesConfigBean configBean;
protected PropertyManager propManager;
private String outputFile;
// ------------------------------------------------------------ Constructors
public JspTLDGenerator(PropertyManager propManager) {
this.propManager = propManager;
File outputDir =
new File(System.getProperty("user.dir") + File.separatorChar +
propManager.getProperty(PropertyManager.BASE_OUTPUT_DIR) +
File.separatorChar + "conf" + File.separatorChar + "share");
if (!outputDir.exists()) {
outputDir.mkdirs();
}
outputFile = outputDir.toString() + File.separatorChar +
propManager.getProperty(PropertyManager.TAGLIB_FILE_NAME);
}
// -------------------------------------------------- Methods from Generator
public void generate(FacesConfigBean configBean) {
this.configBean = configBean;
try {
initWriter();
writeDocument();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
} // END generate
// ------------------------------------------------------- Protected Methods
protected void writeDocument() throws IOException {
writeProlog();
writeTldDescription();
writeValidators();
writeTags();
endDocument();
} // END writeDocument
protected void writeProlog() throws IOException {
writer.writeProlog();
} // END writeProlog
protected abstract void writeTldDescription() throws IOException;
protected abstract void writeTags() throws IOException;
protected void endDocument() throws IOException {
writer.closeAllElements();
writer.flush();
writer.close();
} // END endDocument
protected void writeValidators() throws IOException {
// this one is common to both 1.2 and 2.1
writer.writeComment(
"============== Tag Library Validator =============");
writer.startElement("validator");
writer.startElement("validator-class");
writer.writeText("com.sun.faces.taglib.html_basic.HtmlBasicValidator");
writer.closeElement(2);
} // END tldValidator
protected void initWriter() throws IOException {
writer = new XMLWriter(new FileOutputStream(outputFile));
} // END initWriter
// --------------------------------------------------------- Utility Methods
/**
* Build the tag name from componentFamily and rendererType. The name
* will be "camel case".
*
* @param componentFamily the component family
* @param rendererType the renderer type
*/
protected String makeTldTagName(String componentFamily,
String rendererType) {
if (componentFamily == null) {
return null;
}
if (rendererType.startsWith("resource.")) {
rendererType = rendererType.split("\\.")[1];
}
String tagName =
Character.toLowerCase(componentFamily.charAt(0)) +
componentFamily.substring(1);
if (rendererType == null || componentFamily.equals(rendererType)) {
return tagName;
} else {
return (tagName + rendererType);
}
} // END makeTldTagName
/**
* @return true if this attribute is in the set of attributes to be excluded
* by this renderer.
*/
protected boolean attributeShouldBeExcluded(RendererBean renderer,
String attribute) {
String excludedAttributes = renderer.getExcludeAttributes();
boolean skip = false;
if (excludedAttributes != null) {
skip = (attribute != null &&
excludedAttributes.indexOf(attribute) != -1);
}
return skip;
} // END attributeShouldBeExcluded
/**
* Return the tag body content information (if any) for a given tag.
*/
protected String getBodyContent(String tagName) {
return DEFAULT_BODY_CONTENT;
}
/**
* Return the "rtexprvalue" element value for the tag attribute.
*/
protected String getRtexprvalue(String tagName, String attributeName) {
return DEFAULT_RTEXPRVALUE;
}
/**
* <p>Load any additional tag definitions from the specified file. This
* file might include tags such as "column" which have no renderer, but need
* to be generated into the TLD file.</p>
*/
protected String loadOptionalTags() throws IOException {
String path =
propManager.getProperty(PropertyManager.TAGLIB_INCLUDE);
if (path != null) {
if (path.charAt(0) == '/' || path.charAt(1) == ':') {
// absolute path
if (path.charAt(1) == ':') {
// win32
path = path.replace('/', File.separatorChar);
}
} else {
path = System.getProperty("user.dir") + File.separatorChar +
path;
path = path.replace('/', File.separatorChar);
}
StringBuffer sb = new StringBuffer();
BufferedReader reader =
new BufferedReader(new FileReader(path));
int ch;
while ((ch = reader.read()) >= 0) {
sb.append((char) ch);
}
reader.close();
return sb.toString();
}
return null;
} // END loadOptionalTags
// ---------------------------------------------------------- PrivateMethods
// ----------------------------------------------------------- Inner Classes
/**
* </p>A simple class to handle the writing of XML documents.</p>
*/
protected static class XMLWriter extends OutputStreamWriter {
private static final String XML_PROLOG =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n";
private static final String TAB = " ";
private static final int NUM_COMMENT_CHARS = 10;
private static final String START_COMMENT = "\n<!-- ";
private static final String END_COMMENT = " -->\n\n";
private static final Charset UTF8 = Charset.forName("UTF-8");
private Stack<String> elementStack = new Stack<String>();
// -------------------------------------------------------- Constructors
XMLWriter(OutputStream stream) {
super(stream, UTF8);
} // END XMLWriter
// ----------------------------------------------------- Public Methods
public void writeProlog() throws IOException {
super.write(XML_PROLOG);
} // END writeProlog
public void writeText(String value) throws IOException {
if (value == null) {
// aid in detecting issues
value = "NULL VALUE";
}
StringBuffer sb = new StringBuffer();
String[] tokens = value.split("\n");
for (int i = 0; i < tokens.length; i++) {
String val = tokens[i].trim();
for (int ii = 0, size = elementStack.size(); ii < size; ii++) {
sb.append(TAB);
}
sb.append(val).append('\n');
}
super.write(sb.toString());
} // END writeText
public void startElement(String name,
Map<String,String> attributes) throws IOException {
if (name == null) {
throw new IllegalArgumentException("Null element name");
}
StringBuffer sb = new StringBuffer();
for (int i = 0, size = elementStack.size(); i < size; i++) {
sb.append(TAB);
}
elementStack.push(name);
String attributesString = null;
if (attributes != null) {
attributesString = createAttributesString(attributes);
}
sb.append('<').append(name);
if (attributesString != null) {
sb.append(attributesString);
}
sb.append(">\n");
super.write(sb.toString());
} // END startElement
public void startElement(String name) throws IOException {
startElement(name, null);
} // END startElement
public void closeElement(int elementCount) throws IOException {
if (elementStack.size() == 0) {
throw new IllegalStateException("Cannot close element - " +
"no elements on stack");
}
StringBuffer sb = new StringBuffer();
for (int count = 0; count < elementCount; count++) {
String elementName = elementStack.pop();
for (int i = 0, size = elementStack.size(); i < size; i++) {
sb.append(TAB);
}
sb.append("</").append(elementName).append(">\n");
}
super.write(sb.toString());
} // END closeElement
public void closeElement() throws IOException {
closeElement(1);
} // END closeElement
public void closeAllElements() throws IOException {
closeElement(elementStack.size());
} // END closeAllElements()
public void writeComment(String value) throws IOException {
StringBuffer sb =
new StringBuffer(value.length() + NUM_COMMENT_CHARS);
sb.append(START_COMMENT).append(value).append(END_COMMENT);
super.write(sb.toString());
} // END writeComment
// ----------------------------------------------------- Private Methods
private String createAttributesString(Map<String,String> attributes) {
if (attributes == null) {
throw new IllegalArgumentException("Null attributes map");
}
StringBuffer sb = new StringBuffer();
for (Map.Entry entry : attributes.entrySet()) {
String name = (String)entry.getKey();
sb.append(' ').append(name).append('=');
sb.append('"').append((String)entry.getValue()).append('"');
}
return sb.toString();
} // END createAttributesString
} // END XMLWriter
}