KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > AbstractClassicTag


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.tags;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21 import org.apache.beehive.netui.util.internal.ServletUtils;
22
23 import org.apache.beehive.netui.core.urls.URLRewriterService;
24 import org.apache.beehive.netui.script.ExpressionEvaluationException;
25 import org.apache.beehive.netui.tags.javascript.IScriptReporter;
26 import org.apache.beehive.netui.tags.javascript.ScriptContainer;
27 import org.apache.beehive.netui.tags.naming.FormDataNameInterceptor;
28 import org.apache.beehive.netui.tags.naming.INameInterceptor;
29 import org.apache.beehive.netui.tags.naming.IndexedNameInterceptor;
30 import org.apache.beehive.netui.util.Bundle;
31 import org.apache.beehive.netui.util.logging.Logger;
32 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
33 import org.apache.struts.Globals;
34 import org.apache.struts.util.RequestUtils;
35
36 import javax.servlet.ServletRequest JavaDoc;
37 import javax.servlet.http.HttpServletRequest JavaDoc;
38 import javax.servlet.jsp.JspException JavaDoc;
39 import javax.servlet.jsp.JspWriter JavaDoc;
40 import javax.servlet.jsp.PageContext JavaDoc;
41 import javax.servlet.jsp.tagext.BodyTagSupport JavaDoc;
42 import javax.servlet.jsp.tagext.SimpleTagSupport JavaDoc;
43 import javax.servlet.jsp.tagext.Tag JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.util.*;
46
47 /**
48  * AbstractBaseTag is the base tag for most of the NetUI tags. This tag provides default behavior
49  * and services for NetUI tags. There following categories of services are provided by this tag:
50  * <ul>
51  * <li><b>Generic Services</b> -- These are general services such as access to local, writting
52  * to the response, and writting attributes.</li>
53  * <li><b>Expression Management</b> -- This set of method provide evaluation and information about
54  * expressions. These methods allow tags to fully support expressions for attributes.</li>
55  * <li><b>Naming and NamingInterceptor Services</b> -- This set of methods will apply
56  * <code>INameInterceptor</code>s to a name to produce the name written out. In addition, it allows
57  * the URL Rewritter service to modify names.</li>
58  * <li><b>Attribute Rendering Support</b> -- This set of routine allow tags to keep simple attributes
59  * in a map that can be written into the generated markup. There are two types of attributes, attributes
60  * that contain expression and attributes that do not contain expression supported.</li>
61  * <li><b>Error Reporting</b> -- This set of routines will report errors within the tags. In development
62  * mode errors are reported in-page.</li>
63  * <li><b>JavaScript Services</b> -- This set of routines provide simple access for JavaScript generation.</li>
64  * </ul>
65  * @netui:tag
66  */

67 public abstract class AbstractClassicTag
68         extends BodyTagSupport JavaDoc implements INetuiTag
69 {
70     //@todo: need to implement the flag to turn errors into JSP exceptions
71

72     private static final Logger logger = Logger.getInstance(AbstractClassicTag.class);
73
74     /**
75      * This List represents the default naming chain for handling <code>dataSource</code> attributes. The list
76      * is a read-only list which may be used by any <code>dataSource</code> implementation.
77      */

78     public static final List DefaultNamingChain;
79
80     /**
81      * This is the name of a request scoped attribute which creates a unique id for processing
82      * a request.
83      */

84     public static final String JavaDoc NETUI_UNIQUE_CNT = "netui.unique.id";
85
86     /**
87      * This is a private formRewriter which is used by <code>qualifyName</code> to provide
88      * struts naming behavior.
89      */

90     private static final INameInterceptor formRewriter = new FormDataNameInterceptor();
91
92     /**
93      * String constant for the empty string.
94      */

95     protected static final String JavaDoc EMPTY_STRING = "";
96
97     // create the default naming chain.
98
static
99     {
100         List l = new ArrayList(2);
101         l.add(new FormDataNameInterceptor());
102         l.add(new IndexedNameInterceptor());
103         DefaultNamingChain = Collections.unmodifiableList(l);
104     }
105
106     private ErrorHandling _eh; // This class will track and handle errors
107

108     /////////////////////////// Generic Services support ////////////////////////////
109

110     /**
111      * Return the name of the tag. Used by error reporting to get the name of the tag.
112      * @return the name of the tag.
113      */

114     public abstract String JavaDoc getTagName();
115
116     /**
117      * This is a method that will reinitialize all temporary state on a
118      * tag and should be called in the doEndTag method.
119      */

120     protected void localRelease()
121     {
122         _eh = null;
123     }
124
125     /**
126      * This method will return the user local of the request.
127      * @return the Locale object to use when rendering this tag
128      */

129     protected Locale getUserLocale()
130     {
131         return InternalUtils.lookupLocale(pageContext.getRequest());
132     }
133
134     /**
135      * This mehod will write the passed string to the response.
136      * @param string to be written to the response.
137      */

138     protected final void write(String JavaDoc string)
139     {
140         JspWriter JavaDoc writer = pageContext.getOut();
141         try {
142             writer.print(string);
143         }
144         catch (IOException JavaDoc e) {
145             logger.error(Bundle.getString("Tags_WriteException"), e);
146             RequestUtils.saveException((PageContext JavaDoc) pageContext, e);
147         }
148     }
149
150     /////////////////////////// Naming and NamingInterceptor support ////////////////////////////
151

152     /**
153      * Return an <code>List</code> which represents a chain of <code>INameInterceptor</code>
154      * objects. This method by default returns <code>null</code> and should be overridden
155      * by objects that support naming.
156      * @return an <code>List</code> that will contain <code>INameInterceptor</code> objects.
157      */

158     protected List getNamingChain()
159     {
160         return null;
161     }
162
163     /**
164      * This method walks all of the naming chains and allows them to rewrite the <code>name</code> parameter.
165      * After the naming chain processes the name, it will be passed to <code>rewriteName</code> for final processing.
166      * If the naming chaing returned from <code>getNamingChain</code> returns null, the name will be passed to
167      * <code>rewriteName</code> and returned. If there is an <code>ExpressionEvaluationException</code> thrown
168      * by a <code>INameInterceptor</code>, the error will be registered with the tag and <code>null</code> will
169      * be returned.
170      * @param name the name to rewrite
171      * @return the name after it was passed to all <code>INameInterceptor</code>s in the naming chain.
172      * @see #rewriteName
173      * @see org.apache.beehive.netui.tags.naming.INameInterceptor
174      */

175     protected String JavaDoc applyNamingChain(String JavaDoc name)
176             throws JspException JavaDoc
177     {
178         assert (name != null) : "The name parameter may not be null";
179
180         List namingChain = getNamingChain();
181         if (namingChain == null)
182             return rewriteName(name);
183
184         //if (logger.isDebugEnabled())
185
// logger.debug("rewrite name \"" + name + "\" on tag of type \"" + getClass().getName() + " with namingChain " +
186
// (namingChain != null ? "size " + namingChain.size() : "null"));
187

188         try {
189             String JavaDoc newName = name;
190             int cnt = namingChain.size();
191             for (int i = 0; i < cnt; i++) {
192                 //if (logger.isDebugEnabled())
193
// logger.debug("rewriteName: \"" + newName + "\" with INameInterceptor: " + namingChain.get(i).getClass().getName());
194

195                 newName = ((INameInterceptor) namingChain.get(i)).rewriteName(newName, this);
196
197                 //if (logger.isDebugEnabled())
198
// logger.debug("rewrite result: " + newName);
199
}
200
201             return rewriteName(newName);
202         }
203         catch (ExpressionEvaluationException ee) {
204             // if there is an expression evaluation error set the error and return null;
205
logger.error(Bundle.getString("Tags_ExpressionQualifyingFailure", name));
206
207             // create the expression info an add it to the error tracking
208
EvalErrorInfo info = new EvalErrorInfo();
209             info.evalExcp = ee;
210             info.expression = name;
211             info.attr = "dataSource";
212             info.tagType = getTagName();
213
214             // report the error
215
registerTagError(info);
216             return null;
217         }
218     }
219
220     /**
221      * An internal method that allows a tag to qualify the <code>name</code> paramater by converting
222      * it from a struts style naming convention to an explicit databinding expression. The qualified
223      * name will be returned. This method may report an error if there is an error in the expression.
224      * @param name the name to be qualified
225      * @return the name which has been qualified
226      * @throws JspException throws a JspException if in-page error reporting is turned off.
227      * @see org.apache.beehive.netui.tags.naming.FormDataNameInterceptor
228      */

229     protected String JavaDoc qualifyAttribute(String JavaDoc name)
230             throws JspException JavaDoc
231     {
232         if (name == null)
233             return null;
234
235         // if this is a Struts style name, convert it to an expression
236
try {
237             name = formRewriter.rewriteName(name, this);
238         }
239         catch (ExpressionEvaluationException e) {
240             String JavaDoc s = Bundle.getString("Tags_DataSourceExpressionError", new Object JavaDoc[]{name, e.toString()});
241             registerTagError(s, null);
242         }
243         return name;
244     }
245
246     /**
247      * This method will rewrite the name (id) by passing it to the
248      * URL Rewritter and getting back a value.
249      * @param name the name that will be rewritten
250      * @return a name that has been rewritten by the URLRewriterService.
251      */

252     final protected String JavaDoc rewriteName(String JavaDoc name)
253     {
254         return URLRewriterService.getNamePrefix(pageContext.getServletContext(), pageContext.getRequest(), name) + name;
255     }
256
257     /**
258      * This method will generate a real id based upon the passed in tagId. The generated
259      * id will be constucted by searching upward for all the script containers that have a
260      * scope id set. These will form a fully qualified id.
261      * @param tagId The base tagId set on a tag
262      * @return an id value formed by considering all of the scope id's found in the tag hierarchy.
263      */

264     final protected String JavaDoc getIdForTagId(String JavaDoc tagId)
265     {
266         HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) pageContext.getRequest();
267         ArrayList/*<String>*/ list = (ArrayList/*<String>*/)
268                 org.apache.beehive.netui.tags.RequestUtils.getOuterAttribute(req,
269                         ScriptContainer.SCOPE_ID);
270         if (list == null)
271             return tagId;
272         InternalStringBuilder sb = new InternalStringBuilder();
273         for (int i=0;i<list.size();i++) {
274             sb.append((String JavaDoc)list.get(i));
275             sb.append('.');
276         }
277         sb.append(tagId);
278         return sb.toString();
279
280
281         /*
282         Tag tag = this;
283         while (tag != null) {
284             if (tag instanceof ScriptContainer) {
285                 String sid = ((ScriptContainer) tag).getIdScope();
286                 if (sid != null) {
287                     tagId = sid + "." + tagId;
288                 }
289             }
290             tag = tag.getParent();
291         }
292         return tagId;
293         */

294     }
295
296     /////////////////////////// Generic Attribute Setting Support ////////////////////////////
297

298     /**
299      * Report an error if the value of <code>attrValue</code> is equal to the empty string, otherwise return
300      * that value. If <code>attrValue</code> is equal to the empty string, an error is registered and
301      * null is returned.
302      * @param attrValue The value to be checked for the empty string
303      * @param attrName The name of the attribute
304      * @return either the attrValue if it is not the empty string or null
305      * @throws JspException A JspException will be thrown if inline error reporting is turned off.
306      */

307     protected final String JavaDoc setRequiredValueAttribute(String JavaDoc attrValue, String JavaDoc attrName)
308             throws JspException JavaDoc
309     {
310         assert(attrValue != null) : "parameter 'attrValue' must not be null";
311         assert(attrName != null) : "parameter 'attrName' must not be null";
312
313         if ("".equals(attrValue)) {
314             String JavaDoc s = Bundle.getString("Tags_AttrValueRequired", new Object JavaDoc[]{attrName});
315             registerTagError(s, null);
316             return null;
317         }
318         return attrValue;
319     }
320
321     /**
322      * Filter out the empty string value and return either the value or null. When the value of
323      * <code>attrValue</code> is equal to the empty string this will return null, otherwise it will
324      * return the value of <code>attrValue</code>.
325      * @param attrValue This is the value we will check for the empty string.
326      * @return either the value of attrValue or null
327      */

328     protected final String JavaDoc setNonEmptyValueAttribute(String JavaDoc attrValue)
329     {
330         return ("".equals(attrValue)) ? null : attrValue;
331     }
332
333     /////////////////////////// Generic Error Reporting Support ////////////////////////////
334

335     /**
336      * This is a simple routine which will call the error reporter if there is an
337      * error and then call local release before returning the <code>returnValue</code>.
338      * This is a very common code sequence in the Classic Tags so we provide this routine.
339      * @param returnValue The value that will be returned.
340      * @return <code>returnValue</code> is always returned.
341      * @throws JspException
342      */

343     protected int reportAndExit(int returnValue)
344             throws JspException JavaDoc
345     {
346         if (hasErrors()) {
347             reportErrors();
348         }
349         localRelease();
350         return returnValue;
351     }
352
353     /**
354      * This will report an error from a tag. The error will
355      * contain a message. If error reporting is turned off,
356      * the message will be returned and the caller should throw
357      * a JspException to report the error.
358      * @param message - the message to register with the error
359      * @throws JspException - if in-page error reporting is turned off this method will always
360      * throw a JspException.
361      */

362     public void registerTagError(String JavaDoc message, Throwable JavaDoc e)
363             throws JspException JavaDoc
364     {
365         ErrorHandling eh = getErrorHandling();
366         eh.registerTagError(message, getTagName(), this, e);
367     }
368
369     /**
370      * This will report an error from a tag. The error must
371      * be be an AbstractPageError.
372      * @param error The <code>AbstractPageError</code> to add to the error list.
373      * @throws JspException - if in-page error reporting is turned off this method will always
374      * throw a JspException.
375      */

376     public void registerTagError(AbstractPageError error)
377             throws JspException JavaDoc
378     {
379         ErrorHandling eh = getErrorHandling();
380         eh.registerTagError(error, this);
381     }
382
383     /**
384      * This method will return <code>true</code> if there have been any errors registered on this
385      * tag. Otherwise it returns <code>false</code>
386      * @return <code>true</code> if errors have been reported on this tag.
387      */

388     protected boolean hasErrors()
389     {
390         return (_eh != null);
391     }
392
393     /**
394      * This method will write out the <code>String</code> returned by <code>getErrorsReport</code> to the
395      * response output stream.
396      * @throws JspException if <code>write</code> throws an exception.
397      * @see #write
398      */

399     protected void reportErrors()
400             throws JspException JavaDoc
401     {
402         assert(_eh != null);
403         String JavaDoc err = _eh.getErrorsReport(getTagName());
404         IErrorCollector ec = (IErrorCollector) SimpleTagSupport.findAncestorWithClass(this, IErrorCollector.class);
405         if (ec != null) {
406             ec.collectChildError(err);
407         }
408         else {
409             write(err);
410         }
411     }
412
413     /**
414      * This method will return a <code>String<code> that represents all of the errors that were
415      * registered for the tag. This method assumes that there are errors in the tag and asserts
416      * this is true. Code will typically call <code>hasErrors</code> before calling this method.
417      * @return A <code>String</code> that contains all of the errors registered on this tag.
418      */

419     protected String JavaDoc getErrorsReport()
420     {
421         assert _eh != null;
422         return _eh.getErrorsReport(getTagName());
423     }
424
425
426     /**
427      * This method will return an ErrorHandling instance.
428      * @return
429      */

430     private ErrorHandling getErrorHandling()
431     {
432         if (_eh == null) {
433             _eh = new ErrorHandling();
434         }
435         return _eh;
436     }
437
438     /////////////////////////// JavaScript Support Support ////////////////////////////
439

440     /**
441      * Return the closest <code>ScriptReporter</code> in the parental chain. Searching starts
442      * at this node an moves upward through the parental chain.
443      * @return a <code>ScriptReporter</code> or null if there is not one found.
444      */

445     protected IScriptReporter getScriptReporter()
446     {
447         IScriptReporter sr = (IScriptReporter) SimpleTagSupport.findAncestorWithClass(this, IScriptReporter.class);
448         return sr;
449     }
450
451     /////////////////////////// Misc Features Support ////////////////////////////
452

453     /**
454      * This method will generate the next unique int within the HTML tag.
455      * @param req the Request
456      * @return the next unique integer for this request.
457      */

458     protected int getNextId(ServletRequest JavaDoc req)
459     {
460         Integer JavaDoc i = (Integer JavaDoc) req.getAttribute(NETUI_UNIQUE_CNT);
461         if (i == null) {
462             i = new Integer JavaDoc(0);
463         }
464
465         int ret = i.intValue();
466         req.setAttribute(NETUI_UNIQUE_CNT, new Integer JavaDoc(ret + 1));
467         return ret;
468     }
469 }
470
Popular Tags