22-Jul-04 (Created: 22-Jul-04) | More in 'OSCON-2004'

Clientside Redirector Pattern: Code Examples

Consider a web update request

Consider a url


http://host/webapp/servlet/updateservlet?request_name=update1&arg1=10

See how that "update1" is defined on the server


request.update1.classname=com.ai.db.Pipeline
request.update1.db=my-database
request.update1.request.1=UpdateTable1
request.update1.request.2=UpdateTable
request.update1.request.3=GetTable3

request.update1.redirectURL=/servlet/DisplayServlet?url=ShowURL&arg2={arg2}

Redirection abstracted


public interface IRedirector 
{
   static public String NAME=AspireConstants.PAGE_REDIRECTOR;
   public void redirect(final String url
                        , HttpServletRequest request
                        , HttpServletResponse response 
                        , ServletContext  servletContext)
      throws   java.net.MalformedURLException,
               java.io.IOException,
               ServletException,
               RedirectorException;
}

First attempt at an implementation


public class ExternalRedirector implements IRedirector
{
   public void redirect(final String url
                        , HttpServletRequest request
                        , HttpServletResponse response 
                        , ServletContext  servletContext)
      throws   java.net.MalformedURLException,
               java.io.IOException,
               ServletException,
               com.ai.servlets.RedirectorException
   {
      try
      {
         response.sendRedirect(response.encodeRedirectUrl(url));
      }
      catch(java.io.IOException x)
      {
         AppObjects.log(x);
         throw new RedirectorException("error.redirect: io error", x);
      }         
   }               
}   

I have coded this a couple of years ago. And I fully don't know why I don't use it anymore. But I believe the reason was to do with the browsers back button not that friendly to these redirects. Initial servlet implementations have some issues with https and http and keeping the sessions etc.

ClientsideRedirector: Java script based solution


public class ClientSideRedirector1 implements IRedirector
{
   public void redirect(final String url
                        , HttpServletRequest request
                        , HttpServletResponse response
                        , ServletContext  servletContext)
      throws   java.net.MalformedURLException,
               java.io.IOException,
               ServletException,
               com.ai.servlets.RedirectorException
   {
      try
      {
         writeToOutputStream(response, url);
      }
      catch(java.io.IOException x)
      {
         AppObjects.log(x);
         throw new RedirectorException("error.redirect: io error", x);
      }
      return;
   }
   private void writeToOutputStream(HttpServletResponse response, String targetUrl)
      throws IOException
   {
      PrintWriter out = ServletUtils.prepareResponseAndGetPrintWriter(response,null);
//      targetUrl = targetUrl.replaceAll(regExp, "\\\\\"");
      targetUrl = StringUtils.encode(targetUrl,'\\','"','"');
      AppObjects.log("Info: ClientSideRedirector1: redirectURL after escaping is:" + targetUrl);

      out.println("<html><head>");
      out.println("<script>");
      out.println("function redirectToTarget()");
      out.println("{");
      out.println("   targetUrl = \"" + targetUrl + "\";");
      out.println("   if (targetUrl == \"\")");
      out.println("   {");
      out.println("      alert(\"No target url specified.\");");
      out.println("      return;");
      out.println("   }");
      out.println("   else");
      out.println("   {");
      out.println("      location.replace(targetUrl);");
      out.println("   }");
      out.println("}");
      out.println("</script>");
      out.println("</head>");
      out.println("<body onLoad=redirectToTarget()>");
      out.println("</body>");
      out.println("</html>");
      out.close();
   }
}

As the previous update is taken out from the browsers memory there is no back problem. There is also no refresh problem as refresh is always a get as long as the redirection is done for gets after updates.

For web services


public class DefaultRedirector implements IRedirector
{
   public void redirect(final String url
                        , HttpServletRequest request
                        , HttpServletResponse response 
                        , ServletContext servletContext)
      throws   java.net.MalformedURLException,
               java.io.IOException,
               ServletException,
               com.ai.servlets.RedirectorException
   {

      // figure out what the session is
      AppObjects.log("info.redirect: redirecting to " + url);
      HttpSession session = request.getSession(false);
      
      // figure out the params (if necessary )
      // Retrieve the params from the url
      String queryString = ServletUtils.getQueryString(request,url);
      Hashtable params;
      if (queryString  != null)
      {      
         params = HttpUtils.parseQueryString(queryString);
         params = ServletUtils.convertHashtable(params);
      }
      else
      {
         params = new Hashtable();
      }         
      
      // sync params with the session
      SessionUtils.addParametersToSession( session, params);
      SessionUtils.addParametersFromSessionToUrlParameters(session
                                                      ,params);
      AppObjects.log("info.redirect: values into redirect are: " + params.toString());
      // Call the dispatcher
      com.ai.servlets.PageDispatcher pd = new com.ai.servlets.PageDispatcher();
      try{
         pd.serviceRequest( session,params,request,response,servletContext);  
      }
      catch(AspireServletException x)
      {
         throw new RedirectorException("Error from the PageDispatcher.serviceRequest",x);
      }
      return;
   }               
}   

Client side redirection doesn't work when programs update websites. This redirector is used for those occasions and also for portals where the entire page is not redisplayed but only a portion. This is a server side internal aspire redirect.

References

1. General Introduction to other Server side Patterns in this series

2. OSCON 2004 Summary page for Server side patterns session