KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > html > AnchorBase


1 package org.apache.beehive.netui.tags.html;
2
3 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
4 import org.apache.beehive.netui.tags.ByRef;
5 import org.apache.beehive.netui.tags.HtmlUtils;
6 import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
7 import org.apache.beehive.netui.tags.javascript.CoreScriptFeature;
8 import org.apache.beehive.netui.tags.javascript.IScriptReporter;
9 import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
10 import org.apache.beehive.netui.tags.rendering.*;
11 import org.apache.beehive.netui.util.Bundle;
12 import org.apache.beehive.netui.util.ParamHelper;
13 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
14 import org.apache.beehive.netui.util.logging.Logger;
15 import org.apache.struts.taglib.html.Constants;
16
17 import javax.servlet.ServletRequest JavaDoc;
18 import javax.servlet.http.HttpServletRequest JavaDoc;
19 import javax.servlet.http.HttpServletResponse JavaDoc;
20 import javax.servlet.jsp.JspException JavaDoc;
21 import java.net.URISyntaxException JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24
25 /**
26  * This is the base class that provides most of the features necessary to create an anchor and an area. The Anchor
27  * and Area tags are created as subclasses of this tag. The Area tag is really a subset of the features, so certain
28  * attributes are not defined here, even though the backing fields are defined here and the utility code knows them.
29  * This may not be the best OO design, but the design is optimized for performance of rendering anchor elements.
30  */

31 abstract public class AnchorBase extends HtmlBaseTag
32         implements IUrlParams, IHasPopupSupport
33 {
34     protected static final String JavaDoc REQUIRED_ATTR = "href, action, linkName, clientAction";
35     private static final Logger logger = Logger.getInstance(AnchorBase.class);
36
37     protected AnchorTag.State _state = new AnchorTag.State();
38     protected String JavaDoc _linkName; // name of the link
39
protected String JavaDoc _clientAction; // The client action (javascript)
40

41     private String JavaDoc _action;
42     private String JavaDoc _href;
43     private String JavaDoc _targetScope; // target page flow scope; see comments on setTargetScope()
44
private String JavaDoc _location; // anchor to be added to the end of the hyperlink.
45
private Map JavaDoc _params; // Parameters
46
private Form _form; // the nearest form
47
private boolean _formSubmit = false; // should the anchor submit an enclosing form?
48
private PopupSupport _popupSupport = null; // popup support, if the popup attribute is set to true
49
private boolean _disableSecondClick = false; // When clicked, this anchor will disable itself after being clicked.
50

51     /**
52      * Base support for the attribute tag. This is overridden to prevent setting the <code>href</code>
53      * attribute.
54      * @param name The name of the attribute. This value may not be null or the empty string.
55      * @param value The value of the attribute. This may contain an expression.
56      * @param facet The name of a facet to which the attribute will be applied. This is optional.
57      * @throws JspException A JspException may be thrown if there is an error setting the attribute.
58      */

59     public void setAttribute(String JavaDoc name, String JavaDoc value, String JavaDoc facet)
60             throws JspException JavaDoc
61     {
62         if (name != null && name.equals(HREF)) {
63             String JavaDoc s = Bundle.getString("Tags_AttributeMayNotBeSet", new Object JavaDoc[]{name});
64             registerTagError(s, null);
65         }
66         super.setAttribute(name, value, facet);
67     }
68
69     /**
70      * Sets <code>shape</code> attribute for the area.
71      * @param shape the window target.
72      * @jsptagref.attributedescription The shape.
73      * @jsptagref.databindable false
74      * @jsptagref.attributesyntaxvalue <i>string_shape</i>
75      * @netui:attribute required="false" rtexprvalue="true"
76      * description="The shape."
77      */

78     public void setShape(String JavaDoc shape)
79     {
80         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, SHAPE, shape);
81     }
82
83     /**
84      * Sets <code>coords</code> attribute for the area.
85      * @param coords the window target.
86      * @jsptagref.attributedescription The coordinates.
87      * @jsptagref.databindable false
88      * @jsptagref.attributesyntaxvalue <i>string_coordinates</i>
89      * @netui:attribute required="false" rtexprvalue="true"
90      * description="The coordinates."
91      */

92     public void setCoords(String JavaDoc coords)
93     {
94         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, COORDS, coords);
95     }
96
97     /**
98      * Set the name of the action for the Area.
99      * @param action the name of the action to set for the Area.
100      * @jsptagref.attributedescription The action method to invoke. The action method must be in the Controller file
101      * of the Page Flow directory.
102      * @jsptagref.databindable false
103      * @jsptagref.attributesyntaxvalue <i>string_action</i>
104      * @netui:attribute required="false" rtexprvalue="true"
105      * description="The action method to invoke. The action method must be in the Controller file of the Page Flow directory."
106      */

107     public void setAction(String JavaDoc action)
108             throws JspException JavaDoc
109     {
110         _action = setRequiredValueAttribute(action, "action");
111     }
112
113     /**
114      * Sets the href of the Anchor. This attribute will accept the empty String as a legal value.
115      * @param href the hyperlink URI for the Area.
116      * @jsptagref.attributedescription The URL to go to.
117      * @jsptagref.databindable false
118      * @jsptagref.attributesyntaxvalue <i>string_href</i>
119      * @netui:attribute required="false" rtexprvalue="true"
120      * description="The URL to go to."
121      * reftype="url"
122      */

123     public void setHref(String JavaDoc href)
124             throws JspException JavaDoc
125     {
126         _href = href;
127     }
128
129     /**
130      * Sets the anchor to be added to the end of the generated hyperlink.
131      * @param location the name of the location anchor.
132      * @jsptagref.attributedescription Location within the URI to visit.
133      * @jsptagref.databindable false
134      * @jsptagref.attributesyntaxvalue <i>string_location</i>
135      * @netui:attribute required="false" rtexprvalue="true"
136      * description="Location within the URI to visit."
137      */

138     public void setLocation(String JavaDoc location)
139     {
140         _location = setNonEmptyValueAttribute(location);
141     }
142
143     /**
144      * Set the target "scope" for the anchor's action. Multiple active page flows may exist concurrently within named
145      * scopes. This attribute selects which named scope to use. If omitted, the default scope is assumed.
146      * @param targetScope the name of the target scope in which the associated action's page flow resides.
147      * @jsptagref.attributedescription The target scope in which the associated action's page flow resides.
148      * @jsptagref.databindable true
149      * @jsptagref.attributesyntaxvalue <i>string_targetScope</i>
150      * @netui:attribute required="false" rtexprvalue="true"
151      * description="The target scope in which the associated action's page flow resides"
152      */

153     public void setTargetScope(String JavaDoc targetScope)
154     {
155         _targetScope = targetScope;
156     }
157
158     /**
159      * Sets the formSubmit indicator.
160      * @param formSubmit whether or not the enclosing Form should be submitted.
161      * @jsptagref.attributedescription Boolean. If <code>formSubmit</code> is set to true, and the &lt;netui:anchor> tag
162      * is within a &lt;netui:form> tag,
163      * then the form data will be submitted to the method named in the
164      * &lt;netui:form> tag's <code>action</code> attribute.
165      * @jsptagref.databindable false
166      * @jsptagref.attributesyntaxvalue <i>boolean_formSubmit</i>
167      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
168      * description="If formSubmit is set to true, and the <netui:anchor> tag
169      * is within a <netui:form> tag,
170      * then the form data will be submitted to the method named in the
171      * <netui:form> tag's action attribute."
172      */

173     public void setFormSubmit(boolean formSubmit)
174     {
175         _formSubmit = formSubmit;
176     }
177
178     /**
179      * Sets the popup indicator.
180      * @param popup whether or not the anchor should open a popup window.
181      * @jsptagref.attributedescription Boolean. If <code>popup</code> is set to true,
182      * the anchor will open a popup window.
183      * @jsptagref.databindable true
184      * @jsptagref.attributesyntaxvalue <i>boolean_popup</i>
185      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
186      * description="If popup is set to true, the anchor will open a popup window.
187      */

188     public void setPopup(boolean popup)
189     {
190         _popupSupport = (popup ? new PopupSupport() : null);
191     }
192
193
194     /**
195      * When true, this anchor will disable itself after being clicked.
196      * @param disableSecondClick when true, this anchor will disable itself after being clicked.
197      * @jsptagref.attributedescription Boolean. If <code>disableSecondClick</code> is set to true,
198      * the anchor will disable itself after being clicked.
199      * @jsptagref.databindable true
200      * @jsptagref.attributesyntaxvalue <i>boolean_disableSecondClick</i>
201      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
202      * description="When true, this anchor will disable itself after being clicked."
203      */

204     public void setDisableSecondClick(boolean disableSecondClick)
205     {
206         _disableSecondClick = disableSecondClick;
207     }
208
209
210     /**
211      * Sets the tabIndex of the rendered html tag.
212      * @param tabindex the tab index.
213      * @jsptagref.attributedescription The tabIndex of the rendered HTML tag. This attribute determines the position of the
214      * rendered HTML tag in the sequence of tags that the user may advance through by pressing the TAB key.
215      * @jsptagref.databindable false
216      * @jsptagref.attributesyntaxvalue <i>string_tabIndex</i>
217      * @netui:attribute required="false" rtexprvalue="true" type="int"
218      * description="The tabIndex of the rendered HTML tag. This attribute determines the position of the
219      * rendered HTML tag in the sequence of tags that the user may advance through by pressing the TAB key."
220      */

221     public void setTabindex(int tabindex)
222     {
223         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TABINDEX, Integer.toString(tabindex));
224     }
225
226
227     /**
228      * Sets the accessKey attribute value. This should key value of the
229      * keyboard navigation key. It is recommended not to use the following
230      * values because there are often used by browsers <code>A, C, E, F, G,
231      * H, V, left arrow, and right arrow</code>.
232      * @param accessKey the accessKey value.
233      * @jsptagref.attributedescription The keyboard navigation key for the element.
234      * The following values are not recommended because they
235      * are often used by browsers: <code>A, C, E, F, G,
236      * H, V, left arrow, and right arrow</code>
237      * @jsptagref.databindable false
238      * @jsptagref.attributesyntaxvalue <i>string_accessKey</i>
239      * @netui:attribute required="false" rtexprvalue="true" type="char"
240      * description=" The keyboard navigation key for the element.
241      * The following values are not recommended because they
242      * are often used by browsers: A, C, E, F, G,
243      * H, V, left arrow, and right arrow."
244      */

245     public void setAccessKey(char accessKey)
246     {
247         if (accessKey == 0x00)
248             return;
249         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ACCESSKEY, Character.toString(accessKey));
250     }
251
252     /**
253      * Sets the onBlur javascript event.
254      * @param onblur the onBlur event.
255      * @jsptagref.attributedescription The onBlur JavaScript event.
256      * @jsptagref.databindable false
257      * @jsptagref.attributesyntaxvalue <i>string_onBlur</i>
258      * @netui:attribute required="false" rtexprvalue="true"
259      * description="The onBlur JavaScript event."
260      */

261     public void setOnBlur(String JavaDoc onblur)
262     {
263         _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONBLUR, onblur);
264     }
265
266     /**
267      * Sets the onFocus javascript event.
268      * @param onfocus the onFocus event.
269      * @jsptagref.attributedescription The onFocus JavaScript event.
270      * @jsptagref.databindable false
271      * @jsptagref.attributesyntaxvalue <i>string_onFocus</i>
272      * @netui:attribute required="false" rtexprvalue="true"
273      * description="The onFocus JavaScript event."
274      */

275     public void setOnFocus(String JavaDoc onfocus)
276     {
277         _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONFOCUS, onfocus);
278     }
279
280     //**************************** Helper Routines *********************************************
281

282     /**
283      * Adds a URL parameter to the generated hyperlink.
284      * @param name the name of the parameter to be added.
285      * @param value the value of the parameter to be added (a String or String[]).
286      * @param facet
287      */

288     public void addParameter(String JavaDoc name, Object JavaDoc value, String JavaDoc facet) throws JspException JavaDoc
289     {
290         assert(name != null) : "Parameter 'name' must not be null";
291
292         if (_params == null) {
293             _params = new HashMap JavaDoc();
294         }
295         ParamHelper.addParam(_params, name, value);
296     }
297
298     /**
299      * This method will create the &lt;a> portion of an anchor. It is called by subclasses, for example, the
300      * <code>ImageAnchor</code> relies on this code to generate the &lt;a>.
301      * @param scriptRef a <code>ByRef&lt;String></code> that will contain any JavaScript that may need to be added
302      * to the generated HTML response.
303      * @return a boolean value indicating if an error occur creating the anchor.
304      * @throws JspException
305      */

306     protected final boolean createAnchorBeginTag(HttpServletRequest JavaDoc request, ByRef scriptRef,
307                                                  TagRenderingBase trb, AbstractRenderAppender writer, String JavaDoc requiredAttrs)
308             throws JspException JavaDoc
309     {
310         int have = 0;
311         String JavaDoc formAction = null;
312         String JavaDoc idScript = null;
313
314         if (_formSubmit)
315             _form = getNearestForm();
316
317         ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
318
319         // check the parameters that the user provided
320
if (_href != null) have++;
321         if (_action != null) have++;
322         if (_clientAction != null) have++;
323         if (_linkName != null) have++;
324
325         String JavaDoc tagId = getTagId();
326
327         // if only the _linkName or _tagId is set then we are creating the name attribute only.
328
if (have == 0 && !_formSubmit && tagId != null) {
329             return createNameAnchor(request, trb);
330         }
331
332         // if the anchor is submitting a consider this a submit level problem
333
// set the action to the form action.
334
if (_formSubmit == true) {
335             formAction = getFormAction();
336             if ((formAction != null) && (have == 0)) {
337                 have++;
338             }
339             if (_action == null) {
340                 _action = formAction;
341                 _location = getFormLocation();
342             }
343         }
344
345         // if we have not specified a destination or we've specified too many
346
// then we need to report an error.
347
if (have == 0 || have > 1) {
348             String JavaDoc s = Bundle.getString("Tags_Anchor_InvalidAnchorURI",
349                     new Object JavaDoc[]{getTagName(), requiredAttrs});
350             registerTagError(s, null);
351             return false;
352         }
353
354         if (_linkName != null) {
355             return createPageAnchor(request, trb);
356         }
357
358         if (_action != null) {
359             // report that action is not an action
360
if (!PageFlowTagUtils.isAction(request, _action)) {
361                 String JavaDoc s = null;
362                 if (_action.equals("")) {
363                     s = Bundle.getString("Tags_NullBadAction", null);
364                 }
365                 else {
366                     s = Bundle.getString("Tags_BadAction", _action);
367                 }
368                 registerTagError(s, null);
369             }
370             else {
371                 //
372
// If the action we're submitting to is checking for double-submits, save a token in the session.
373
// This will be written out as a param (below), and will be checked in PageFlowRequestProcessor.
374
//
375
String JavaDoc token = PageFlowTagUtils.getToken(request, _action);
376                 if (token != null) {
377                     addParamInternal(Constants.TOKEN_KEY, token);
378                 }
379             }
380         }
381         
382         // we assume that tagId will over have override id if both
383
// are defined.
384
if (tagId != null) {
385             _state.id = tagId;
386             idScript = renderNameAndId(request, _state, null);
387         }
388
389         // Special case for name anchors
390
if (_clientAction != null) {
391             _state.href = "";
392         }
393         else {
394             // Add the scope-ID parameter, if the targetScope attribute is present.
395
if (_targetScope != null) {
396                 addParamInternal(ScopedServletUtils.SCOPE_ID_PARAM, _targetScope);
397             }
398
399             if (_popupSupport != null) {
400                 _popupSupport.addParams(this, request);
401             }
402             
403             // Generate the opening anchor element
404
String JavaDoc uri = null;
405             try {
406                 if (_action != null) {
407                     uri = PageFlowTagUtils.rewriteActionURL(pageContext, _action, _params, _location);
408                 }
409                 else if (_href != null) {
410                     uri = PageFlowTagUtils.rewriteHrefURL(pageContext, _href, _params, _location);
411                 }
412             }
413             catch (URISyntaxException JavaDoc e) {
414                 // report the error...
415
logger.error(Bundle.getString("Tags_URISyntaxException"));
416                 String JavaDoc s = Bundle.getString("Tags_Anchor_URLException",
417                         new Object JavaDoc[]{e.getMessage()});
418                 registerTagError(s, e);
419             }
420
421             if (uri == null) {
422                 if (hasErrors())
423                     return false;
424             }
425             else {
426                 HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) pageContext.getResponse();
427                 _state.href = response.encodeURL(uri);
428             }
429         }
430
431         // We need to combine the onclick features
432
IScriptReporter sr = getScriptReporter();
433         if (_clientAction != null && srs.isFeatureWritten(CoreScriptFeature.DYNAMIC_INIT)) {
434             //@todo: we need to support onclick chaining here also...
435
String JavaDoc action = HtmlUtils.escapeEscapes(_clientAction);
436             String JavaDoc entry = ScriptRequestState.getString("netuiAction",
437                     new Object JavaDoc[]{action});
438             _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, entry);
439             // Jira 299
440
//_state.onClick = entry;
441
}
442
443         // if the user overrides the onclick we will ignore this
444
String JavaDoc onclick = _state.getAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK);
445         if (onclick == null) {
446             if (_formSubmit && formAction != null) {
447                 String JavaDoc realFormName = getFormId();
448                 String JavaDoc key = (_disableSecondClick ? "anchorDisableAndSubmitFormAction" : "anchorFormSubmitAction");
449                 String JavaDoc entry = ScriptRequestState.getString(key, new Object JavaDoc[]{realFormName, _state.href});
450                 _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, entry);
451                 // Jira 299
452
//_state.onClick = ScriptRequestState.getString("anchorFormSubmitAction",
453
// new Object[]{realFormName, _state.href});
454
if (_form != null)
455                     _form.insureRealId();
456             }
457             else if (_disableSecondClick) {
458                 String JavaDoc entry = ScriptRequestState.getString("anchorDisableAction", null);
459                 _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, entry);
460             }
461             else if (_popupSupport != null) {
462                 _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, _popupSupport.getOnClick(request,_state.href));
463                 // Jira 299
464
//_state.onClick = _popupSupport.getOnClick(_state.href);
465
}
466         }
467
468         if (hasErrors())
469             return false;
470
471         trb.doStartTag(writer, _state);
472
473         // Emit javascript if this anchor needs to sumbit the form or open a popup window
474
if (_formSubmit && formAction != null || idScript != null || _popupSupport != null) {
475             InternalStringBuilder script = new InternalStringBuilder(32);
476             StringBuilderRenderAppender scriptWriter = new StringBuilderRenderAppender(script);
477
478             if (_formSubmit && formAction != null)
479                 srs.writeFeature(sr, scriptWriter, CoreScriptFeature.ANCHOR_SUBMIT, true, false,
480                         null);
481             if (_popupSupport != null)
482                 _popupSupport.writeScript(request, srs, getScriptReporter(), scriptWriter);
483             if (idScript != null)
484                 scriptWriter.append(idScript);
485             scriptRef.setRef(script.toString());
486         }
487
488         // create the javaScript
489
return true;
490     }
491
492     private void addParamInternal(String JavaDoc paramName, String JavaDoc paramVal)
493     {
494         if (_params == null) {
495             _params = new HashMap JavaDoc();
496         }
497         _params.put(paramName, paramVal);
498     }
499
500     /**
501      * @param req
502      * @param trb
503      * @return
504      */

505     private boolean createNameAnchor(ServletRequest JavaDoc req, TagRenderingBase trb)
506     {
507         assert(_state.id != null) : "tagId must not be nulll";
508
509         WriteRenderAppender writer = new WriteRenderAppender(pageContext);
510
511         // the tagId must be qualified and we need to output the lookup methods
512
// @todo: need to output the Script?
513
// @todo: I don't believe that this works. The id is not encoded correctly
514
_state.id = getIdForTagId(_state.id);
515         String JavaDoc script = renderDefaultNameAndId((HttpServletRequest JavaDoc) req, _state, _state.id, null);
516
517         //set the name so legacy browsers can support this.
518
_state.name = _state.id;
519
520         // output the tag.
521
trb = TagRenderingBase.Factory.getRendering(TagRenderingBase.ANCHOR_TAG, req);
522         trb.doStartTag(writer, _state);
523         return !hasErrors();
524     }
525
526     /**
527      * This method will output an anchor with a fragment identifier. This should
528      * be a valid ID within the document. If the name begins with the "#" we will
529      * not qualify the set link name. If the name doesn't begin with #, then we
530      * will qualify it into the current scope container.
531      * @param req The servlet request.
532      * @param trb The TagRenderer that will output the link
533      * @return
534      */

535     private boolean createPageAnchor(ServletRequest JavaDoc req, TagRenderingBase trb)
536     {
537         // create the fragment identifier. If the _linkName starts with
538
// '#' then we treat it as if it was fully qualified. Otherwise we
539
// need to qualify it before we add the '#'.
540
_linkName = _linkName.trim();
541         if (_linkName.charAt(0) != '#') {
542             _state.href = "#" + getIdForTagId(_linkName);
543         }
544         else {
545             _state.href = _linkName;
546         }
547
548         // if the tagId was set then rewrite it and output it.
549
if (_state.id != null) {
550             //_state.id = getIdForTagId(_state.id);
551
_state.name = _state.id;
552             renderNameAndId((HttpServletRequest JavaDoc) req, _state,null);
553             //renderDefaultNameAndId((HttpServletRequest) req, _state, _state.id, _state.id);
554
}
555
556         // write out the tag.
557
WriteRenderAppender writer = new WriteRenderAppender(pageContext);
558         trb = TagRenderingBase.Factory.getRendering(TagRenderingBase.ANCHOR_TAG, req);
559         trb.doStartTag(writer, _state);
560         return !hasErrors();
561     }
562
563     /**
564      * Return the action attribute for the nearest form.
565      * @return The action attribute of the enclosing form
566      */

567     private String JavaDoc getFormAction()
568     {
569         if (_form != null)
570             return _form.getAction();
571         return null;
572     }
573
574     private String JavaDoc getFormLocation()
575     {
576         if (_form != null)
577             return _form.getLocation();
578         return null;
579     }
580
581     /**
582      * This will get the real name of the form. This is set in the
583      * id attribute.
584      * @return The String real name of the containing form.
585      */

586     private String JavaDoc getFormId()
587     {
588         if (_form != null) {
589             return _form.getRealFormId();
590         }
591         return null;
592     }
593
594     /**
595      * Release any acquired resources.
596      */

597     protected void localRelease()
598     {
599         super.localRelease();
600
601         _state.clear();
602         _linkName = null;
603         _clientAction = null;
604
605         _action = null;
606         _href = null;
607         _targetScope = null;
608         _location = null;
609         _params = null;
610         _form = null;
611         _formSubmit = false;
612         _popupSupport = null;
613         _disableSecondClick = false;
614     }
615
616     public PopupSupport getPopupSupport()
617     {
618         return _popupSupport;
619     }
620 }
621
Popular Tags