I have a question. It's possible create a rule to rewrite every request to put .jsf in the end?
Eg: Request: myapp/admin/mypage rewrite to myapp/admin/mypage.jsf
Thanks
I have a question. It's possible create a rule to rewrite every request to put .jsf in the end?
Eg: Request: myapp/admin/mypage rewrite to myapp/admin/mypage.jsf
Thanks
Yep!
http://ocpsoft.com/docs/prettyfaces/snapshot/en-US/html_single/#inbound_rewriting
<rewrite match="^(.*)(?!\\.jsf)$" substitute="/$1.jsf" redirect="301"/>
I think you didn't understand. I only want something like
myapp/admin/mypage, without respond with a redirect, but my server understand that i request myapp/admin/mypage.jsf.
My link will be myapp/admin/mypage and this will appear on
address bar.
This is possible?`
Change 301 to chain in my example. This is all in the documentation :)
The regex ^(.*)(?!\\.jsf)$ did't work.
Any request is being rewritten.
I request: http://localhost:8080/myapp/teste
and the rewrite rule entered into a loop...
See the stack:
javax.servlet.ServletException: com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste]>
root cause
com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste]>
root cause
javax.servlet.ServletException: com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste.jsf]>
root cause
com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste.jsf]>
root cause
javax.servlet.ServletException: com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste.jsf.jsf]>
root cause
com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste.jsf.jsf]>
root cause
javax.servlet.ServletException: com.ocpsoft.pretty.PrettyException: Error occurred during canonicalization of request <[/teste.jsf.jsf.jsf]>
......
I try to change the regex without success.
Any suggestion?
Try creating a rewrite-processor instead of using Regexes, you'll have more control in Java:
Thanks Lincoln. This solved my problem.
More one issue. It's possible rewrite only the 404's requests?
I'm trying to do something similar - where every request that comes through tries to forward to *.jsf (if there isn't a previous mapping that forwards it to a different resource). With the UrlRewriteFilter, I'm almost able to accomplish what I want using the following:
<rule>
<from>/</from>
<to type="redirect" last="true">mainMenu</to>
</rule>
<rule>
<from>/j_security_check</from>
<to>/j_security_check</to>
</rule>
<rule>
<from>/images/**</from>
<to>/images/$1</to>
</rule>
<rule>
<from>/scripts/**</from>
<to>/scripts/$1</to>
</rule>
<rule>
<from>/styles/**</from>
<to>/styles/$1</to>
</rule>
<rule>
<from>/login*</from>
<to>/login.jsp</to>
</rule>
<rule>
<from>/logout*</from>
<to>/logout.jsp</to>
</rule>
<!-- Struts -->
<rule match-type="regex">
<from>^([^?]*)/([^?/\.]+)(\?.*)?$</from>
<to last="true">$1/$2.jsf$3</to>
</rule>
<outbound-rule match-type="regex">
<from>^(.*)\.jsf(\?.*)?$</from>
<to last="false">$1$2</to>
</outbound-rule>
However, I've run into an issue where UrlRewriteFilter intercepts a post on my File Upload form and doesn't submit it to my managed bean properly. So I've turned to Pretty Faces in hopes of getting something similar setup.
Here's what I have so far:
<rewrite match="^/login$" substitute="/login.jsp" redirect="chain"/>
<rewrite match="/$" substitute="/mainMenu" redirect="302"/>
<rewrite match="^([^?]*)/([^?/\.]+)(\?.*)?$" substitute="$1/$2.jsf$3" redirect="chain"/>
Unfortunately, this results in the following, which I'm guessing is caused by a continuous redirect.
2011-01-28 07:58:49.761:WARN::Error for /mainMenu
java.lang.StackOverflowError
at java.util.HashMap.removeEntryForKey(HashMap.java:548)
at java.util.HashMap.remove(HashMap.java:538)
at org.mortbay.util.AttributesMap.removeAttribute(AttributesMap.java:51)
at org.mortbay.jetty.servlet.Dispatcher$ForwardAttributes.setAttribute(Dispatcher.java:441)
at org.mortbay.jetty.servlet.Dispatcher$ForwardAttributes.removeAttribute(Dispatcher.java:461)
Does Pretty Faces have the ability to say "last" on a rewrite rule and forward from there w/o processing again?
Thanks,
Matt
Hey Matt,
I was going to write a longer post to answer your question, but my first glance tells me that your assumption is correct; you're using a regexp that will continually loop -
You might consider using a negative lookahead (or lookbehind) for the purposes of restricting what is actually matched. Unfortunately, we don't have the concept of *last* yet (it might take some header manipulation/trickery for that to work.)
Negative lookbehind:
(?<!\.jsf)
<rewrite match="^([^?]*)/([^?/\.]+)(?<!\.jsf)(\?.*)?$" substitute="$1/$2.jsf$3" redirect="chain"/>
This should prevent matching on URLs that already inclue .jsf.
If this isn't quite working, you could try the custum rewrite processor:
http://ocpsoft.com/docs/prettyfaces/3.2.0/en-US/html/inbound_rewriting.html
<rewrite processor="com.raible.AddJSFProcessor" inbound="true" />
public class AddJSFProcessor implements com.ocpsoft.pretty.faces.rewrite.Processor
{
public String process(RewriteRule rule, String url)
{
return "new/url/";
}
}
We are currently working on refactoring and improving the processor interface to provide access to the request/response, and also enable more complete control over the prettyfaces lifecycle. So stay tuned for these updates in the next snapshot.
Sorry for the difficulty you've been having, we're coming up to speed slowly but surely :) This is all supposed to be "easy," but as I'm sure you know, "easy" only comes once you see what many kinds of things people want to do, and design accordingly.
--Lincoln
Doesn't look like negative lookback is a valid syntax:
ERROR [main] Digester.fatalError(1655) | Parse Fatal Error at line 11 column 42: The value of attribute "match" associated with an element type "null" must not contain the '<' character.
org.xml.sax.SAXParseException: The value of attribute "match" associated with an element type "null" must not contain the '<' character.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
Ok, in that case a lookahead should work as well - I guess Digester doesn't like <, even in quoted strings. Though, looking at this regex, I don't think you even need the lookahead, since there's no way a '.' could be matched in the first place.
^([^?]*)/([^?/\.]+)(\?.*)?$
Or you could just do the same in a Processor.
However, in looking at your example again, I don't think you really want to be using rewrite rules for this.
Why not just use URL mappings, which is what are really intended to solve this issue.
<url-mapping>
<pattern value="/login" />
<view-id value="/login.jsf" />
</url-mapping>
You'll have to set up multiple mappings, but this will work. Query strings are automatically handled and propagated for you.
The following processor works, but my app still shows .jsf on URLs in my browser, which is what I'm trying to get rid of:
public class UrlProcessor implements Processor {
public String process(RewriteRule rule, String url) {
if (url.contains("/images") || url.contains("/styles") || url.contains("/scripts") ||
url.contains("/login") || url.contains("/logout") || url.contains("/j_security_check")
|| url.equals("/")) {
return url;
} else if (!url.contains(".jsf")) {
return url + ".jsf";
} else {
return url;
}
}
}
My pretty-config.xml is as follows, but it seems the final one gets hit everytime, even for /login.
<url-mapping>
<pattern value="/login" />
<view-id value="/login.jsp" />
</url-mapping>
<url-mapping>
<pattern value="/logout" />
<view-id value="/logout.jsp" />
</url-mapping>
<rewrite processor="org.appfuse.webapp.util.UrlProcessor" inbound="true"/>
Keep in mind that your rewrite rule is explicitly *adding* ".jsf" to inbound URLs, so it would certainly update the browser URL unless you specify a chaining/internal redirect (servlet forward.)
Try: <rewrite processor="org.appfuse.webapp.util.UrlProcessor" inbound="true" redirect="chain"/>
Note: You do not need this rewrite rule if you create a mapping for each page in your application - as you have done for 'login' and 'logout.'
It is on our short list of enhancements to enable "default" discovery of mappings / removing *.jsf* from URLs, making this process simpler.
Also note that inbound / outbound rewriting are both enabled by default, so inbound="true" is redundant :) Just FYI!
I hate to raise this post from the dead.
Lincoln, you said that the "enable 'default' discovery of mappings / removing *.jsf* from URLs" was on the list of enhancements.
I currently have:
<url-mapping>
<pattern> /main </pattern>
<view-id> /main.html </view-id>
</url-mapping>
<url-mapping>
<pattern> /about </pattern>
<view-id> /about.html </view-id>
</url-mapping>
...
It would be great to have one rewrite rule to just remove the ".html" from the URL while preserving parameters if present. I looked through the forums and latest docs and didn't see an example of this.
No problem - what you have there should do exactly what you want. This should not affect parameters :)
I was hoping to not create a url-mapping for every page just to remove the extension! From your statement above, I thought there might be a new feature to suppress extensions on a global scale.
I went ahead and prepared a Processor but I can't get that to work either!
Here is my pretty-config.xml:
<rewrite match="^(.*)$" processor="com.example.URLProcessor" redirect="chain" />
Here is my processor:
public class URLProcessor implements Processor {
protected static final String EXTENSION = ".html";
/**
* Example: http://localhost/login is actually http://localhost/login.html
* Example: http://localhost/login?test=1 is actually http://localhost/login.html?test=1
*/
@Override
public String processInbound(HttpServletRequest request, HttpServletResponse response, RewriteRule rewrite, String url) {
StringBuilder newURL = new StringBuilder(url);
if (!url.contains(".")) {
if (url.contains("?")) {
newURL.insert(url.indexOf("?"), EXTENSION);
} else {
newURL.append(EXTENSION);
}
}
return newURL.toString();
}
/**
* Example: http://localhost/login.html is masked to http://localhost/login
* Example: http://localhost/login.html?test=1 is masked http://localhost/login?test=1
*/
@Override
public String processOutbound(HttpServletRequest request, HttpServletResponse response, RewriteRule rewrite, String url) {
StringBuilder newURL = new StringBuilder(url);
if (url.contains(EXTENSION)) {
newURL.delete(url.indexOf(EXTENSION), url.indexOf(EXTENSION) + EXTENSION.length());
}
return newURL.toString();
}
}
The URL string manipulation looks correct. If I use /login.html, the page renders as expected. If I use /login, the page doesn't render, even though I see the inbound process add the ".html" at the end. When I do use /login.html, the output links render without the extension as expected. So what am I missing on the inbound??
Interesting, and when you debug, it looks right on the inbound? Which version of PrettyFaces?
Yes, when I put a System.out.println statement right before the return statement of the inbound, it shows correctly ("/login.html"). I am using PrettyFaces 3.3.2.
I am seeing this a lot in the logs:
[#|2012-02-04T09:59:22.407-0500|INFO|sun-appserver2.1|javax.enterprise.system.stream.out|_ThreadID=17;_ThreadName=httpSSLWorkerThread-80-0;|13509 [httpSSLWorkerThread-80-0] TRACE com.ocpsoft.pretty.PrettyFilter - Request is not mapped using PrettyFaces. Continue.
And I am not seeing anything else.
Here is my web.xml filters:
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
I am using prettyfaces-jsf12-3.3.2.
I swapped the filters above and it now works!
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I thought the PrettyFilter needed to be the last filter applied.
I was using Tuckey previously and didn't think much about the order of filters. I just replaced the Tuckey filter with the PrettyFaces filter in the Web.xml. Looking back at that section of the documentation, it does specify the order...
Awesome! Glad you got it working :)
You must log in to post.