I am still trying to find the best place to add support for Java portlets to Valuelist.
Basically the spec says that one should not encode URLs in a portlet without using the portlet API. The reason being that different portals may encode their URLs in incompatible ways. The spec doesn't tell you how to encode, but rather provides an API that is implemented by the vendor. (I can make it work without the API, but URL parameters would not be properly namespaced and could cause improper functioning of ValueList)
JSR168 support will add a new dependency to ValueList, the portlet API jar. The DisplayProvider interface doesn't allow me a clean way of getting to the portlet response object that is needed to encode ValueList's parameters. All other objects that need to be modified are tags and I can get what I need.
I was toying with storing the HttpRequest object in the TableInfo Object for easy access or adding an overloaded method to the DisplayProvider Interface that would allow me to pass the HTTPRequest Object from the tag code that calls getHeaderLabel(). Your other implementations of the DisplayProvider would need to implement the new method.
OR....
We could abstract all URL encoding tasks into specialized classes (one for regular webapps and an other for portlets) When ValueListSpace is initialized, we could check if the portlet response object is present. If it is not, we are not running in a portlet and then setup the normal encoding object, if it does exist, then use the portlet encoder. An other option would be to pass a flag as a tag parameter specifying the encoder to use...
This is your baby so I will let you decide if and how you would like to implement this. I can then work out the code within your parameters.
Regards,
Keith
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think adding a parameter to the DisplayProvider will allow the most flexability going forward. Also its the simplest solution. I do not know of anyone actually implementing thier own DisplayProvider, so we may be able to change this interface without upsetting anyone.
The DisplayProvider needs to be thread safe, so we will have to add the aditional parameter to all methods that may need it.
Might as well add the pageContext to all methods?
Does this sound right?
I am open to discussion if you have any conserns.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I will modify the interface and any implementers of DisplayProvider to accept the pageContext as a parameter. I will also add a param to the tag to pass a portlet flag. I think we are on the same page.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
>>I will also add a param to the tag to pass a portlet flag
If your changes are contained in a DisplayProvider, what will this flag do? Aren't you creating a ProtletHtmlDisplayProvider, or am I missing something?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I don't think I need the tag param... my mistake. I wasn't going to create a new provider. I was simply going to check if the portlet objects were present in the pageContext and encode appropriately.
If you would prefer that I create a new DisplayProvider do I also need to create new portlet row, header, filter, export and paging objects to keep my changes totally separate? You know what I mean here, new implementations where the encoding needs to be changed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
1) I don't want to require the dependicy of portlet.jar, unless you are using that functionaly.
2) It would be nice to tell the valuelist tags to to encode in configuration, not runtime... maybe...
I forgot about al the other tags that have to encode. Maybe an encoder interface is the way to go! If so the ValueListConfigBean is a good place for it...
Your thoughts?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I need to think about this some more, the encoding interface is the best solution to the encoding problem. Since I know nothing about spring, how would I specify an encoder class in the application context and have it loaded and stored in the ValueListConfigBean?
This would be a very simple solution as the user just needs to config an encoder class and off you go!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I now agree and see that the encoding interface is the best solution. It will affect all the taglibs, but it is needed to cleanly support portals.
I think something like <a href="http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/LinkEncoder.html">LinkEncoder</a> is the way to go. Will this interface meet your needs? Or do we need a pageContext on there as well?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I need to convert the other tags to use this new interface. But to support protals you should implement this interface, and not have to touch the taglibs :)
Paging should work now, I'll get sorting and the others in soon. Thanks for your help on this.
Are we on the same page still?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Almost there, in your top level 'root' tag you specifiy a 'base' URL to append to. With the portlets I don't need this (I think) can I get your new paging code (developer CVS access or email) so I can try it out?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I created a PortletLinkEncoder and so far everything appears to work. I have a few minor items to fix and I will forward the portlet encoder code to you.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It should work for all portals that support the Java Portlet specification (JSR-168). Just remember to leave the url attribute in the root tag set as url="".
I am using the Liferay portal with their Struts based portlet that isn't quite JSR168... so I have to find an elegant solution to pass a couple of extra parameters in the URL. I can't use your url attribute with the top level tag as the portlet API generates the URL.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I would make a special adapter named LiferayStrutsPortalLinkEncoder that extends the GenericPortalLinkEncoder. The LiferayStrutsPortalLinkEncoder could append the two additional parameters since it has a reference to tha pageContext.
Also, do we need a LinkDecoder also?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I got everything working with Liferay! Thanks for your help on this, it is greatly appreciated!
PorletLinkEncoder.java:
/**
* Copyright (c) 2003 held jointly by the individual authors.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; with out even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* > http://www.gnu.org/copyleft/lesser.html
* > http://www.opensource.org/licenses/lgpl-license.php
*/
package net.mlw.vlh.web.tag.support;
/**
* @author Matthew L. Wilson
* @version $Revision: 1.3 $ $Date: 2004/08/10 15:15:37 $
*/
public class PortletLinkEncoder implements LinkEncoder
{
/*** Returns an encoded String from the given parameters.
*
* @param pageContext The PageContext.
* @param parameters A Map containing all the parameters to encode.
* @param includedKeys The parameters to include. Includes all if null or empty.
* @param ignoredKeys The parameters to exclude. Excludes none if null or empty.
* @return An encoded String
*/
public String encode(PageContext pageContext, Map parameters, Collection includedKeys, Collection ignoredKeys) {
// This only applies to Liferay Struts portlets - remove if not using Liferay
url.setParameter("struts_action", (String)req.getAttribute("struts_action"));
for (Iterator iter = parameters.keySet().iterator(); iter.hasNext();)
{
String key = (String) iter.next();
if (includedKeys == null || includedKeys.isEmpty() || ignoredKeys.contains(key))
{
if (ignoredKeys == null || ignoredKeys.isEmpty() || !ignoredKeys.contains(key))
{
Object value = parameters.get(key);
if (value instanceof String[])
{
String[] values = (String[]) value;
url.setParameter(key, values);
}
else if (value instanceof String)
{
url.setParameter(key, (String)value);
}
else if (value != null)
{
url.setParameter(key, value.toString());
}
}
}
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return url.toString();
}
}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have a problem with portlet support in vlh:select tag. It looks for request parameter which appears to be lost as a portlet request parameter on render. (This happens in jetspeed2) As a result filters and the like don't get applied and the encoded links also don't get the request parameter. I think this may have something to do with the fact that according to jsr-168 spec attributes can't be assumed to propagate from action to render. I can't be sure this applies here but it may. I know for a fact that in liferay they do propagate request attributes but jetspeed2 doesn't. If anyone has any ideas let me know.
BTW: Sorry I'm doing so much posting but I am basically documenting the issues I am finding with hope that it can help someone later.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Matthew,
I am still trying to find the best place to add support for Java portlets to Valuelist.
Basically the spec says that one should not encode URLs in a portlet without using the portlet API. The reason being that different portals may encode their URLs in incompatible ways. The spec doesn't tell you how to encode, but rather provides an API that is implemented by the vendor. (I can make it work without the API, but URL parameters would not be properly namespaced and could cause improper functioning of ValueList)
JSR168 support will add a new dependency to ValueList, the portlet API jar. The DisplayProvider interface doesn't allow me a clean way of getting to the portlet response object that is needed to encode ValueList's parameters. All other objects that need to be modified are tags and I can get what I need.
I was toying with storing the HttpRequest object in the TableInfo Object for easy access or adding an overloaded method to the DisplayProvider Interface that would allow me to pass the HTTPRequest Object from the tag code that calls getHeaderLabel(). Your other implementations of the DisplayProvider would need to implement the new method.
OR....
We could abstract all URL encoding tasks into specialized classes (one for regular webapps and an other for portlets) When ValueListSpace is initialized, we could check if the portlet response object is present. If it is not, we are not running in a portlet and then setup the normal encoding object, if it does exist, then use the portlet encoder. An other option would be to pass a flag as a tag parameter specifying the encoder to use...
This is your baby so I will let you decide if and how you would like to implement this. I can then work out the code within your parameters.
Regards,
Keith
Hmmmm.
I think adding a parameter to the DisplayProvider will allow the most flexability going forward. Also its the simplest solution. I do not know of anyone actually implementing thier own DisplayProvider, so we may be able to change this interface without upsetting anyone.
The DisplayProvider needs to be thread safe, so we will have to add the aditional parameter to all methods that may need it.
Might as well add the pageContext to all methods?
Does this sound right?
I am open to discussion if you have any conserns.
I will modify the interface and any implementers of DisplayProvider to accept the pageContext as a parameter. I will also add a param to the tag to pass a portlet flag. I think we are on the same page.
>>I will also add a param to the tag to pass a portlet flag
If your changes are contained in a DisplayProvider, what will this flag do? Aren't you creating a ProtletHtmlDisplayProvider, or am I missing something?
I don't think I need the tag param... my mistake. I wasn't going to create a new provider. I was simply going to check if the portlet objects were present in the pageContext and encode appropriately.
If you would prefer that I create a new DisplayProvider do I also need to create new portlet row, header, filter, export and paging objects to keep my changes totally separate? You know what I mean here, new implementations where the encoding needs to be changed.
1) I don't want to require the dependicy of portlet.jar, unless you are using that functionaly.
2) It would be nice to tell the valuelist tags to to encode in configuration, not runtime... maybe...
I forgot about al the other tags that have to encode. Maybe an encoder interface is the way to go! If so the ValueListConfigBean is a good place for it...
Your thoughts?
I need to think about this some more, the encoding interface is the best solution to the encoding problem. Since I know nothing about spring, how would I specify an encoder class in the application context and have it loaded and stored in the ValueListConfigBean?
This would be a very simple solution as the user just needs to config an encoder class and off you go!
I now agree and see that the encoding interface is the best solution. It will affect all the taglibs, but it is needed to cleanly support portals.
I think something like <a href="http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/LinkEncoder.html">LinkEncoder</a> is the way to go. Will this interface meet your needs? Or do we need a pageContext on there as well?
I now agree and see that the encoding interface is the best solution. It will affect all the taglibs, but it is needed to cleanly support portals.
I think something like http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/LinkEncoder.html is the way to go. Will this interface meet your needs? Or do we need a pageContext on there as well?
I need a pageContext to get the javax.portlet.* objects
O.K. The http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/LinkEncoder.html now contains a pageContext parameter. I have modified the DefaultPagingTag to use the LinkEncoder. The LinkEncoder is specified in the standardJspApplicationContext.xml, it defaults to the http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/DefaultLinkEncoder.html.
I need to convert the other tags to use this new interface. But to support protals you should implement this interface, and not have to touch the taglibs :)
Paging should work now, I'll get sorting and the others in soon. Thanks for your help on this.
Are we on the same page still?
Almost there, in your top level 'root' tag you specifiy a 'base' URL to append to. With the portlets I don't need this (I think) can I get your new paging code (developer CVS access or email) so I can try it out?
You can get the code from Anonymous CVS Access.
This page instructs how: http://sourceforge.net/cvs/?group_id=109417
I will email you the new jar :)
Got the new code from CVS...
I created a PortletLinkEncoder and so far everything appears to work. I have a few minor items to fix and I will forward the portlet encoder code to you.
Great! This will work for all protals correct?
It should work for all portals that support the Java Portlet specification (JSR-168). Just remember to leave the url attribute in the root tag set as url="".
I am using the Liferay portal with their Struts based portlet that isn't quite JSR168... so I have to find an elegant solution to pass a couple of extra parameters in the URL. I can't use your url attribute with the top level tag as the portlet API generates the URL.
I would make a special adapter named LiferayStrutsPortalLinkEncoder that extends the GenericPortalLinkEncoder. The LiferayStrutsPortalLinkEncoder could append the two additional parameters since it has a reference to tha pageContext.
Also, do we need a LinkDecoder also?
I don't think we need a decoder...
I got everything working with Liferay! Thanks for your help on this, it is greatly appreciated!
PorletLinkEncoder.java:
/**
* Copyright (c) 2003 held jointly by the individual authors.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; with out even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* > http://www.gnu.org/copyleft/lesser.html
* > http://www.opensource.org/licenses/lgpl-license.php
*/
package net.mlw.vlh.web.tag.support;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.portlet.PortletURL;
import javax.portlet.RenderResponse;
import javax.servlet.ServletRequest;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
/**
* @author Matthew L. Wilson
* @version $Revision: 1.3 $ $Date: 2004/08/10 15:15:37 $
*/
public class PortletLinkEncoder implements LinkEncoder
{
/*** Returns an encoded String from the given parameters.
*
* @param pageContext The PageContext.
* @param parameters A Map containing all the parameters to encode.
* @param includedKeys The parameters to include. Includes all if null or empty.
* @param ignoredKeys The parameters to exclude. Excludes none if null or empty.
* @return An encoded String
*/
public String encode(PageContext pageContext, Map parameters, Collection includedKeys, Collection ignoredKeys) {
PortletURL url = null;
try
{
ServletRequest req = pageContext.getRequest();
RenderResponse renderResponse = (RenderResponse)req.getAttribute("javax.portlet.response");
url = renderResponse.createRenderURL();
// This only applies to Liferay Struts portlets - remove if not using Liferay
url.setParameter("struts_action", (String)req.getAttribute("struts_action"));
for (Iterator iter = parameters.keySet().iterator(); iter.hasNext();)
{
String key = (String) iter.next();
if (includedKeys == null || includedKeys.isEmpty() || ignoredKeys.contains(key))
{
if (ignoredKeys == null || ignoredKeys.isEmpty() || !ignoredKeys.contains(key))
{
Object value = parameters.get(key);
if (value instanceof String[])
{
String[] values = (String[]) value;
url.setParameter(key, values);
}
else if (value instanceof String)
{
url.setParameter(key, (String)value);
}
else if (value != null)
{
url.setParameter(key, value.toString());
}
}
}
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
return url.toString();
}
}
Very good. I will get this in the 0.1.6 release. I'll get you the release asap for your approval.
CVS is still behind... got the jar, Thanks!
I have checked in the following files:
http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/PortletLinkEncoder.html
http://valuelist.sourceforge.net/xref/net/mlw/vlh/web/tag/support/LiferayPortletLinkEncoder.html
You can download the current (8/17/2004) cvs head build here: http://valuelist.sourceforge.net/valuelist-0.1.6.jar
Let me know if this works for you.
Matthew,
Everything appears to functioning correctly! If I run into any other portlet issues in the future, I will forward any workarounds or fixes to you.
Keith
I have a problem with portlet support in vlh:select tag. It looks for request parameter which appears to be lost as a portlet request parameter on render. (This happens in jetspeed2) As a result filters and the like don't get applied and the encoded links also don't get the request parameter. I think this may have something to do with the fact that according to jsr-168 spec attributes can't be assumed to propagate from action to render. I can't be sure this applies here but it may. I know for a fact that in liferay they do propagate request attributes but jetspeed2 doesn't. If anyone has any ideas let me know.
BTW: Sorry I'm doing so much posting but I am basically documenting the issues I am finding with hope that it can help someone later.
I have not used portlets, but keidav is the expert. I wold try to contact them.
Also see https://sourceforge.net/forum/forum.php?thread_id=1267796&forum_id=375420 for the results of my test with Liferay