View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.conversation;
20  
21  import org.apache.myfaces.custom.redirectTracker.RedirectTrackerManager;
22  
23  import javax.faces.context.FacesContext;
24  import javax.faces.el.ValueBinding;
25  import java.io.IOException;
26  
27  /**
28   * <p>
29   * Ensures a named conversation is running
30   * </p>
31   * <p>
32   * check if a conversation is active.
33   * </p>
34   * <p>
35   * The way this is done here is sub-optimal, once we are on jsf 1.2 it should be possible to
36   * check this before ANY rendering - and maybe to invoke a navigation then
37   * </p>
38   *
39   * @JSFComponent
40   *   name = "s:ensureConversation"
41   *   tagClass = "org.apache.myfaces.custom.conversation.EnsureConversationTag"
42   *   
43   * @JSFJspProperty name="action" longDesc = "the action which should be called in case of a not running conversation"
44   *   
45   * @author imario@apache.org
46   */
47  public class UIEnsureConversation extends AbstractConversationComponent
48  {
49      public static final String COMPONENT_TYPE = "org.apache.myfaces.EnsureConversation";
50  
51      private String redirectTo;
52      private Boolean preCheck;
53  
54      public void encodeBegin(FacesContext context) throws IOException
55      {
56          super.encodeBegin(context);
57  
58          checkConversation(context, getName());
59      }
60  
61      public void decode(FacesContext context)
62      {
63          super.decode(context);
64  
65          try
66          {
67              checkConversation(context, getName());
68          }
69          catch (IOException e)
70          {
71              throw new RuntimeException(e);
72          }
73      }
74  
75      public void restoreState(FacesContext context, Object state)
76      {
77          Object[] states = (Object[]) state;
78  
79          super.restoreState(context, states[0]);
80          redirectTo = (String) states[1];
81          preCheck = (Boolean) states[2];
82      }
83  
84      public Object saveState(FacesContext context)
85      {
86          return new Object[]
87              {
88                  super.saveState(context),
89                  redirectTo,
90                  preCheck
91              };
92      }
93  
94      protected void checkConversation(FacesContext context, String name) throws IOException
95      {
96          ConversationManager conversationManager = ConversationManager.getInstance();
97  
98          if (Boolean.TRUE.equals(preCheck))
99          {
100             String actionResult = (String) getAction().invoke(context, null);
101             if (actionResult == null)
102             {
103                 // no further action, maybe the user started a conversation
104                 return;
105             }
106 
107             conversationManager.getMessager().setConversationNotActive(context, getName());
108             return;
109         }
110         else if (!conversationManager.hasConversation(name))
111         {
112             if (getAction() != null)
113             {
114                 String actionResult = (String) getAction().invoke(context, null);
115                 if (actionResult == null)
116                 {
117                     // no further action, maybe the user started a conversation
118                     return;
119                 }
120                 conversationManager.getMessager().setConversationNotActive(context, getName());
121 
122                 // hopefully the user configured the navigation as redirect ...
123                 context.getApplication().getNavigationHandler().handleNavigation(context, null, actionResult);
124             }
125             else
126             {
127                 conversationManager.getMessager().setConversationNotActive(context, getName());
128 
129                 String actionUrl = context.getApplication().getViewHandler().getActionURL(
130                             context, getRedirectTo());
131                 String encodedActionUrl = context.getExternalContext().encodeActionURL(actionUrl);
132 
133                 // XXX: figure out a way to avoid this ==>
134                 RedirectTrackerManager manager = RedirectTrackerManager.getInstance(context);
135                 if (manager != null)
136                 {
137                     encodedActionUrl = manager.trackRedirect(context, encodedActionUrl);
138                 }
139                 // XXX: figure out a way to avoid this <==
140 
141                 context.getExternalContext().redirect(encodedActionUrl);
142             }
143 
144             return;
145         }
146     }
147 
148     /**
149      * redirect to the given view if the conversation is not running
150      * 
151      * @JSFProperty
152      * @return
153      */
154     public String getRedirectTo()
155     {
156         if (redirectTo != null)
157         {
158             return redirectTo;
159         }
160         ValueBinding vb = getValueBinding("redirectTo");
161         if (vb == null)
162         {
163             return null;
164         }
165         return (String) vb.getValue(getFacesContext());
166     }
167 
168     public void setRedirectTo(String redirectTo)
169     {
170         this.redirectTo = redirectTo;
171     }
172     
173     /**
174      * Delegate the check to the action method at all. The user has to check if 
175      * a conversation is running. A action method is mandatory.
176      * 
177      * @JSFProperty
178      * @return
179      */
180     public Boolean getPreCheck()
181     {
182         if (preCheck != null)
183         {
184             return preCheck;
185         }
186         ValueBinding vb = getValueBinding("preCheck");
187         if (vb == null)
188         {
189             return null;
190         }
191         return (Boolean) vb.getValue(getFacesContext());
192     }
193 
194     public void setPreCheck(Boolean preCheck)
195     {
196         this.preCheck = preCheck;
197     }
198 
199 }