You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by "Preston L. Bannister" <pr...@bannister.us> on 2005/05/12 19:51:44 UTC

Re: How to add a qurey parameter to all generated links?

Preston L. Bannister wrote:
>>>> I have a web application (to be implemented using Tapestry) that 
>>>> will be called from another web application with a single 
>>>> parameter.  All the generated links within the application should 
>>>> encode this parameter into the link (most likely in the query 
>>>> string?).  I could push the parameter into the session, but I want 
>>>> the user to be able to bookmark the link and capture the parameter.
>>>>
>>>> For whatever reason it is not clear to me where this should be 
>>>> hooked into the Tapestry framework...

Finally got back(!) to this particular problem, and after far too much 
mucking around in the code, came up with an answer of sorts.  What seems 
to do the trick is to override the ILink implementations to change the 
render used for links.

For example the re-done PageLink class looks like:
--------------------------------------------------------------------
public abstract class PageLink extends AbstractLinkComponent {

     public ILink getLink(IRequestCycle cycle) {
         String targetPage = getTargetPage();
         INamespace namespace = getTargetNamespace();
         String parameter = ((null == namespace) ? targetPage : 
namespace.constructQualifiedName(targetPage));
         IEngineService service = 
cycle.getEngine().getService(Tapestry.PAGE_SERVICE);
         ILink o = service.getLink(cycle,this,new String[] { parameter });
         return o;
     }
     protected void finishLoad() {
         setRenderer(DefaultLinkRenderer.SHARED_INSTANCE);
     }
     public abstract String getTargetPage();
     public abstract INamespace getTargetNamespace();
}
--------------------------------------------------------------------

Note the call to setRender() in finishLoad(), and that the class 
DefaultLinkRenderer is in fact from an application (not from the 
Tapestry library).

The added parameter is built into the link by the DefaultLinkRenderer.
--------------------------------------------------------------------
public class DefaultLinkRenderer implements ILinkRenderer {

     // A shared instance used as a default for any link that doesn't 
explicitly override.
     public static final ILinkRenderer SHARED_INSTANCE = new 
DefaultLinkRenderer();

     public void renderLink(IMarkupWriter writer, IRequestCycle cycle, 
ILinkComponent linkComponent) {
         if (null != 
cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME)) {
             throw new ApplicationRuntimeException(
 
Tapestry.getMessage("AbstractLinkComponent.no-nesting"),
                     linkComponent,
                     null,
                     null
                     );
         }
 
cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME,linkComponent);
         if (linkComponent.isDisabled()) {
             if (getHasBody()) {
                 linkComponent.renderBody(writer,cycle);
             }
         } else {
             ILink l = linkComponent.getLink(cycle);
             String url = l.getURL(linkComponent.getAnchor(),true);
             String id = cycle.getRequestContext().getParameter("id");
             url = url + "&id=" + id;
             if (getHasBody()) {
                 writer.begin(getElement());
                 writer.attribute(getUrlAttribute(),url);
                 beforeBodyRender(writer,cycle,linkComponent);
                 IMarkupWriter wrappedWriter = writer.getNestedWriter();
                 linkComponent.renderBody(wrappedWriter,cycle);
                 afterBodyRender(writer,cycle,linkComponent);
                 linkComponent.renderAdditionalAttributes(writer,cycle);
                 wrappedWriter.close();
                 writer.end();
             } else {
                 writer.beginEmpty(getElement());
                 writer.attribute(getUrlAttribute(),url);
                 beforeBodyRender(writer,cycle,linkComponent);
                 afterBodyRender(writer,cycle,linkComponent);
                 linkComponent.renderAdditionalAttributes(writer,cycle);
                 writer.closeTag();
             }
         }
         cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
     }

     protected String constructURL(ILink link, String anchor, 
IRequestCycle cycle) {
         return link.getURL(anchor,true);
     }
     protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle 
cycle, ILinkComponent link) {
         // do nothing
     }
     protected void afterBodyRender(IMarkupWriter writer, IRequestCycle 
cycle, ILinkComponent link) {
         // do nothing
     }
     protected String getElement() {
         return "a";
     }
     protected String getUrlAttribute() {
         return "href";
     }
     protected boolean getHasBody() {
         return true;
     }
}
--------------------------------------------------------------------

Doubtless the above is somewhat mangled by line wrap.  This would better 
be sent in HTML format, but though the rationale faded away long ago, 
the ban remains.

Whether the above solution is particularly elegant is an entirely 
different question.  It seems that link generation should be more a 
top-level notion in the page generation model, perhaps.


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: How to add a qurey parameter to all generated links?

Posted by Howard Lewis Ship <hl...@gmail.com>.
In Tapestry 4.0, you could easily override the
tapestry.url.LinkFactory service for this purpose.

On 5/12/05, Robert Zeigler <ro...@scazdl.org> wrote:
> Question: why not just specify your custom renderer to the page link
> component?
> 
> <a jwcid="@PageLink" page="somePage"
> renderer="ognl:defaultLinkRenderer">Some Link</a>
> 
> You could wrap the page link component in your own custom component,
> specify the renderer in your custom component, and then just you your
> AppPageLink (or whatever you decide to call it) throughout your
> application. :)
> 
> Robert
> 
> Preston L. Bannister wrote:
> > Preston L. Bannister wrote:
> >
> >>>>> I have a web application (to be implemented using Tapestry) that
> >>>>> will be called from another web application with a single
> >>>>> parameter.  All the generated links within the application should
> >>>>> encode this parameter into the link (most likely in the query
> >>>>> string?).  I could push the parameter into the session, but I want
> >>>>> the user to be able to bookmark the link and capture the parameter.
> >>>>>
> >>>>> For whatever reason it is not clear to me where this should be
> >>>>> hooked into the Tapestry framework...
> >
> >
> > Finally got back(!) to this particular problem, and after far too much
> > mucking around in the code, came up with an answer of sorts.  What seems
> > to do the trick is to override the ILink implementations to change the
> > render used for links.
> >
> > For example the re-done PageLink class looks like:
> > --------------------------------------------------------------------
> > public abstract class PageLink extends AbstractLinkComponent {
> >
> >     public ILink getLink(IRequestCycle cycle) {
> >         String targetPage = getTargetPage();
> >         INamespace namespace = getTargetNamespace();
> >         String parameter = ((null == namespace) ? targetPage :
> > namespace.constructQualifiedName(targetPage));
> >         IEngineService service =
> > cycle.getEngine().getService(Tapestry.PAGE_SERVICE);
> >         ILink o = service.getLink(cycle,this,new String[] { parameter });
> >         return o;
> >     }
> >     protected void finishLoad() {
> >         setRenderer(DefaultLinkRenderer.SHARED_INSTANCE);
> >     }
> >     public abstract String getTargetPage();
> >     public abstract INamespace getTargetNamespace();
> > }
> > --------------------------------------------------------------------
> >
> > Note the call to setRender() in finishLoad(), and that the class
> > DefaultLinkRenderer is in fact from an application (not from the
> > Tapestry library).
> >
> > The added parameter is built into the link by the DefaultLinkRenderer.
> > --------------------------------------------------------------------
> > public class DefaultLinkRenderer implements ILinkRenderer {
> >
> >     // A shared instance used as a default for any link that doesn't
> > explicitly override.
> >     public static final ILinkRenderer SHARED_INSTANCE = new
> > DefaultLinkRenderer();
> >
> >     public void renderLink(IMarkupWriter writer, IRequestCycle cycle,
> > ILinkComponent linkComponent) {
> >         if (null !=
> > cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME)) {
> >             throw new ApplicationRuntimeException(
> >
> > Tapestry.getMessage("AbstractLinkComponent.no-nesting"),
> >                     linkComponent,
> >                     null,
> >                     null
> >                     );
> >         }
> >
> > cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME,linkComponent);
> >         if (linkComponent.isDisabled()) {
> >             if (getHasBody()) {
> >                 linkComponent.renderBody(writer,cycle);
> >             }
> >         } else {
> >             ILink l = linkComponent.getLink(cycle);
> >             String url = l.getURL(linkComponent.getAnchor(),true);
> >             String id = cycle.getRequestContext().getParameter("id");
> >             url = url + "&id=" + id;
> >             if (getHasBody()) {
> >                 writer.begin(getElement());
> >                 writer.attribute(getUrlAttribute(),url);
> >                 beforeBodyRender(writer,cycle,linkComponent);
> >                 IMarkupWriter wrappedWriter = writer.getNestedWriter();
> >                 linkComponent.renderBody(wrappedWriter,cycle);
> >                 afterBodyRender(writer,cycle,linkComponent);
> >                 linkComponent.renderAdditionalAttributes(writer,cycle);
> >                 wrappedWriter.close();
> >                 writer.end();
> >             } else {
> >                 writer.beginEmpty(getElement());
> >                 writer.attribute(getUrlAttribute(),url);
> >                 beforeBodyRender(writer,cycle,linkComponent);
> >                 afterBodyRender(writer,cycle,linkComponent);
> >                 linkComponent.renderAdditionalAttributes(writer,cycle);
> >                 writer.closeTag();
> >             }
> >         }
> >         cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
> >     }
> >
> >     protected String constructURL(ILink link, String anchor,
> > IRequestCycle cycle) {
> >         return link.getURL(anchor,true);
> >     }
> >     protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle
> > cycle, ILinkComponent link) {
> >         // do nothing
> >     }
> >     protected void afterBodyRender(IMarkupWriter writer, IRequestCycle
> > cycle, ILinkComponent link) {
> >         // do nothing
> >     }
> >     protected String getElement() {
> >         return "a";
> >     }
> >     protected String getUrlAttribute() {
> >         return "href";
> >     }
> >     protected boolean getHasBody() {
> >         return true;
> >     }
> > }
> > --------------------------------------------------------------------
> >
> > Doubtless the above is somewhat mangled by line wrap.  This would better
> > be sent in HTML format, but though the rationale faded away long ago,
> > the ban remains.
> >
> > Whether the above solution is particularly elegant is an entirely
> > different question.  It seems that link generation should be more a
> > top-level notion in the page generation model, perhaps.
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
> 


-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: How to add a qurey parameter to all generated links?

Posted by Robert Zeigler <ro...@scazdl.org>.
That's why you make your custom component. Or, in tapestry-4.0, you can
do as Howard suggested. It would be all of five minutes work (probably
closer to 2 or less, with spindle) to create a component that wraps
PageLink and sets the renderer once i that component; you can then
use your custom component throughout your app /instead/ of page link.
Seems a bit simpler an approach than subclassing to return the
appropriate link renderer. But, to each his own. :)

Robert

Preston L. Bannister wrote:
> Specifying a renderer for each PageLink in the HTML would be tedious,
> especially given all the links within this application *must* encode
> this additional parameter.
> 
> Perhaps I do not understand your meaning.
> 
> Robert Zeigler wrote:
> 
>> Question: why not just specify your custom renderer to the page link
>> component?
>>
>> <a jwcid="@PageLink" page="somePage"
>> renderer="ognl:defaultLinkRenderer">Some Link</a>
>>
>> You could wrap the page link component in your own custom component,
>> specify the renderer in your custom component, and then just you your
>> AppPageLink (or whatever you decide to call it) throughout your
>> application. :)
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: How to add a qurey parameter to all generated links?

Posted by "Preston L. Bannister" <pr...@bannister.us>.
Specifying a renderer for each PageLink in the HTML would be tedious, 
especially given all the links within this application *must* encode 
this additional parameter.

Perhaps I do not understand your meaning.

Robert Zeigler wrote:
> Question: why not just specify your custom renderer to the page link
> component?
> 
> <a jwcid="@PageLink" page="somePage"
> renderer="ognl:defaultLinkRenderer">Some Link</a>
> 
> You could wrap the page link component in your own custom component,
> specify the renderer in your custom component, and then just you your
> AppPageLink (or whatever you decide to call it) throughout your
> application. :)


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: How to add a qurey parameter to all generated links?

Posted by Robert Zeigler <ro...@scazdl.org>.
Question: why not just specify your custom renderer to the page link
component?

<a jwcid="@PageLink" page="somePage"
renderer="ognl:defaultLinkRenderer">Some Link</a>

You could wrap the page link component in your own custom component,
specify the renderer in your custom component, and then just you your
AppPageLink (or whatever you decide to call it) throughout your
application. :)

Robert

Preston L. Bannister wrote:
> Preston L. Bannister wrote:
> 
>>>>> I have a web application (to be implemented using Tapestry) that
>>>>> will be called from another web application with a single
>>>>> parameter.  All the generated links within the application should
>>>>> encode this parameter into the link (most likely in the query
>>>>> string?).  I could push the parameter into the session, but I want
>>>>> the user to be able to bookmark the link and capture the parameter.
>>>>>
>>>>> For whatever reason it is not clear to me where this should be
>>>>> hooked into the Tapestry framework...
> 
> 
> Finally got back(!) to this particular problem, and after far too much
> mucking around in the code, came up with an answer of sorts.  What seems
> to do the trick is to override the ILink implementations to change the
> render used for links.
> 
> For example the re-done PageLink class looks like:
> --------------------------------------------------------------------
> public abstract class PageLink extends AbstractLinkComponent {
> 
>     public ILink getLink(IRequestCycle cycle) {
>         String targetPage = getTargetPage();
>         INamespace namespace = getTargetNamespace();
>         String parameter = ((null == namespace) ? targetPage :
> namespace.constructQualifiedName(targetPage));
>         IEngineService service =
> cycle.getEngine().getService(Tapestry.PAGE_SERVICE);
>         ILink o = service.getLink(cycle,this,new String[] { parameter });
>         return o;
>     }
>     protected void finishLoad() {
>         setRenderer(DefaultLinkRenderer.SHARED_INSTANCE);
>     }
>     public abstract String getTargetPage();
>     public abstract INamespace getTargetNamespace();
> }
> --------------------------------------------------------------------
> 
> Note the call to setRender() in finishLoad(), and that the class
> DefaultLinkRenderer is in fact from an application (not from the
> Tapestry library).
> 
> The added parameter is built into the link by the DefaultLinkRenderer.
> --------------------------------------------------------------------
> public class DefaultLinkRenderer implements ILinkRenderer {
> 
>     // A shared instance used as a default for any link that doesn't
> explicitly override.
>     public static final ILinkRenderer SHARED_INSTANCE = new
> DefaultLinkRenderer();
> 
>     public void renderLink(IMarkupWriter writer, IRequestCycle cycle,
> ILinkComponent linkComponent) {
>         if (null !=
> cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME)) {
>             throw new ApplicationRuntimeException(
> 
> Tapestry.getMessage("AbstractLinkComponent.no-nesting"),
>                     linkComponent,
>                     null,
>                     null
>                     );
>         }
> 
> cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME,linkComponent);
>         if (linkComponent.isDisabled()) {
>             if (getHasBody()) {
>                 linkComponent.renderBody(writer,cycle);
>             }
>         } else {
>             ILink l = linkComponent.getLink(cycle);
>             String url = l.getURL(linkComponent.getAnchor(),true);
>             String id = cycle.getRequestContext().getParameter("id");
>             url = url + "&id=" + id;
>             if (getHasBody()) {
>                 writer.begin(getElement());
>                 writer.attribute(getUrlAttribute(),url);
>                 beforeBodyRender(writer,cycle,linkComponent);
>                 IMarkupWriter wrappedWriter = writer.getNestedWriter();
>                 linkComponent.renderBody(wrappedWriter,cycle);
>                 afterBodyRender(writer,cycle,linkComponent);
>                 linkComponent.renderAdditionalAttributes(writer,cycle);
>                 wrappedWriter.close();
>                 writer.end();
>             } else {
>                 writer.beginEmpty(getElement());
>                 writer.attribute(getUrlAttribute(),url);
>                 beforeBodyRender(writer,cycle,linkComponent);
>                 afterBodyRender(writer,cycle,linkComponent);
>                 linkComponent.renderAdditionalAttributes(writer,cycle);
>                 writer.closeTag();
>             }
>         }
>         cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
>     }
> 
>     protected String constructURL(ILink link, String anchor,
> IRequestCycle cycle) {
>         return link.getURL(anchor,true);
>     }
>     protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle
> cycle, ILinkComponent link) {
>         // do nothing
>     }
>     protected void afterBodyRender(IMarkupWriter writer, IRequestCycle
> cycle, ILinkComponent link) {
>         // do nothing
>     }
>     protected String getElement() {
>         return "a";
>     }
>     protected String getUrlAttribute() {
>         return "href";
>     }
>     protected boolean getHasBody() {
>         return true;
>     }
> }
> --------------------------------------------------------------------
> 
> Doubtless the above is somewhat mangled by line wrap.  This would better
> be sent in HTML format, but though the rationale faded away long ago,
> the ban remains.
> 
> Whether the above solution is particularly elegant is an entirely
> different question.  It seems that link generation should be more a
> top-level notion in the page generation model, perhaps.
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org