001    /**
002     * Copyright (c) 2000-2013 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.portal.struts;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
020    import com.liferay.portal.kernel.portlet.PortletModeFactory;
021    import com.liferay.portal.kernel.portlet.WindowStateFactory;
022    import com.liferay.portal.kernel.servlet.URLEncoder;
023    import com.liferay.portal.kernel.util.CharPool;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.HttpUtil;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.StringUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    
030    import java.util.HashMap;
031    
032    import javax.portlet.PortletMode;
033    import javax.portlet.PortletModeException;
034    import javax.portlet.PortletRequest;
035    import javax.portlet.WindowState;
036    import javax.portlet.WindowStateException;
037    
038    import javax.servlet.http.HttpServletResponse;
039    
040    /**
041     * @author Brian Wing Shun Chan
042     */
043    public class StrutsURLEncoder implements URLEncoder {
044    
045            public static void setParameters(
046                    LiferayPortletURL liferayPortletURL, String queryString) {
047    
048                    String[] params = StringUtil.split(queryString, '&');
049    
050                    for (int i = 0; i < params.length; i++) {
051                            int pos = params[i].indexOf("=");
052    
053                            if (pos != -1) {
054                                    String param = params[i].substring(0, pos);
055                                    String value = params[i].substring(pos + 1);
056    
057                                    if (param.equals("windowState")) {
058                                            try {
059                                                    liferayPortletURL.setWindowState(
060                                                            WindowStateFactory.getWindowState(value));
061                                            }
062                                            catch (WindowStateException wse) {
063                                                    _log.error(wse.getMessage());
064                                            }
065                                    }
066                                    else if (param.equals("portletMode")) {
067                                            try {
068                                                    liferayPortletURL.setPortletMode(
069                                                            PortletModeFactory.getPortletMode(value));
070                                            }
071                                            catch (PortletModeException pme) {
072                                                    _log.error(pme.getMessage());
073                                            }
074                                    }
075                                    else if (param.equals("actionURL")) {
076                                            String lifecycle = PortletRequest.RENDER_PHASE;
077    
078                                            if (GetterUtil.getBoolean(value)) {
079                                                    lifecycle = PortletRequest.ACTION_PHASE;
080                                            }
081    
082                                            liferayPortletURL.setLifecycle(lifecycle);
083                                    }
084                                    else {
085                                            liferayPortletURL.setParameter(
086                                                    param, HttpUtil.decodeURL(value), true);
087                                    }
088                            }
089                    }
090            }
091    
092            public StrutsURLEncoder(
093                    String contextPath, String mainPath, String servletMapping,
094                    LiferayPortletURL liferayPortletURL) {
095    
096                    _contextPath = contextPath;
097                    _mainPath = mainPath;
098                    _setServletMapping(servletMapping);
099                    _liferayPortletURL = liferayPortletURL;
100                    _windowState = liferayPortletURL.getWindowState();
101                    _portletMode = liferayPortletURL.getPortletMode();
102            }
103    
104            @Override
105            public String encodeURL(HttpServletResponse response, String path) {
106                    if (_log.isDebugEnabled()) {
107                            _log.debug("Path " + path);
108                            _log.debug("Context path " + _contextPath);
109                            _log.debug("Servlet mapping " + _servletMapping);
110                    }
111    
112                    String encodedURL = path;
113    
114                    if (!path.startsWith("//") &&
115                            !path.startsWith(_contextPath) &&
116                            !path.startsWith(_servletMapping)) {
117    
118                            return encodedURL;
119                    }
120    
121                    // Struts uses &amp; instead of & to delimit parameter key value pairs
122                    // when you set the "name" attribute for html:link.
123    
124                    path = StringUtil.replace(path, "&amp;", "&");
125    
126                    // Reset portlet URL settings so it can be reused
127    
128                    _liferayPortletURL.setLifecycle(PortletRequest.RENDER_PHASE);
129                    _liferayPortletURL.setParameters(new HashMap<String, String[]>());
130    
131                    try {
132                            _liferayPortletURL.setWindowState(_windowState);
133                    }
134                    catch (WindowStateException wse) {
135                    }
136    
137                    try {
138                            _liferayPortletURL.setPortletMode(_portletMode);
139                    }
140                    catch (PortletModeException pme) {
141                    }
142    
143                    // Separate the Struts action from the query string
144    
145                    String strutsAction = path;
146                    String queryString = StringPool.BLANK;
147    
148                    int pos = strutsAction.indexOf(CharPool.QUESTION);
149    
150                    if (pos != -1) {
151                            strutsAction = path.substring(0, pos);
152                            queryString = path.substring(pos + 1);
153                    }
154    
155                    // Set the Struts action
156    
157                    if (strutsAction.startsWith("c/")) {
158                            strutsAction = strutsAction.substring(1);
159                    }
160                    else if (strutsAction.startsWith("/c/")) {
161                            strutsAction = strutsAction.substring(2);
162                    }
163    
164                    if (Validator.isNotNull(_contextPath)) {
165                            strutsAction = strutsAction.substring(_contextPath.length());
166                    }
167    
168                    if (strutsAction.startsWith(_servletMapping)) {
169                            strutsAction = strutsAction.substring(_servletMapping.length());
170                    }
171    
172                    if (!strutsAction.startsWith(StringPool.SLASH)) {
173                            strutsAction = StringPool.SLASH + strutsAction;
174                    }
175    
176                    if (_log.isDebugEnabled()) {
177                            _log.debug("Struts action " + strutsAction);
178                    }
179    
180                    _liferayPortletURL.setParameter("struts_action", strutsAction);
181    
182                    // Set the query string
183    
184                    setParameters(_liferayPortletURL, queryString);
185    
186                    // Return the portlet URL
187    
188                    encodedURL = _liferayPortletURL.toString();
189    
190                    if (_log.isDebugEnabled()) {
191                            _log.debug("Encoded portlet URL " + encodedURL);
192                    }
193    
194                    return encodedURL;
195            }
196    
197            private void _setServletMapping(String servletMapping) {
198                    if (servletMapping != null) {
199    
200                            // See org.apache.struts.util.RequestUtils.getActionMappingURL
201    
202                            if (servletMapping.endsWith("/*")) {
203                                    int pos = 0;
204    
205                                    if (servletMapping.startsWith(_mainPath)) {
206                                            pos = _mainPath.length() - 2;
207                                    }
208    
209                                    _servletMapping = servletMapping.substring(
210                                            pos, servletMapping.length() - 1);
211                            }
212                    }
213            }
214    
215            private static Log _log = LogFactoryUtil.getLog(StrutsURLEncoder.class);
216    
217            private String _contextPath;
218            private LiferayPortletURL _liferayPortletURL;
219            private String _mainPath;
220            private PortletMode _portletMode;
221            private String _servletMapping = StringPool.BLANK;
222            private WindowState _windowState;
223    
224    }