[seam-commits] Seam SVN: r15397 - in branches/enterprise/WFK-2_1: jboss-seam/src/main/java/org/jboss/seam/util and 1 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Thu Jan 17 07:36:10 EST 2013


Author: manaRH
Date: 2013-01-17 07:36:10 -0500 (Thu, 17 Jan 2013)
New Revision: 15397

Added:
   branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/util/FacesUrlTransformer.java
Modified:
   branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/jsf/SeamViewHandler.java
   branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/BoundComponentConversationTest.java
   branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/RestoreViewComponentAccessTest.java
Log:
JBSEAM-5020, JBSEAM-4976 added new JSF2 methods like getActionURL, getRedirectURL and getBookmarkableURL into SeamViewHandler

Modified: branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/jsf/SeamViewHandler.java
===================================================================
--- branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/jsf/SeamViewHandler.java	2013-01-17 12:35:52 UTC (rev 15396)
+++ branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/jsf/SeamViewHandler.java	2013-01-17 12:36:10 UTC (rev 15397)
@@ -1,7 +1,9 @@
 package org.jboss.seam.jsf;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 import javax.faces.FacesException;
 import javax.faces.application.ViewHandler;
@@ -10,27 +12,35 @@
 import javax.faces.context.FacesContext;
 
 import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.Conversation;
+import org.jboss.seam.core.Manager;
 import org.jboss.seam.international.LocaleSelector;
+import org.jboss.seam.util.FacesUrlTransformer;
 
 /**
  * Allows the JSF view locale to be integrated with
  * the locale coming from Seam internationalization.
- * 
+ *
  * @see org.jboss.seam.international.LocaleSelector
- * 
+ *
  * @author Gavin King
  *
  */
 public class SeamViewHandler extends ViewHandlerWrapper
 {
-   
+   private static enum Source
+   {
+      ACTION, BOOKMARKABLE, REDIRECT, RESOURCE
+   }
+
    private ViewHandler viewHandler;
-   
+   private static final ThreadLocal<Source> source = new ThreadLocal<Source>();
+
    public SeamViewHandler(ViewHandler viewHandler)
    {
       this.viewHandler = viewHandler;
    }
-   
+
    @Override
    public String calculateCharacterEncoding(FacesContext context)
    {
@@ -42,9 +52,9 @@
    {
       viewHandler.initView(context);
    }
-   
+
    @Override
-   public Locale calculateLocale(FacesContext facesContext) 
+   public Locale calculateLocale(FacesContext facesContext)
    {
       Locale jsfLocale = viewHandler.calculateLocale(facesContext);
       if ( !Contexts.isSessionContextActive() )
@@ -58,38 +68,124 @@
    }
 
    @Override
-   public String calculateRenderKitId(FacesContext ctx) 
+   public String calculateRenderKitId(FacesContext ctx)
    {
       return viewHandler.calculateRenderKitId(ctx);
    }
 
    @Override
-   public UIViewRoot createView(FacesContext ctx, String viewId) 
+   public UIViewRoot createView(FacesContext ctx, String viewId)
    {
       return viewHandler.createView(ctx, viewId);
    }
 
+   /**
+    * Allow the delegate to produce the action URL. If the conversation is
+    * long-running, append the conversation id request parameter to the query
+    * string part of the URL, but only if the request parameter is not already
+    * present.
+    * <p/>
+    * This covers form actions Ajax calls, and redirect URLs (which we want) and
+    * link hrefs (which we don't)
+    *
+    * @see {@link ViewHandler#getActionURL(FacesContext, String)}
+    */
    @Override
-   public String getActionURL(FacesContext ctx, String viewId) 
+   public String getActionURL(FacesContext facesContext, String viewId) {
+       String actionUrl = super.getActionURL(facesContext, viewId);
+       Conversation conversation = Conversation.instance();
+       Manager manager = Manager.instance();
+       String conversationIdParameter = manager.getConversationIdParameter();
+
+       if (!getSource().equals(Source.BOOKMARKABLE) )
+       {
+          if ( !conversation.isNested() || conversation.isLongRunning() )
+          {
+             return new FacesUrlTransformer(actionUrl, facesContext)
+             .appendConversationIdIfNecessary(conversationIdParameter, conversation.getId())
+             .getUrl();
+          }
+          else
+          {
+             return new FacesUrlTransformer(actionUrl, facesContext)
+             .appendConversationIdIfNecessary(conversationIdParameter, conversation.getParentId())
+             .getUrl();
+          }
+
+       } else {
+           return actionUrl;
+       }
+   }
+
+   /* (non-Javadoc)
+    * @see javax.faces.application.ViewHandlerWrapper#getRedirectURL(javax.faces.context.FacesContext, java.lang.String, java.util.Map, boolean)
+    */
+   @Override
+   public String getRedirectURL(FacesContext context, String viewId, Map<String, List<String>> parameters, boolean includeViewParams)
    {
-      return viewHandler.getActionURL(ctx, viewId);
+      try
+      {
+         source.set(Source.REDIRECT);
+         return super.getRedirectURL(context, viewId, parameters, includeViewParams);
+      }
+      finally
+      {
+         source.remove();
+      }
    }
 
+   /* (non-Javadoc)
+    * @see javax.faces.application.ViewHandlerWrapper#getBookmarkableURL(javax.faces.context.FacesContext, java.lang.String, java.util.Map, boolean)
+    */
    @Override
-   public String getResourceURL(FacesContext ctx, String path) 
+   public String getBookmarkableURL(FacesContext context, String viewId, Map<String, List<String>> parameters, boolean includeViewParams)
    {
-      return viewHandler.getResourceURL(ctx, path);
+      try
+      {
+         source.set(Source.BOOKMARKABLE);
+         return super.getBookmarkableURL(context, viewId, parameters, includeViewParams);
+      }
+      finally
+      {
+         source.remove();
+      }
    }
 
+   private Source getSource()
+   {
+      if (source.get() == null)
+      {
+         return Source.ACTION;
+      }
+      else
+      {
+         return source.get();
+      }
+   }
+
    @Override
+   public String getResourceURL(FacesContext ctx, String path)
+   {
+      try
+      {
+         source.set(Source.RESOURCE);
+         return super.getResourceURL(ctx, path);
+      }
+      finally
+      {
+         source.remove();
+      }
+   }
+
+   @Override
    public void renderView(FacesContext ctx, UIViewRoot viewRoot)
-         throws IOException, FacesException 
+         throws IOException, FacesException
    {
       viewHandler.renderView(ctx, viewRoot);
    }
 
    @Override
-   public UIViewRoot restoreView(FacesContext ctx, String viewId) 
+   public UIViewRoot restoreView(FacesContext ctx, String viewId)
    {
       UIViewRoot viewRoot =viewHandler.restoreView(ctx, viewId);
       if (viewRoot != null)
@@ -100,7 +196,7 @@
    }
 
    @Override
-   public void writeState(FacesContext ctx) throws IOException 
+   public void writeState(FacesContext ctx) throws IOException
    {
       viewHandler.writeState(ctx);
    }

Added: branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/util/FacesUrlTransformer.java
===================================================================
--- branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/util/FacesUrlTransformer.java	                        (rev 0)
+++ branches/enterprise/WFK-2_1/jboss-seam/src/main/java/org/jboss/seam/util/FacesUrlTransformer.java	2013-01-17 12:36:10 UTC (rev 15397)
@@ -0,0 +1,117 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat, Inc., and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jboss.seam.util;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * Helper class for preparing JSF URLs which include the conversation id.
+ * <p/>
+ * TODO This class has the potential to be better designed to make it fit more use cases.
+ *
+ * @author Nicklas Karlsson
+ * @author Dan Allen
+ * @author Marko Luksa
+ */
+public class FacesUrlTransformer {
+    private static final String HTTP_PROTOCOL_URL_PREFIX = "http://";
+    private static final String HTTPS_PROTOCOL_URL_PREFIX = "https://";
+    private static final String QUERY_STRING_DELIMITER = "?";
+    private static final String PARAMETER_PAIR_DELIMITER = "&";
+    private static final String PARAMETER_ASSIGNMENT_OPERATOR = "=";
+
+    private String url;
+    private final FacesContext context;
+
+    public FacesUrlTransformer(String url, FacesContext facesContext) {
+        this.url = url;
+        this.context = facesContext;
+    }
+
+    public FacesUrlTransformer appendConversationIdIfNecessary(String cidParameterName, String cid) {
+        this.url = appendParameterIfNeeded(url, cidParameterName, cid);
+        return this;
+    }
+
+    private static String appendParameterIfNeeded(String url, String parameterName, String parameterValue) {
+        int queryStringIndex = url.indexOf(QUERY_STRING_DELIMITER);
+        // if there is no query string or there is a query string but the param is
+        // absent, then append it
+        if (queryStringIndex < 0 || url.indexOf(parameterName + PARAMETER_ASSIGNMENT_OPERATOR, queryStringIndex) < 0) {
+            StringBuilder builder = new StringBuilder(url);
+            if (queryStringIndex < 0) {
+                builder.append(QUERY_STRING_DELIMITER);
+            } else {
+                builder.append(PARAMETER_PAIR_DELIMITER);
+            }
+            builder.append(parameterName).append(PARAMETER_ASSIGNMENT_OPERATOR);
+            if (parameterValue != null) {
+                builder.append(parameterValue);
+            }
+            return builder.toString();
+        } else {
+            return url;
+        }
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public FacesUrlTransformer toRedirectViewId() {
+        String requestPath = context.getExternalContext().getRequestContextPath();
+        if (isUrlAbsolute()) {
+            url = url.substring(url.indexOf(requestPath) + requestPath.length());
+        } else if (url.startsWith(requestPath)) {
+            url = url.substring(requestPath.length());
+        }
+        return this;
+    }
+
+    public FacesUrlTransformer toActionUrl() {
+        String actionUrl = context.getApplication().getViewHandler().getActionURL(context, url);
+
+        int queryStringIndex = url.indexOf(QUERY_STRING_DELIMITER);
+        if (queryStringIndex < 0) {
+            url = actionUrl;
+        } else {
+            String queryParameters = url.substring(queryStringIndex + 1);
+
+            int actionQueryStringIndex = actionUrl.indexOf(QUERY_STRING_DELIMITER);
+            if (actionQueryStringIndex < 0) {
+                url = actionUrl + QUERY_STRING_DELIMITER + queryParameters;
+            } else {
+                String actionQueryParameters = actionUrl.substring(actionQueryStringIndex + 1);
+                if (queryParameters.startsWith(actionQueryParameters)) {
+                    url = actionUrl.substring(0, actionQueryStringIndex) + QUERY_STRING_DELIMITER + queryParameters;
+                } else {
+                    url = actionUrl + PARAMETER_PAIR_DELIMITER + queryParameters;
+                }
+            }
+        }
+        return this;
+    }
+
+    public String encode() {
+        return context.getExternalContext().encodeActionURL(url);
+    }
+
+    private boolean isUrlAbsolute() {
+        // TODO: any API call to do this?
+        return url.startsWith(HTTP_PROTOCOL_URL_PREFIX) || url.startsWith(HTTPS_PROTOCOL_URL_PREFIX);
+    }
+}

Modified: branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/BoundComponentConversationTest.java
===================================================================
--- branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/BoundComponentConversationTest.java	2013-01-17 12:35:52 UTC (rev 15396)
+++ branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/BoundComponentConversationTest.java	2013-01-17 12:36:10 UTC (rev 15397)
@@ -64,7 +64,6 @@
                   "</html>"), "test.xhtml");
    }
    
-   @Ignore // JBSEAM-5020
    @Test
    public void testConversationRestoration() throws Exception
    {

Modified: branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/RestoreViewComponentAccessTest.java
===================================================================
--- branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/RestoreViewComponentAccessTest.java	2013-01-17 12:35:52 UTC (rev 15396)
+++ branches/enterprise/WFK-2_1/seam-integration-tests/src/test/java/org/jboss/seam/test/integration/faces/RestoreViewComponentAccessTest.java	2013-01-17 12:36:10 UTC (rev 15397)
@@ -1,9 +1,8 @@
 package org.jboss.seam.test.integration.faces;
 
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-
 import java.io.Serializable;
 import java.net.URL;
 import java.util.Deque;
@@ -21,7 +20,6 @@
 import org.jboss.seam.test.integration.Deployments;
 import org.jboss.shrinkwrap.api.asset.StringAsset;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -38,21 +36,21 @@
 public class RestoreViewComponentAccessTest
 {
    private final WebClient client = new WebClient();
-         
+
    @ArquillianResource
    URL contextPath;
-   
+
    @Deployment(name="RestoreViewComponentAccessTest")
-   @OverProtocol("Servlet 3.0") 
+   @OverProtocol("Servlet 3.0")
    public static WebArchive createDeployment()
    {
       // This is a client test, use a real (non-mocked) Seam deployment
       WebArchive war = Deployments.realSeamDeployment()
             .addClasses(SequenceAction.class);
-      
+
       war.delete("WEB-INF/pages.xml");
       war.delete("WEB-INF/components.xml");
-      
+
       war.addAsWebResource(new StringAsset(
             "<html xmlns=\"http://www.w3.org/1999/xhtml\"" +
             " xmlns:h=\"http://java.sun.com/jsf/html\"" +
@@ -69,7 +67,7 @@
                   "</h:inputText>" +
                   "<h:commandButton id='append' value='Append' action='#{sequence.append}'/>" +
                "</h:form>" +
-            "</h:body>" + 
+            "</h:body>" +
             "</html>"), "test.xhtml");
 
       war.addAsWebInfResource(new StringAsset(
@@ -79,56 +77,56 @@
             "<begin-conversation join='true'/>" +
             "<navigation><redirect view-id='/test.xhtml'/></navigation>" +
             "</page></pages>"), "pages.xml");
-      
+
       return war;
    }
-   
-   @Ignore // JBSEAM-4976
+
+   //@Ignore // JBSEAM-4976
    @Test
    public void testConversationWithValidator() throws Exception {
       HtmlPage page = client.getPage(contextPath + "test.seam");
       assertTrue(page.getBody().getTextContent().contains("Sequence: "));
-      
+
       ((HtmlTextInput)page.getElementById("form:input")).setText("1");
       page = page.getElementById("form:append").click();
-      
+
       assertTrue(page.getBody().getTextContent().contains("Sequence: 1"));
-      
+
       ((HtmlTextInput)page.getElementById("form:input")).setText("2");
       page = page.getElementById("form:append").click();
-      
+
       assertTrue(page.getBody().getTextContent().contains("Sequence: 1, 2"));
-      
+
       ((HtmlTextInput)page.getElementById("form:input")).setText("1");
       page = page.getElementById("form:append").click();
-      
+
       assertFalse(page.getBody().getTextContent().contains("Sequence: 1, 2, 1"));
       assertTrue(page.getBody().getTextContent().contains("value must be greater than or equal to 2"));
    }
-   
+
    @Name("sequence")
    @Scope(ScopeType.CONVERSATION)
    public static class SequenceAction implements Serializable {
       private static final long serialVersionUID = 1L;
-      
+
       private Deque<Long> sequence;
       private Long input;
-      
+
       @Create
       public void create() {
          sequence = new LinkedList<Long>();
       }
-      
+
       public String getOutput() {
          StringBuilder sb = new StringBuilder();
          for (Long n : sequence) {
             sb.append(n);
             sb.append(", ");
          }
-         
+
          return sb.toString();
       }
-      
+
       public void append() {
          sequence.add(input);
       }
@@ -142,12 +140,12 @@
       {
          this.input = input;
       }
-      
+
       public Long getMinimum() {
          if (sequence.isEmpty()) {
             return 0L;
          }
-         
+
          return sequence.getLast();
       }
    }



More information about the seam-commits mailing list