2 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
\r
4 * This library is free software; you can redistribute it and/or modify it under
\r
5 * the terms of the GNU Lesser General Public License as published by the Free
\r
6 * Software Foundation; either version 2.1 of the License, or (at your option)
\r
9 * This library is distributed in the hope that it will be useful, but WITHOUT
\r
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
\r
15 package com.liferay.portlet;
\r
17 import com.liferay.portal.kernel.exception.PortalException;
\r
18 import com.liferay.portal.kernel.exception.SystemException;
\r
19 import com.liferay.portal.kernel.log.Log;
\r
20 import com.liferay.portal.kernel.log.LogFactoryUtil;
\r
21 import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
\r
22 import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
\r
23 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
\r
24 import com.liferay.portal.kernel.portlet.LiferayWindowState;
\r
25 import com.liferay.portal.kernel.portlet.PortletModeFactory;
\r
26 import com.liferay.portal.kernel.portlet.WindowStateFactory;
\r
27 import com.liferay.portal.kernel.util.ArrayUtil;
\r
28 import com.liferay.portal.kernel.util.Base64;
\r
29 import com.liferay.portal.kernel.util.CharPool;
\r
30 import com.liferay.portal.kernel.util.GetterUtil;
\r
31 import com.liferay.portal.kernel.util.HtmlUtil;
\r
32 import com.liferay.portal.kernel.util.Http;
\r
33 import com.liferay.portal.kernel.util.HttpUtil;
\r
34 import com.liferay.portal.kernel.util.MapUtil;
\r
35 import com.liferay.portal.kernel.util.ParamUtil;
\r
36 import com.liferay.portal.kernel.util.StringBundler;
\r
37 import com.liferay.portal.kernel.util.StringPool;
\r
38 import com.liferay.portal.kernel.util.Validator;
\r
39 import com.liferay.portal.kernel.xml.QName;
\r
40 import com.liferay.portal.model.Company;
\r
41 import com.liferay.portal.model.Group;
\r
42 import com.liferay.portal.model.Layout;
\r
43 import com.liferay.portal.model.Portlet;
\r
44 import com.liferay.portal.model.PortletApp;
\r
45 import com.liferay.portal.model.PublicRenderParameter;
\r
46 import com.liferay.portal.model.impl.VirtualLayout;
\r
47 import com.liferay.portal.security.auth.AuthTokenUtil;
\r
48 import com.liferay.portal.service.GroupLocalServiceUtil;
\r
49 import com.liferay.portal.service.LayoutLocalServiceUtil;
\r
50 import com.liferay.portal.service.PortletLocalServiceUtil;
\r
51 import com.liferay.portal.theme.PortletDisplay;
\r
52 import com.liferay.portal.theme.ThemeDisplay;
\r
53 import com.liferay.portal.util.CookieKeys;
\r
54 import com.liferay.portal.util.PortalUtil;
\r
55 import com.liferay.portal.util.PortletKeys;
\r
56 import com.liferay.portal.util.PropsValues;
\r
57 import com.liferay.portal.util.WebKeys;
\r
58 import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
\r
59 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
\r
60 import com.liferay.portlet.social.util.FacebookUtil;
\r
61 import com.liferay.util.Encryptor;
\r
62 import com.liferay.util.EncryptorException;
\r
64 import java.io.IOException;
\r
65 import java.io.Serializable;
\r
66 import java.io.UnsupportedEncodingException;
\r
67 import java.io.Writer;
\r
69 import java.security.Key;
\r
71 import java.util.Collections;
\r
72 import java.util.Iterator;
\r
73 import java.util.LinkedHashMap;
\r
74 import java.util.LinkedHashSet;
\r
75 import java.util.Map;
\r
76 import java.util.Set;
\r
78 import javax.portlet.PortletMode;
\r
79 import javax.portlet.PortletModeException;
\r
80 import javax.portlet.PortletRequest;
\r
81 import javax.portlet.PortletURL;
\r
82 import javax.portlet.ResourceRequest;
\r
83 import javax.portlet.ResourceURL;
\r
84 import javax.portlet.WindowState;
\r
85 import javax.portlet.WindowStateException;
\r
87 import javax.servlet.http.HttpServletRequest;
\r
90 * @author Brian Wing Shun Chan
\r
91 * @author Jorge Ferrer
\r
92 * @author Connor McKay
\r
94 public class PortletURLImpl
\r
95 implements LiferayPortletURL, PortletURL, ResourceURL, Serializable {
\r
97 public PortletURLImpl(
\r
98 HttpServletRequest request, String portletId, long plid,
\r
101 _request = request;
\r
102 _portletId = portletId;
\r
104 _lifecycle = lifecycle;
\r
105 _parametersIncludedInPath = new LinkedHashSet<String>();
\r
106 _params = new LinkedHashMap<String, String[]>();
\r
107 _removePublicRenderParameters = new LinkedHashMap<String, String[]>();
\r
108 _secure = PortalUtil.isSecure(request);
\r
110 _wsrp = ParamUtil.getBoolean(request, "wsrp");
\r
112 Portlet portlet = getPortlet();
\r
114 if (portlet != null) {
\r
115 Set<String> autopropagatedParameters =
\r
116 portlet.getAutopropagatedParameters();
\r
118 for (String autopropagatedParameter : autopropagatedParameters) {
\r
119 if (PortalUtil.isReservedParameter(autopropagatedParameter)) {
\r
123 String value = request.getParameter(autopropagatedParameter);
\r
125 if (value != null) {
\r
126 setParameter(autopropagatedParameter, value);
\r
130 PortletApp portletApp = portlet.getPortletApp();
\r
132 _escapeXml = MapUtil.getBoolean(
\r
133 portletApp.getContainerRuntimeOptions(),
\r
134 LiferayPortletConfig.RUNTIME_OPTION_ESCAPE_XML,
\r
135 PropsValues.PORTLET_URL_ESCAPE_XML);
\r
138 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
\r
140 if ((layout != null) && (layout.getPlid() == _plid) &&
\r
141 (layout instanceof VirtualLayout)) {
\r
147 public PortletURLImpl(
\r
148 HttpServletRequest request, String portletId, long plid,
\r
149 String lifecycle, boolean isSearch) {
\r
151 _request = request;
\r
152 _portletId = portletId;
\r
154 _lifecycle = lifecycle;
\r
155 _parametersIncludedInPath = new LinkedHashSet<String>();
\r
156 _params = new LinkedHashMap<String, String[]>();
\r
157 _removePublicRenderParameters = new LinkedHashMap<String, String[]>();
\r
158 _secure = PortalUtil.isSecure(request);
\r
159 _search = isSearch;
\r
160 _wsrp = ParamUtil.getBoolean(request, "wsrp");
\r
162 Portlet portlet = getPortlet();
\r
164 if (portlet != null) {
\r
165 Set<String> autopropagatedParameters =
\r
166 portlet.getAutopropagatedParameters();
\r
168 for (String autopropagatedParameter : autopropagatedParameters) {
\r
169 if (PortalUtil.isReservedParameter(autopropagatedParameter)) {
\r
173 String value = request.getParameter(autopropagatedParameter);
\r
175 if (value != null) {
\r
176 setParameter(autopropagatedParameter, value);
\r
180 PortletApp portletApp = portlet.getPortletApp();
\r
182 _escapeXml = MapUtil.getBoolean(
\r
183 portletApp.getContainerRuntimeOptions(),
\r
184 LiferayPortletConfig.RUNTIME_OPTION_ESCAPE_XML,
\r
185 PropsValues.PORTLET_URL_ESCAPE_XML);
\r
188 Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
\r
190 if ((layout != null) && (layout.getPlid() == _plid) &&
\r
191 (layout instanceof VirtualLayout)) {
\r
197 public PortletURLImpl(
\r
198 PortletRequest portletRequest, String portletId, long plid,
\r
199 String lifecycle) {
\r
202 PortalUtil.getHttpServletRequest(portletRequest), portletId, plid,
\r
205 _portletRequest = portletRequest;
\r
208 public boolean is_search() {
\r
212 public void set_search(boolean _search) {
\r
213 this._search = _search;
\r
216 public void addParameterIncludedInPath(String name) {
\r
217 _parametersIncludedInPath.add(name);
\r
220 public void addProperty(String key, String value) {
\r
222 throw new IllegalArgumentException();
\r
226 public String getCacheability() {
\r
227 return _cacheability;
\r
230 public HttpServletRequest getHttpServletRequest() {
\r
234 public Layout getLayout() {
\r
235 if (_layout == null) {
\r
238 _layout = LayoutLocalServiceUtil.getLayout(_plid);
\r
241 catch (Exception e) {
\r
242 if (_log.isWarnEnabled()) {
\r
243 _log.warn("Layout cannot be found for " + _plid);
\r
251 public String getLayoutFriendlyURL() {
\r
252 return _layoutFriendlyURL;
\r
255 public String getLifecycle() {
\r
259 public String getNamespace() {
\r
260 if (_namespace == null) {
\r
261 _namespace = PortalUtil.getPortletNamespace(_portletId);
\r
267 public String getParameter(String name) {
\r
268 String[] values = _params.get(name);
\r
270 if ((values != null) && (values.length > 0)) {
\r
278 public Map<String, String[]> getParameterMap() {
\r
282 public Set<String> getParametersIncludedInPath() {
\r
283 return _parametersIncludedInPath;
\r
286 public long getPlid() {
\r
290 public Portlet getPortlet() {
\r
291 if (_portlet == null) {
\r
293 _portlet = PortletLocalServiceUtil.getPortletById(
\r
294 PortalUtil.getCompanyId(_request), _portletId);
\r
296 catch (SystemException se) {
\r
297 _log.error(se.getMessage());
\r
304 public String getPortletFriendlyURLPath() {
\r
305 String portletFriendlyURLPath = null;
\r
307 Portlet portlet = getPortlet();
\r
309 if (portlet != null) {
\r
310 FriendlyURLMapper mapper = portlet.getFriendlyURLMapperInstance();
\r
312 if (mapper != null) {
\r
313 portletFriendlyURLPath = mapper.buildPath(this);
\r
315 if (_log.isDebugEnabled()) {
\r
317 "Portlet friendly URL path " + portletFriendlyURLPath);
\r
322 return portletFriendlyURLPath;
\r
325 public String getPortletId() {
\r
329 public PortletMode getPortletMode() {
\r
330 if (_portletModeString == null) {
\r
334 return PortletModeFactory.getPortletMode(_portletModeString);
\r
337 public PortletRequest getPortletRequest() {
\r
338 return _portletRequest;
\r
341 public Set<String> getRemovedParameterNames() {
\r
342 return _removedParameterNames;
\r
345 public Map<String, String> getReservedParameterMap() {
\r
346 if (_reservedParameters != null) {
\r
347 return _reservedParameters;
\r
350 _reservedParameters = new LinkedHashMap<String, String>();
\r
352 _reservedParameters.put("p_p_id", _portletId);
\r
354 if (_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
\r
355 _reservedParameters.put("p_p_lifecycle", "1");
\r
357 else if (_lifecycle.equals(PortletRequest.RENDER_PHASE)) {
\r
358 _reservedParameters.put("p_p_lifecycle", "0");
\r
360 else if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
\r
361 _reservedParameters.put("p_p_lifecycle", "2");
\r
364 if (_windowStateString != null) {
\r
365 _reservedParameters.put("p_p_state", _windowStateString);
\r
368 if (_windowStateRestoreCurrentView) {
\r
369 _reservedParameters.put("p_p_state_rcv", "1");
\r
372 if (_portletModeString != null) {
\r
373 _reservedParameters.put("p_p_mode", _portletModeString);
\r
376 if (_resourceID != null) {
\r
377 _reservedParameters.put("p_p_resource_id", _resourceID);
\r
380 if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
\r
381 _reservedParameters.put("p_p_cacheability", _cacheability);
\r
384 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
\r
385 WebKeys.THEME_DISPLAY);
\r
387 PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
\r
389 if (Validator.isNotNull(portletDisplay.getColumnId())) {
\r
390 _reservedParameters.put("p_p_col_id", portletDisplay.getColumnId());
\r
393 if (portletDisplay.getColumnPos() > 0) {
\r
394 _reservedParameters.put(
\r
395 "p_p_col_pos", String.valueOf(portletDisplay.getColumnPos()));
\r
398 if (portletDisplay.getColumnCount() > 0) {
\r
399 _reservedParameters.put(
\r
401 String.valueOf(portletDisplay.getColumnCount()));
\r
404 _reservedParameters = Collections.unmodifiableMap(_reservedParameters);
\r
406 return _reservedParameters;
\r
409 public String getResourceID() {
\r
410 return _resourceID;
\r
413 public WindowState getWindowState() {
\r
414 if (_windowStateString == null) {
\r
418 return WindowStateFactory.getWindowState(_windowStateString);
\r
421 public boolean isAnchor() {
\r
425 public boolean isCopyCurrentRenderParameters() {
\r
426 return _copyCurrentRenderParameters;
\r
429 public boolean isEncrypt() {
\r
433 public boolean isEscapeXml() {
\r
437 public boolean isParameterIncludedInPath(String name) {
\r
438 if (_parametersIncludedInPath.contains(name)) {
\r
446 public boolean isSecure() {
\r
450 public void removePublicRenderParameter(String name) {
\r
451 if (name == null) {
\r
452 throw new IllegalArgumentException();
\r
455 PublicRenderParameter publicRenderParameter =
\r
456 _portlet.getPublicRenderParameter(name);
\r
458 if (publicRenderParameter == null) {
\r
459 if (_log.isWarnEnabled()) {
\r
460 _log.warn("Public parameter " + name + "does not exist");
\r
466 QName qName = publicRenderParameter.getQName();
\r
468 _removePublicRenderParameters.put(
\r
469 PortletQNameUtil.getRemovePublicRenderParameterName(qName),
\r
470 new String[] {"1"});
\r
473 public void setAnchor(boolean anchor) {
\r
479 public void setCacheability(String cacheability) {
\r
480 if (cacheability == null) {
\r
481 throw new IllegalArgumentException("Cacheability is null");
\r
484 if (!cacheability.equals(FULL) && !cacheability.equals(PORTLET) &&
\r
485 !cacheability.equals(PAGE)) {
\r
487 throw new IllegalArgumentException(
\r
488 "Cacheability " + cacheability + " is not " + FULL + ", " +
\r
489 PORTLET + ", or " + PAGE);
\r
492 if (_portletRequest instanceof ResourceRequest) {
\r
493 ResourceRequest resourceRequest = (ResourceRequest)_portletRequest;
\r
495 String parentCacheability = resourceRequest.getCacheability();
\r
497 if (parentCacheability.equals(FULL)) {
\r
498 if (!cacheability.equals(FULL)) {
\r
499 throw new IllegalStateException(
\r
500 "Unable to set a weaker cacheability " + cacheability);
\r
503 else if (parentCacheability.equals(PORTLET)) {
\r
504 if (!cacheability.equals(FULL) &&
\r
505 !cacheability.equals(PORTLET)) {
\r
507 throw new IllegalStateException(
\r
508 "Unable to set a weaker cacheability " + cacheability);
\r
513 _cacheability = cacheability;
\r
518 public void setControlPanelCategory(String controlPanelCategory) {
\r
519 _controlPanelCategory = controlPanelCategory;
\r
524 public void setCopyCurrentRenderParameters(
\r
525 boolean copyCurrentRenderParameters) {
\r
527 _copyCurrentRenderParameters = copyCurrentRenderParameters;
\r
530 public void setDoAsGroupId(long doAsGroupId) {
\r
531 _doAsGroupId = doAsGroupId;
\r
536 public void setDoAsUserId(long doAsUserId) {
\r
537 _doAsUserId = doAsUserId;
\r
542 public void setDoAsUserLanguageId(String doAsUserLanguageId) {
\r
543 _doAsUserLanguageId = doAsUserLanguageId;
\r
548 public void setEncrypt(boolean encrypt) {
\r
549 _encrypt = encrypt;
\r
554 public void setEscapeXml(boolean escapeXml) {
\r
555 _escapeXml = escapeXml;
\r
560 public void setLifecycle(String lifecycle) {
\r
561 _lifecycle = lifecycle;
\r
566 public void setParameter(String name, String value) {
\r
567 setParameter(name, value, PropsValues.PORTLET_URL_APPEND_PARAMETERS);
\r
570 public void setParameter(String name, String value, boolean append) {
\r
571 if ((name == null) || (value == null)) {
\r
572 throw new IllegalArgumentException();
\r
575 setParameter(name, new String[] {value}, append);
\r
578 public void setParameter(String name, String[] values) {
\r
579 setParameter(name, values, PropsValues.PORTLET_URL_APPEND_PARAMETERS);
\r
582 public void setParameter(String name, String[] values, boolean append) {
\r
583 if ((name == null) || (values == null)) {
\r
584 throw new IllegalArgumentException();
\r
587 for (String value : values) {
\r
588 if (value == null) {
\r
589 throw new IllegalArgumentException();
\r
594 _params.put(name, values);
\r
597 String[] oldValues = _params.get(name);
\r
599 if (oldValues == null) {
\r
600 _params.put(name, values);
\r
603 String[] newValues = ArrayUtil.append(oldValues, values);
\r
605 _params.put(name, newValues);
\r
612 public void setParameters(Map<String, String[]> params) {
\r
613 if (params == null) {
\r
614 throw new IllegalArgumentException();
\r
617 Map<String, String[]> newParams =
\r
618 new LinkedHashMap<String, String[]>();
\r
620 for (Map.Entry<String, String[]> entry : params.entrySet()) {
\r
622 String key = entry.getKey();
\r
623 String[] value = entry.getValue();
\r
626 throw new IllegalArgumentException();
\r
628 else if (value == null) {
\r
629 throw new IllegalArgumentException();
\r
632 newParams.put(key, value);
\r
634 catch (ClassCastException cce) {
\r
635 throw new IllegalArgumentException(cce);
\r
639 _params = newParams;
\r
645 public void setPlid(long plid) {
\r
651 public void setPortletId(String portletId) {
\r
652 _portletId = portletId;
\r
657 public void setPortletMode(PortletMode portletMode)
\r
658 throws PortletModeException {
\r
660 if (_portletRequest != null) {
\r
661 if (!getPortlet().hasPortletMode(
\r
662 _portletRequest.getResponseContentType(), portletMode)) {
\r
664 throw new PortletModeException(
\r
665 portletMode.toString(), portletMode);
\r
669 _portletModeString = portletMode.toString();
\r
674 public void setPortletMode(String portletMode) throws PortletModeException {
\r
675 setPortletMode(PortletModeFactory.getPortletMode(portletMode));
\r
678 public void setProperty(String key, String value) {
\r
680 throw new IllegalArgumentException();
\r
684 public void setRefererPlid(long refererPlid) {
\r
685 _refererPlid = refererPlid;
\r
690 public void setRemovedParameterNames(Set<String> removedParameterNames) {
\r
691 _removedParameterNames = removedParameterNames;
\r
696 public void setResourceID(String resourceID) {
\r
697 _resourceID = resourceID;
\r
700 public void setSecure(boolean secure) {
\r
706 public void setWindowState(String windowState) throws WindowStateException {
\r
707 setWindowState(WindowStateFactory.getWindowState(windowState));
\r
710 public void setWindowState(WindowState windowState)
\r
711 throws WindowStateException {
\r
713 if (_portletRequest != null) {
\r
714 if (!_portletRequest.isWindowStateAllowed(windowState)) {
\r
715 throw new WindowStateException(
\r
716 windowState.toString(), windowState);
\r
720 if (LiferayWindowState.isWindowStatePreserved(
\r
721 getWindowState(), windowState)) {
\r
723 _windowStateString = windowState.toString();
\r
729 public void setWindowStateRestoreCurrentView(
\r
730 boolean windowStateRestoreCurrentView) {
\r
732 _windowStateRestoreCurrentView = windowStateRestoreCurrentView;
\r
736 public String toString() {
\r
737 if (_toString != null) {
\r
742 Portlet portlet = getPortlet();
\r
743 if(portlet.getPortletId().equals("cahierDeTexte_WAR_cahierDeTexteportlet")){
\r
744 _toString = toStringCahierDeTexte();
\r
745 } else if(portlet.getPortletId().equals(PortletKeys.BLOGS)){
\r
746 _toString = toStringActualites();
\r
747 } else if(portlet.getPortletId().equals(PortletKeys.MESSAGE_BOARDS)){
\r
748 _toString = toStringForum();
\r
749 } else if(portlet.getPortletId().equals(PortletKeys.USERS_ADMIN)){
\r
750 _toString = toStringAnnuaire();
\r
751 } else if(portlet.getPortletId().equals("internalMessaging_WAR_internalMessagingportlet") || portlet.getPortletId().equals("internalmessagingawarness_WAR_internalMessagingportlet")){
\r
752 _toString = toStringMessagerie();
\r
753 } else if(portlet.getPortletId().equals("agenda_WAR_agendaportlet")){
\r
754 _toString = toStringAgenda();
\r
755 } else if(portlet.getPortletId().equals("fluxRss_WAR_internalMessagingportlet")){
\r
756 _toString = toStringFluxRss();
\r
758 _toString = generateToString();
\r
762 _toString = generateWSRPToString();
\r
765 _toString = generateToString();
\r
771 public String toStringCahierDeTexte(){
\r
772 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
774 return themeDisplay.getURLPortal() + "/user/" + themeDisplay.getUser().getLogin() + "/cahier-de-texte?eventId="+ Long.valueOf(this.getParameter("eventId"));
\r
775 } catch (PortalException e) {
\r
776 e.printStackTrace();
\r
777 } catch (SystemException e) {
\r
778 e.printStackTrace();
\r
783 public String toStringActualites() {
\r
784 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
786 Group group = GroupLocalServiceUtil.getGroup(BlogsEntryLocalServiceUtil.getBlogsEntry(Long.valueOf(this.getParameter("entryId"))).getGroupId());
\r
787 return themeDisplay.getURLPortal() + "/group" + group.getFriendlyURL() + "?p_p_id=actualites_WAR_actualitesportlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&entryId=" + Long.valueOf(this.getParameter("entryId"));
\r
788 } catch (PortalException e) {
\r
789 e.printStackTrace();
\r
790 } catch (SystemException e) {
\r
791 e.printStackTrace();
\r
796 public String toStringForum() {
\r
797 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
799 Group group = GroupLocalServiceUtil.getGroup(MBMessageLocalServiceUtil.getMBMessage( Long.valueOf(this.getParameter("messageId"))).getGroupId());
\r
800 return themeDisplay.getURLPortal() + "/group" + group.getFriendlyURL() + "?p_p_id=forum_WAR_forumportlet&p_p_lifecycle=0&p_p_state=maximized&p_p_mode=view&messageId=" + Long.valueOf(this.getParameter("messageId"));
\r
801 } catch (PortalException e) {
\r
802 e.printStackTrace();
\r
803 } catch (SystemException e) {
\r
804 e.printStackTrace();
\r
809 public String toStringAnnuaire() {
\r
810 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
812 return themeDisplay.getURLPortal() + "/user/" + themeDisplay.getUser().getLogin() + "/carnet-d-adresses?userId=" + this.getParameterMap().get("p_u_i_d")[0];
\r
813 } catch (PortalException e) {
\r
814 e.printStackTrace();
\r
815 } catch (SystemException e) {
\r
816 e.printStackTrace();
\r
821 public String toStringMessagerie(){
\r
822 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
824 return themeDisplay.getURLPortal() + "/user/" + themeDisplay.getUser().getLogin() + "/messagerie?messageId=" + Long.valueOf(this.getParameter("messageId"));
\r
825 } catch (PortalException e) {
\r
826 e.printStackTrace();
\r
827 } catch (SystemException e) {
\r
828 e.printStackTrace();
\r
833 private String toStringAgenda() {
\r
834 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
836 return themeDisplay.getURLPortal() + "/user/" + themeDisplay.getUser().getLogin() + "/agenda?eventAgendaId="+ Long.valueOf(this.getParameter("eventAgendaId"));
\r
837 } catch (PortalException e) {
\r
838 e.printStackTrace();
\r
839 } catch (SystemException e) {
\r
840 e.printStackTrace();
\r
845 private String toStringFluxRss() {
\r
846 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(WebKeys.THEME_DISPLAY);
\r
848 return themeDisplay.getURLPortal() + "/user/" + themeDisplay.getUser().getLogin() + "/messagerie?rssItemId="+ Long.valueOf(this.getParameter("rssItemId"));
\r
849 } catch (PortalException e) {
\r
850 e.printStackTrace();
\r
851 } catch (SystemException e) {
\r
852 e.printStackTrace();
\r
857 public void write(Writer writer) throws IOException {
\r
858 write(writer, _escapeXml);
\r
861 public void write(Writer writer, boolean escapeXml) throws IOException {
\r
862 String toString = toString();
\r
864 if (escapeXml && !_escapeXml) {
\r
865 toString = HtmlUtil.escape(toString);
\r
868 writer.write(toString);
\r
871 protected void addPortalAuthToken(StringBundler sb, Key key) {
\r
872 if (!PropsValues.AUTH_TOKEN_CHECK_ENABLED ||
\r
873 !_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
\r
878 Set<String> authTokenIgnorePortlets =
\r
879 PortalUtil.getAuthTokenIgnorePortlets();
\r
881 if (authTokenIgnorePortlets.contains(_portletId)) {
\r
885 sb.append("p_auth");
\r
886 sb.append(StringPool.EQUAL);
\r
887 sb.append(processValue(key, AuthTokenUtil.getToken(_request)));
\r
888 sb.append(StringPool.AMPERSAND);
\r
891 protected void addPortletAuthToken(StringBundler sb, Key key) {
\r
892 if (!PropsValues.PORTLET_ADD_DEFAULT_RESOURCE_CHECK_ENABLED) {
\r
896 HttpServletRequest request = PortalUtil.getOriginalServletRequest(
\r
899 String ppauth = ParamUtil.getString(request, "p_p_auth");
\r
901 String actualPortletAuthenticationToken = AuthTokenUtil.getToken(
\r
902 _request, _plid, _portletId);
\r
904 if (Validator.isNotNull(ppauth) &&
\r
905 ppauth.equals(actualPortletAuthenticationToken)) {
\r
907 sb.append("p_p_auth");
\r
908 sb.append(StringPool.EQUAL);
\r
909 sb.append(processValue(key, ppauth));
\r
910 sb.append(StringPool.AMPERSAND);
\r
915 Portlet portlet = (Portlet)_request.getAttribute(
\r
916 WebKeys.RENDER_PORTLET);
\r
918 if (portlet != null) {
\r
919 String portletId = portlet.getPortletId();
\r
921 if (portletId.equals(_portletId) ||
\r
922 portletId.equals(PortletKeys.CONTROL_PANEL_MENU) ||
\r
923 !_portlet.isAddDefaultResource()) {
\r
929 Set<String> portletAddDefaultResourceCheckWhiteList =
\r
930 PortalUtil.getPortletAddDefaultResourceCheckWhitelist();
\r
932 if (portletAddDefaultResourceCheckWhiteList.contains(_portletId)) {
\r
936 sb.append("p_p_auth");
\r
937 sb.append(StringPool.EQUAL);
\r
938 sb.append(processValue(key, actualPortletAuthenticationToken));
\r
939 sb.append(StringPool.AMPERSAND);
\r
942 protected void clearCache() {
\r
943 _reservedParameters = null;
\r
947 protected String generateToString() {
\r
948 StringBundler sb = new StringBundler(64);
\r
950 ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
\r
951 WebKeys.THEME_DISPLAY);
\r
953 String portalURL = null;
\r
955 if (themeDisplay.isFacebook()) {
\r
957 FacebookUtil.FACEBOOK_APPS_URL +
\r
958 themeDisplay.getFacebookCanvasPageURL();
\r
961 portalURL = PortalUtil.getPortalURL(_request, _secure);
\r
965 if (_layoutFriendlyURL == null) {
\r
966 Layout layout = getLayout();
\r
968 if (layout != null) {
\r
969 _layoutFriendlyURL = GetterUtil.getString(
\r
970 PortalUtil.getLayoutFriendlyURL(layout, themeDisplay));
\r
973 _layoutFriendlyURL = HttpUtil.protocolize(
\r
974 _layoutFriendlyURL, true);
\r
979 catch (Exception e) {
\r
987 Company company = PortalUtil.getCompany(_request);
\r
989 key = company.getKeyObj();
\r
992 catch (Exception e) {
\r
996 if (Validator.isNull(_layoutFriendlyURL)) {
\r
997 sb.append(portalURL);
\r
998 sb.append(themeDisplay.getPathMain());
\r
999 sb.append("/portal/layout?");
\r
1001 addPortalAuthToken(sb, key);
\r
1003 sb.append("p_l_id");
\r
1004 sb.append(StringPool.EQUAL);
\r
1005 sb.append(processValue(key, _plid));
\r
1006 sb.append(StringPool.AMPERSAND);
\r
1009 if (themeDisplay.isFacebook()) {
\r
1010 sb.append(portalURL);
\r
1014 // A virtual host URL will contain the complete path. Do not
\r
1015 // append the portal URL if the virtual host URL starts with
\r
1016 // "http://" or "https://".
\r
1018 if (!_layoutFriendlyURL.startsWith(Http.HTTP_WITH_SLASH) &&
\r
1019 !_layoutFriendlyURL.startsWith(Http.HTTPS_WITH_SLASH)) {
\r
1021 sb.append(portalURL);
\r
1024 sb.append(_layoutFriendlyURL);
\r
1027 String friendlyURLPath = getPortletFriendlyURLPath();
\r
1029 if (Validator.isNotNull(friendlyURLPath)) {
\r
1030 if (themeDisplay.isFacebook()) {
\r
1031 int pos = friendlyURLPath.indexOf(CharPool.SLASH, 1);
\r
1034 sb.append(friendlyURLPath.substring(pos));
\r
1037 sb.append(friendlyURLPath);
\r
1042 sb.append(friendlyURLPath);
\r
1046 sb.append(StringPool.QUESTION);
\r
1048 addPortalAuthToken(sb, key);
\r
1051 addPortletAuthToken(sb, key);
\r
1053 for (Map.Entry<String, String> entry :
\r
1054 getReservedParameterMap().entrySet()) {
\r
1056 String name = entry.getKey();
\r
1058 if (!isParameterIncludedInPath(name)) {
\r
1060 sb.append(StringPool.EQUAL);
\r
1061 sb.append(processValue(key, entry.getValue()));
\r
1062 sb.append(StringPool.AMPERSAND);
\r
1066 String outerPortletId = PortalUtil.getOuterPortletId(_request);
\r
1068 if (outerPortletId != null) {
\r
1069 sb.append("p_o_p_id");
\r
1070 sb.append(StringPool.EQUAL);
\r
1071 sb.append(processValue(key, outerPortletId));
\r
1072 sb.append(StringPool.AMPERSAND);
\r
1075 if (_doAsUserId > 0) {
\r
1077 Company company = PortalUtil.getCompany(_request);
\r
1079 sb.append("doAsUserId");
\r
1080 sb.append(StringPool.EQUAL);
\r
1081 sb.append(processValue(company.getKeyObj(), _doAsUserId));
\r
1082 sb.append(StringPool.AMPERSAND);
\r
1084 catch (Exception e) {
\r
1089 String doAsUserId = themeDisplay.getDoAsUserId();
\r
1091 if (Validator.isNotNull(doAsUserId)) {
\r
1092 sb.append("doAsUserId");
\r
1093 sb.append(StringPool.EQUAL);
\r
1094 sb.append(processValue(key, doAsUserId));
\r
1095 sb.append(StringPool.AMPERSAND);
\r
1099 String doAsUserLanguageId = _doAsUserLanguageId;
\r
1101 if (Validator.isNull(doAsUserLanguageId)) {
\r
1102 doAsUserLanguageId = themeDisplay.getDoAsUserLanguageId();
\r
1105 if (Validator.isNotNull(doAsUserLanguageId)) {
\r
1106 sb.append("doAsUserLanguageId");
\r
1107 sb.append(StringPool.EQUAL);
\r
1108 sb.append(processValue(key, doAsUserLanguageId));
\r
1109 sb.append(StringPool.AMPERSAND);
\r
1112 long doAsGroupId = _doAsGroupId;
\r
1114 if (doAsGroupId <= 0) {
\r
1115 doAsGroupId = themeDisplay.getDoAsGroupId();
\r
1118 if (doAsGroupId > 0) {
\r
1119 sb.append("doAsGroupId");
\r
1120 sb.append(StringPool.EQUAL);
\r
1121 sb.append(processValue(key, doAsGroupId));
\r
1122 sb.append(StringPool.AMPERSAND);
\r
1125 long refererPlid = _refererPlid;
\r
1127 if (refererPlid <= 0) {
\r
1128 refererPlid = themeDisplay.getRefererPlid();
\r
1131 if (refererPlid > 0) {
\r
1132 sb.append("refererPlid");
\r
1133 sb.append(StringPool.EQUAL);
\r
1134 sb.append(processValue(key, refererPlid));
\r
1135 sb.append(StringPool.AMPERSAND);
\r
1138 String controlPanelCategory = _controlPanelCategory;
\r
1140 if (Validator.isNull(controlPanelCategory)) {
\r
1141 controlPanelCategory = themeDisplay.getControlPanelCategory();
\r
1144 if (Validator.isNotNull(controlPanelCategory)) {
\r
1145 sb.append("controlPanelCategory");
\r
1146 sb.append(StringPool.EQUAL);
\r
1147 sb.append(processValue(key, controlPanelCategory));
\r
1148 sb.append(StringPool.AMPERSAND);
\r
1151 Iterator<Map.Entry<String, String[]>> itr =
\r
1152 _removePublicRenderParameters.entrySet().iterator();
\r
1154 while (itr.hasNext()) {
\r
1155 String lastString = sb.stringAt(sb.index() - 1);
\r
1157 if (lastString.charAt(lastString.length() - 1) !=
\r
1158 CharPool.AMPERSAND) {
\r
1160 sb.append(StringPool.AMPERSAND);
\r
1163 Map.Entry<String, String[]> entry = itr.next();
\r
1165 sb.append(entry.getKey());
\r
1166 sb.append(StringPool.EQUAL);
\r
1167 sb.append(processValue(key, entry.getValue()[0]));
\r
1168 sb.append(StringPool.AMPERSAND);
\r
1171 if (_copyCurrentRenderParameters) {
\r
1172 mergeRenderParameters();
\r
1175 itr = _params.entrySet().iterator();
\r
1177 while (itr.hasNext()) {
\r
1178 Map.Entry<String, String[]> entry = itr.next();
\r
1180 String name = entry.getKey();
\r
1181 String[] values = entry.getValue();
\r
1183 if (isParameterIncludedInPath(name)) {
\r
1187 String publicRenderParameterName = getPublicRenderParameterName(
\r
1190 if (Validator.isNotNull(publicRenderParameterName)) {
\r
1191 name = publicRenderParameterName;
\r
1194 name = prependNamespace(name);
\r
1196 for (int i = 0; i < values.length; i++) {
\r
1198 sb.append(StringPool.EQUAL);
\r
1199 sb.append(processValue(key, values[i]));
\r
1201 if (((i + 1) < values.length) || itr.hasNext()) {
\r
1202 sb.append(StringPool.AMPERSAND);
\r
1208 sb.append(StringPool.AMPERSAND + WebKeys.ENCRYPT + "=1");
\r
1211 if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
\r
1212 if (_anchor && (_windowStateString != null) &&
\r
1213 !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
\r
1214 !_windowStateString.equals(
\r
1215 LiferayWindowState.EXCLUSIVE.toString()) &&
\r
1216 !_windowStateString.equals(
\r
1217 LiferayWindowState.POP_UP.toString())) {
\r
1219 String lastString = sb.stringAt(sb.index() - 1);
\r
1221 if (lastString.charAt(lastString.length() - 1) !=
\r
1222 CharPool.AMPERSAND) {
\r
1224 sb.append(StringPool.AMPERSAND);
\r
1228 sb.append(_portletId);
\r
1232 String result = sb.toString();
\r
1234 if (result.endsWith(StringPool.AMPERSAND) ||
\r
1235 result.endsWith(StringPool.QUESTION)) {
\r
1237 result = result.substring(0, result.length() - 1);
\r
1240 if (themeDisplay.isFacebook()) {
\r
1242 // Facebook requires the path portion of the URL to end with a slash
\r
1244 int pos = result.indexOf(CharPool.QUESTION);
\r
1247 if (!result.endsWith(StringPool.SLASH)) {
\r
1248 result += StringPool.SLASH;
\r
1252 String path = result.substring(0, pos);
\r
1254 if (!result.endsWith(StringPool.SLASH)) {
\r
1255 result = path + StringPool.SLASH + result.substring(pos);
\r
1259 else if (!CookieKeys.hasSessionId(_request)) {
\r
1260 result = PortalUtil.getURLWithSessionId(
\r
1261 result, _request.getSession().getId());
\r
1265 result = HtmlUtil.escape(result);
\r
1268 if (result.length() > _URL_MAXIMUM_LENGTH) {
\r
1269 result = shortenURL(result, 2);
\r
1275 protected String generateWSRPToString() {
\r
1276 StringBundler sb = new StringBundler("wsrp_rewrite?");
\r
1278 sb.append("wsrp-urlType");
\r
1279 sb.append(StringPool.EQUAL);
\r
1281 if (_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
\r
1282 sb.append(HttpUtil.encodeURL("blockingAction"));
\r
1284 else if (_lifecycle.equals(PortletRequest.RENDER_PHASE)) {
\r
1285 sb.append(HttpUtil.encodeURL("render"));
\r
1287 else if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
\r
1288 sb.append(HttpUtil.encodeURL("resource"));
\r
1291 sb.append(StringPool.AMPERSAND);
\r
1293 if (_windowStateString != null) {
\r
1294 sb.append("wsrp-windowState");
\r
1295 sb.append(StringPool.EQUAL);
\r
1296 sb.append(HttpUtil.encodeURL("wsrp:" + _windowStateString));
\r
1297 sb.append(StringPool.AMPERSAND);
\r
1300 if (_portletModeString != null) {
\r
1301 sb.append("wsrp-mode");
\r
1302 sb.append(StringPool.EQUAL);
\r
1303 sb.append(HttpUtil.encodeURL("wsrp:" + _portletModeString));
\r
1304 sb.append(StringPool.AMPERSAND);
\r
1307 if (_resourceID != null) {
\r
1308 sb.append("wsrp-resourceID");
\r
1309 sb.append(StringPool.EQUAL);
\r
1310 sb.append(HttpUtil.encodeURL(_resourceID));
\r
1311 sb.append(StringPool.AMPERSAND);
\r
1314 if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
\r
1315 sb.append("wsrp-resourceCacheability");
\r
1316 sb.append(StringPool.EQUAL);
\r
1317 sb.append(HttpUtil.encodeURL(_cacheability));
\r
1318 sb.append(StringPool.AMPERSAND);
\r
1321 if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
\r
1322 if (_anchor && (_windowStateString != null) &&
\r
1323 !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
\r
1324 !_windowStateString.equals(
\r
1325 LiferayWindowState.EXCLUSIVE.toString()) &&
\r
1326 !_windowStateString.equals(
\r
1327 LiferayWindowState.POP_UP.toString())) {
\r
1329 sb.append("wsrp-fragmentID");
\r
1330 sb.append(StringPool.EQUAL);
\r
1332 sb.append(_portletId);
\r
1333 sb.append(StringPool.AMPERSAND);
\r
1337 if (_copyCurrentRenderParameters) {
\r
1338 mergeRenderParameters();
\r
1341 StringBundler parameterSb = new StringBundler();
\r
1343 Iterator<Map.Entry<String, String[]>> itr =
\r
1344 _params.entrySet().iterator();
\r
1346 while (itr.hasNext()) {
\r
1347 Map.Entry<String, String[]> entry = itr.next();
\r
1349 String name = entry.getKey();
\r
1350 String[] values = entry.getValue();
\r
1352 if (isParameterIncludedInPath(name)) {
\r
1356 String publicRenderParameterName = getPublicRenderParameterName(
\r
1359 if (Validator.isNotNull(publicRenderParameterName)) {
\r
1360 name = publicRenderParameterName;
\r
1363 name = prependNamespace(name);
\r
1365 for (int i = 0; i < values.length; i++) {
\r
1366 parameterSb.append(name);
\r
1367 parameterSb.append(StringPool.EQUAL);
\r
1368 parameterSb.append(HttpUtil.encodeURL(values[i]));
\r
1370 if (((i + 1) < values.length) || itr.hasNext()) {
\r
1371 parameterSb.append(StringPool.AMPERSAND);
\r
1376 sb.append("wsrp-navigationalState");
\r
1377 sb.append(StringPool.EQUAL);
\r
1379 byte[] parameterBytes = null;
\r
1382 String parameterString = parameterSb.toString();
\r
1384 parameterBytes = parameterString.getBytes(StringPool.UTF8);
\r
1386 catch (UnsupportedEncodingException uee) {
\r
1387 if (_log.isWarnEnabled()) {
\r
1388 _log.warn(uee, uee);
\r
1392 String navigationalState = Base64.toURLSafe(
\r
1393 Base64.encode(parameterBytes));
\r
1395 sb.append(navigationalState);
\r
1397 sb.append("/wsrp_rewrite");
\r
1399 return sb.toString();
\r
1402 protected String getPublicRenderParameterName(String name) {
\r
1403 Portlet portlet = getPortlet();
\r
1405 String publicRenderParameterName = null;
\r
1407 if (portlet != null) {
\r
1408 PublicRenderParameter publicRenderParameter =
\r
1409 portlet.getPublicRenderParameter(name);
\r
1411 if (publicRenderParameter != null) {
\r
1412 QName qName = publicRenderParameter.getQName();
\r
1414 publicRenderParameterName =
\r
1415 PortletQNameUtil.getPublicRenderParameterName(qName);
\r
1419 return publicRenderParameterName;
\r
1422 protected boolean isBlankValue(String[] value) {
\r
1423 if ((value != null) && (value.length == 1) &&
\r
1424 value[0].equals(StringPool.BLANK)) {
\r
1433 protected void mergeRenderParameters() {
\r
1434 String namespace = getNamespace();
\r
1436 Layout layout = getLayout();
\r
1438 Map<String, String[]> renderParameters = RenderParametersPool.get(
\r
1439 _request, layout.getPlid(), getPortlet().getPortletId());
\r
1441 for (Map.Entry<String, String[]> entry : renderParameters.entrySet()) {
\r
1442 String name = entry.getKey();
\r
1444 if (name.indexOf(namespace) != -1) {
\r
1445 name = name.substring(namespace.length());
\r
1448 if (!_lifecycle.equals(PortletRequest.RESOURCE_PHASE) &&
\r
1449 (_removedParameterNames != null) &&
\r
1450 _removedParameterNames.contains(name)) {
\r
1455 String[] oldValues = entry.getValue();
\r
1456 String[] newValues = _params.get(name);
\r
1458 if (newValues == null) {
\r
1459 _params.put(name, oldValues);
\r
1461 else if (isBlankValue(newValues)) {
\r
1462 _params.remove(name);
\r
1465 newValues = ArrayUtil.append(newValues, oldValues);
\r
1467 _params.put(name, newValues);
\r
1472 protected String prependNamespace(String name) {
\r
1473 String namespace = getNamespace();
\r
1475 if (!PortalUtil.isReservedParameter(name) &&
\r
1476 !name.startsWith(PortletQName.PUBLIC_RENDER_PARAMETER_NAMESPACE) &&
\r
1477 !name.startsWith(namespace)) {
\r
1479 return namespace.concat(name);
\r
1486 protected String processValue(Key key, int value) {
\r
1487 return processValue(key, String.valueOf(value));
\r
1490 protected String processValue(Key key, long value) {
\r
1491 return processValue(key, String.valueOf(value));
\r
1494 protected String processValue(Key key, String value) {
\r
1495 if (key == null) {
\r
1496 return HttpUtil.encodeURL(value);
\r
1500 return HttpUtil.encodeURL(Encryptor.encrypt(key, value));
\r
1502 catch (EncryptorException ee) {
\r
1508 protected String shortenURL(String url, int count) {
\r
1513 StringBundler sb = new StringBundler();
\r
1515 String[] params = url.split(StringPool.AMPERSAND);
\r
1517 for (int i = 0; i < params.length; i++) {
\r
1518 String param = params[i];
\r
1520 if (param.contains("_backURL=") || param.contains("_redirect=") ||
\r
1521 param.contains("_returnToFullPageURL=")) {
\r
1523 int pos = param.indexOf(StringPool.EQUAL);
\r
1525 String qName = param.substring(0, pos);
\r
1527 String redirect = param.substring(pos + 1);
\r
1529 redirect = HttpUtil.decodeURL(redirect);
\r
1531 String newURL = shortenURL(redirect, count - 1);
\r
1533 if (newURL != null) {
\r
1534 newURL = HttpUtil.encodeURL(newURL);
\r
1537 sb.append(StringPool.EQUAL);
\r
1538 sb.append(newURL);
\r
1540 if (i < (params.length - 1)) {
\r
1541 sb.append(StringPool.AMPERSAND);
\r
1548 if (i < (params.length - 1)) {
\r
1549 sb.append(StringPool.AMPERSAND);
\r
1554 return sb.toString();
\r
1557 private static final long _URL_MAXIMUM_LENGTH = 2083;
\r
1559 private static Log _log = LogFactoryUtil.getLog(PortletURLImpl.class);
\r
1561 private boolean _anchor = true;
\r
1562 private String _cacheability = ResourceURL.PAGE;
\r
1563 private String _controlPanelCategory;
\r
1564 private boolean _copyCurrentRenderParameters;
\r
1565 private long _doAsGroupId;
\r
1566 private long _doAsUserId;
\r
1567 private String _doAsUserLanguageId;
\r
1568 private boolean _encrypt;
\r
1569 private boolean _escapeXml = PropsValues.PORTLET_URL_ESCAPE_XML;
\r
1570 private Layout _layout;
\r
1571 private String _layoutFriendlyURL;
\r
1572 private String _lifecycle;
\r
1573 private String _namespace;
\r
1574 private Set<String> _parametersIncludedInPath;
\r
1575 private Map<String, String[]> _params;
\r
1576 private long _plid;
\r
1577 private Portlet _portlet;
\r
1578 private String _portletId;
\r
1579 private String _portletModeString;
\r
1580 private PortletRequest _portletRequest;
\r
1581 private long _refererPlid;
\r
1582 private Set<String> _removedParameterNames;
\r
1583 private Map<String, String[]> _removePublicRenderParameters;
\r
1584 private HttpServletRequest _request;
\r
1585 private Map<String, String> _reservedParameters;
\r
1586 private String _resourceID;
\r
1587 private boolean _secure;
\r
1588 private String _toString;
\r
1589 private boolean _windowStateRestoreCurrentView;
\r
1590 private String _windowStateString;
\r
1591 private boolean _search;
\r
1592 private boolean _wsrp;
\r