001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet;
016    
017    import com.liferay.portal.kernel.exception.SystemException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.portlet.FriendlyURLMapper;
021    import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
022    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
023    import com.liferay.portal.kernel.portlet.LiferayWindowState;
024    import com.liferay.portal.kernel.portlet.PortletModeFactory;
025    import com.liferay.portal.kernel.portlet.WindowStateFactory;
026    import com.liferay.portal.kernel.util.ArrayUtil;
027    import com.liferay.portal.kernel.util.Base64;
028    import com.liferay.portal.kernel.util.CharPool;
029    import com.liferay.portal.kernel.util.CookieKeys;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.HtmlUtil;
032    import com.liferay.portal.kernel.util.Http;
033    import com.liferay.portal.kernel.util.HttpUtil;
034    import com.liferay.portal.kernel.util.MapUtil;
035    import com.liferay.portal.kernel.util.ParamUtil;
036    import com.liferay.portal.kernel.util.StringBundler;
037    import com.liferay.portal.kernel.util.StringPool;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.kernel.xml.QName;
040    import com.liferay.portal.model.Company;
041    import com.liferay.portal.model.Layout;
042    import com.liferay.portal.model.Portlet;
043    import com.liferay.portal.model.PortletApp;
044    import com.liferay.portal.model.PublicRenderParameter;
045    import com.liferay.portal.model.impl.VirtualLayout;
046    import com.liferay.portal.security.auth.AuthTokenUtil;
047    import com.liferay.portal.security.lang.DoPrivilegedUtil;
048    import com.liferay.portal.service.LayoutLocalServiceUtil;
049    import com.liferay.portal.service.PortletLocalServiceUtil;
050    import com.liferay.portal.theme.PortletDisplay;
051    import com.liferay.portal.theme.ThemeDisplay;
052    import com.liferay.portal.util.PortalUtil;
053    import com.liferay.portal.util.PortletKeys;
054    import com.liferay.portal.util.PropsValues;
055    import com.liferay.portal.util.WebKeys;
056    import com.liferay.portlet.social.util.FacebookUtil;
057    import com.liferay.util.Encryptor;
058    import com.liferay.util.EncryptorException;
059    
060    import java.io.IOException;
061    import java.io.Serializable;
062    import java.io.UnsupportedEncodingException;
063    import java.io.Writer;
064    
065    import java.security.Key;
066    import java.security.PrivilegedAction;
067    
068    import java.util.Collections;
069    import java.util.LinkedHashMap;
070    import java.util.LinkedHashSet;
071    import java.util.Map;
072    import java.util.Set;
073    
074    import javax.portlet.PortletMode;
075    import javax.portlet.PortletModeException;
076    import javax.portlet.PortletRequest;
077    import javax.portlet.PortletURL;
078    import javax.portlet.ResourceRequest;
079    import javax.portlet.ResourceURL;
080    import javax.portlet.WindowState;
081    import javax.portlet.WindowStateException;
082    
083    import javax.servlet.http.HttpServletRequest;
084    
085    /**
086     * @author Brian Wing Shun Chan
087     * @author Jorge Ferrer
088     * @author Connor McKay
089     */
090    public class PortletURLImpl
091            implements LiferayPortletURL, PortletURL, ResourceURL, Serializable {
092    
093            public PortletURLImpl(
094                    HttpServletRequest request, String portletId, long plid,
095                    String lifecycle) {
096    
097                    _request = request;
098                    _portletId = portletId;
099                    _plid = plid;
100                    _lifecycle = lifecycle;
101                    _parametersIncludedInPath = new LinkedHashSet<String>();
102                    _params = new LinkedHashMap<String, String[]>();
103                    _removePublicRenderParameters = new LinkedHashMap<String, String[]>();
104                    _secure = PortalUtil.isSecure(request);
105                    _wsrp = ParamUtil.getBoolean(request, "wsrp");
106    
107                    Portlet portlet = getPortlet();
108    
109                    if (portlet != null) {
110                            Set<String> autopropagatedParameters =
111                                    portlet.getAutopropagatedParameters();
112    
113                            for (String autopropagatedParameter : autopropagatedParameters) {
114                                    if (PortalUtil.isReservedParameter(autopropagatedParameter)) {
115                                            continue;
116                                    }
117    
118                                    String value = request.getParameter(autopropagatedParameter);
119    
120                                    if (value != null) {
121                                            setParameter(autopropagatedParameter, value);
122                                    }
123                            }
124    
125                            PortletApp portletApp = portlet.getPortletApp();
126    
127                            _escapeXml = MapUtil.getBoolean(
128                                    portletApp.getContainerRuntimeOptions(),
129                                    LiferayPortletConfig.RUNTIME_OPTION_ESCAPE_XML,
130                                    PropsValues.PORTLET_URL_ESCAPE_XML);
131                    }
132    
133                    Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
134    
135                    if ((layout != null) && (layout.getPlid() == _plid) &&
136                            (layout instanceof VirtualLayout)) {
137    
138                            _layout = layout;
139                    }
140            }
141    
142            public PortletURLImpl(
143                    PortletRequest portletRequest, String portletId, long plid,
144                    String lifecycle) {
145    
146                    this(
147                            PortalUtil.getHttpServletRequest(portletRequest), portletId, plid,
148                            lifecycle);
149    
150                    _portletRequest = portletRequest;
151            }
152    
153            public void addParameterIncludedInPath(String name) {
154                    _parametersIncludedInPath.add(name);
155            }
156    
157            public void addProperty(String key, String value) {
158                    if (key == null) {
159                            throw new IllegalArgumentException();
160                    }
161            }
162    
163            public String getCacheability() {
164                    return _cacheability;
165            }
166    
167            public HttpServletRequest getHttpServletRequest() {
168                    return _request;
169            }
170    
171            public Layout getLayout() {
172                    if (_layout == null) {
173                            try {
174                                    if (_plid > 0) {
175                                            _layout = LayoutLocalServiceUtil.getLayout(_plid);
176                                    }
177                            }
178                            catch (Exception e) {
179                                    if (_log.isWarnEnabled()) {
180                                            _log.warn("Layout cannot be found for " + _plid);
181                                    }
182                            }
183                    }
184    
185                    return _layout;
186            }
187    
188            public String getLayoutFriendlyURL() {
189                    return _layoutFriendlyURL;
190            }
191    
192            public String getLifecycle() {
193                    return _lifecycle;
194            }
195    
196            public String getNamespace() {
197                    if (_namespace == null) {
198                            _namespace = PortalUtil.getPortletNamespace(_portletId);
199                    }
200    
201                    return _namespace;
202            }
203    
204            public String getParameter(String name) {
205                    String[] values = _params.get(name);
206    
207                    if ((values != null) && (values.length > 0)) {
208                            return values[0];
209                    }
210                    else {
211                            return null;
212                    }
213            }
214    
215            public Map<String, String[]> getParameterMap() {
216                    return _params;
217            }
218    
219            public Set<String> getParametersIncludedInPath() {
220                    return _parametersIncludedInPath;
221            }
222    
223            public long getPlid() {
224                    return _plid;
225            }
226    
227            public Portlet getPortlet() {
228                    if (_portlet == null) {
229                            try {
230                                    _portlet = PortletLocalServiceUtil.getPortletById(
231                                            PortalUtil.getCompanyId(_request), _portletId);
232                            }
233                            catch (SystemException se) {
234                                    _log.error(se.getMessage());
235                            }
236                    }
237    
238                    return _portlet;
239            }
240    
241            public String getPortletFriendlyURLPath() {
242                    String portletFriendlyURLPath = null;
243    
244                    Portlet portlet = getPortlet();
245    
246                    if (portlet != null) {
247                            FriendlyURLMapper mapper = portlet.getFriendlyURLMapperInstance();
248    
249                            if (mapper != null) {
250                                    portletFriendlyURLPath = mapper.buildPath(this);
251    
252                                    if (_log.isDebugEnabled()) {
253                                            _log.debug(
254                                                    "Portlet friendly URL path " + portletFriendlyURLPath);
255                                    }
256                            }
257                    }
258    
259                    return portletFriendlyURLPath;
260            }
261    
262            public String getPortletId() {
263                    return _portletId;
264            }
265    
266            public PortletMode getPortletMode() {
267                    if (_portletModeString == null) {
268                            return null;
269                    }
270    
271                    return PortletModeFactory.getPortletMode(_portletModeString);
272            }
273    
274            public PortletRequest getPortletRequest() {
275                    return _portletRequest;
276            }
277    
278            public Set<String> getRemovedParameterNames() {
279                    return _removedParameterNames;
280            }
281    
282            public Map<String, String> getReservedParameterMap() {
283                    if (_reservedParameters != null) {
284                            return _reservedParameters;
285                    }
286    
287                    _reservedParameters = new LinkedHashMap<String, String>();
288    
289                    _reservedParameters.put("p_p_id", _portletId);
290    
291                    if (_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
292                            _reservedParameters.put("p_p_lifecycle", "1");
293                    }
294                    else if (_lifecycle.equals(PortletRequest.RENDER_PHASE)) {
295                            _reservedParameters.put("p_p_lifecycle", "0");
296                    }
297                    else if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
298                            _reservedParameters.put("p_p_lifecycle", "2");
299                    }
300    
301                    if (_windowStateString != null) {
302                            _reservedParameters.put("p_p_state", _windowStateString);
303                    }
304    
305                    if (_windowStateRestoreCurrentView) {
306                            _reservedParameters.put("p_p_state_rcv", "1");
307                    }
308    
309                    if (_portletModeString != null) {
310                            _reservedParameters.put("p_p_mode", _portletModeString);
311                    }
312    
313                    if (_resourceID != null) {
314                            _reservedParameters.put("p_p_resource_id", _resourceID);
315                    }
316    
317                    if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
318                            _reservedParameters.put("p_p_cacheability", _cacheability);
319                    }
320    
321                    ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
322                            WebKeys.THEME_DISPLAY);
323    
324                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
325    
326                    if (Validator.isNotNull(portletDisplay.getColumnId())) {
327                            _reservedParameters.put("p_p_col_id", portletDisplay.getColumnId());
328                    }
329    
330                    if (portletDisplay.getColumnPos() > 0) {
331                            _reservedParameters.put(
332                                    "p_p_col_pos", String.valueOf(portletDisplay.getColumnPos()));
333                    }
334    
335                    if (portletDisplay.getColumnCount() > 0) {
336                            _reservedParameters.put(
337                                    "p_p_col_count",
338                                    String.valueOf(portletDisplay.getColumnCount()));
339                    }
340    
341                    _reservedParameters = Collections.unmodifiableMap(_reservedParameters);
342    
343                    return _reservedParameters;
344            }
345    
346            public String getResourceID() {
347                    return _resourceID;
348            }
349    
350            public WindowState getWindowState() {
351                    if (_windowStateString == null) {
352                            return null;
353                    }
354    
355                    return WindowStateFactory.getWindowState(_windowStateString);
356            }
357    
358            public boolean isAnchor() {
359                    return _anchor;
360            }
361    
362            public boolean isCopyCurrentRenderParameters() {
363                    return _copyCurrentRenderParameters;
364            }
365    
366            public boolean isEncrypt() {
367                    return _encrypt;
368            }
369    
370            public boolean isEscapeXml() {
371                    return _escapeXml;
372            }
373    
374            public boolean isParameterIncludedInPath(String name) {
375                    if (_parametersIncludedInPath.contains(name)) {
376                            return true;
377                    }
378                    else {
379                            return false;
380                    }
381            }
382    
383            public boolean isSecure() {
384                    return _secure;
385            }
386    
387            public void removePublicRenderParameter(String name) {
388                    if (name == null) {
389                            throw new IllegalArgumentException();
390                    }
391    
392                    PublicRenderParameter publicRenderParameter =
393                            _portlet.getPublicRenderParameter(name);
394    
395                    if (publicRenderParameter == null) {
396                            if (_log.isWarnEnabled()) {
397                                    _log.warn("Public parameter " + name + "does not exist");
398                            }
399    
400                            return;
401                    }
402    
403                    QName qName = publicRenderParameter.getQName();
404    
405                    _removePublicRenderParameters.put(
406                            PortletQNameUtil.getRemovePublicRenderParameterName(qName),
407                            new String[] {"1"});
408            }
409    
410            public void setAnchor(boolean anchor) {
411                    _anchor = anchor;
412    
413                    clearCache();
414            }
415    
416            public void setCacheability(String cacheability) {
417                    if (cacheability == null) {
418                            throw new IllegalArgumentException("Cacheability is null");
419                    }
420    
421                    if (!cacheability.equals(FULL) && !cacheability.equals(PORTLET) &&
422                            !cacheability.equals(PAGE)) {
423    
424                            throw new IllegalArgumentException(
425                                    "Cacheability " + cacheability + " is not " + FULL + ", " +
426                                            PORTLET + ", or " + PAGE);
427                    }
428    
429                    if (_portletRequest instanceof ResourceRequest) {
430                            ResourceRequest resourceRequest = (ResourceRequest)_portletRequest;
431    
432                            String parentCacheability = resourceRequest.getCacheability();
433    
434                            if (parentCacheability.equals(FULL)) {
435                                    if (!cacheability.equals(FULL)) {
436                                            throw new IllegalStateException(
437                                                    "Unable to set a weaker cacheability " + cacheability);
438                                    }
439                            }
440                            else if (parentCacheability.equals(PORTLET)) {
441                                    if (!cacheability.equals(FULL) &&
442                                            !cacheability.equals(PORTLET)) {
443    
444                                            throw new IllegalStateException(
445                                                    "Unable to set a weaker cacheability " + cacheability);
446                                    }
447                            }
448                    }
449    
450                    _cacheability = cacheability;
451    
452                    clearCache();
453            }
454    
455            public void setControlPanelCategory(String controlPanelCategory) {
456                    _controlPanelCategory = controlPanelCategory;
457    
458                    clearCache();
459            }
460    
461            public void setCopyCurrentRenderParameters(
462                    boolean copyCurrentRenderParameters) {
463    
464                    _copyCurrentRenderParameters = copyCurrentRenderParameters;
465            }
466    
467            public void setDoAsGroupId(long doAsGroupId) {
468                    _doAsGroupId = doAsGroupId;
469    
470                    clearCache();
471            }
472    
473            public void setDoAsUserId(long doAsUserId) {
474                    _doAsUserId = doAsUserId;
475    
476                    clearCache();
477            }
478    
479            public void setDoAsUserLanguageId(String doAsUserLanguageId) {
480                    _doAsUserLanguageId = doAsUserLanguageId;
481    
482                    clearCache();
483            }
484    
485            public void setEncrypt(boolean encrypt) {
486                    _encrypt = encrypt;
487    
488                    clearCache();
489            }
490    
491            public void setEscapeXml(boolean escapeXml) {
492                    _escapeXml = escapeXml;
493    
494                    clearCache();
495            }
496    
497            public void setLifecycle(String lifecycle) {
498                    _lifecycle = lifecycle;
499    
500                    clearCache();
501            }
502    
503            public void setParameter(String name, String value) {
504                    setParameter(name, value, PropsValues.PORTLET_URL_APPEND_PARAMETERS);
505            }
506    
507            public void setParameter(String name, String value, boolean append) {
508                    if ((name == null) || (value == null)) {
509                            throw new IllegalArgumentException();
510                    }
511    
512                    setParameter(name, new String[] {value}, append);
513            }
514    
515            public void setParameter(String name, String[] values) {
516                    setParameter(name, values, PropsValues.PORTLET_URL_APPEND_PARAMETERS);
517            }
518    
519            public void setParameter(String name, String[] values, boolean append) {
520                    if ((name == null) || (values == null)) {
521                            throw new IllegalArgumentException();
522                    }
523    
524                    for (String value : values) {
525                            if (value == null) {
526                                    throw new IllegalArgumentException();
527                            }
528                    }
529    
530                    if (!append) {
531                            _params.put(name, values);
532                    }
533                    else {
534                            String[] oldValues = _params.get(name);
535    
536                            if (oldValues == null) {
537                                    _params.put(name, values);
538                            }
539                            else {
540                                    String[] newValues = ArrayUtil.append(oldValues, values);
541    
542                                    _params.put(name, newValues);
543                            }
544                    }
545    
546                    clearCache();
547            }
548    
549            public void setParameters(Map<String, String[]> params) {
550                    if (params == null) {
551                            throw new IllegalArgumentException();
552                    }
553                    else {
554                            Map<String, String[]> newParams =
555                                    new LinkedHashMap<String, String[]>();
556    
557                            for (Map.Entry<String, String[]> entry : params.entrySet()) {
558                                    try {
559                                            String key = entry.getKey();
560                                            String[] value = entry.getValue();
561    
562                                            if (key == null) {
563                                                    throw new IllegalArgumentException();
564                                            }
565                                            else if (value == null) {
566                                                    throw new IllegalArgumentException();
567                                            }
568    
569                                            newParams.put(key, value);
570                                    }
571                                    catch (ClassCastException cce) {
572                                            throw new IllegalArgumentException(cce);
573                                    }
574                            }
575    
576                            _params = newParams;
577                    }
578    
579                    clearCache();
580            }
581    
582            public void setPlid(long plid) {
583                    _plid = plid;
584    
585                    clearCache();
586            }
587    
588            public void setPortletId(String portletId) {
589                    _portletId = portletId;
590    
591                    clearCache();
592            }
593    
594            public void setPortletMode(PortletMode portletMode)
595                    throws PortletModeException {
596    
597                    if (_portletRequest != null) {
598                            if (!getPortlet().hasPortletMode(
599                                            _portletRequest.getResponseContentType(), portletMode)) {
600    
601                                    throw new PortletModeException(
602                                            portletMode.toString(), portletMode);
603                            }
604                    }
605    
606                    _portletModeString = portletMode.toString();
607    
608                    clearCache();
609            }
610    
611            public void setPortletMode(String portletMode) throws PortletModeException {
612                    setPortletMode(PortletModeFactory.getPortletMode(portletMode));
613            }
614    
615            public void setProperty(String key, String value) {
616                    if (key == null) {
617                            throw new IllegalArgumentException();
618                    }
619            }
620    
621            public void setRefererGroupId(long refererGroupId) {
622                    _refererGroupId = refererGroupId;
623    
624                    clearCache();
625            }
626    
627            public void setRefererPlid(long refererPlid) {
628                    _refererPlid = refererPlid;
629    
630                    clearCache();
631            }
632    
633            public void setRemovedParameterNames(Set<String> removedParameterNames) {
634                    _removedParameterNames = removedParameterNames;
635    
636                    clearCache();
637            }
638    
639            public void setResourceID(String resourceID) {
640                    _resourceID = resourceID;
641            }
642    
643            public void setSecure(boolean secure) {
644                    _secure = secure;
645    
646                    clearCache();
647            }
648    
649            public void setWindowState(String windowState) throws WindowStateException {
650                    setWindowState(WindowStateFactory.getWindowState(windowState));
651            }
652    
653            public void setWindowState(WindowState windowState)
654                    throws WindowStateException {
655    
656                    if (_portletRequest != null) {
657                            if (!_portletRequest.isWindowStateAllowed(windowState)) {
658                                    throw new WindowStateException(
659                                            windowState.toString(), windowState);
660                            }
661                    }
662    
663                    if (LiferayWindowState.isWindowStatePreserved(
664                                    getWindowState(), windowState)) {
665    
666                            _windowStateString = windowState.toString();
667                    }
668    
669                    clearCache();
670            }
671    
672            public void setWindowStateRestoreCurrentView(
673                    boolean windowStateRestoreCurrentView) {
674    
675                    _windowStateRestoreCurrentView = windowStateRestoreCurrentView;
676            }
677    
678            @Override
679            public String toString() {
680                    if (_toString != null) {
681                            return _toString;
682                    }
683    
684                    _toString = DoPrivilegedUtil.wrap(new ToStringPrivilegedAction());
685    
686                    return _toString;
687            }
688    
689            public void write(Writer writer) throws IOException {
690                    write(writer, _escapeXml);
691            }
692    
693            public void write(Writer writer, boolean escapeXml) throws IOException {
694                    String toString = toString();
695    
696                    if (escapeXml && !_escapeXml) {
697                            toString = HtmlUtil.escape(toString);
698                    }
699    
700                    writer.write(toString);
701            }
702    
703            protected void addPortalAuthToken(StringBundler sb, Key key) {
704                    if (!PropsValues.AUTH_TOKEN_CHECK_ENABLED ||
705                            !_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
706    
707                            return;
708                    }
709    
710                    Set<String> authTokenIgnorePortlets =
711                            PortalUtil.getAuthTokenIgnorePortlets();
712    
713                    if (authTokenIgnorePortlets.contains(_portletId)) {
714                            return;
715                    }
716    
717                    sb.append("p_auth");
718                    sb.append(StringPool.EQUAL);
719                    sb.append(processValue(key, AuthTokenUtil.getToken(_request)));
720                    sb.append(StringPool.AMPERSAND);
721            }
722    
723            protected void addPortletAuthToken(StringBundler sb, Key key) {
724                    if (!PropsValues.PORTLET_ADD_DEFAULT_RESOURCE_CHECK_ENABLED) {
725                            return;
726                    }
727    
728                    HttpServletRequest request = PortalUtil.getOriginalServletRequest(
729                            _request);
730    
731                    String ppauth = ParamUtil.getString(request, "p_p_auth");
732    
733                    String actualPortletAuthenticationToken = AuthTokenUtil.getToken(
734                            _request, _plid, _portletId);
735    
736                    if (Validator.isNotNull(ppauth) &&
737                            ppauth.equals(actualPortletAuthenticationToken)) {
738    
739                            sb.append("p_p_auth");
740                            sb.append(StringPool.EQUAL);
741                            sb.append(processValue(key, ppauth));
742                            sb.append(StringPool.AMPERSAND);
743    
744                            return;
745                    }
746    
747                    Portlet portlet = (Portlet)_request.getAttribute(
748                            WebKeys.RENDER_PORTLET);
749    
750                    if (portlet != null) {
751                            String portletId = portlet.getPortletId();
752    
753                            if (portletId.equals(_portletId) ||
754                                    portletId.equals(PortletKeys.CONTROL_PANEL_MENU) ||
755                                    !_portlet.isAddDefaultResource()) {
756    
757                                    return;
758                            }
759                    }
760    
761                    Set<String> portletAddDefaultResourceCheckWhiteList =
762                            PortalUtil.getPortletAddDefaultResourceCheckWhitelist();
763    
764                    if (portletAddDefaultResourceCheckWhiteList.contains(_portletId)) {
765                            return;
766                    }
767    
768                    sb.append("p_p_auth");
769                    sb.append(StringPool.EQUAL);
770                    sb.append(processValue(key, actualPortletAuthenticationToken));
771                    sb.append(StringPool.AMPERSAND);
772            }
773    
774            protected void clearCache() {
775                    _reservedParameters = null;
776                    _toString = null;
777            }
778    
779            protected String generateToString() {
780                    StringBundler sb = new StringBundler(64);
781    
782                    ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
783                            WebKeys.THEME_DISPLAY);
784    
785                    String portalURL = null;
786    
787                    if (themeDisplay.isFacebook()) {
788                            portalURL =
789                                    FacebookUtil.FACEBOOK_APPS_URL +
790                                            themeDisplay.getFacebookCanvasPageURL();
791                    }
792                    else {
793                            portalURL = PortalUtil.getPortalURL(_request, _secure);
794                    }
795    
796                    try {
797                            if (_layoutFriendlyURL == null) {
798                                    Layout layout = getLayout();
799    
800                                    if (layout != null) {
801                                            _layoutFriendlyURL = GetterUtil.getString(
802                                                    PortalUtil.getLayoutFriendlyURL(layout, themeDisplay));
803    
804                                            if (_secure) {
805                                                    _layoutFriendlyURL = HttpUtil.protocolize(
806                                                            _layoutFriendlyURL, true);
807                                            }
808                                    }
809                            }
810                    }
811                    catch (Exception e) {
812                            _log.error(e);
813                    }
814    
815                    Key key = null;
816    
817                    try {
818                            if (_encrypt) {
819                                    Company company = PortalUtil.getCompany(_request);
820    
821                                    key = company.getKeyObj();
822                            }
823                    }
824                    catch (Exception e) {
825                            _log.error(e);
826                    }
827    
828                    if (Validator.isNull(_layoutFriendlyURL)) {
829                            sb.append(portalURL);
830                            sb.append(themeDisplay.getPathMain());
831                            sb.append("/portal/layout?");
832    
833                            addPortalAuthToken(sb, key);
834    
835                            sb.append("p_l_id");
836                            sb.append(StringPool.EQUAL);
837                            sb.append(processValue(key, _plid));
838                            sb.append(StringPool.AMPERSAND);
839                    }
840                    else {
841                            if (themeDisplay.isFacebook()) {
842                                    sb.append(portalURL);
843                            }
844                            else {
845    
846                                    // A virtual host URL will contain the complete path. Do not
847                                    // append the portal URL if the virtual host URL starts with
848                                    // "http://" or "https://".
849    
850                                    if (!_layoutFriendlyURL.startsWith(Http.HTTP_WITH_SLASH) &&
851                                            !_layoutFriendlyURL.startsWith(Http.HTTPS_WITH_SLASH)) {
852    
853                                            sb.append(portalURL);
854                                    }
855    
856                                    sb.append(_layoutFriendlyURL);
857                            }
858    
859                            String friendlyURLPath = getPortletFriendlyURLPath();
860    
861                            if (Validator.isNotNull(friendlyURLPath)) {
862                                    if (themeDisplay.isFacebook()) {
863                                            int pos = friendlyURLPath.indexOf(CharPool.SLASH, 1);
864    
865                                            if (pos != -1) {
866                                                    sb.append(friendlyURLPath.substring(pos));
867                                            }
868                                            else {
869                                                    sb.append(friendlyURLPath);
870                                            }
871                                    }
872                                    else {
873                                            sb.append("/-");
874                                            sb.append(friendlyURLPath);
875                                    }
876                            }
877    
878                            sb.append(StringPool.QUESTION);
879    
880                            addPortalAuthToken(sb, key);
881                    }
882    
883                    addPortletAuthToken(sb, key);
884    
885                    for (Map.Entry<String, String> entry :
886                                    getReservedParameterMap().entrySet()) {
887    
888                            String name = entry.getKey();
889    
890                            if (!isParameterIncludedInPath(name)) {
891                                    sb.append(HttpUtil.encodeURL(name));
892                                    sb.append(StringPool.EQUAL);
893                                    sb.append(processValue(key, entry.getValue()));
894                                    sb.append(StringPool.AMPERSAND);
895                            }
896                    }
897    
898                    if (_doAsUserId > 0) {
899                            try {
900                                    Company company = PortalUtil.getCompany(_request);
901    
902                                    sb.append("doAsUserId");
903                                    sb.append(StringPool.EQUAL);
904                                    sb.append(processValue(company.getKeyObj(), _doAsUserId));
905                                    sb.append(StringPool.AMPERSAND);
906                            }
907                            catch (Exception e) {
908                                    _log.error(e);
909                            }
910                    }
911                    else {
912                            String doAsUserId = themeDisplay.getDoAsUserId();
913    
914                            if (Validator.isNotNull(doAsUserId)) {
915                                    sb.append("doAsUserId");
916                                    sb.append(StringPool.EQUAL);
917                                    sb.append(processValue(key, doAsUserId));
918                                    sb.append(StringPool.AMPERSAND);
919                            }
920                    }
921    
922                    String doAsUserLanguageId = _doAsUserLanguageId;
923    
924                    if (Validator.isNull(doAsUserLanguageId)) {
925                            doAsUserLanguageId = themeDisplay.getDoAsUserLanguageId();
926                    }
927    
928                    if (Validator.isNotNull(doAsUserLanguageId)) {
929                            sb.append("doAsUserLanguageId");
930                            sb.append(StringPool.EQUAL);
931                            sb.append(processValue(key, doAsUserLanguageId));
932                            sb.append(StringPool.AMPERSAND);
933                    }
934    
935                    long doAsGroupId = _doAsGroupId;
936    
937                    if (doAsGroupId <= 0) {
938                            doAsGroupId = themeDisplay.getDoAsGroupId();
939                    }
940    
941                    if (doAsGroupId > 0) {
942                            sb.append("doAsGroupId");
943                            sb.append(StringPool.EQUAL);
944                            sb.append(processValue(key, doAsGroupId));
945                            sb.append(StringPool.AMPERSAND);
946                    }
947    
948                    long refererGroupId = _refererGroupId;
949    
950                    if (refererGroupId <= 0) {
951                            refererGroupId = themeDisplay.getRefererGroupId();
952                    }
953    
954                    if (refererGroupId > 0) {
955                            sb.append("refererGroupId");
956                            sb.append(StringPool.EQUAL);
957                            sb.append(processValue(key, refererGroupId));
958                            sb.append(StringPool.AMPERSAND);
959                    }
960    
961                    long refererPlid = _refererPlid;
962    
963                    if (refererPlid <= 0) {
964                            refererPlid = themeDisplay.getRefererPlid();
965                    }
966    
967                    if (refererPlid > 0) {
968                            sb.append("refererPlid");
969                            sb.append(StringPool.EQUAL);
970                            sb.append(processValue(key, refererPlid));
971                            sb.append(StringPool.AMPERSAND);
972                    }
973    
974                    String controlPanelCategory = _controlPanelCategory;
975    
976                    if (Validator.isNull(controlPanelCategory)) {
977                            HttpServletRequest request = PortalUtil.getOriginalServletRequest(
978                                    _request);
979    
980                            controlPanelCategory = ParamUtil.getString(
981                                    request, "controlPanelCategory");
982                    }
983    
984                    if (Validator.isNotNull(controlPanelCategory)) {
985                            sb.append("controlPanelCategory");
986                            sb.append(StringPool.EQUAL);
987                            sb.append(processValue(key, controlPanelCategory));
988                            sb.append(StringPool.AMPERSAND);
989                    }
990    
991                    for (Map.Entry<String, String[]> entry :
992                                    _removePublicRenderParameters.entrySet()) {
993    
994                            String lastString = sb.stringAt(sb.index() - 1);
995    
996                            if (lastString.charAt(lastString.length() - 1) !=
997                                            CharPool.AMPERSAND) {
998    
999                                    sb.append(StringPool.AMPERSAND);
1000                            }
1001    
1002                            sb.append(HttpUtil.encodeURL(entry.getKey()));
1003                            sb.append(StringPool.EQUAL);
1004                            sb.append(processValue(key, entry.getValue()[0]));
1005                            sb.append(StringPool.AMPERSAND);
1006                    }
1007    
1008                    if (_copyCurrentRenderParameters) {
1009                            mergeRenderParameters();
1010                    }
1011    
1012                    int previousSbIndex = sb.index();
1013    
1014                    for (Map.Entry<String, String[]> entry : _params.entrySet()) {
1015                            String name = entry.getKey();
1016                            String[] values = entry.getValue();
1017    
1018                            if (isParameterIncludedInPath(name)) {
1019                                    continue;
1020                            }
1021    
1022                            String publicRenderParameterName = getPublicRenderParameterName(
1023                                    name);
1024    
1025                            if (Validator.isNotNull(publicRenderParameterName)) {
1026                                    name = publicRenderParameterName;
1027                            }
1028    
1029                            name = HttpUtil.encodeURL(prependNamespace(name));
1030    
1031                            for (String value : values) {
1032                                    sb.append(name);
1033                                    sb.append(StringPool.EQUAL);
1034                                    sb.append(processValue(key, value));
1035                                    sb.append(StringPool.AMPERSAND);
1036                            }
1037                    }
1038    
1039                    if (sb.index() > previousSbIndex) {
1040                            sb.setIndex(sb.index() - 1);
1041                    }
1042    
1043                    if (_encrypt) {
1044                            sb.append(StringPool.AMPERSAND + WebKeys.ENCRYPT + "=1");
1045                    }
1046    
1047                    if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
1048                            if (_anchor && (_windowStateString != null) &&
1049                                    !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
1050                                    !_windowStateString.equals(
1051                                            LiferayWindowState.EXCLUSIVE.toString()) &&
1052                                    !_windowStateString.equals(
1053                                            LiferayWindowState.POP_UP.toString())) {
1054    
1055                                    String lastString = sb.stringAt(sb.index() - 1);
1056    
1057                                    if (lastString.charAt(lastString.length() - 1) !=
1058                                                    CharPool.AMPERSAND) {
1059    
1060                                            sb.append(StringPool.AMPERSAND);
1061                                    }
1062    
1063                                    sb.append("#p_");
1064                                    sb.append(HttpUtil.encodeURL(_portletId));
1065                            }
1066                    }
1067    
1068                    String result = sb.toString();
1069    
1070                    if (result.endsWith(StringPool.AMPERSAND) ||
1071                            result.endsWith(StringPool.QUESTION)) {
1072    
1073                            result = result.substring(0, result.length() - 1);
1074                    }
1075    
1076                    if (themeDisplay.isFacebook()) {
1077    
1078                            // Facebook requires the path portion of the URL to end with a slash
1079    
1080                            int pos = result.indexOf(CharPool.QUESTION);
1081    
1082                            if (pos == -1) {
1083                                    if (!result.endsWith(StringPool.SLASH)) {
1084                                            result += StringPool.SLASH;
1085                                    }
1086                            }
1087                            else {
1088                                    String path = result.substring(0, pos);
1089    
1090                                    if (!result.endsWith(StringPool.SLASH)) {
1091                                            result = path + StringPool.SLASH + result.substring(pos);
1092                                    }
1093                            }
1094                    }
1095                    else if (!CookieKeys.hasSessionId(_request)) {
1096                            result = PortalUtil.getURLWithSessionId(
1097                                    result, _request.getSession().getId());
1098                    }
1099    
1100                    if (_escapeXml) {
1101                            result = HtmlUtil.escape(result);
1102                    }
1103    
1104                    if (result.length() > _URL_MAXIMUM_LENGTH) {
1105                            result = shortenURL(result, 2);
1106                    }
1107    
1108                    return result;
1109            }
1110    
1111            protected String generateWSRPToString() {
1112                    StringBundler sb = new StringBundler("wsrp_rewrite?");
1113    
1114                    sb.append("wsrp-urlType");
1115                    sb.append(StringPool.EQUAL);
1116    
1117                    if (_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
1118                            sb.append(HttpUtil.encodeURL("blockingAction"));
1119                    }
1120                    else if (_lifecycle.equals(PortletRequest.RENDER_PHASE)) {
1121                            sb.append(HttpUtil.encodeURL("render"));
1122                    }
1123                    else if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
1124                            sb.append(HttpUtil.encodeURL("resource"));
1125                    }
1126    
1127                    sb.append(StringPool.AMPERSAND);
1128    
1129                    if (_windowStateString != null) {
1130                            sb.append("wsrp-windowState");
1131                            sb.append(StringPool.EQUAL);
1132                            sb.append(HttpUtil.encodeURL("wsrp:" + _windowStateString));
1133                            sb.append(StringPool.AMPERSAND);
1134                    }
1135    
1136                    if (_portletModeString != null) {
1137                            sb.append("wsrp-mode");
1138                            sb.append(StringPool.EQUAL);
1139                            sb.append(HttpUtil.encodeURL("wsrp:" + _portletModeString));
1140                            sb.append(StringPool.AMPERSAND);
1141                    }
1142    
1143                    if (_resourceID != null) {
1144                            sb.append("wsrp-resourceID");
1145                            sb.append(StringPool.EQUAL);
1146                            sb.append(HttpUtil.encodeURL(_resourceID));
1147                            sb.append(StringPool.AMPERSAND);
1148                    }
1149    
1150                    if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
1151                            sb.append("wsrp-resourceCacheability");
1152                            sb.append(StringPool.EQUAL);
1153                            sb.append(HttpUtil.encodeURL(_cacheability));
1154                            sb.append(StringPool.AMPERSAND);
1155                    }
1156    
1157                    if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
1158                            if (_anchor && (_windowStateString != null) &&
1159                                    !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
1160                                    !_windowStateString.equals(
1161                                            LiferayWindowState.EXCLUSIVE.toString()) &&
1162                                    !_windowStateString.equals(
1163                                            LiferayWindowState.POP_UP.toString())) {
1164    
1165                                    sb.append("wsrp-fragmentID");
1166                                    sb.append(StringPool.EQUAL);
1167                                    sb.append("#p_");
1168                                    sb.append(HttpUtil.encodeURL(_portletId));
1169                                    sb.append(StringPool.AMPERSAND);
1170                            }
1171                    }
1172    
1173                    if (_copyCurrentRenderParameters) {
1174                            mergeRenderParameters();
1175                    }
1176    
1177                    StringBundler parameterSb = new StringBundler();
1178    
1179                    int previousSbIndex = sb.index();
1180    
1181                    for (Map.Entry<String, String[]> entry : _params.entrySet()) {
1182                            String name = entry.getKey();
1183                            String[] values = entry.getValue();
1184    
1185                            if (isParameterIncludedInPath(name)) {
1186                                    continue;
1187                            }
1188    
1189                            String publicRenderParameterName = getPublicRenderParameterName(
1190                                    name);
1191    
1192                            if (Validator.isNotNull(publicRenderParameterName)) {
1193                                    name = publicRenderParameterName;
1194                            }
1195    
1196                            name = HttpUtil.encodeURL(prependNamespace(name));
1197    
1198                            for (String value : values) {
1199                                    parameterSb.append(name);
1200                                    parameterSb.append(StringPool.EQUAL);
1201                                    parameterSb.append(HttpUtil.encodeURL(value));
1202                                    parameterSb.append(StringPool.AMPERSAND);
1203                            }
1204                    }
1205    
1206                    if (sb.index() > previousSbIndex) {
1207                            sb.setIndex(sb.index() - 1);
1208                    }
1209    
1210                    sb.append("wsrp-navigationalState");
1211                    sb.append(StringPool.EQUAL);
1212    
1213                    byte[] parameterBytes = null;
1214    
1215                    try {
1216                            String parameterString = parameterSb.toString();
1217    
1218                            parameterBytes = parameterString.getBytes(StringPool.UTF8);
1219                    }
1220                    catch (UnsupportedEncodingException uee) {
1221                            if (_log.isWarnEnabled()) {
1222                                    _log.warn(uee, uee);
1223                            }
1224                    }
1225    
1226                    String navigationalState = Base64.toURLSafe(
1227                            Base64.encode(parameterBytes));
1228    
1229                    sb.append(navigationalState);
1230    
1231                    sb.append("/wsrp_rewrite");
1232    
1233                    return sb.toString();
1234            }
1235    
1236            protected String getPublicRenderParameterName(String name) {
1237                    Portlet portlet = getPortlet();
1238    
1239                    String publicRenderParameterName = null;
1240    
1241                    if (portlet != null) {
1242                            PublicRenderParameter publicRenderParameter =
1243                                    portlet.getPublicRenderParameter(name);
1244    
1245                            if (publicRenderParameter != null) {
1246                                    QName qName = publicRenderParameter.getQName();
1247    
1248                                    publicRenderParameterName =
1249                                            PortletQNameUtil.getPublicRenderParameterName(qName);
1250                            }
1251                    }
1252    
1253                    return publicRenderParameterName;
1254            }
1255    
1256            protected boolean isBlankValue(String[] value) {
1257                    if ((value != null) && (value.length == 1) &&
1258                            value[0].equals(StringPool.BLANK)) {
1259    
1260                            return true;
1261                    }
1262                    else {
1263                            return false;
1264                    }
1265            }
1266    
1267            protected void mergeRenderParameters() {
1268                    String namespace = getNamespace();
1269    
1270                    Layout layout = getLayout();
1271    
1272                    Map<String, String[]> renderParameters = RenderParametersPool.get(
1273                            _request, layout.getPlid(), getPortlet().getPortletId());
1274    
1275                    for (Map.Entry<String, String[]> entry : renderParameters.entrySet()) {
1276                            String name = entry.getKey();
1277    
1278                            if (name.contains(namespace)) {
1279                                    name = name.substring(namespace.length());
1280                            }
1281    
1282                            if (!_lifecycle.equals(PortletRequest.RESOURCE_PHASE) &&
1283                                    (_removedParameterNames != null) &&
1284                                    _removedParameterNames.contains(name)) {
1285    
1286                                    continue;
1287                            }
1288    
1289                            String[] oldValues = entry.getValue();
1290                            String[] newValues = _params.get(name);
1291    
1292                            if (newValues == null) {
1293                                    _params.put(name, oldValues);
1294                            }
1295                            else if (isBlankValue(newValues)) {
1296                                    _params.remove(name);
1297                            }
1298                            else {
1299                                    newValues = ArrayUtil.append(newValues, oldValues);
1300    
1301                                    _params.put(name, newValues);
1302                            }
1303                    }
1304            }
1305    
1306            protected String prependNamespace(String name) {
1307                    String namespace = getNamespace();
1308    
1309                    if (!PortalUtil.isReservedParameter(name) &&
1310                            !name.startsWith(PortletQName.PUBLIC_RENDER_PARAMETER_NAMESPACE) &&
1311                            !name.startsWith(namespace)) {
1312    
1313                            return namespace.concat(name);
1314                    }
1315                    else {
1316                            return name;
1317                    }
1318            }
1319    
1320            protected String processValue(Key key, int value) {
1321                    return processValue(key, String.valueOf(value));
1322            }
1323    
1324            protected String processValue(Key key, long value) {
1325                    return processValue(key, String.valueOf(value));
1326            }
1327    
1328            protected String processValue(Key key, String value) {
1329                    if (key == null) {
1330                            return HttpUtil.encodeURL(value);
1331                    }
1332                    else {
1333                            try {
1334                                    return HttpUtil.encodeURL(Encryptor.encrypt(key, value));
1335                            }
1336                            catch (EncryptorException ee) {
1337                                    return value;
1338                            }
1339                    }
1340            }
1341    
1342            protected String shortenURL(String url, int count) {
1343                    if (count == 0) {
1344                            return null;
1345                    }
1346    
1347                    StringBundler sb = new StringBundler();
1348    
1349                    String[] params = url.split(StringPool.AMPERSAND);
1350    
1351                    for (int i = 0; i < params.length; i++) {
1352                            String param = params[i];
1353    
1354                            if (param.contains("_backURL=") || param.contains("_redirect=") ||
1355                                    param.contains("_returnToFullPageURL=")) {
1356    
1357                                    int pos = param.indexOf(StringPool.EQUAL);
1358    
1359                                    String qName = param.substring(0, pos);
1360    
1361                                    String redirect = param.substring(pos + 1);
1362    
1363                                    redirect = HttpUtil.decodeURL(redirect);
1364    
1365                                    String newURL = shortenURL(redirect, count - 1);
1366    
1367                                    if (newURL != null) {
1368                                            newURL = HttpUtil.encodeURL(newURL);
1369    
1370                                            sb.append(qName);
1371                                            sb.append(StringPool.EQUAL);
1372                                            sb.append(newURL);
1373    
1374                                            if (i < (params.length - 1)) {
1375                                                    sb.append(StringPool.AMPERSAND);
1376                                            }
1377                                    }
1378                            }
1379                            else {
1380                                    sb.append(param);
1381    
1382                                    if (i < (params.length - 1)) {
1383                                            sb.append(StringPool.AMPERSAND);
1384                                    }
1385                            }
1386                    }
1387    
1388                    return sb.toString();
1389            }
1390    
1391            private static final long _URL_MAXIMUM_LENGTH = 2083;
1392    
1393            private static Log _log = LogFactoryUtil.getLog(PortletURLImpl.class);
1394    
1395            private boolean _anchor = true;
1396            private String _cacheability = ResourceURL.PAGE;
1397            private String _controlPanelCategory;
1398            private boolean _copyCurrentRenderParameters;
1399            private long _doAsGroupId;
1400            private long _doAsUserId;
1401            private String _doAsUserLanguageId;
1402            private boolean _encrypt;
1403            private boolean _escapeXml = PropsValues.PORTLET_URL_ESCAPE_XML;
1404            private Layout _layout;
1405            private String _layoutFriendlyURL;
1406            private String _lifecycle;
1407            private String _namespace;
1408            private Set<String> _parametersIncludedInPath;
1409            private Map<String, String[]> _params;
1410            private long _plid;
1411            private Portlet _portlet;
1412            private String _portletId;
1413            private String _portletModeString;
1414            private PortletRequest _portletRequest;
1415            private long _refererGroupId;
1416            private long _refererPlid;
1417            private Set<String> _removedParameterNames;
1418            private Map<String, String[]> _removePublicRenderParameters;
1419            private HttpServletRequest _request;
1420            private Map<String, String> _reservedParameters;
1421            private String _resourceID;
1422            private boolean _secure;
1423            private String _toString;
1424            private boolean _windowStateRestoreCurrentView;
1425            private String _windowStateString;
1426            private boolean _wsrp;
1427    
1428            private class ToStringPrivilegedAction implements PrivilegedAction<String> {
1429    
1430                    public String run() {
1431                            if (_wsrp) {
1432                                    return generateWSRPToString();
1433                            }
1434    
1435                            return generateToString();
1436                    }
1437            }
1438    
1439    }