com.jsftoolkit.gen.TemplateComponentGenerator Maven / Gradle / Ivy
Go to download
The core classes for the JSF Toolkit Component Framework. Includes all
framework base and utility classes as well as component
kick-start/code-generation and registration tools.
Also includes some classes for testing that are reused in other projects.
They cannot be factored out into a separate project because they are
referenced by the tests and they reference this code (circular
dependence).
The newest version!
package com.jsftoolkit.gen;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.faces.component.UIInput;
import org.xml.sax.SAXException;
import com.jsftoolkit.base.ResourceInfo;
import com.jsftoolkit.base.renderer.DecodeEvent;
import com.jsftoolkit.base.renderer.HtmlRenderer;
import com.jsftoolkit.base.renderer.PassThrough;
import com.jsftoolkit.base.renderer.RenderEventsCollector;
import com.jsftoolkit.base.renderer.VarAttribEvent;
import com.jsftoolkit.base.renderer.VarTextEvent;
import com.jsftoolkit.gen.info.ComponentInfo;
import com.jsftoolkit.gen.info.PropertyInfo;
import com.jsftoolkit.gen.info.RendererInfo;
import com.jsftoolkit.utils.Utils;
import com.jsftoolkit.utils.xmlpull.PullEvent;
import com.jsftoolkit.utils.xmlpull.StartElement;
/**
* Reads in an XHTML template and generates the component, renderer and tag
* handler. The component and tag handler are generated using
* {@link ComponentGenerator}, but this class adds additional metadata from the
* parsed template.
*
* @author noah
*/
public class TemplateComponentGenerator {
private static final String DEFAULT_TEMPLATE_ENC = "UTF-8";
private static class Tab {
public String tab(int count) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++) {
sb.append(toString());
}
return sb.toString();
}
@Override
public String toString() {
return " ";
}
}
private static final Tab T = new Tab();
/**
* Debugging method. Prints render, component and tag handler to the given
* stream.
*
* @param info
* @param out
* @throws Exception
*/
public void generate(ComponentInfo info, PrintStream out) throws Exception {
generate(info, info.getRenderer().getTemplate(), info.getRenderer()
.getHeadTemplate(), info.getRenderer().getTemplateEncoding(),
out, out, out);
}
/**
* Generates renderer, component and tag handler in the default locations.
*
* @see ComponentGenerator#defaultStream(String, String)
* @param info
* @throws Exception
*/
public void generate(ComponentInfo info) throws Exception {
generate(info, info.getRenderer().getTemplate(), info.getRenderer()
.getHeadTemplate(), info.getRenderer().getTemplateEncoding());
}
/**
* Generates renderer, component and tag handler in the default locations
* and uses the given template.
*
* @see ComponentGenerator#defaultStream(String, String)
* @param info
* @param resource
* @param headTemplate
* @param encoding
* @throws Exception
*/
public void generate(ComponentInfo info, String resource,
String headTemplate, String encoding) throws Exception {
generate(info, resource, headTemplate, encoding,
resource == null ? null : ComponentGenerator
.defaultRendererStream(info), ComponentGenerator
.defaultComponentStream(info), ComponentGenerator
.defaultTagStream(info));
}
/**
* Writes the generated code to the given streams.
*
* @param info
* @param resource
* @param headTemplate
* @param encoding
* @param rendererOut
* @param componentOut
* @param tagOut
* @throws Exception
*/
public void generate(ComponentInfo info, String resource,
String headTemplate, String encoding, PrintStream rendererOut,
PrintStream componentOut, PrintStream tagOut) throws Exception {
if (resource != null) {
System.out.println("Creating renderer based on template(s): "
+ resource + " and " + headTemplate);
// can't generate a renderer without a template
fillIn(info, Utils.resourceToString(resource, encoding));
String head = Utils.resourceToString(headTemplate, encoding, null);
if (head != null) {
fillIn(info, head);
}
generateRenderer(info, resource, encoding, rendererOut);
}
// defer the rest of generation to ComponentGenerator
ComponentGenerator generator = new ComponentGenerator(info);
generator.generateComponent(componentOut);
generator.generateTagHandler(tagOut);
}
/**
*
* @param info
* the {@link ComponentInfo}
* @param resource
* the classpath resource that is the template
* @param encoding
* the encoding of the template
* @param out
*/
public void generateRenderer(ComponentInfo info, String resource,
String encoding, PrintStream out) {
RendererInfo renderInfo = info.getRenderer();
Class[] imports = { IOException.class, SAXException.class, Set.class,
ResourceInfo.Type.class, ResourceInfo.class,
HtmlRenderer.class, Utils.class };
for (Class i : imports) {
renderInfo.addImport(i);
}
ComponentGenerator
.printDeclaration(out, renderInfo, HtmlRenderer.class);
Set resources = new LinkedHashSet();
// create a constant for each resource required
for (ResourceInfo ii : info.getRenderer().getIncludes()) {
String id = ii.getId();
String name = id.substring(id.lastIndexOf('.') + 1);
out.printf(T + "private static final ResourceInfo %s = %s;\n\n",
name, ii.getCodeString());
resources.add(name);
}
// create a set of the constants
out.printf(T + "public static final Set "
+ "RESOURCES = Utils.asSet(%s);\n\n", Utils.join(resources
.iterator(), ","));
// write out the constructor
out.printf(T + "public %1$s() throws IOException, SAXException {\n" + T
+ T + "super(Utils.resourceToString(\"%2$s\",%3$s),\n"
+ T.tab(4) + "Utils.resourceToString(%4$s,%3$s,null),\n"
+ T.tab(4) + "RESOURCES);\n", renderInfo.getClassName(),
resource, Utils.toStringConstant(Utils.getValue(encoding,
DEFAULT_TEMPLATE_ENC)), Utils
.toStringConstant(renderInfo.getHeadTemplate()));
// add decode information, if it was provided
String decodeParam = info.getRenderer().getDecodeParam();
if (UIInput.class.isAssignableFrom(info.getSuperClass())
&& !Utils.isEmpty(decodeParam)) {
writeDecode(out, decodeParam);
}
out.println(T + "}\n\n" + T + "public boolean getRendersChildren() {\n"
+ T + T + "return true;\n" + T + "}\n\n");
out.println('}');
out.close();
}
protected void writeDecode(PrintStream out, String decodeParam) {
VarAttribEvent vae = RenderEventsCollector
.convertToVarAttribute(new DecodeEvent(decodeParam));
String format = Utils.toStringConstant(vae == null ? decodeParam : vae
.getPattern());
String props = Utils.toStringConstantArray(vae.getProperties()
.toArray());
String defaults = Utils.toStringConstantArray(vae.getDefaultValues()
.toArray());
out.printf(T.tab(2)
+ "setDecodeInfo(%s,new String[]%s,new String[]%s);\n", format,
props, defaults);
}
public ComponentInfo fillIn(ComponentInfo info) throws IOException,
SAXException, IntrospectionException {
RendererInfo ri = info.getRenderer();
String enc = ri.getTemplateEncoding();
return fillIn(fillIn(info, Utils
.resourceToString(ri.getTemplate(), enc)), Utils
.resourceToString(ri.getHeadTemplate(), enc));
}
/**
* Scans the given template for references to component properties and
* updates info accordingly.
*
* @param info
* the {@link ComponentInfo} to update
* @param text
* the template text
* @return info
* @throws IOException
* @throws SAXException
* @throws IntrospectionException
*/
public ComponentInfo fillIn(ComponentInfo info, String text)
throws IOException, SAXException, IntrospectionException {
Map properties = info.getProperties();
for (PullEvent event : new RenderEventsCollector(text)) {
switch (event.getType()) {
case VarAttribEvent.TYPE: {
VarAttribEvent ev = (VarAttribEvent) event;
for (String property : ev.getProperties()) {
String name = Utils.toConstantName(property);
if (!properties.containsKey(name)
&& !isIgnoreProperty(property)) {
properties.put(name, new PropertyInfo(null, property));
}
}
}
break;
case VarTextEvent.TYPE: {
VarTextEvent ev = (VarTextEvent) event;
String name = Utils.toConstantName(ev.getProperty());
if (!properties.containsKey(name)
&& !isIgnoreProperty(ev.getProperty())) {
properties.put(name, new PropertyInfo(null, ev
.getProperty(), ev.getDefaultValue()));
}
}
break;
case PassThrough.TYPE: {
PassThrough ev = (PassThrough) event;
// remove pass through attributes that already have a
// getter/setter pair in the super class, because it is not
// necessary to have another get/set pair
for (PropertyDescriptor pd : info.getTag()
.getPropertyDescriptors()) {
ev.getAllowed().remove(pd.getName());
}
info.getRenderer().getAttribs().addAll(ev.getAllowed());
}
break;
case StartElement.TYPE: {
StartElement ev = (StartElement) event;
if (ev.getName().startsWith(HtmlRenderer.TAG_PREFIX)) {
info.getRenderer().addAttribute(HtmlRenderer.TAG);
}
}
break;
case DecodeEvent.TYPE: {
info.getRenderer().setDecodeParam(
((DecodeEvent) event).getValue());
}
default:
// don't care about other events
}
}
return info;
}
private boolean isIgnoreProperty(String property) {
return "id".equalsIgnoreCase(property)
|| "binding".equalsIgnoreCase(property)
|| "rendered".equalsIgnoreCase(property);
}
}