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