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