!!!Parameterisierter Validator Tag SomeValidator.java {{{ import javax.el.ValueExpression; import javax.faces.application.FacesMessage; import javax.faces.component.StateHolder; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; public class SomeValidator implements Validator, Stateholder { private ValueExpression type; private boolean transientValue; public ValueExpression getType() { return type; } public void setType(ValueExpression type) { this.type = type; } @Override public Object saveState(FacesContext context) { Object values[] = new Object[1]; values[0] = type; return values; } @Override public void restoreState(FacesContext context, Object state) { Object[] values = (Object[])state; type = (ValueExpression)values[0]; } @Override public boolean isTransient() { return transientValue; } @Override public void setTransient(boolean transientValue) { this.transientValue = transientValue; } @Override public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { ... } } }}} SomeValidatorHandler.java {{{ public class SomeValidatorHandler extends ValidateHandler { private TagAttribute type; public SomeValidatorHandler(ValidatorConfig config) { super(config); type = getRequiredAttribute("type"); } @Override protected Validator createValidator(FaceletContext context) { SomeValidator validator = (SomeValidator)context.getFacesContext().getApplication().createValidator( "intersult.some"); if (type != null) validator.setType(type.getValueExpression(context, QueryType.class)); return validator; } @Override protected MetaRuleset createMetaRuleset(Class type) { return super.createMetaRuleset(type).ignoreAll(); } } }}} faces-config.xml {{{ <validator> <validator-id>intersult.some</validator-id> <validator-class>com.intersult.SomeValidator</validator-class> </validator> }}} intersult.taglib.xml {{{ <tag> <tag-name>SomeValidator</tag-name> <validator> <validator-id>intersult.some</validator-id> <handler-class>com.intersult.SomeValidatorHandler</handler-class> </validator> </tag> }}} intersult.tld {{{ <tag> <name>SomeValidator</name> <tag-class/> <body-content>empty</body-content> <attribute> <name>type</name> </attribute> </tag> }}} !!!ViewHandler {{{ package com.intersult.jsf; import java.io.IOException; import javax.faces.FacesException; import javax.faces.application.ViewHandler; import javax.faces.component.UIComponent; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import com.sun.facelets.FaceletViewHandler; import com.sun.facelets.tag.jsf.ComponentSupport; public class PartialViewHandler extends FaceletViewHandler { public PartialViewHandler(ViewHandler parent) { super(parent); } @Override public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException { String region = context.getExternalContext().getRequestParameterMap().get("region"); if (region == null) { super.renderView(context, viewToRender); } else { renderRegion(context, viewToRender, region); } } private void renderRegion(FacesContext context, UIViewRoot viewToRender, String region) { try { this.buildView(context, viewToRender); UIComponent component = viewToRender.findComponent(region); ResponseWriter writer = super.createResponseWriter(context); FacesContext.getCurrentInstance().setResponseWriter(writer); ComponentSupport.encodeRecursive(context, component); writer.close(); FacesContext.getCurrentInstance().responseComplete(); } catch (IOException exception) { throw new RuntimeException(exception); } } @Override public void writeState(FacesContext context) throws IOException { String region = context.getExternalContext().getRequestParameterMap().get("region"); if (region == null) super.writeState(context); } } }}} !!!Einfache Komponente Component: {{{ public class OutputStream extends UIComponentBase { private String url; @Override public String getFamily() { return "javax.faces.Output"; } public String getUrl() { ValueExpression expression = getValueExpression("url"); if (expression != null) return (String)expression.getValue(getFacesContext().getELContext()); return url; } public void setUrl(String url) { this.url = url; } } }}} Renderer: {{{ public class OutputStreamRenderer extends Renderer { @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { OutputStream outputStream = (OutputStream)component; ResponseWriter writer = context.getResponseWriter(); URL url = new URL(outputStream.getUrl()); InputStream inputStream = null; try { inputStream = url.openStream(); IOUtils.copy(inputStream, writer); } finally { if (inputStream != null) inputStream.close(); } } } }}} faces-config.xml: {{{ <component> <component-type>intersult.OutputStream</component-type> <component-class>com.intersult.OutputStream</component-class> </component> <render-kit> <render-kit-id>HTML_BASIC</render-kit-id> <renderer> <component-family>javax.faces.Output</component-family> <renderer-type>intersult.OutputStream</renderer-type> <renderer-class>com.intersult.OutputStreamRenderer</renderer-class> </renderer> </render-kit> }}} intersult.taglib.xml: {{{ <tag> <tag-name>outputStream</tag-name> <component> <component-type>intersult.OutputStream</component-type> <renderer-type>intersult.OutputStream</renderer-type> </component> </tag> }}} !!!ClearValuesActionListener ClearValuesActionListenerHandler: {{{ public class ClearValuesActionListenerHandler extends TagHandler { public static class ClearValuesActionListener implements ActionListener, Serializable { private ValueExpression forValue; public ClearValuesActionListener() { } public ClearValuesActionListener(ValueExpression forValue) { this.forValue = forValue; } public ValueExpression getFor() { return forValue; } public void setFor(ValueExpression forValue) { this.forValue = forValue; } @Override public void processAction(ActionEvent actionEvent) { String id = (String)forValue.getValue(FacesContext.getCurrentInstance().getELContext()); UIComponent component = RendererUtils.getInstance().findComponentFor(actionEvent.getComponent(), id); clearValues(component); } private void clearValues(UIComponent component) { if (component instanceof UIInput) { UIInput input = (UIInput)component; input.setSubmittedValue(null); } for (UIComponent child : component.getChildren()) { clearValues(child); } } } private TagAttribute forAttribute; public ClearValuesActionListenerHandler(TagConfig config) { super(config); forAttribute = getRequiredAttribute("for"); } @Override public void apply(FaceletContext context, UIComponent parent) { if (!(parent instanceof ActionSource)) throw new TagException(tag, "Parent component must be action source"); ActionSource actionSource = (ActionSource)parent; ValueExpression forValue = forAttribute.getValueExpression(context, String.class); actionSource.addActionListener(new ClearValuesActionListener(forValue)); } } }}} Taglib: {{{ <tag> <tag-name>clearValuesActionListener</tag-name> <handler-class>com.intersult.ClearValuesActionListenerHandler</handler-class> </tag> }}} !!!RES_NOT_FOUND finden Wenn im HTML-Code Stylesheets, Javascripts oder andere Resourcen als {{{ <link type="text/css" rel="stylesheet" href="RES_NOT_FOUND"/> }}} gerendert werden, ist die Quelle des Fehlers oft schwer zu finden. Dazu kann ein Breakpoint in {{{ com.sun.faces.renderkit.html_basic.HtmlResponseWriter.writeURIAttributeIgnoringPassThroughAttributes(String, Object, String, boolean) }}} gesetzt werden mit der Condition {{{ "RES_NOT_FOUND".equals(value) }}} und dann entsprechend im Stack zur Ursache zurückgegangen werden, etwa zu {{{ com.sun.faces.renderkit.html_basic.ScriptStyleBaseRenderer.encodeEnd(FacesContext, UIComponent) line: 249 }}} dort findet man {{{ Resource resource = resourceHandler.createResource(name, library); }}} den Name und Library der angeforderten Resources.