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