/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package javax.faces.webapp; import java.io.*; import java.util.*; import java.util.logging.Logger; import javax.faces.application.*; import javax.faces.component.*; import javax.faces.component.html.*; import javax.faces.context.*; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import javax.servlet.ServletRequest; public abstract class UIComponentClassicTagBase extends UIComponentTagBase implements JspIdConsumer, BodyTag { protected static final String UNIQUE_ID_PREFIX = "j_id_"; protected static Logger log = Logger.getLogger(UIComponentClassicTagBase.class.getName()); private String _id; private String _jspId; protected PageContext pageContext; protected BodyContent bodyContent; private FacesContext _facesContext; private UIComponentClassicTagBase _parentUIComponentTag; private Tag _parent; private UIComponent _component; private boolean _created; public UIComponentClassicTagBase() { _facesContext = FacesContext.getCurrentInstance(); } protected String getFacetName() { return null; } public void setJspId(String id) { _jspId = id; } public String getJspId() { return _jspId; } public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; } public Tag getParent() { return _parent; } public void setParent(Tag parent) { _parent = parent; } public void setBodyContent(BodyContent bodyContent) { this.bodyContent = bodyContent; } public BodyContent getBodyContent() { return this.bodyContent; } public JspWriter getPreviousOut() { if (bodyContent != null) return bodyContent.getEnclosingWriter(); else return pageContext.getOut(); } public void setId(String id) { if (id.startsWith(UNIQUE_ID_PREFIX)) throw new IllegalArgumentException("id may not begin with " + UNIQUE_ID_PREFIX); _id = id; } protected String getFacesJspId(){ if (true) throw new UnsupportedOperationException("unimplemented"); return null; } protected String getId() { return _id; } protected abstract boolean hasBinding(); public UIComponent getComponentInstance() { return _component; } public boolean getCreated() { return _created; } public int doStartTag() throws JspException { PageContext pageContext = this.pageContext; this.bodyContent = null; _created = false; _component = null; _parentUIComponentTag = getParentUIComponentClassicTagBase(pageContext); ServletRequest request = pageContext.getRequest(); Map tagMap = (Map) request.getAttribute("caucho.jsf.tag.map"); if (tagMap == null) { tagMap = new HashMap(); request.setAttribute("caucho.jsf.tag.map", tagMap); } Integer iterCounter = (Integer) tagMap.get(_jspId); iterCounter = (iterCounter == null ? new Integer(0) : new Integer(iterCounter.intValue() + 1)); tagMap.put(_jspId, iterCounter); _component = findComponent(_facesContext); request.setAttribute("caucho.jsf.parent", this); return getDoStartValue(); } /** * Returns the doStart value for the tag. Defaults to EVAL_BODY_BUFFERED. */ protected int getDoStartValue() throws JspException { return BodyTag.EVAL_BODY_BUFFERED; } public void doInitBody() throws JspException { } public int doAfterBody() throws JspException { UIComponent verbatim = createVerbatimComponentFromBodyContent(); if (verbatim != null) { UIComponent component = getComponentInstance(); if (component != null) component.getChildren().add(verbatim); } return getDoAfterBodyValue(); } protected int getDoAfterBodyValue() throws JspException { return BodyTag.SKIP_PAGE; } public int doEndTag() throws JspException { pageContext.getRequest().setAttribute("caucho.jsf.parent", _parentUIComponentTag); return getDoEndValue(); } protected int getDoEndValue() throws JspException { return Tag.EVAL_PAGE; } protected abstract UIComponent createComponent(FacesContext context, String newId) throws JspException; protected abstract void setProperties(UIComponent component); protected UIComponent findComponent(FacesContext context) throws JspException { _created = false; if (_component != null) return _component; UIComponentClassicTagBase parentTag = _parentUIComponentTag; if (parentTag == null) { _component = context.getViewRoot(); // XXX: if (_component.getChildCount() == 0){ _created = true; setProperties(_component); } return _component; } UIComponent verbatim = parentTag.createVerbatimComponentFromBodyContent(); UIComponent parent = parentTag.getComponentInstance(); String id = getId(); String facetName = null; if (id == null) id = UIViewRoot.UNIQUE_ID_PREFIX + getJspId(); Map tagMap = (Map) pageContext.getRequest() .getAttribute("caucho.jsf.tag.map"); Integer iterCounter = (Integer) tagMap.get(_jspId); if (iterCounter.intValue() > 0) id = id + "_" + iterCounter.intValue(); if (_parent instanceof FacetTag) { facetName = ((FacetTag) _parent).getName(); _component = parent.getFacet(facetName); if (_component != null) return _component; } else { _component = parent.findComponent(id); if (_component != null) { if (verbatim != null) { addVerbatimBeforeComponent(parentTag, verbatim, _component); } return _component; } if (verbatim != null) { parent.getChildren().add(verbatim); } } String componentType = getComponentType(); if (hasBinding()) { // XXX: binding } _component = createComponent(context, id); _created = true; _component.setId(id); setProperties(_component); if (facetName != null) parent.getFacets().put(facetName, _component); else parent.getChildren().add(_component); return _component; } protected int getIndexOfNextChildTag() { throw new UnsupportedOperationException(); } protected void addChild(UIComponent child) { getComponentInstance().getChildren().add(child); } protected void addFacet(String name) { throw new UnsupportedOperationException(); } protected UIComponent createVerbatimComponentFromBodyContent() { BodyContent bodyContent = this.bodyContent; if (bodyContent == null) return null; String text = bodyContent.getString(); bodyContent.clearBody(); boolean isWhitespace = true; for (int i = text.length() - 1; i >= 0; i--) { char ch = text.charAt(i); if (!Character.isWhitespace(ch)) { // check for comment if (ch == '>' && text.indexOf("-->") + 2 == i) { int head = text.indexOf("<!--"); if (head >= 0) { for (int j = 0; j < head; j++) { if (!Character.isWhitespace(text.charAt(j))) { isWhitespace = false; break; } } if (isWhitespace) return null; } } isWhitespace = false; break; } } if (isWhitespace) return null; UIOutput verbatim = createVerbatimComponent(); verbatim.setValue(text); return verbatim; } protected UIOutput createVerbatimComponent() { Application app = _facesContext.getApplication(); UIOutput output = (UIOutput) app.createComponent(HtmlOutputText.COMPONENT_TYPE); output.setId(_facesContext.getViewRoot().createUniqueId()); output.setTransient(true); if (output instanceof HtmlOutputText) ((HtmlOutputText) output).setEscape(false); return output; } protected void addVerbatimBeforeComponent(UIComponentClassicTagBase parentTag, UIComponent verbatim, UIComponent component) { UIComponent parent = parentTag.getComponentInstance(); int size = parent.getChildCount(); if (size > 0) { List<UIComponent> children = parent.getChildren(); for (int i = 0; i < size; i++) { if (children.get(i) == component) children.add(i, verbatim); } } } protected void addVerbatimAfterComponent(UIComponentClassicTagBase parentTag, UIComponent verbatim, UIComponent component) { UIComponent parent = parentTag.getComponentInstance(); int size = parent.getChildCount(); if (size > 0) { List<UIComponent> children = parent.getChildren(); for (int i = 0; i < size; i++) { if (children.get(i) == component) children.add(i + 1, verbatim); } } } protected List<String> getCreatedComponents() { throw new UnsupportedOperationException(); } protected FacesContext getFacesContext() { return _facesContext; } /** * @deprecated */ protected void setupResponseWriter() { } /** * @deprecated */ protected void encodeBegin() throws IOException { UIComponent component = getComponentInstance(); FacesContext context = getFacesContext(); if (component != null && context != null) component.encodeBegin(context); } /** * @deprecated */ protected void encodeChildren() throws IOException { UIComponent component = getComponentInstance(); FacesContext context = getFacesContext(); if (component != null && context != null) component.encodeChildren(context); } /** * @deprecated */ protected void encodeEnd() throws IOException { UIComponent component = getComponentInstance(); FacesContext context = getFacesContext(); if (component != null && context != null) component.encodeEnd(context); } public void release() { } public static UIComponentClassicTagBase getParentUIComponentClassicTagBase(PageContext pageContext) { return (UIComponentClassicTagBase) pageContext.getRequest().getAttribute("caucho.jsf.parent"); } }