blob: dfb857b950fa022a7d6341b02547014935f2c0e3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.faces.taglib;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.taglib.Tag;
import org.apache.cocoon.taglib.XMLProducerTagSupport;
import org.apache.cocoon.faces.FacesUtils;
import org.apache.cocoon.faces.renderkit.XMLResponseWriter;
import org.apache.commons.lang.BooleanUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import javax.faces.application.Application;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.ValueBinding;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @version $Id$
*/
public abstract class UIComponentTag extends XMLProducerTagSupport {
private static final String CREATED_COMPONENTS = "javax.faces.webapp.COMPONENT_IDS";
private static final String CREATED_FACETS = "javax.faces.webapp.FACET_NAMES";
//
// Attributes
//
private String id;
private String binding;
private String rendered;
//
// Internal state
//
private FacesContext context;
private UIComponent component;
private boolean created;
private List createdComponents;
private List createdFacets;
//
// Services for subclasses
//
protected final FacesContext getFacesContext() {
return this.context;
}
protected final Application getApplication() {
return getFacesContext().getApplication();
}
protected final UIComponent getComponentInstance() {
return this.component;
}
protected final boolean getCreated() {
return this.created;
}
protected final ValueBinding createValueBinding(String valueRef) {
return getApplication().createValueBinding(valueRef);
}
protected final Object evaluate(String value) {
if (FacesUtils.isExpression(value)) {
return createValueBinding(value).getValue(getFacesContext());
}
return value;
}
protected final boolean evaluateBoolean(String value) {
if (FacesUtils.isExpression(value)) {
Boolean obj = (Boolean) createValueBinding(value).getValue(getFacesContext());
return obj.booleanValue();
}
return BooleanUtils.toBoolean(value);
}
protected final int evaluateInteger(String value) {
if (FacesUtils.isExpression(value)) {
Number obj = (Number) createValueBinding(value).getValue(getFacesContext());
return obj.intValue();
}
return Integer.parseInt(value);
}
protected final long evaluateLong(String value) {
if (FacesUtils.isExpression(value)) {
Number obj = (Number) createValueBinding(value).getValue(getFacesContext());
return obj.longValue();
}
return Long.parseLong(value);
}
protected final double evaluateDouble(String value) {
if (FacesUtils.isExpression(value)) {
Number obj = (Number) createValueBinding(value).getValue(getFacesContext());
return obj.doubleValue();
}
return Double.parseDouble(value);
}
//
// Tag Interface
//
public void setup(SourceResolver resolver, Map objectModel, Parameters parameters)
throws SAXException, IOException {
super.setup(resolver, objectModel, parameters);
// Obtain Faces context
this.context = FacesUtils.getFacesContext(this, objectModel);
// Set up response writer
ResponseWriter writer = this.context.getResponseWriter();
if (writer == null) {
// Not calling RenderKit here.
Request request = ObjectModelHelper.getRequest(objectModel);
writer = new XMLResponseWriter(this.xmlConsumer, null, request.getCharacterEncoding());
this.context.setResponseWriter(writer);
}
}
public int doStartTag(String namespaceURI, String localName, String qName, Attributes attrs)
throws SAXException {
final UIComponentTag parentTag = findParent();
this.component = findComponent(parentTag);
try {
if (!isSuppressed()) {
if (!this.component.getRendersChildren()) {
encodeBegin();
getFacesContext().getResponseWriter().flush();
}
}
} catch (IOException e) {
throw new SAXException("Exception in doStartTag", e);
}
return getDoStartValue();
}
public int doEndTag(String namespaceURI, String localName, String qName)
throws SAXException {
removeOldChildren();
removeOldFacets();
try {
if (!isSuppressed()) {
if (this.component.getRendersChildren()) {
encodeBegin();
encodeChildren();
}
encodeEnd();
getFacesContext().getResponseWriter().flush();
}
} catch (IOException e) {
throw new SAXException("Exception in doEndTag", e);
}
return getDoEndValue();
}
//
// Lifecycle
//
public void recycle() {
super.recycle();
this.component = null;
this.context = null;
this.id = null;
this.binding = null;
this.created = false;
this.rendered = null;
this.createdComponents = null;
this.createdFacets = null;
}
//
// Methods to be implemented or overridden in subclasses
//
protected abstract String getComponentType();
protected abstract String getRendererType();
protected int getDoEndValue() {
return Tag.EVAL_PAGE;
}
protected int getDoStartValue() {
return Tag.EVAL_BODY;
}
protected void encodeBegin() throws IOException {
this.component.encodeBegin(this.context);
}
protected void encodeChildren() throws IOException {
this.component.encodeChildren(this.context);
}
protected void encodeEnd() throws IOException {
this.component.encodeEnd(this.context);
}
protected void setProperties(UIComponent component) {
if (this.rendered != null) {
if (FacesUtils.isExpression(this.rendered)) {
ValueBinding vb = createValueBinding(this.rendered);
component.setValueBinding("rendered", vb);
} else {
component.setRendered(BooleanUtils.toBoolean(this.rendered));
}
}
if (getRendererType() != null) {
component.setRendererType(getRendererType());
}
}
protected final void setProperty(UIComponent component, String name, String value) {
if (value != null) {
if (FacesUtils.isExpression(value)) {
ValueBinding vb = createValueBinding(value);
component.setValueBinding(name, vb);
} else {
component.getAttributes().put(name, value);
}
}
}
protected final void setBooleanProperty(UIComponent component, String name, String value) {
if (value != null) {
if (FacesUtils.isExpression(value)) {
ValueBinding vb = createValueBinding(value);
component.setValueBinding(name, vb);
} else {
component.getAttributes().put(name, BooleanUtils.toBooleanObject(value));
}
}
}
protected final void setIntegerProperty(UIComponent component, String name, String value) {
if (value != null) {
if (FacesUtils.isExpression(value)) {
ValueBinding vb = createValueBinding(value);
component.setValueBinding(name, vb);
} else {
component.getAttributes().put(name, new Integer(value));
}
}
}
//
// Implementation methods
//
private UIComponentTag findParent() {
Tag parent = this;
do {
parent = parent.getParent();
} while (parent != null && !(parent instanceof UIComponentTag));
return (UIComponentTag) parent;
}
/**
* Creates or finds (if pre-created) UIComponent for this tag instance
*/
private UIComponent findComponent(UIComponentTag parentTag) {
// Check if this is root
if (parentTag == null) {
UIComponent root = getFacesContext().getViewRoot();
setProperties(root);
if (this.id != null) {
root.setId(this.id);
}
return root;
}
String id = createId();
// Create facet
String facet = getFacetName();
if (facet != null) {
return createFacet(parentTag, facet, id);
}
// Create child
return createChild(parentTag, id);
}
/**
* Get name of the facet or null
*/
private String getFacetName() {
final Tag parentTag = getParent();
if (parentTag instanceof FacetTag) {
return ((FacetTag) parentTag).getName();
}
return null;
}
private boolean isSuppressed() {
if (getFacetName() != null) {
return true;
}
if (!this.component.isRendered()) {
return true;
}
for (UIComponent component = this.component.getParent(); component != null; component = component.getParent()) {
if (!component.isRendered()) {
return true;
}
if (component.getRendersChildren()) {
return true;
}
}
return false;
}
private void addChild(UIComponent child) {
if (createdComponents == null) {
createdComponents = new ArrayList();
}
createdComponents.add(child.getId());
}
private void addFacet(String name) {
if (createdFacets == null) {
createdFacets = new ArrayList();
}
createdFacets.add(name);
}
private UIComponent createComponent(String id) {
UIComponent component;
Application application = context.getApplication();
if (this.binding != null) {
ValueBinding vb = application.createValueBinding(this.binding);
component = application.createComponent(vb, context, getComponentType());
component.setValueBinding("binding", vb);
} else {
component = application.createComponent(getComponentType());
}
component.setId(id);
this.created = true;
setProperties(component);
return component;
}
private UIComponent createChild(UIComponentTag parentTag, String id) {
final UIComponent parent = parentTag.getComponentInstance();
UIComponent component = FacesUtils.getChild(parent, id);
if (component == null) {
component = createComponent(id);
parent.getChildren().add(component);
}
parentTag.addChild(component);
return component;
}
private UIComponent createFacet(UIComponentTag parentTag, String name, String id) {
final UIComponent parent = parentTag.getComponentInstance();
UIComponent component = (UIComponent) parent.getFacets().get(name);
if (component == null) {
component = createComponent(id);
parent.getFacets().put(name, component);
}
parentTag.addFacet(name);
return component;
}
private String createId() {
if (this.id == null) {
return getFacesContext().getViewRoot().createUniqueId();
}
return this.id;
}
private void removeOldChildren() {
List oldList = (List) component.getAttributes().remove(CREATED_COMPONENTS);
if (oldList != null) {
if (createdComponents != null) {
for (Iterator olds = oldList.iterator(); olds.hasNext();) {
String old = (String) olds.next();
if (!createdComponents.contains(old)) {
FacesUtils.removeChild(component, old);
}
}
} else {
for (Iterator i = oldList.iterator(); i.hasNext();) {
FacesUtils.removeChild(component, (String) i.next());
}
}
}
if (createdComponents != null) {
component.getAttributes().put(CREATED_COMPONENTS, createdComponents);
createdComponents = null;
}
}
private void removeOldFacets() {
List oldList = (List) component.getAttributes().remove(CREATED_FACETS);
if (oldList != null) {
if (createdFacets != null) {
for (Iterator olds = oldList.iterator(); olds.hasNext();) {
String old = (String) olds.next();
if (!createdFacets.contains(old)) {
component.getFacets().remove(old);
}
}
} else {
for (Iterator olds = oldList.iterator(); olds.hasNext(); ) {
String old = (String) olds.next();
component.getFacets().remove(old);
}
}
}
if (createdFacets != null) {
component.getAttributes().put(CREATED_FACETS, createdFacets);
createdFacets = null;
}
}
//
// Setters / Getters
//
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getBinding() {
return this.binding;
}
public void setBinding(String binding) {
if (!FacesUtils.isExpression(binding)) {
throw new IllegalArgumentException("Binding value must be an expression");
}
this.binding = binding;
}
public String getRendered() {
return this.rendered;
}
public void setRendered(String rendered) {
this.rendered = rendered;
}
}