View Javadoc

1   /*
2    * Copyright 2003,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  /* 
17  
18   */
19  
20  package org.apache.pluto.portalImpl.core;
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.StringTokenizer;
27  
28  import javax.portlet.PortletMode;
29  import javax.portlet.WindowState;
30  
31  import org.apache.pluto.om.window.PortletWindow;
32  import org.apache.pluto.portalImpl.aggregation.Fragment;
33  import org.apache.pluto.portalImpl.aggregation.PortletFragment;
34  import org.apache.pluto.util.StringUtils;
35  
36  public class PortalControlParameter {
37  
38      static public final String ACTION = "ac";
39      static public final String MODE = "md";
40      static public final String PORTLET_ID = "pid";
41      static public final String PREFIX = "_";
42      static public final String PREV_MODE = "pm";
43      static public final String PREV_STATE = "ps";
44      static public final String RENDER_PARAM = "rp";
45      static public final String STATE = "st";
46  
47      private Map requestParameter = new HashMap();
48  
49      /***
50       * The map containing the encoded statefull control parameters.
51       * They are encoded in the sense, that names and values of 
52       * <i>render parameters</i> and render parameters only are encoded
53       * using {{@link #encodeRenderParamName(PortletWindow, String)}}
54       * and {{@link #encodeRenderParamValues(String[])}}.
55       */
56      private Map encodedStateFullControlParameter;
57      
58      private Map stateLessControlParameter;
59      private PortalURL url;
60  
61      
62      public PortalControlParameter(PortalURL url) {
63          this.url = url;
64          encodedStateFullControlParameter = this.url.getClonedEncodedStateFullControlParameter();
65          stateLessControlParameter = this.url.getClonedStateLessControlParameter();
66      }
67  
68      
69      /***
70       * Encodes the given String. Encoding means that all characters that might
71       * interfere with the algorithm used to prefix parameters to associate them
72       * with the correct portal window will be encoded. The reverse method is
73       * {{@link #decodeString(String)}}.  
74       * @param value The String to be encoded.
75       * @return The encoded String.
76       * @see #decodeParameterName(String)
77       */
78      private static String encodeString(String value) {
79      	value = StringUtils.replace(value, "0x", "0xx");
80          value = StringUtils.replace(value, "_", "0x1" );
81          value = StringUtils.replace(value, ".", "0x2" );
82          value = StringUtils.replace(value, "/", "0x3" );
83          value = StringUtils.replace(value, "\r", "0x4" );
84          value = StringUtils.replace(value, "\n", "0x5" );
85          value = StringUtils.replace(value, "<", "0x6" );
86          value = StringUtils.replace(value, ">", "0x7" );
87          value = StringUtils.replace(value, " ", "0x8" );
88          return value;
89      }
90  
91      /***
92       * Decodes the given String. This is the reverse method to
93       * {{@link #encodeString(String)}}.
94       * @param value The string to be decoded.
95       * @return The decoded String.
96       */
97      private static String decodeString(String value) {
98          value = StringUtils.replace(value, "0x1", "_" );
99          value = StringUtils.replace(value, "0x2", "." );
100         value = StringUtils.replace(value, "0x3", "/" );
101         value = StringUtils.replace(value, "0x4", "\r" );
102         value = StringUtils.replace(value, "0x5", "\n" );
103         value = StringUtils.replace(value, "0x6", "<" );
104         value = StringUtils.replace(value, "0x7", ">" );
105         value = StringUtils.replace(value, "0x8", " " );
106         value = StringUtils.replace(value, "0xx", "0x");
107         return value;
108     }
109     
110     /***
111      * Each parameter is encoded by prefixing it with the String
112      * {@link #PREFIX}. The reverse method is {{@link #decodeParameterName(String)}}.
113      * Don't mistake this method for {{@link #encodeRenderParamName(PortletWindow, String)}}
114      * or {{@link #encodeRenderParamValues(String[])}}.
115      * @param param The parameter to be encoded / prefixed.
116      * @return The encoded parameter.
117      */
118     public static String encodeParameterName(String param) {
119         return PREFIX + param;
120     }
121 
122     /***
123      * Decodes a parameter by deleting the prefix, if the parameter
124      * was prefixed. Reverse method to {{@link #encodeParameterName(String)}}.
125      * Don't mistake this method for {{@link #decodeRenderParameterName(String)}}
126      * or {{@link #decodeRenderParamValues(String)}}.
127      * @param param The parameter to be decoded.
128      * @return The decoded parameter.
129      */
130     public static String decodeParameterName(String param) {
131     	if (param.startsWith(PREFIX)) {
132     		return param.substring(PREFIX.length());
133     	} else {
134     		return param;
135     	}
136     }
137     
138     /***
139      * Dummy method. Does nothing!
140      */
141     public static String decodeParameterValue(String paramName, String paramValue) {
142         return paramValue;
143     }
144 
145     /***
146      * Encodes the given render parameter name. The name will be encoded using the
147      * {{@link #encodeValue(String)}} method, meaning that characters that will 
148      * interfere with plutos internal url encoding and decoding
149      * mechanisms, like "/" or "_" will be encoded. The parameter name will then
150      * be prefixed with a string that encodes the portlet window the parameter belongs to.
151      * This prefix contains the characters ("/", "_", ...) that had to be encoded in
152      * the parameter name to later allow for a safe parsing of the prefix.
153      * @return A string encoding the given render parameter name to be used in portal urls.
154      */
155     public static String encodeRenderParamName(PortletWindow window, String paramName) {
156     	String encodedParamName = encodeString(paramName);
157         StringBuffer returnvalue = new StringBuffer(50);
158         returnvalue.append(getRenderParamKey(window));
159         returnvalue.append("_");
160         returnvalue.append(encodedParamName);
161         return returnvalue.toString();
162     }
163 
164     /***
165      * Reverse method for method {{@link #encodeRenderParamName(PortletWindow, String)}}.
166      */
167     public static String decodeRenderParamName(PortletWindow window, String encodedRenderParamName) {
168     	String prefix = getRenderParamKey(window);
169     	String unprefixedRenderParamName = null;
170     	if (encodedRenderParamName.startsWith(prefix)) {
171     		unprefixedRenderParamName = encodedRenderParamName.substring(prefix.length());
172     	} else {
173     		unprefixedRenderParamName = encodedRenderParamName;
174     	}
175     	return decodeString(unprefixedRenderParamName);
176     }
177     
178     /***
179      * Encodes the given render parameter values. The values are encoded
180      * in one single string that will be used in portal urls. 
181      * @param paramValues The render parameter values to be encoded.
182      * @return A string containing the encoded render parameter values.
183      */
184     public static String encodeRenderParamValues(String[] paramValues)
185     {
186         StringBuffer returnvalue = new StringBuffer(100);
187         returnvalue.append(paramValues.length);
188         for (int i=0; i<paramValues.length; i++) {
189             returnvalue.append("_");
190             if(paramValues[i]!=null) {
191                 returnvalue.append(encodeString(paramValues[i]));
192             }
193         }
194         return returnvalue.toString();
195     }
196 
197     /***
198      * Reverse method for the method {{@link #encodeRenderParamValues(String[])}}.
199      */
200     private static String[] decodeRenderParamValues(String encodedParamValues) {
201         StringTokenizer tokenizer = new StringTokenizer(encodedParamValues, "_");
202         if (!tokenizer.hasMoreTokens()) {
203         	return null;
204         }
205         String _count = tokenizer.nextToken();
206         int count = Integer.valueOf(_count).intValue();
207         String[] values = new String[count];
208         for (int i = 0; i < count; i++) {
209             if (!tokenizer.hasMoreTokens()) {
210             	return null;
211             }
212             values[i] = decodeString(tokenizer.nextToken());
213         }
214         return values;
215     }
216 
217     /***
218      * Retrieve the key to use to prefix render parameters of the given
219      * portlet window.
220      * @param window
221      * @return
222      */
223     public static String getRenderParamKey(PortletWindow window) {
224         return RENDER_PARAM + "_" + window.getId().toString();
225     }
226 
227     /***
228      * Check whether the given string encodes a control parameter.
229      */
230     public static boolean isControlParameter(String param) {
231         return param.startsWith(PREFIX);
232     }
233 
234     /***
235      * Check whether the given string encodes a stateful parameter,
236      * i.e. mode, previous mode, window state, previous window state or 
237      * render parameter.
238      */
239     public static boolean isStateFullParameter(String param) {
240         if (isControlParameter(param)) {
241             if ((param.startsWith(PREFIX + MODE)) ||
242                 (param.startsWith(PREFIX + PREV_MODE)) ||
243                 (param.startsWith(PREFIX + STATE)) ||
244                 (param.startsWith(PREFIX + PREV_STATE)) ||
245                 (param.startsWith(PREFIX + RENDER_PARAM))) {
246                 return true;
247             }
248         }
249         return false;
250     }
251     
252     /***
253      * Deletes all render parameter that belong to the given window.
254      */
255     public void clearRenderParameters(PortletWindow portletWindow) {
256         String prefix = getRenderParamKey(portletWindow);
257         Iterator keyIterator = encodedStateFullControlParameter.keySet().iterator();
258         while (keyIterator.hasNext()) {
259             String encodedName = (String)keyIterator.next();
260             if (encodedName.startsWith(prefix)) {
261                 keyIterator.remove();
262             }
263         }
264     }
265 
266     private String getActionKey(PortletWindow window)
267     {
268         return ACTION+"_"+window.getId().toString();
269     }
270 
271     public String[] getActionParameter(PortletWindow window, String paramName) {
272         String encodedValues = (String)encodedStateFullControlParameter.get(encodeRenderParamName(window, paramName));
273         String[] decodedValues = decodeRenderParamValues(encodedValues);
274         return decodedValues;
275     }
276 
277     public PortletMode getMode(PortletWindow window) {
278         String mode = (String)encodedStateFullControlParameter.get(getModeKey(window));
279         if (mode != null) {
280             return new PortletMode(mode);
281         } else {
282             return PortletMode.VIEW;
283         }
284     }
285 
286     private String getModeKey(PortletWindow window) {
287         return MODE + "_" + window.getId().toString();
288     }
289 
290     public String getPIDValue() {
291         String value = (String)stateLessControlParameter.get(getPortletIdKey());
292         return value == null ? "" : value;
293     }
294 
295     private String getPortletIdKey() {
296         return PORTLET_ID;
297     }
298 
299     public PortletWindow getPortletWindowOfAction() {
300         Iterator iterator = getStateLessControlParameter().keySet().iterator();
301         while (iterator.hasNext()) {
302             String name = (String)iterator.next();
303             if (name.startsWith(ACTION)) {
304                 String id = name.substring(ACTION.length()+1);
305                 Fragment fragment = org.apache.pluto.portalImpl.services.pageregistry.PageRegistry.getFragment(id);
306                 if (fragment instanceof PortletFragment) {
307                     return((PortletFragment)fragment).getPortletWindow();
308                 }
309             }
310         }
311         return null;
312     }
313 
314     public PortletMode getPrevMode(PortletWindow window) {
315         String mode = (String)encodedStateFullControlParameter.get(getPrevModeKey(window));
316         if (mode != null) {
317             return new PortletMode(mode);
318         } else {
319             return null;
320         }
321     }
322     
323     private String getPrevModeKey(PortletWindow window) {
324         return PREV_MODE + "_" + window.getId().toString();
325     }
326 
327     public WindowState getPrevState(PortletWindow window) {
328         String state = (String)encodedStateFullControlParameter.get(getPrevStateKey(window));
329         if (state!=null)
330             return new WindowState(state);
331         else
332             return null;
333     }
334     
335     private String getPrevStateKey(PortletWindow window) {
336         return PREV_STATE + "_" + window.getId().toString();
337     }
338 
339     public Iterator getRenderParamNames(PortletWindow window) {
340         ArrayList returnvalue = new ArrayList();
341         String prefix = getRenderParamKey(window);
342         Iterator keyIterator = encodedStateFullControlParameter.keySet().iterator();
343         while (keyIterator.hasNext()) {
344             String encodedName = (String)keyIterator.next();
345             if (encodedName.startsWith(prefix)) {
346             	// remove specific render parameter name encoding
347             	String decodedName = decodeRenderParamName(window, encodedName);
348             	// remove general parameter encoding
349             	String unprefixedName = decodeParameterName(decodedName);
350             	returnvalue.add(unprefixedName);
351             }
352         }
353         return returnvalue.iterator();
354     }
355 
356     public String[] getRenderParamValues(PortletWindow window, String paramName) {
357         String encodedValues = (String)encodedStateFullControlParameter.get(encodeRenderParamName(window, paramName));
358         String[] decodedValues = decodeRenderParamValues(encodedValues);
359         return decodedValues;
360     }
361 
362     public Map getRequestParameter() {
363         return requestParameter;
364     }
365 
366     public WindowState getState(PortletWindow window) {
367         String state = (String)encodedStateFullControlParameter.get(getStateKey(window));
368         if (state!=null)
369             return new WindowState(state);
370         else
371             return WindowState.NORMAL;
372     }
373 
374     public Map getEncodedStateFullControlParameter() {
375         return encodedStateFullControlParameter;
376     }
377 
378     private String getStateKey(PortletWindow window) {
379         return STATE+"_"+window.getId().toString();
380     }
381 
382     public Map getStateLessControlParameter() {
383         return stateLessControlParameter;
384     }
385 
386     public boolean isOnePortletWindowMaximized() {
387         Iterator iterator = encodedStateFullControlParameter.keySet().iterator();
388         while (iterator.hasNext()) {
389             String encodedName = (String)iterator.next();
390             if (encodedName.startsWith(STATE)) {
391                 if (encodedStateFullControlParameter.get(encodedName).equals(WindowState.MAXIMIZED.toString())) {
392                     return true;
393                 }
394             }
395         }
396         return false;
397     }
398 
399     public void setAction(PortletWindow window) {
400         getEncodedStateFullControlParameter().put(getActionKey(window),ACTION.toUpperCase());
401     }
402 
403     public void setMode(PortletWindow window, PortletMode mode) {
404         Object prevMode = encodedStateFullControlParameter.get(getModeKey(window));
405         if (prevMode!=null)
406             encodedStateFullControlParameter.put(getPrevModeKey(window), prevMode);
407         // set current mode
408         encodedStateFullControlParameter.put(getModeKey(window), mode.toString());
409     }
410 
411     public void setPortletId(PortletWindow window) {
412         getEncodedStateFullControlParameter().put(getPortletIdKey(),window.getId().toString());
413         //getStateLessControlParameter().put(getPortletIdKey(),window.getId().toString());
414     }
415 
416     /***
417      * Sets the given render parameter. Note that its name as well as its values will
418      * be encoded for storage using {{@link #encodeRenderParamName(PortletWindow, String)}}
419      * and {{@link #encodeRenderParamValues(String[])}.
420      */
421     public void setRenderParam(PortletWindow window, String name, String[] values) {
422         encodedStateFullControlParameter.put(encodeRenderParamName(window, name), 
423                                       encodeRenderParamValues(values) );
424     }
425 
426     public void setRequestParam(String name, String[] values ) {
427         requestParameter.put(name, values );
428     }
429 
430 
431     public void setState(PortletWindow window, WindowState state) {
432         Object prevState = encodedStateFullControlParameter.get(getStateKey(window));
433         if (prevState != null) {
434             encodedStateFullControlParameter.put(getPrevStateKey(window), prevState);
435         }
436         encodedStateFullControlParameter.put(getStateKey(window), state.toString());
437     }
438 
439 }