-
1. Re: Searchengine friendly links
gavin.king Nov 22, 2006 10:27 PM (in response to spambob)No, its not supported by JSF. You need to do URL rewriting (a servlet filter would work).
-
2. Re: Searchengine friendly links
spambob Nov 24, 2006 7:06 PM (in response to spambob)Hi Gavin,
now I wrote me a little filter which extracts request scoped variables from a URL and forwards to some target page.
I.e. from a URL "http://www.example.com/products/12345.xhtml" a request variable 'productId' with value '12345' is extracted and the request is forwarded to /showProduct.xhtml.
The product reference I use in showProduct.xhtml via EL is created by a @Factory annotated method that uses a 'productId' attribute of the same class to know which product to load.
This works fine when the productId is injected in the class with the @In annotation but not when I use the @RequestParameter annotation - which I would prefer because I'm not sure if the @In solution would be threadsafe - because the 'productId' is in the attribute map and not in the parameter map of the request. Further there's no method to add an additional parameter.
So the possible solutions I can think of are:
1. add a wrapper around every request in the filter - I don't like that because it would be quite an overhead just to set these parameters
2. use @In(scope=EVENT) - I'm not sure if there would be any impacts on performance / scalability
3. we get a @RequestAttribute annotation (like the @RequestParameter but for the attribute map of the request)
4. It is somehow possible to pass parameters to a factory method - i like that one but found no examples for it, is it possible?
So: how would you solve that and would there be any difference between 2nd and 3rd? -
3. Re: Searchengine friendly links
gavin.king Nov 24, 2006 9:19 PM (in response to spambob)Setting a request attribute is exactly the same as Contexts.getEventContext().set(...). There are no negative performance implications of that. I would go for that approach.
-
4. Re: Searchengine friendly links
spambob Nov 24, 2006 9:56 PM (in response to spambob)Thank you for your answer. I'm just not sure if I understood the concept of thread safety in Seam or when exactly stuff is in- & outjected.
So would a component like this:@Name("productService") @Scope(STATELESS) public class ProductServiceBean { @In private EntityManager em; @In private String productId; @Factory("product") public Product getProductById() { return em.find(Product.class, productId); } }
be thread safe ('productId' is my request attribute and 'product' is used to reference the product in the jsf page)? -
5. Re: Searchengine friendly links
gavin.king Nov 24, 2006 11:33 PM (in response to spambob)Of course. I really don't understand what you are fussing about here. Request state is by definition scoped to a single thread.
-
6. Re: Searchengine friendly links
norman.richards Nov 25, 2006 11:35 AM (in response to spambob)I really think this is a feature that a lot of people want. I'd like to be able to simply write something like /products/1234, or at worst /products.seam/1234.
What do you think of something to complement @RequestParameter? Maybe @UrlParameter that takes a regexp to match against the end of the URL?
@UrlParamter("/([0-9]*)$")
Long productId; -
7. Re: Searchengine friendly links
spambob Nov 25, 2006 11:54 AM (in response to spambob)Now I don't understand it too - a classic case of 'I don't see the forest cause of all the trees'. Thanks for your clarification & patience!
EDIT: i just saw normans post while editing mine - so i post my solution, feel free to integrate / modify it:
The filterclass:public class UrlRewriteFilter implements Filter { private FilterConfig filterConfig; private String[] variableNames; private String[] delimiters; private String targetUrl; public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; this.targetUrl = filterConfig.getInitParameter("target"); String pattern = "#\\{[^}]+}"; String configString = filterConfig.getInitParameter("pattern"); Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(configString); List<String> variableNames = new ArrayList<String>(); while(m.find()) { variableNames.add(configString.substring(m.start()+2, m.end()-1)); } this.variableNames = variableNames.toArray(new String[variableNames.size()]); this.delimiters = configString.split(pattern); } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; String request = httpRequest.getRequestURI(); int start; int end = request.indexOf(delimiters[0]); for(int i=0; i<variableNames.length; i++) { start = end + delimiters[ i ].length(); end = request.indexOf(delimiters[i+1], start); servletRequest.setAttribute(variableNames, request.substring(start, end)); } filterConfig.getServletContext().getRequestDispatcher(targetUrl).forward(servletRequest, servletResponse); } public void destroy() {; }
The config in web.xml:<filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class>com.example.UrlRewriteFilter</filter-class> <init-param> <param-name>pattern</param-name> <param-value>/products/#{categoryId}/#{productId}.xhtml</param-value> </init-param> <init-param> <param-name>target</param-name> <param-value>/showProduct.xhtml</param-value> </init-param> </filter> <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/products/*</url-pattern> </filter-mapping>
The bean that loads the product is the one above and the jsf is trivial.
With a configuration like this a URL likehttp://www.example.com/products/cars/123.xhtml
is mapped tohttp://www.example.com/showProducts.xhtml?categoryId=cars&productId=123
Note that the request variables are attributes not parameteres therefore @RequestParameter doesn't work. -
8. Re: Searchengine friendly links
spambob Nov 25, 2006 12:13 PM (in response to spambob)The board somehow screwed my code. The line
servletRequest.setAttribute(variableNames, request.substring(start, end));
should beservletRequest.setAttribute(variableNames[ i ], request.substring(start, end));
-
9. Re: Searchengine friendly links
gavin.king Nov 25, 2006 2:42 PM (in response to spambob)Norman, I think that's very reasonable. I would see this as an extension of both @RequestParameter and page parameters. So basically we (Seam) would provide a servlet filter that could do the rewriting for you, and extract some extra strings from the end of the URL. Right?