!!!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.