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