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