001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.tags.databinding.datagrid;
020:
021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
022:
023: import java.io.IOException;
024: import javax.servlet.jsp.JspException;
025: import javax.servlet.ServletException;
026:
027: import org.apache.beehive.netui.databinding.datagrid.api.rendering.DataGridTagModel;
028: import org.apache.beehive.netui.databinding.datagrid.api.rendering.CellModel;
029: import org.apache.beehive.netui.tags.rendering.AbstractRenderAppender;
030: import org.apache.beehive.netui.tags.rendering.StringBuilderRenderAppender;
031: import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
032: import org.apache.beehive.netui.tags.html.HtmlConstants;
033: import org.apache.beehive.netui.tags.html.FormatTag.Formatter;
034: import org.apache.beehive.netui.util.Bundle;
035: import org.apache.beehive.netui.util.logging.Logger;
036:
037: /**
038: * <p>
039: * Abstract base class for JSP tags that render data grid cells. This class provides support to
040: * subclasses in several areas:
041: * <ul>
042: * <li>formatting -- this class accepts instances of {@link Formatter} which can optionally be used
043: * by a subclass to perform formatting on content that is written to a rendered page</li>
044: * <li>applying attributes</li>
045: * <li>applying state attributes to {@link AbstractHtmlState} instances used by subclasses.
046: * </ul>
047: * </p>
048: */
049: public abstract class AbstractCell extends AbstractDataGridHtmlTag {
050:
051: private static final Logger LOGGER = Logger
052: .getInstance(AbstractCell.class);
053:
054: /* todo: switch onto ConstantRendering.NBSP */
055: private static final String EMPTY_CELL = " ";
056:
057: /**
058: * Add a {@link Formatter}. Subclasses can optionally use the support formatting; formatters
059: * are added to the {@link CellModel} associated with an instance of the subclass.
060: * @param formatter the formatter to add
061: */
062: public void addFormatter(Formatter formatter) {
063: internalGetCellModel().addFormatter(formatter);
064: }
065:
066: /**
067: * Indicate that a formatter has reported an error so the formatter should output it's body text.
068: */
069: public void formatterHasError() {
070: /* todo: error reporting */
071: }
072:
073: /**
074: * <p>
075: * This method implements the rendering process for data grid cells. When the data grid's
076: * rendering state is <b>not</b> {@link DataGridTagModel#RENDER_STATE_START}, this tag processes
077: * its body. The tag performs the following steps in order:
078: * <ol>
079: * <li>The tag invokes its {@link #applyAttributes()} method to allow subclasses to apply attributes
080: * to their {@link CellModel} instances at a well known time. Any errors in attribute checking
081: * should be thrown here.</li>
082: * <li>The tag adds the {@link CellModel} associated with the data grid to the
083: * {@link javax.servlet.jsp.JspContext} under the key <code>cellModel</code>.</li>
084: * <li>Rendering is performed by invoking
085: * {@link #renderCell(org.apache.beehive.netui.tags.rendering.AbstractRenderAppender)}. If content is
086: * rendered when the body of the tag is rendered, it is written to the output stream.
087: * </li>
088: * <li>The tag removes the {@link CellModel} instance. If an exception is thrown after the
089: * {@link CellModel} is added to the {@link javax.servlet.jsp.JspContext}, it the cell model
090: * will still be removed from the JspContext.</li>
091: * </ol>
092: * </p>
093: * @throws JspException
094: * @throws IOException
095: */
096: public void doTag() throws JspException, IOException {
097:
098: DataGridTagModel dataGridModel = DataGridUtil
099: .getDataGridTagModel(getJspContext());
100: if (dataGridModel == null) {
101: String s = Bundle.getString(
102: "Tags_DataGrid_MissingDataGridModel",
103: new Object[] { getTagName() });
104: throw new JspException(s);
105: }
106:
107: int gridRenderState = dataGridModel.getRenderState();
108:
109: /* RENDER_STATE_START is a no-op for cells */
110: if (gridRenderState == DataGridTagModel.RENDER_STATE_START) {
111: return;
112: }
113: /*
114: otherwise, the CellModel associated with this tag
115: needs to be fetched from the <cell> tag for the current
116: iteration
117: */
118: else {
119: CellModel model = internalGetCellModel();
120: model.setDataGridTagModel(dataGridModel);
121:
122: applyAttributes();
123:
124: try {
125: DataGridUtil.putCellModel(getJspContext(), model);
126:
127: InternalStringBuilder content = new InternalStringBuilder();
128: AbstractRenderAppender appender = new StringBuilderRenderAppender(
129: content);
130:
131: renderCell(appender);
132:
133: if (content != null && content.length() > 0)
134: getJspContext().getOut()
135: .println(content.toString());
136: } finally {
137: DataGridUtil.removeCellModel(getJspContext());
138: }
139: }
140:
141: return;
142: }
143:
144: /**
145: * <p>
146: * Abstract method implemented by subclasses. Implementers should return the {@link CellModel} associated
147: * with the UI that is being rendered by the JSP tag.
148: * </p>
149: * @return the cell's {@link CellModel}
150: */
151: protected abstract CellModel internalGetCellModel();
152:
153: /**
154: * <p>
155: * Abstract method implemented by subclasses to perform cell-specific rendering.
156: * </p>
157: * @param appender the {@link AbstractRenderAppender} to which any output should be rendered
158: * @throws IOException
159: * @throws JspException
160: */
161: protected abstract void renderCell(AbstractRenderAppender appender)
162: throws IOException, JspException;
163:
164: /**
165: * Utility method usable by subclasses that renders an HTML &nbsp; to represent an empty HTML table cell.
166: * @param appender the {@link AbstractRenderAppender} to which any output should be rendered
167: */
168: protected void renderEmptyCell(AbstractRenderAppender appender) {
169: appender.append(EMPTY_CELL);
170: }
171:
172: /**
173: * Utility method invoked during tag rendering. Subclasses should place attribute validation logic
174: * here.
175: * @throws JspException if application of attributes fails
176: */
177: protected void applyAttributes() throws JspException {
178: }
179:
180: /**
181: * <p>
182: * Add an HTML state attribute to a {@link AbstractHtmlState} object. This method performs
183: * checks on common attributes and sets their values on the state object or throws an exception.
184: * </p>
185: * <p>
186: * For the HTML tags it is not legal to set the <code>id</code> or <code>name</code> attributes.
187: * In addition, the base tag does
188: * not allow facets to be set. If the attribute is legal it will be added to the
189: * general expression map stored in the <code>AbstractHtmlState</code> of the tag.
190: * </p>
191: *
192: * @param state the state object to which attributes are appliedn
193: * @param name the name of an attribute
194: * @param value the value of the attribute
195: * @throws JspException when an error occurs setting the attribute on the state object
196: */
197: protected final void addStateAttribute(AbstractHtmlState state,
198: String name, String value) throws JspException {
199:
200: // validate the name attribute, in the case of an error simply return.
201: if (name == null || name.length() <= 0) {
202: String s = Bundle.getString("Tags_AttributeNameNotSet");
203: throw new JspException(s);
204: }
205:
206: // it's not legal to set the id or name attributes this way
207: if (name.equals(HtmlConstants.ID)
208: || name.equals(HtmlConstants.NAME)) {
209: String s = Bundle.getString("Tags_AttributeMayNotBeSet",
210: new Object[] { name });
211: throw new JspException(s);
212: }
213:
214: // if there is a style or class we will let them override the base
215: if (name.equals(HtmlConstants.CLASS)) {
216: state.styleClass = value;
217: return;
218: } else if (name.equals(HtmlConstants.STYLE)) {
219: state.style = value;
220: return;
221: }
222:
223: state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, name,
224: value);
225: }
226: }
|