001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.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("//") && !path.startsWith(_contextPath) &&
115                            !path.startsWith(_servletMapping)) {
116    
117                            return encodedURL;
118                    }
119    
120                    // Struts uses &amp; instead of & to delimit parameter key value pairs
121                    // when you set the "name" attribute for html:link.
122    
123                    path = StringUtil.replace(path, "&amp;", "&");
124    
125                    // Reset portlet URL settings so it can be reused
126    
127                    _liferayPortletURL.setLifecycle(PortletRequest.RENDER_PHASE);
128                    _liferayPortletURL.setParameters(new HashMap<String, String[]>());
129    
130                    try {
131                            _liferayPortletURL.setWindowState(_windowState);
132                    }
133                    catch (WindowStateException wse) {
134                    }
135    
136                    try {
137                            _liferayPortletURL.setPortletMode(_portletMode);
138                    }
139                    catch (PortletModeException pme) {
140                    }
141    
142                    // Separate the Struts action from the query string
143    
144                    String strutsAction = path;
145                    String queryString = StringPool.BLANK;
146    
147                    int pos = strutsAction.indexOf(CharPool.QUESTION);
148    
149                    if (pos != -1) {
150                            strutsAction = path.substring(0, pos);
151                            queryString = path.substring(pos + 1);
152                    }
153    
154                    // Set the Struts action
155    
156                    if (strutsAction.startsWith("c/")) {
157                            strutsAction = strutsAction.substring(1);
158                    }
159                    else if (strutsAction.startsWith("/c/")) {
160                            strutsAction = strutsAction.substring(2);
161                    }
162    
163                    if (Validator.isNotNull(_contextPath)) {
164                            strutsAction = strutsAction.substring(_contextPath.length());
165                    }
166    
167                    if (strutsAction.startsWith(_servletMapping)) {
168                            strutsAction = strutsAction.substring(_servletMapping.length());
169                    }
170    
171                    if (!strutsAction.startsWith(StringPool.SLASH)) {
172                            strutsAction = StringPool.SLASH + strutsAction;
173                    }
174    
175                    if (_log.isDebugEnabled()) {
176                            _log.debug("Struts action " + strutsAction);
177                    }
178    
179                    _liferayPortletURL.setParameter("struts_action", strutsAction);
180    
181                    // Set the query string
182    
183                    setParameters(_liferayPortletURL, queryString);
184    
185                    // Return the portlet URL
186    
187                    encodedURL = _liferayPortletURL.toString();
188    
189                    if (_log.isDebugEnabled()) {
190                            _log.debug("Encoded portlet URL " + encodedURL);
191                    }
192    
193                    return encodedURL;
194            }
195    
196            private void _setServletMapping(String servletMapping) {
197                    if (servletMapping != null) {
198    
199                            // See org.apache.struts.util.RequestUtils.getActionMappingURL
200    
201                            if (servletMapping.endsWith("/*")) {
202                                    int pos = 0;
203    
204                                    if (servletMapping.startsWith(_mainPath)) {
205                                            pos = _mainPath.length() - 2;
206                                    }
207    
208                                    _servletMapping = servletMapping.substring(
209                                            pos, servletMapping.length() - 1);
210                            }
211                    }
212            }
213    
214            private static final Log _log = LogFactoryUtil.getLog(
215                    StrutsURLEncoder.class);
216    
217            private final String _contextPath;
218            private final LiferayPortletURL _liferayPortletURL;
219            private final String _mainPath;
220            private final PortletMode _portletMode;
221            private String _servletMapping = StringPool.BLANK;
222            private final WindowState _windowState;
223    
224    }