| /* |
| * 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; |
| } |
| } |