1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet;
24  
25  import com.liferay.portal.SystemException;
26  import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
27  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
28  import com.liferay.portal.kernel.portlet.LiferayWindowState;
29  import com.liferay.portal.kernel.util.ArrayUtil;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.StringMaker;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.Company;
35  import com.liferay.portal.model.Layout;
36  import com.liferay.portal.model.Portlet;
37  import com.liferay.portal.service.LayoutLocalServiceUtil;
38  import com.liferay.portal.service.PortletLocalServiceUtil;
39  import com.liferay.portal.theme.PortletDisplay;
40  import com.liferay.portal.theme.ThemeDisplay;
41  import com.liferay.portal.util.PortalUtil;
42  import com.liferay.portal.util.PropsUtil;
43  import com.liferay.portal.util.WebKeys;
44  import com.liferay.util.Encryptor;
45  import com.liferay.util.EncryptorException;
46  import com.liferay.util.Http;
47  import com.liferay.util.HttpUtil;
48  
49  import java.io.Serializable;
50  
51  import java.security.Key;
52  
53  import java.util.Iterator;
54  import java.util.LinkedHashMap;
55  import java.util.LinkedHashSet;
56  import java.util.Map;
57  import java.util.Set;
58  
59  import javax.portlet.PortletMode;
60  import javax.portlet.PortletModeException;
61  import javax.portlet.PortletRequest;
62  import javax.portlet.PortletSecurityException;
63  import javax.portlet.WindowState;
64  import javax.portlet.WindowStateException;
65  
66  import javax.servlet.http.HttpServletRequest;
67  
68  import org.apache.commons.logging.Log;
69  import org.apache.commons.logging.LogFactory;
70  
71  /**
72   * <a href="PortletURLImpl.java.html"><b><i>View Source</i></b></a>
73   *
74   * @author Brian Wing Shun Chan
75   * @author Jorge Ferrer
76   *
77   */
78  public class PortletURLImpl implements LiferayPortletURL, Serializable {
79  
80      public static final boolean APPEND_PARAMETERS = GetterUtil.getBoolean(
81          PropsUtil.get(PropsUtil.PORTLET_URL_APPEND_PARAMETERS));
82  
83      public PortletURLImpl(
84          ActionRequestImpl req, String portletId, long plid, boolean action) {
85  
86          this(req.getHttpServletRequest(), portletId, plid, action);
87  
88          _portletReq = req;
89      }
90  
91      public PortletURLImpl(
92          RenderRequestImpl req, String portletId, long plid, boolean action) {
93  
94          this(req.getHttpServletRequest(), portletId, plid, action);
95  
96          _portletReq = req;
97      }
98  
99      public PortletURLImpl(
100         HttpServletRequest req, String portletId, long plid, boolean action) {
101 
102         _req = req;
103         _portletId = portletId;
104         _plid = plid;
105         _secure = req.isSecure();
106         _action = action;
107         _params = new LinkedHashMap();
108         _parametersIncludedInPath = new LinkedHashSet();
109     }
110 
111     public HttpServletRequest getReq() {
112         return _req;
113     }
114 
115     public PortletRequest getPortletReq() {
116         return _portletReq;
117     }
118 
119     public String getPortletId() {
120         return _portletId;
121     }
122 
123     public void setPortletId(String portletId) {
124         _portletId = portletId;
125 
126         // Clear cache
127 
128         _toString = null;
129     }
130 
131     /**
132      * @deprecated Use <code>getPortletId</code>.
133      */
134     public String getPortletName() {
135         return getPortletId();
136     }
137 
138     /**
139      * @deprecated Use <code>setPortletId</code>.
140      */
141     public void setPortletName(String portletName) {
142         setPortletId(portletName);
143     }
144 
145     public Portlet getPortlet() {
146         if (_portlet == null) {
147             try {
148                 _portlet = PortletLocalServiceUtil.getPortletById(
149                     PortalUtil.getCompanyId(_req), _portletId);
150             }
151             catch (SystemException se) {
152                 _log.error(se.getMessage());
153             }
154         }
155 
156         return _portlet;
157     }
158 
159     public String getPortletFriendlyURLPath() {
160         String portletFriendlyURLPath = null;
161 
162         Portlet portlet = getPortlet();
163 
164         if (portlet != null) {
165             FriendlyURLMapper mapper = portlet.getFriendlyURLMapperInstance();
166 
167             if (mapper != null) {
168                 portletFriendlyURLPath = mapper.buildPath(this);
169 
170                 if (_log.isDebugEnabled()) {
171                     _log.debug(
172                         "Portlet friendly URL path " + portletFriendlyURLPath);
173                 }
174             }
175         }
176 
177         return portletFriendlyURLPath;
178     }
179 
180     public String getNamespace() {
181         if (_namespace == null) {
182             _namespace = PortalUtil.getPortletNamespace(_portletId);
183         }
184 
185         return _namespace;
186     }
187 
188     public long getPlid() {
189         return _plid;
190     }
191 
192     public Layout getLayout() {
193         if (_layout == null) {
194             try {
195                 if (_plid > 0) {
196                     _layout = LayoutLocalServiceUtil.getLayout(_plid);
197                 }
198             }
199             catch (Exception e) {
200                 if (_log.isWarnEnabled()) {
201                     _log.warn("Layout cannot be found for " + _plid);
202                 }
203             }
204         }
205 
206         return _layout;
207     }
208 
209     public String getLayoutFriendlyURL() {
210         return _layoutFriendlyURL;
211     }
212 
213     public boolean isAction() {
214         return _action;
215     }
216 
217     public void setAction(boolean action) {
218         _action = action;
219 
220         // Clear cache
221 
222         _toString = null;
223     }
224 
225     public WindowState getWindowState() {
226         return _windowState;
227     }
228 
229     public void setWindowState(WindowState windowState)
230         throws WindowStateException {
231 
232         if (_portletReq != null) {
233             if (!_portletReq.isWindowStateAllowed(windowState)) {
234                 throw new WindowStateException(
235                     windowState.toString(), windowState);
236             }
237         }
238 
239         if (LiferayWindowState.isWindowStatePreserved(
240                 getWindowState(), windowState)) {
241 
242             _windowState = windowState;
243         }
244 
245         // Clear cache
246 
247         _toString = null;
248     }
249 
250     public void setWindowState(String windowState)
251         throws WindowStateException {
252 
253         setWindowState(new WindowState(windowState));
254     }
255 
256     public PortletMode getPortletMode() {
257         return _portletMode;
258     }
259 
260     public void setPortletMode(PortletMode portletMode)
261         throws PortletModeException {
262 
263         if (_portletReq != null) {
264             if (!getPortlet().hasPortletMode(
265                     _portletReq.getResponseContentType(), portletMode)) {
266 
267                 throw new PortletModeException(
268                     portletMode.toString(), portletMode);
269             }
270         }
271 
272         _portletMode = portletMode;
273 
274         // Clear cache
275 
276         _toString = null;
277     }
278 
279     public void setPortletMode(String portletMode)
280         throws PortletModeException {
281 
282         setPortletMode(new PortletMode(portletMode));
283     }
284 
285     public String getParameter(String name) {
286         String[] values = (String[])_params.get(name);
287 
288         if ((values != null) && (values.length > 0)) {
289             return values[0];
290         }
291         else {
292             return null;
293         }
294     }
295 
296     public void setParameter(String name, String value) {
297         setParameter(name, value, APPEND_PARAMETERS);
298     }
299 
300     public void setParameter(String name, String value, boolean append) {
301         if ((name == null) || (value == null)) {
302             throw new IllegalArgumentException();
303         }
304 
305         setParameter(name, new String[] {value}, append);
306     }
307 
308     public void setParameter(String name, String[] values) {
309         setParameter(name, values, APPEND_PARAMETERS);
310     }
311 
312     public void setParameter(String name, String[] values, boolean append) {
313         if ((name == null) || (values == null)) {
314             throw new IllegalArgumentException();
315         }
316 
317         for (int i = 0; i < values.length; i++) {
318             if (values[i] == null) {
319                 throw new IllegalArgumentException();
320             }
321         }
322 
323         if (append && _params.containsKey(name)) {
324             String[] oldValues = (String[])_params.get(name);
325 
326             String[] newValues = ArrayUtil.append(oldValues, values);
327 
328             _params.put(name, newValues);
329         }
330         else {
331             _params.put(name, values);
332         }
333 
334         // Clear cache
335 
336         _toString = null;
337     }
338 
339     public void setParameters(Map params) {
340         if (params == null) {
341             throw new IllegalArgumentException();
342         }
343         else {
344             Map newParams = new LinkedHashMap();
345 
346             Iterator itr = params.entrySet().iterator();
347 
348             while (itr.hasNext()) {
349                 Map.Entry entry = (Map.Entry)itr.next();
350 
351                 Object key = entry.getKey();
352                 Object value = entry.getValue();
353 
354                 if (key == null) {
355                     throw new IllegalArgumentException();
356                 }
357                 else if (value == null) {
358                     throw new IllegalArgumentException();
359                 }
360 
361                 if (value instanceof String[]) {
362                     newParams.put(key, value);
363                 }
364                 else {
365                     throw new IllegalArgumentException();
366                 }
367             }
368 
369             _params = newParams;
370         }
371 
372         // Clear cache
373 
374         _toString = null;
375     }
376 
377     public Map getParameterMap() {
378         return _params;
379     }
380 
381     public Set getParametersIncludedInPath() {
382         return _parametersIncludedInPath;
383     }
384 
385     public void addParameterIncludedInPath(String name) {
386         _parametersIncludedInPath.add(name);
387     }
388 
389     public boolean isParameterIncludedInPath(String name) {
390         if (_parametersIncludedInPath.contains(name)) {
391             return true;
392         }
393         else {
394             return false;
395         }
396     }
397 
398     public boolean isSecure() {
399         return _secure;
400     }
401 
402     public void setSecure(boolean secure) throws PortletSecurityException {
403         _secure = secure;
404 
405         // Clear cache
406 
407         _toString = null;
408     }
409 
410     public boolean isAnchor() {
411         return _anchor;
412     }
413 
414     public void setAnchor(boolean anchor) {
415         _anchor = anchor;
416 
417         // Clear cache
418 
419         _toString = null;
420     }
421 
422     public boolean isEncrypt() {
423         return _encrypt;
424     }
425 
426     public void setEncrypt(boolean encrypt) {
427         _encrypt = encrypt;
428 
429         // Clear cache
430 
431         _toString = null;
432     }
433 
434     public void setDoAsUserId(long doAsUserId) {
435         _doAsUserId = doAsUserId;
436 
437         // Clear cache
438 
439         _toString = null;
440     }
441 
442     public String toString() {
443         if (_toString != null) {
444             return _toString;
445         }
446 
447         _toString = generateToString();
448 
449         return _toString;
450     }
451 
452     protected String generateToString() {
453         StringMaker sm = new StringMaker();
454 
455         ThemeDisplay themeDisplay =
456             (ThemeDisplay)_req.getAttribute(WebKeys.THEME_DISPLAY);
457 
458         PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
459 
460         String portalURL = PortalUtil.getPortalURL(_req, _secure);
461 
462         try {
463             if (_layoutFriendlyURL == null) {
464                 Layout layout = getLayout();
465 
466                 if (layout != null) {
467                     _layoutFriendlyURL = GetterUtil.getString(
468                         PortalUtil.getLayoutFriendlyURL(layout, themeDisplay));
469                 }
470             }
471         }
472         catch (Exception e) {
473             _log.error(e);
474         }
475 
476         Key key = null;
477 
478         try {
479             if (_encrypt) {
480                 Company company = PortalUtil.getCompany(_req);
481 
482                 key = company.getKeyObj();
483             }
484         }
485         catch (Exception e) {
486             _log.error(e);
487         }
488 
489         if (Validator.isNull(_layoutFriendlyURL)) {
490             sm.append(portalURL);
491             sm.append(themeDisplay.getPathMain());
492             sm.append("/portal/layout?");
493 
494             sm.append("p_l_id");
495             sm.append(StringPool.EQUAL);
496             sm.append(processValue(key, _plid));
497             sm.append(StringPool.AMPERSAND);
498         }
499         else {
500 
501             // A virtual host URL will contain the complete path. Do not append
502             // the portal URL if the virtual host URL starts with "http://" or
503             // "https://".
504 
505             if (!_layoutFriendlyURL.startsWith(Http.HTTP_WITH_SLASH) &&
506                 !_layoutFriendlyURL.startsWith(Http.HTTPS_WITH_SLASH)) {
507 
508                 sm.append(portalURL);
509             }
510 
511             sm.append(_layoutFriendlyURL);
512 
513             String friendlyURLPath = getPortletFriendlyURLPath();
514 
515             if (Validator.isNotNull(friendlyURLPath)) {
516                 sm.append(friendlyURLPath);
517 
518                 if (!isAction()) {
519                     addParameterIncludedInPath("p_p_action");
520                 }
521 
522                 //if ((_windowState != null) &&
523                 //  _windowState.equals(WindowState.MAXIMIZED)) {
524 
525                     addParameterIncludedInPath("p_p_state");
526                 //}
527 
528                 //if ((_portletMode != null) &&
529                 //  _portletMode.equals(PortletMode.VIEW)) {
530 
531                     addParameterIncludedInPath("p_p_mode");
532                 //}
533 
534                 addParameterIncludedInPath("p_p_col_id");
535                 addParameterIncludedInPath("p_p_col_pos");
536                 addParameterIncludedInPath("p_p_col_count");
537             }
538 
539             sm.append(StringPool.QUESTION);
540         }
541 
542         if (!isParameterIncludedInPath("p_p_id")) {
543             sm.append("p_p_id");
544             sm.append(StringPool.EQUAL);
545             sm.append(processValue(key, _portletId));
546             sm.append(StringPool.AMPERSAND);
547         }
548 
549         if (!isParameterIncludedInPath("p_p_action")) {
550             sm.append("p_p_action");
551             sm.append(StringPool.EQUAL);
552 
553             if (_action) {
554                 sm.append(processValue(key, "1"));
555             }
556             else {
557                 sm.append(processValue(key, "0"));
558             }
559 
560             sm.append(StringPool.AMPERSAND);
561         }
562 
563         if (!isParameterIncludedInPath("p_p_state")) {
564             if (_windowState != null) {
565                 sm.append("p_p_state");
566                 sm.append(StringPool.EQUAL);
567                 sm.append(processValue(key, _windowState.toString()));
568                 sm.append(StringPool.AMPERSAND);
569             }
570         }
571 
572         if (!isParameterIncludedInPath("p_p_mode")) {
573             if (_portletMode != null) {
574                 sm.append("p_p_mode");
575                 sm.append(StringPool.EQUAL);
576                 sm.append(processValue(key, _portletMode.toString()));
577                 sm.append(StringPool.AMPERSAND);
578             }
579         }
580 
581         if (!isParameterIncludedInPath("p_p_col_id")) {
582             if (Validator.isNotNull(portletDisplay.getColumnId())) {
583                 sm.append("p_p_col_id");
584                 sm.append(StringPool.EQUAL);
585                 sm.append(processValue(key, portletDisplay.getColumnId()));
586                 sm.append(StringPool.AMPERSAND);
587             }
588         }
589 
590         if (!isParameterIncludedInPath("p_p_col_pos")) {
591             if (portletDisplay.getColumnPos() > 0) {
592                 sm.append("p_p_col_pos");
593                 sm.append(StringPool.EQUAL);
594                 sm.append(processValue(key, portletDisplay.getColumnPos()));
595                 sm.append(StringPool.AMPERSAND);
596             }
597         }
598 
599         if (!isParameterIncludedInPath("p_p_col_count")) {
600             if (portletDisplay.getColumnCount() > 0) {
601                 sm.append("p_p_col_count");
602                 sm.append(StringPool.EQUAL);
603                 sm.append(processValue(key, portletDisplay.getColumnCount()));
604                 sm.append(StringPool.AMPERSAND);
605             }
606         }
607 
608         if (_doAsUserId > 0) {
609             try {
610                 Company company = PortalUtil.getCompany(_req);
611 
612                 sm.append("doAsUserId");
613                 sm.append(StringPool.EQUAL);
614                 sm.append(processValue(company.getKeyObj(), _doAsUserId));
615                 sm.append(StringPool.AMPERSAND);
616             }
617             catch (Exception e) {
618                 _log.error(e);
619             }
620         }
621         else {
622             String doAsUserId = themeDisplay.getDoAsUserId();
623 
624             if (Validator.isNotNull(doAsUserId)) {
625                 sm.append("doAsUserId");
626                 sm.append(StringPool.EQUAL);
627                 sm.append(processValue(key, doAsUserId));
628                 sm.append(StringPool.AMPERSAND);
629             }
630         }
631 
632         Iterator itr = _params.entrySet().iterator();
633 
634         while (itr.hasNext()) {
635             Map.Entry entry = (Map.Entry)itr.next();
636 
637             String name = (String)entry.getKey();
638             String[] values = (String[])entry.getValue();
639 
640             for (int i = 0; i < values.length; i++) {
641                 if (isParameterIncludedInPath(name)) {
642                     continue;
643                 }
644 
645                 if (!PortalUtil.isReservedParameter(name)) {
646                     sm.append(getNamespace());
647                 }
648 
649                 sm.append(name);
650                 sm.append(StringPool.EQUAL);
651                 sm.append(processValue(key, values[i]));
652 
653                 if ((i + 1 < values.length) || itr.hasNext()) {
654                     sm.append(StringPool.AMPERSAND);
655                 }
656             }
657         }
658 
659         if (_encrypt) {
660             sm.append(StringPool.AMPERSAND + WebKeys.ENCRYPT + "=1");
661         }
662 
663         if (GetterUtil.getBoolean(PropsUtil.get(
664                 PropsUtil.PORTLET_URL_ANCHOR_ENABLE))) {
665 
666             if (_anchor && (_windowState != null) &&
667                 (!_windowState.equals(WindowState.MAXIMIZED)) &&
668                 (!_windowState.equals(LiferayWindowState.EXCLUSIVE)) &&
669                 (!_windowState.equals(LiferayWindowState.POP_UP))) {
670 
671                 if (sm.lastIndexOf(StringPool.AMPERSAND) != (sm.length() - 1)) {
672                     sm.append(StringPool.AMPERSAND);
673                 }
674 
675                 sm.append("#p_").append(_portletId);
676             }
677         }
678 
679         // Remove trailing question mark
680 
681         String result = sm.toString();
682 
683         if (result.endsWith(StringPool.QUESTION)) {
684             result = result.substring(0, result.length() - 1);
685         }
686 
687         return result;
688     }
689 
690     protected String processValue(Key key, int value) {
691         return processValue(key, String.valueOf(value));
692     }
693 
694     protected String processValue(Key key, long value) {
695         return processValue(key, String.valueOf(value));
696     }
697 
698     protected String processValue(Key key, String value) {
699         if (key == null) {
700             return HttpUtil.encodeURL(value);
701         }
702         else {
703             try {
704                 return HttpUtil.encodeURL(Encryptor.encrypt(key, value));
705             }
706             catch (EncryptorException ee) {
707                 return value;
708             }
709         }
710     }
711 
712     private static Log _log = LogFactory.getLog(PortletURLImpl.class);
713 
714     private HttpServletRequest _req;
715     private PortletRequest _portletReq;
716     private String _portletId;
717     private Portlet _portlet;
718     private String _namespace;
719     private long _plid;
720     private Layout _layout;
721     private String _layoutFriendlyURL;
722     private boolean _action;
723     private WindowState _windowState;
724     private PortletMode _portletMode;
725     private Map _params;
726     private Set _parametersIncludedInPath;
727     private boolean _secure;
728     private boolean _anchor = true;
729     private boolean _encrypt = false;
730     private long _doAsUserId;
731     private String _toString;
732 
733 }