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