URL Rewriting Solution Needed for JSF

Assume the following application landscape:

+-----------------+ | App server | +-----------------+ | | +-------+ | ear1 | | | | +-web1 (/ctx1) +--<-- http://localhost/ctx1/xxx/ --+ +--<-- http://www.example.com/xxx/ | | | | | | | proxy | | ear2 | | | | +-web2 (/ctx2) +--<-- http://localhost/ctx2/yyy/ --+ +--<-- http://abc.example.com/yyy/ | | | | +-----------------+ +-------+ 

As you can see, the proxy (in my case nginx ) forwards requests to one instance of the application server, which, in turn, has several web modules with different context paths. Of course, I do not want my public server to provide access to the internal roots of the context, and the proxy server works well, wraps and deploys http requests, etc. But there is another big problem: the HTML code generated by JSF (links, CSS resources, JS, action form) contains context paths, /ctx1 and /ctx2 in my case. This is what I want to avoid.

At this point, I did not find a solution, except for using an increasing number of different instances (domains) of the application server, as a result of which my hardware resources disappeared. As I understand it, I need to extend my JSF applications with some wrappers that are potentially registered in faces-config.xml that will remove the context prefix in the generated html. Any other solutions are also welcome.

Please point me in the right direction.

+8
source share
3 answers

I am posting a solution that may be useful to others facing the same problem. All I had to do was implement my own javax.faces.application.ViewHandler and register it in faces-config.xml :

 public class CustomViewHandler extends ViewHandlerWrapper { private ViewHandler wrappped; public CustomViewHandler(ViewHandler wrappped) { super(); this.wrappped = wrappped; } @Override public ViewHandler getWrapped() { return wrappped; } @Override public String getActionURL(FacesContext context, String viewId) { String url = super.getActionURL(context, viewId); return removeContextPath(context, url); } @Override public String getRedirectURL(FacesContext context, String viewId, Map<String, List<String>> parameters, boolean includeViewParams) { String url = super.getRedirectURL(context, viewId, parameters, includeViewParams); return removeContextPath(context, url); } @Override public String getResourceURL(FacesContext context, String path) { String url = super.getResourceURL(context, path); return removeContextPath(context, url); } private String removeContextPath(FacesContext context, String url) { ServletContext servletContext = (ServletContext) context.getExternalContext().getContext(); String contextPath = servletContext.getContextPath(); if("".equals(contextPath)) return url; // root context path, nothing to remove return url.startsWith(contextPath) ? url.substring(contextPath.length()) : url; } } 

faces-config.xml:

 <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <application> <view-handler>test.CustomViewHandler</view-handler> </application> </faces-config> 
+4
source

You can use OCPsoft Rewrite URLRewriteFilter for this (not PrettyFaces at the moment, but you can use both of them at the same time until they officially unite after the release of PrettyFaces 4 - Rewrite is the main project for PrettyFaces 4)

Doing something like this should be simple enough using one configuration rule. Obviously, you can play if this rule is too strict or too general.

 .defineRule() .when(URL.matches("{prefix}" + context.getContextPath() + "{suffix}") .perform(Substitute.with("{prefix}{suffix}")) 

Check the rewrite site. It is pretty easy to set up. http://ocpsoft.org/rewrite/

+5
source

I ran into the same problem and tried your solution. Although it worked more or less, there were still several glitches. And frankly, this is more like fighting symptoms, rather than treating a disease.

So here is what finally worked for me:

Instead of installing the deployments separately along the way, I assigned each deployment to its own port:

 foo.war <-- http://localhost:8080/ -- | Proxy | <-- http://www.foo.com -- | Client | bar.war <-- http://localhost:8181/ -- | Proxy | <-- http://www.bar.com -- | Client | 

Thus, both deployments can use / as their context path, so there is no need to edit the context path.

To do this, you do not have to run two application servers. In my case (Wildfly 10.0), it was enough to define two pallets in the wildfly configuration, each with its own virtual host and http listener, for example:

 <server name="foo-server"> <http-listener name="foo-listener" proxy-address-forwarding="true" socket-binding="foo-http"/> <host name="foo-host" default-web-module="foo.war" alias="localhost, foo.com, wwww.foo.com"/> </server> <server name="bar-server"> <http-listener name="bar-listener" proxy-address-forwarding="true" socket-binding="bar-http"/> <host name="bar-host" default-web-module="bar.war" alias="localhost, bar.com, wwww.bar.com"/> </server> <socket-binding name="foo-http" port="${jboss.http.port:8080}"/> <socket-binding name="bar-http" port="${jboss.http.port:8181}"/> 

You will also need jboss-web.xml in your project:

 <?xml version="1.0" encoding="UTF-8"?> <jboss-web> <server-instance>foo-server</server-instance> <virtual-host>foo-host</virtual-host> <context-root>/</context-root> </jboss-web> 

Two servers are needed because you cannot add socket binding to a virtual host. Thus, there is little overhead, but they are negligible compared to the launch of two full application servers.

Change 1:

It just seemed to me that probably you don’t even need to use different ports, and using one subsystem server for each object is probably also redundant.

Since the proxy server can redirect the host at the client’s request to the application server, it should be able to select the desired virtual host through the alias parameter.

Thus, the proxy would forward any request to foo.com or bar.com to localhost: 8080 and allow AS sort out.

I have not tested this one , but here is how it could work (again, this is for Wildfly 10.0):

 <server name="default-server"> <http-listener name="http" proxy-address-forwarding="true" socket-binding="http"/> <host name="foo-host" default-web-module="foo.war" alias="foo.com, wwww.foo.com"/> <host name="bar-host" default-web-module="bar.war" alias="bar.com, wwww.bar.com"/> </server> 

And jboss-web.xml will lose the server tag:

 <?xml version="1.0" encoding="UTF-8"?> <jboss-web> <virtual-host>foo-host</virtual-host> <context-root>/</context-root> </jboss-web> 

In case this works, there will be no overhead.

Edit 2:

Just tested a simplified approach - yep, it works :)

+1
source

All Articles