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