Search code examples
jsfprettyfacesocpsoft-rewrite

JSF - How to migrate URLs by intercepting and redirecting potential 404 errors?


When migrating websites often dead URLs happen since old website used different URL structure or technology. Correct 301 "permanent" redirect is important for SEO friendly migrations.

Example:

Old page https://example.com/product/coca-cola-bottle.html moved in our JSF project to https://example.com/p/coca-cola-1-l/1000

Concept

We will save those mappings in our database and add them to our JSF application.

If an URL is requested that is not valid or rewritten we want to check the current requested URL if it exists in our database and redirect to the new target.

Some Ideas?

  • Create a custom exception handler and redirect if resource was not found
  • Override navigation handler to handle it before exception handler
  • Use @WebFilter with DispatcherType.ERROR and 404 error code check
  • Use OCPSoft rewrite solution. Not sure how to do this without loading all mappings into configuration. I prefer dynamic (lazy) approach.

Right now i implemented @WebFilter version using an injected bean to lookup the mapping.


Solution

  • I would start by including the rewrite-integration-cdi module:

    https://github.com/ocpsoft/rewrite/blob/master/documentation/src/main/asciidoc/integration/cdi.asciidoc

    Then create a CDI bean/Java class that can access your database.

    Inject an instance of that class into your Rewrite ConfigurationProvider, then use it to build / create your Rewrite rules.

    Here is an example of both @Injecting beans into your ConfigurationProvider, and also defining custom HTTP operations:

    https://github.com/ocpsoft/rewrite/blob/master/showcase/rest-ws/src/main/java/org/ocpsoft/rewrite/showcase/rest/RestRewriteConfiguration.java

    Depending on how dynamic you want your database lookups to be, you could either preload them at startup time (when the Config is built), or load & cache them inside the Request/Response lifecycle itself using a custom HttpCondition and `HttpOperation:

    https://github.com/ocpsoft/rewrite/blob/master/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/HttpCondition.java

    https://github.com/ocpsoft/rewrite/blob/master/api-servlet/src/main/java/org/ocpsoft/rewrite/servlet/config/HttpOperation.java

    Then use those operations in your ConfigurationProvider to perform the database operations. Essentially you will do something like this, but check the database to see if the requested URL is a ‘known/stored’ redirect:

    https://github.com/ocpsoft/rewrite/blob/851ccbabb8b6248c66589076fa67cb0ec07b3132/impl-servlet-tests/src/test/java/org/ocpsoft/rewrite/servlet/config/HttpRequestParameterTestProvider.java#L45

    And then use an custom HttpOperation to perform the actions you want to take.

    https://github.com/ocpsoft/rewrite/blob/851ccbabb8b6248c66589076fa67cb0ec07b3132/config-servlet/src/test/java/org/ocpsoft/rewrite/servlet/config/JoinBindingConfigurationProvider.java#L48

    You could also technically just use a Condition that matches all requests, and an HttpOperation That only takes action if there is a database entry.

    All that said, this sounds more complicated than it is, but there’s no good example I can find to link to that does exactly what you want, so I’m trying to piece it together.