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