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.security.auth.AuthTokenUtil;
027    import com.liferay.portal.kernel.util.ArrayUtil;
028    import com.liferay.portal.kernel.util.Base64;
029    import com.liferay.portal.kernel.util.CharPool;
030    import com.liferay.portal.kernel.util.CookieKeys;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.HtmlUtil;
033    import com.liferay.portal.kernel.util.Http;
034    import com.liferay.portal.kernel.util.HttpUtil;
035    import com.liferay.portal.kernel.util.MapUtil;
036    import com.liferay.portal.kernel.util.ParamUtil;
037    import com.liferay.portal.kernel.util.StringBundler;
038    import com.liferay.portal.kernel.util.StringPool;
039    import com.liferay.portal.kernel.util.Validator;
040    import com.liferay.portal.kernel.util.WebKeys;
041    import com.liferay.portal.kernel.xml.QName;
042    import com.liferay.portal.model.Company;
043    import com.liferay.portal.model.Layout;
044    import com.liferay.portal.model.Portlet;
045    import com.liferay.portal.model.PortletApp;
046    import com.liferay.portal.model.PublicRenderParameter;
047    import com.liferay.portal.model.impl.VirtualLayout;
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                    try {
817                            if (_layoutFriendlyURL == null) {
818                                    Layout layout = getLayout();
819    
820                                    if (layout != null) {
821                                            _layoutFriendlyURL = GetterUtil.getString(
822                                                    PortalUtil.getLayoutFriendlyURL(layout, themeDisplay));
823    
824                                            if (_secure) {
825                                                    _layoutFriendlyURL = HttpUtil.protocolize(
826                                                            _layoutFriendlyURL,
827                                                            PropsValues.WEB_SERVER_HTTPS_PORT, true);
828                                            }
829                                    }
830                            }
831                    }
832                    catch (Exception e) {
833                            _log.error(e);
834                    }
835    
836                    Key key = null;
837    
838                    try {
839                            if (_encrypt) {
840                                    Company company = PortalUtil.getCompany(_request);
841    
842                                    key = company.getKeyObj();
843                            }
844                    }
845                    catch (Exception e) {
846                            _log.error(e);
847                    }
848    
849                    if (Validator.isNull(_layoutFriendlyURL)) {
850                            sb.append(PortalUtil.getPortalURL(_request, _secure));
851                            sb.append(themeDisplay.getPathMain());
852                            sb.append("/portal/layout?");
853    
854                            addPortalAuthToken(sb, key);
855    
856                            sb.append("p_l_id");
857                            sb.append(StringPool.EQUAL);
858                            sb.append(processValue(key, _plid));
859                            sb.append(StringPool.AMPERSAND);
860                    }
861                    else {
862                            if (themeDisplay.isFacebook()) {
863                                    sb.append(FacebookUtil.FACEBOOK_APPS_URL);
864                                    sb.append(themeDisplay.getFacebookCanvasPageURL());
865                            }
866                            else {
867    
868                                    // A virtual host URL will contain the complete path. Do not
869                                    // append the portal URL if the virtual host URL starts with
870                                    // "http://" or "https://".
871    
872                                    if (!_layoutFriendlyURL.startsWith(Http.HTTP_WITH_SLASH) &&
873                                            !_layoutFriendlyURL.startsWith(Http.HTTPS_WITH_SLASH)) {
874    
875                                            sb.append(PortalUtil.getPortalURL(_request, _secure));
876                                    }
877    
878                                    sb.append(_layoutFriendlyURL);
879                            }
880    
881                            String friendlyURLPath = getPortletFriendlyURLPath();
882    
883                            if (Validator.isNotNull(friendlyURLPath)) {
884                                    if (themeDisplay.isFacebook()) {
885                                            int pos = friendlyURLPath.indexOf(CharPool.SLASH, 1);
886    
887                                            if (pos != -1) {
888                                                    sb.append(friendlyURLPath.substring(pos));
889                                            }
890                                            else {
891                                                    sb.append(friendlyURLPath);
892                                            }
893                                    }
894                                    else {
895                                            sb.append("/-");
896                                            sb.append(friendlyURLPath);
897                                    }
898                            }
899    
900                            sb.append(StringPool.QUESTION);
901    
902                            addPortalAuthToken(sb, key);
903                    }
904    
905                    addPortletAuthToken(sb, key);
906    
907                    for (Map.Entry<String, String> entry :
908                                    getReservedParameterMap().entrySet()) {
909    
910                            String name = entry.getKey();
911    
912                            if (!isParameterIncludedInPath(name)) {
913                                    sb.append(HttpUtil.encodeURL(name));
914                                    sb.append(StringPool.EQUAL);
915                                    sb.append(processValue(key, entry.getValue()));
916                                    sb.append(StringPool.AMPERSAND);
917                            }
918                    }
919    
920                    if (_doAsUserId > 0) {
921                            try {
922                                    Company company = PortalUtil.getCompany(_request);
923    
924                                    sb.append("doAsUserId");
925                                    sb.append(StringPool.EQUAL);
926                                    sb.append(processValue(company.getKeyObj(), _doAsUserId));
927                                    sb.append(StringPool.AMPERSAND);
928                            }
929                            catch (Exception e) {
930                                    _log.error(e);
931                            }
932                    }
933                    else {
934                            String doAsUserId = themeDisplay.getDoAsUserId();
935    
936                            if (Validator.isNotNull(doAsUserId)) {
937                                    sb.append("doAsUserId");
938                                    sb.append(StringPool.EQUAL);
939                                    sb.append(processValue(key, doAsUserId));
940                                    sb.append(StringPool.AMPERSAND);
941                            }
942                    }
943    
944                    String doAsUserLanguageId = _doAsUserLanguageId;
945    
946                    if (Validator.isNull(doAsUserLanguageId)) {
947                            doAsUserLanguageId = themeDisplay.getDoAsUserLanguageId();
948                    }
949    
950                    if (Validator.isNotNull(doAsUserLanguageId)) {
951                            sb.append("doAsUserLanguageId");
952                            sb.append(StringPool.EQUAL);
953                            sb.append(processValue(key, doAsUserLanguageId));
954                            sb.append(StringPool.AMPERSAND);
955                    }
956    
957                    long doAsGroupId = _doAsGroupId;
958    
959                    if (doAsGroupId <= 0) {
960                            doAsGroupId = themeDisplay.getDoAsGroupId();
961                    }
962    
963                    if (doAsGroupId > 0) {
964                            sb.append("doAsGroupId");
965                            sb.append(StringPool.EQUAL);
966                            sb.append(processValue(key, doAsGroupId));
967                            sb.append(StringPool.AMPERSAND);
968                    }
969    
970                    long refererGroupId = _refererGroupId;
971    
972                    if (refererGroupId <= 0) {
973                            refererGroupId = themeDisplay.getRefererGroupId();
974                    }
975    
976                    if (refererGroupId > 0) {
977                            sb.append("refererGroupId");
978                            sb.append(StringPool.EQUAL);
979                            sb.append(processValue(key, refererGroupId));
980                            sb.append(StringPool.AMPERSAND);
981                    }
982    
983                    long refererPlid = _refererPlid;
984    
985                    if (refererPlid <= 0) {
986                            refererPlid = themeDisplay.getRefererPlid();
987                    }
988    
989                    if (refererPlid > 0) {
990                            sb.append("refererPlid");
991                            sb.append(StringPool.EQUAL);
992                            sb.append(processValue(key, refererPlid));
993                            sb.append(StringPool.AMPERSAND);
994                    }
995    
996                    for (Map.Entry<String, String[]> entry :
997                                    _removePublicRenderParameters.entrySet()) {
998    
999                            String lastString = sb.stringAt(sb.index() - 1);
1000    
1001                            if (lastString.charAt(lastString.length() - 1) !=
1002                                            CharPool.AMPERSAND) {
1003    
1004                                    sb.append(StringPool.AMPERSAND);
1005                            }
1006    
1007                            sb.append(HttpUtil.encodeURL(entry.getKey()));
1008                            sb.append(StringPool.EQUAL);
1009                            sb.append(processValue(key, entry.getValue()[0]));
1010                            sb.append(StringPool.AMPERSAND);
1011                    }
1012    
1013                    if (_copyCurrentRenderParameters) {
1014                            mergeRenderParameters();
1015                    }
1016    
1017                    int previousSbIndex = sb.index();
1018    
1019                    for (Map.Entry<String, String[]> entry : _params.entrySet()) {
1020                            String name = entry.getKey();
1021                            String[] values = entry.getValue();
1022    
1023                            if (isParameterIncludedInPath(name)) {
1024                                    continue;
1025                            }
1026    
1027                            String publicRenderParameterName = getPublicRenderParameterName(
1028                                    name);
1029    
1030                            if (Validator.isNotNull(publicRenderParameterName)) {
1031                                    name = publicRenderParameterName;
1032                            }
1033    
1034                            name = HttpUtil.encodeURL(prependNamespace(name));
1035    
1036                            for (String value : values) {
1037                                    sb.append(name);
1038                                    sb.append(StringPool.EQUAL);
1039                                    sb.append(processValue(key, value));
1040                                    sb.append(StringPool.AMPERSAND);
1041                            }
1042                    }
1043    
1044                    if (sb.index() > previousSbIndex) {
1045                            sb.setIndex(sb.index() - 1);
1046                    }
1047    
1048                    if (_encrypt) {
1049                            sb.append(StringPool.AMPERSAND);
1050                            sb.append(WebKeys.ENCRYPT);
1051                            sb.append("=1");
1052                    }
1053    
1054                    if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
1055                            if (_anchor && (_windowStateString != null) &&
1056                                    !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
1057                                    !_windowStateString.equals(
1058                                            LiferayWindowState.EXCLUSIVE.toString()) &&
1059                                    !_windowStateString.equals(
1060                                            LiferayWindowState.POP_UP.toString())) {
1061    
1062                                    String lastString = sb.stringAt(sb.index() - 1);
1063    
1064                                    char lastChar = lastString.charAt(lastString.length() - 1);
1065    
1066                                    if ((lastChar != CharPool.AMPERSAND) &&
1067                                            (lastChar != CharPool.QUESTION)) {
1068    
1069                                            sb.append(StringPool.AMPERSAND);
1070                                    }
1071    
1072                                    sb.append("#p_");
1073                                    sb.append(HttpUtil.encodeURL(_portletId));
1074                            }
1075                    }
1076    
1077                    String result = sb.toString();
1078    
1079                    if (result.endsWith(StringPool.AMPERSAND) ||
1080                            result.endsWith(StringPool.QUESTION)) {
1081    
1082                            result = result.substring(0, result.length() - 1);
1083                    }
1084    
1085                    if (themeDisplay.isFacebook()) {
1086    
1087                            // Facebook requires the path portion of the URL to end with a slash
1088    
1089                            int pos = result.indexOf(CharPool.QUESTION);
1090    
1091                            if (pos == -1) {
1092                                    if (!result.endsWith(StringPool.SLASH)) {
1093                                            result += StringPool.SLASH;
1094                                    }
1095                            }
1096                            else {
1097                                    String path = result.substring(0, pos);
1098    
1099                                    if (!result.endsWith(StringPool.SLASH)) {
1100                                            result = path + StringPool.SLASH + result.substring(pos);
1101                                    }
1102                            }
1103                    }
1104                    else if (!CookieKeys.hasSessionId(_request)) {
1105                            result = PortalUtil.getURLWithSessionId(
1106                                    result, _request.getSession().getId());
1107                    }
1108    
1109                    if (_escapeXml) {
1110                            result = HtmlUtil.escape(result);
1111                    }
1112    
1113                    if (result.length() > Http.URL_MAXIMUM_LENGTH) {
1114                            result = HttpUtil.shortenURL(result, 2);
1115                    }
1116    
1117                    return result;
1118            }
1119    
1120            protected String generateWSRPToString() {
1121                    StringBundler sb = new StringBundler("wsrp_rewrite?");
1122    
1123                    sb.append("wsrp-urlType");
1124                    sb.append(StringPool.EQUAL);
1125    
1126                    if (_lifecycle.equals(PortletRequest.ACTION_PHASE)) {
1127                            sb.append(HttpUtil.encodeURL("blockingAction"));
1128                    }
1129                    else if (_lifecycle.equals(PortletRequest.RENDER_PHASE)) {
1130                            sb.append(HttpUtil.encodeURL("render"));
1131                    }
1132                    else if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
1133                            sb.append(HttpUtil.encodeURL("resource"));
1134                    }
1135    
1136                    sb.append(StringPool.AMPERSAND);
1137    
1138                    if (_windowStateString != null) {
1139                            sb.append("wsrp-windowState");
1140                            sb.append(StringPool.EQUAL);
1141                            sb.append(HttpUtil.encodeURL("wsrp:" + _windowStateString));
1142                            sb.append(StringPool.AMPERSAND);
1143                    }
1144    
1145                    if (_portletModeString != null) {
1146                            sb.append("wsrp-mode");
1147                            sb.append(StringPool.EQUAL);
1148                            sb.append(HttpUtil.encodeURL("wsrp:" + _portletModeString));
1149                            sb.append(StringPool.AMPERSAND);
1150                    }
1151    
1152                    if (_resourceID != null) {
1153                            sb.append("wsrp-resourceID");
1154                            sb.append(StringPool.EQUAL);
1155                            sb.append(HttpUtil.encodeURL(_resourceID));
1156                            sb.append(StringPool.AMPERSAND);
1157                    }
1158    
1159                    if (_lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
1160                            sb.append("wsrp-resourceCacheability");
1161                            sb.append(StringPool.EQUAL);
1162                            sb.append(HttpUtil.encodeURL(_cacheability));
1163                            sb.append(StringPool.AMPERSAND);
1164                    }
1165    
1166                    if (PropsValues.PORTLET_URL_ANCHOR_ENABLE) {
1167                            if (_anchor && (_windowStateString != null) &&
1168                                    !_windowStateString.equals(WindowState.MAXIMIZED.toString()) &&
1169                                    !_windowStateString.equals(
1170                                            LiferayWindowState.EXCLUSIVE.toString()) &&
1171                                    !_windowStateString.equals(
1172                                            LiferayWindowState.POP_UP.toString())) {
1173    
1174                                    sb.append("wsrp-fragmentID");
1175                                    sb.append(StringPool.EQUAL);
1176                                    sb.append("#p_");
1177                                    sb.append(HttpUtil.encodeURL(_portletId));
1178                                    sb.append(StringPool.AMPERSAND);
1179                            }
1180                    }
1181    
1182                    if (_copyCurrentRenderParameters) {
1183                            mergeRenderParameters();
1184                    }
1185    
1186                    StringBundler parameterSb = new StringBundler();
1187    
1188                    int previousSbIndex = sb.index();
1189    
1190                    for (Map.Entry<String, String[]> entry : _params.entrySet()) {
1191                            String name = entry.getKey();
1192                            String[] values = entry.getValue();
1193    
1194                            if (isParameterIncludedInPath(name)) {
1195                                    continue;
1196                            }
1197    
1198                            String publicRenderParameterName = getPublicRenderParameterName(
1199                                    name);
1200    
1201                            if (Validator.isNotNull(publicRenderParameterName)) {
1202                                    name = publicRenderParameterName;
1203                            }
1204    
1205                            name = HttpUtil.encodeURL(prependNamespace(name));
1206    
1207                            for (String value : values) {
1208                                    parameterSb.append(name);
1209                                    parameterSb.append(StringPool.EQUAL);
1210                                    parameterSb.append(HttpUtil.encodeURL(value));
1211                                    parameterSb.append(StringPool.AMPERSAND);
1212                            }
1213                    }
1214    
1215                    if (sb.index() > previousSbIndex) {
1216                            sb.setIndex(sb.index() - 1);
1217                    }
1218    
1219                    sb.append("wsrp-navigationalState");
1220                    sb.append(StringPool.EQUAL);
1221    
1222                    byte[] parameterBytes = null;
1223    
1224                    try {
1225                            String parameterString = parameterSb.toString();
1226    
1227                            parameterBytes = parameterString.getBytes(StringPool.UTF8);
1228                    }
1229                    catch (UnsupportedEncodingException uee) {
1230                            if (_log.isWarnEnabled()) {
1231                                    _log.warn(uee, uee);
1232                            }
1233                    }
1234    
1235                    String navigationalState = Base64.toURLSafe(
1236                            Base64.encode(parameterBytes));
1237    
1238                    sb.append(navigationalState);
1239    
1240                    sb.append("/wsrp_rewrite");
1241    
1242                    return sb.toString();
1243            }
1244    
1245            protected String getPublicRenderParameterName(String name) {
1246                    Portlet portlet = getPortlet();
1247    
1248                    String publicRenderParameterName = null;
1249    
1250                    if (portlet != null) {
1251                            PublicRenderParameter publicRenderParameter =
1252                                    portlet.getPublicRenderParameter(name);
1253    
1254                            if (publicRenderParameter != null) {
1255                                    QName qName = publicRenderParameter.getQName();
1256    
1257                                    publicRenderParameterName =
1258                                            PortletQNameUtil.getPublicRenderParameterName(qName);
1259                            }
1260                    }
1261    
1262                    return publicRenderParameterName;
1263            }
1264    
1265            protected boolean isBlankValue(String[] value) {
1266                    if ((value != null) && (value.length == 1) &&
1267                            value[0].equals(StringPool.BLANK)) {
1268    
1269                            return true;
1270                    }
1271                    else {
1272                            return false;
1273                    }
1274            }
1275    
1276            protected void mergeRenderParameters() {
1277                    String namespace = getNamespace();
1278    
1279                    Layout layout = getLayout();
1280    
1281                    Map<String, String[]> renderParameters = RenderParametersPool.get(
1282                            _request, layout.getPlid(), getPortlet().getPortletId());
1283    
1284                    for (Map.Entry<String, String[]> entry : renderParameters.entrySet()) {
1285                            String name = entry.getKey();
1286    
1287                            if (name.contains(namespace)) {
1288                                    name = name.substring(namespace.length());
1289                            }
1290    
1291                            if (!_lifecycle.equals(PortletRequest.RESOURCE_PHASE) &&
1292                                    (_removedParameterNames != null) &&
1293                                    _removedParameterNames.contains(name)) {
1294    
1295                                    continue;
1296                            }
1297    
1298                            String[] oldValues = entry.getValue();
1299                            String[] newValues = _params.get(name);
1300    
1301                            if (newValues == null) {
1302                                    _params.put(name, oldValues);
1303                            }
1304                            else if (isBlankValue(newValues)) {
1305                                    _params.remove(name);
1306                            }
1307                            else {
1308                                    newValues = ArrayUtil.append(newValues, oldValues);
1309    
1310                                    _params.put(name, newValues);
1311                            }
1312                    }
1313            }
1314    
1315            protected String prependNamespace(String name) {
1316                    String namespace = getNamespace();
1317    
1318                    if (!name.startsWith(PortletQName.PUBLIC_RENDER_PARAMETER_NAMESPACE) &&
1319                            !name.startsWith(namespace) &&
1320                            !PortalUtil.isReservedParameter(name)) {
1321    
1322                            return namespace.concat(name);
1323                    }
1324    
1325                    return name;
1326            }
1327    
1328            protected String processValue(Key key, int value) {
1329                    return processValue(key, String.valueOf(value));
1330            }
1331    
1332            protected String processValue(Key key, long value) {
1333                    return processValue(key, String.valueOf(value));
1334            }
1335    
1336            protected String processValue(Key key, String value) {
1337                    if (key == null) {
1338                            return HttpUtil.encodeURL(value);
1339                    }
1340    
1341                    try {
1342                            return HttpUtil.encodeURL(Encryptor.encrypt(key, value));
1343                    }
1344                    catch (EncryptorException ee) {
1345                            return value;
1346                    }
1347            }
1348    
1349            protected void removeParameter(String name) {
1350                    if (_params.containsKey(name)) {
1351                            _params.remove(name);
1352                    }
1353            }
1354    
1355            private static final Log _log = LogFactoryUtil.getLog(PortletURLImpl.class);
1356    
1357            private boolean _anchor = true;
1358            private String _cacheability = ResourceURL.PAGE;
1359            private boolean _copyCurrentRenderParameters;
1360            private long _doAsGroupId;
1361            private long _doAsUserId;
1362            private String _doAsUserLanguageId;
1363            private boolean _encrypt;
1364            private boolean _escapeXml = PropsValues.PORTLET_URL_ESCAPE_XML;
1365            private Layout _layout;
1366            private String _layoutFriendlyURL;
1367            private String _lifecycle;
1368            private String _namespace;
1369            private final Set<String> _parametersIncludedInPath;
1370            private Map<String, String[]> _params;
1371            private long _plid;
1372            private Portlet _portlet;
1373            private String _portletId;
1374            private String _portletModeString;
1375            private final PortletRequest _portletRequest;
1376            private long _refererGroupId;
1377            private long _refererPlid;
1378            private Set<String> _removedParameterNames;
1379            private final Map<String, String[]> _removePublicRenderParameters;
1380            private final HttpServletRequest _request;
1381            private Map<String, String> _reservedParameters;
1382            private String _resourceID;
1383            private boolean _secure;
1384            private String _toString;
1385            private boolean _windowStateRestoreCurrentView;
1386            private String _windowStateString;
1387            private final boolean _wsrp;
1388    
1389            private class ToStringPrivilegedAction implements PrivilegedAction<String> {
1390    
1391                    @Override
1392                    public String run() {
1393                            if (_wsrp) {
1394                                    return generateWSRPToString();
1395                            }
1396    
1397                            return generateToString();
1398                    }
1399    
1400            }
1401    
1402    }