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  
20  package org.apache.myfaces.orchestra.requestParameterProvider;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
25  
26  import java.io.Serializable;
27  import java.util.ArrayList;
28  import java.util.Iterator;
29  import java.util.List;
30  
31  /**
32   * The manager which manage all the attached providers and add their fields to the url.
33   * <p>
34   * This class has an instance per user http session. Code that wishes to add values
35   * to urls generated within pages register a "provider" with this object. When request
36   * params need to be output this manager invokes each provider in turn.
37   * <p>
38   * If the data accessed by a registered "provider" has scope shorter than an http session
39   * then the registered provider should obviously be <i>deregistered</i> when the data
40   * is no longer valid.
41   * <p>
42   * This class works together with the RequestParameterServletFilter and
43   * RequestParameterResponseWrapper so that every call to response.encodeURL(...) gets
44   * forwarded to this class. As encodeURL is used by JSF commandButton, commandLink, etc,
45   * this ensures that whatever the user clicks on the parameters provided by the
46   * registered provider objects are present on the next JSF request.
47   */
48  public class RequestParameterProviderManager implements Serializable
49  {
50      private final Log LOG = LogFactory.getLog(RequestParameterProviderManager.class);
51  
52      private static final String PAGE_LINK_SEP = "#";
53      private static final String PAGE_PARAMETER_SEP = "?";
54      private static final String PARAMETER_SEP = "&";
55      private static final String PARAMETER_PROVIDER_MANAGER_KEY = RequestParameterProviderManager.class.getName();
56  
57      // TODO: investigate why this is transient. At least some callers of register call
58      // it only once per session, so if the session data is passed to another machine or is
59      // saved then restored then it seems the registered providers will be lost when they
60      // should not be...
61      private transient List providers;
62  
63      private RequestParameterProviderManager()
64      {
65      }
66  
67      public static RequestParameterProviderManager getInstance()
68      {
69          RequestParameterProviderManager manager =
70              (RequestParameterProviderManager) FrameworkAdapter.getCurrentInstance().getSessionAttribute(PARAMETER_PROVIDER_MANAGER_KEY);
71  
72          if (manager == null)
73          {
74              // TODO: remove this factory code. Not IOC-friendly.
75              manager = new RequestParameterProviderManager();
76              FrameworkAdapter.getCurrentInstance().setSessionAttribute(PARAMETER_PROVIDER_MANAGER_KEY, manager);
77          }
78  
79          return manager;
80      }
81  
82  
83      /**
84       * Register the given provider.
85       *
86       * @param provider the provider to register.
87       */
88  
89      public void register(RequestParameterProvider provider)
90      {
91          if (provider == null)
92          {
93              LOG.warn("RequestParameterProvider is null -> no registration!");
94          }
95          else
96          {
97              getProviders().add(provider);
98          }
99      }
100 
101 
102     /**
103      * Encode all fields of all providers, and attach the name-value pairs to url.
104      *
105      * @param url the URL to which the fields should be attached.
106      * @return the url after attaching all fields.
107      */
108 
109     public String encodeAndAttachParameters(String url)
110     {
111         if (!isResponseIntercepted())
112         {
113             throw new IllegalStateException("RequestParameterServletFilter not called. Please configure the filter " + RequestParameterServletFilter.class.getName() + " in your web.xml to cover your faces requests.");
114         }
115 
116         if (PAGE_LINK_SEP.equals(url))
117         {
118             // just an inner page link, ignore
119             return url;
120         }
121 
122         StringBuffer sb = new StringBuffer();
123         if (url == null)
124         {
125             LOG.warn("URL is null -> empty string is returned.");
126             return sb.toString();
127         }
128 
129         int nuofParams = -1;
130         String firstSeparator = url.indexOf(PAGE_PARAMETER_SEP) == -1 ? PAGE_PARAMETER_SEP : PARAMETER_SEP;
131         int pageLinkPos = url.indexOf(PAGE_LINK_SEP);
132         if (pageLinkPos < 0)
133         {
134             sb.append(url);
135         }
136         else
137         {
138             sb.append(url.substring(0, pageLinkPos));
139         }
140 
141         for (Iterator it = getProviders().iterator(); it.hasNext();)
142         {
143             RequestParameterProvider provider = (RequestParameterProvider) it.next();
144             String[] fields = provider.getFields();
145             if (fields == null)
146             {
147                 continue;
148             }
149             for (int i = 0; i < fields.length; i++)
150             {
151                 nuofParams++;
152 
153                 sb.append(nuofParams == 0 ? firstSeparator : PARAMETER_SEP);
154                 sb.append(fields[i]);
155                 sb.append("=");
156                 sb.append(provider.getFieldValue(fields[i]));
157             }
158         }
159 
160         if (pageLinkPos > -1)
161         {
162             sb.append(url.substring(pageLinkPos));
163         }
164         return sb.toString();
165     }
166 
167     protected boolean isResponseIntercepted()
168     {
169         FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
170 
171         return Boolean.TRUE.equals(fa.getRequestAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED))
172             || Boolean.TRUE.equals(fa.getRequestAttribute(RequestParameterServletFilter.REQUEST_PARAM_RESPONSE_WRAPPED));
173     }
174 
175     protected List getProviders()
176     {
177         if (providers == null)
178         {
179             providers = new ArrayList();
180         }
181 
182         return providers;
183     }
184 }