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.servlet;
016    
017    import com.liferay.portal.NoSuchGroupException;
018    import com.liferay.portal.NoSuchLayoutException;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.servlet.PortalMessages;
023    import com.liferay.portal.kernel.servlet.SessionMessages;
024    import com.liferay.portal.kernel.struts.LastPath;
025    import com.liferay.portal.kernel.util.CharPool;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.LocaleUtil;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.model.Group;
032    import com.liferay.portal.model.Layout;
033    import com.liferay.portal.model.LayoutConstants;
034    import com.liferay.portal.model.LayoutFriendlyURL;
035    import com.liferay.portal.model.LayoutFriendlyURLComposite;
036    import com.liferay.portal.model.User;
037    import com.liferay.portal.service.GroupLocalServiceUtil;
038    import com.liferay.portal.service.LayoutFriendlyURLLocalServiceUtil;
039    import com.liferay.portal.service.LayoutLocalServiceUtil;
040    import com.liferay.portal.service.ServiceContext;
041    import com.liferay.portal.service.ServiceContextFactory;
042    import com.liferay.portal.service.ServiceContextThreadLocal;
043    import com.liferay.portal.service.UserLocalServiceUtil;
044    import com.liferay.portal.util.Portal;
045    import com.liferay.portal.util.PortalInstances;
046    import com.liferay.portal.util.PortalUtil;
047    import com.liferay.portal.util.WebKeys;
048    
049    import java.io.IOException;
050    
051    import java.util.HashMap;
052    import java.util.List;
053    import java.util.Locale;
054    import java.util.Map;
055    
056    import javax.servlet.RequestDispatcher;
057    import javax.servlet.ServletConfig;
058    import javax.servlet.ServletContext;
059    import javax.servlet.ServletException;
060    import javax.servlet.http.HttpServlet;
061    import javax.servlet.http.HttpServletRequest;
062    import javax.servlet.http.HttpServletResponse;
063    
064    /**
065     * @author Brian Wing Shun Chan
066     * @author Jorge Ferrer
067     * @author Shuyang Zhou
068     */
069    public class FriendlyURLServlet extends HttpServlet {
070    
071            @Override
072            public void init(ServletConfig servletConfig) throws ServletException {
073                    super.init(servletConfig);
074    
075                    _private = GetterUtil.getBoolean(
076                            servletConfig.getInitParameter("private"));
077                    _user = GetterUtil.getBoolean(servletConfig.getInitParameter("user"));
078    
079                    if (_private) {
080                            if (_user) {
081                                    _friendlyURLPathPrefix =
082                                            PortalUtil.getPathFriendlyURLPrivateUser();
083                            }
084                            else {
085                                    _friendlyURLPathPrefix =
086                                            PortalUtil.getPathFriendlyURLPrivateGroup();
087                            }
088                    }
089                    else {
090                            _friendlyURLPathPrefix = PortalUtil.getPathFriendlyURLPublic();
091                    }
092            }
093    
094            @Override
095            public void service(
096                            HttpServletRequest request, HttpServletResponse response)
097                    throws IOException, ServletException {
098    
099                    // Do not set the entire full main path. See LEP-456.
100    
101                    //String mainPath = (String)ctx.getAttribute(WebKeys.MAIN_PATH);
102                    String mainPath = Portal.PATH_MAIN;
103    
104                    String redirect = mainPath;
105    
106                    String pathInfo = getPathInfo(request);
107    
108                    request.setAttribute(WebKeys.FRIENDLY_URL, getFriendlyURL(pathInfo));
109    
110                    Object[] redirectArray = null;
111    
112                    boolean forcePermanentRedirect = false;
113    
114                    try {
115                            redirectArray = getRedirect(
116                                    request, pathInfo, mainPath, request.getParameterMap());
117    
118                            redirect = (String)redirectArray[0];
119                            forcePermanentRedirect = (Boolean)redirectArray[1];
120    
121                            if (request.getAttribute(WebKeys.LAST_PATH) == null) {
122                                    LastPath lastPath = new LastPath(
123                                            _friendlyURLPathPrefix, pathInfo,
124                                            request.getParameterMap());
125    
126                                    request.setAttribute(WebKeys.LAST_PATH, lastPath);
127                            }
128                    }
129                    catch (Exception e) {
130                            if (_log.isWarnEnabled()) {
131                                    _log.warn(e);
132                            }
133    
134                            if ((e instanceof NoSuchGroupException) ||
135                                    (e instanceof NoSuchLayoutException)) {
136    
137                                    PortalUtil.sendError(
138                                            HttpServletResponse.SC_NOT_FOUND, e, request, response);
139    
140                                    return;
141                            }
142                    }
143    
144                    if (Validator.isNull(redirect)) {
145                            redirect = mainPath;
146                    }
147    
148                    if (_log.isDebugEnabled()) {
149                            _log.debug("Redirect " + redirect);
150                    }
151    
152                    if ((redirect.charAt(0) == CharPool.SLASH) && !forcePermanentRedirect) {
153                            ServletContext servletContext = getServletContext();
154    
155                            RequestDispatcher requestDispatcher =
156                                    servletContext.getRequestDispatcher(redirect);
157    
158                            if (requestDispatcher != null) {
159                                    requestDispatcher.forward(request, response);
160                            }
161                    }
162                    else {
163                            if (forcePermanentRedirect) {
164                                    response.setHeader("Location", redirect);
165                                    response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
166                            }
167                            else {
168                                    response.sendRedirect(redirect);
169                            }
170                    }
171            }
172    
173            protected String getFriendlyURL(String pathInfo) {
174                    String friendlyURL = _friendlyURLPathPrefix;
175    
176                    if (Validator.isNotNull(pathInfo)) {
177                            friendlyURL = friendlyURL.concat(pathInfo);
178                    }
179    
180                    return friendlyURL;
181            }
182    
183            protected String getPathInfo(HttpServletRequest request) {
184                    String requestURI = request.getRequestURI();
185    
186                    int pos = requestURI.indexOf(Portal.JSESSIONID);
187    
188                    if (pos != -1) {
189                            requestURI = requestURI.substring(0, pos);
190                    }
191    
192                    String pathProxy = PortalUtil.getPathProxy();
193    
194                    pos = _friendlyURLPathPrefix.length() - pathProxy.length();
195    
196                    return requestURI.substring(pos);
197            }
198    
199            protected Object[] getRedirect(
200                            HttpServletRequest request, String path, String mainPath,
201                            Map<String, String[]> params)
202                    throws Exception {
203    
204                    if (Validator.isNull(path) || (path.charAt(0) != CharPool.SLASH)) {
205                            return new Object[] {mainPath, false};
206                    }
207    
208                    // Group friendly URL
209    
210                    String friendlyURL = null;
211    
212                    int pos = path.indexOf(CharPool.SLASH, 1);
213    
214                    if (pos != -1) {
215                            friendlyURL = path.substring(0, pos);
216                    }
217                    else if (path.length() > 1) {
218                            friendlyURL = path;
219                    }
220    
221                    if (Validator.isNull(friendlyURL)) {
222                            return new Object[] {mainPath, Boolean.FALSE};
223                    }
224    
225                    long companyId = PortalInstances.getCompanyId(request);
226    
227                    Group group = GroupLocalServiceUtil.fetchFriendlyURLGroup(
228                            companyId, friendlyURL);
229    
230                    if (group == null) {
231                            String screenName = friendlyURL.substring(1);
232    
233                            if (_user || !Validator.isNumber(screenName)) {
234                                    User user = UserLocalServiceUtil.fetchUserByScreenName(
235                                            companyId, screenName);
236    
237                                    if (user != null) {
238                                            group = user.getGroup();
239                                    }
240                                    else if (_log.isWarnEnabled()) {
241                                            _log.warn("No user exists with friendly URL " + screenName);
242                                    }
243                            }
244                            else {
245                                    long groupId = GetterUtil.getLong(screenName);
246    
247                                    group = GroupLocalServiceUtil.fetchGroup(groupId);
248    
249                                    if (group == null) {
250                                            if (_log.isDebugEnabled()) {
251                                                    _log.debug(
252                                                            "No group exists with friendly URL " + groupId +
253                                                                    ". Try fetching by screen name instead.");
254                                            }
255    
256                                            User user = UserLocalServiceUtil.fetchUserByScreenName(
257                                                    companyId, screenName);
258    
259                                            if (user != null) {
260                                                    group = user.getGroup();
261                                            }
262                                            else if (_log.isWarnEnabled()) {
263                                                    _log.warn(
264                                                            "No user or group exists with friendly URL " +
265                                                                    groupId);
266                                            }
267                                    }
268                            }
269                    }
270    
271                    if (group == null) {
272                            StringBundler sb = new StringBundler(5);
273    
274                            sb.append("{companyId=");
275                            sb.append(companyId);
276                            sb.append(", friendlyURL=");
277                            sb.append(friendlyURL);
278                            sb.append("}");
279    
280                            throw new NoSuchGroupException(sb.toString());
281                    }
282    
283                    // Layout friendly URL
284    
285                    friendlyURL = null;
286    
287                    if ((pos != -1) && ((pos + 1) != path.length())) {
288                            friendlyURL = path.substring(pos);
289                    }
290    
291                    if (Validator.isNull(friendlyURL)) {
292                            request.setAttribute(
293                                    WebKeys.REDIRECT_TO_DEFAULT_LAYOUT, Boolean.TRUE);
294                    }
295    
296                    Map<String, Object> requestContext = new HashMap<>();
297    
298                    requestContext.put("request", request);
299    
300                    ServiceContext serviceContext =
301                            ServiceContextThreadLocal.getServiceContext();
302    
303                    if (serviceContext == null) {
304                            serviceContext = ServiceContextFactory.getInstance(request);
305    
306                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
307                    }
308    
309                    if (Validator.isNotNull(friendlyURL)) {
310                            try {
311                                    LayoutFriendlyURLComposite layoutFriendlyURLComposite =
312                                            PortalUtil.getLayoutFriendlyURLComposite(
313                                                    group.getGroupId(), _private, friendlyURL, params,
314                                                    requestContext);
315    
316                                    Layout layout = layoutFriendlyURLComposite.getLayout();
317    
318                                    String layoutFriendlyURLCompositeFriendlyURL =
319                                            layoutFriendlyURLComposite.getFriendlyURL();
320    
321                                    pos = layoutFriendlyURLCompositeFriendlyURL.indexOf(
322                                            Portal.FRIENDLY_URL_SEPARATOR);
323    
324                                    if (pos != 0) {
325                                            if (pos != -1) {
326                                                    layoutFriendlyURLCompositeFriendlyURL =
327                                                            layoutFriendlyURLCompositeFriendlyURL.substring(
328                                                                    0, pos);
329                                            }
330    
331                                            Locale locale = PortalUtil.getLocale(request);
332    
333                                            if (LanguageUtil.isAvailableLocale(
334                                                            group.getGroupId(), locale) &&
335                                                    !StringUtil.equalsIgnoreCase(
336                                                            layoutFriendlyURLCompositeFriendlyURL,
337                                                            layout.getFriendlyURL(locale))) {
338    
339                                                    Locale originalLocale = setAlternativeLayoutFriendlyURL(
340                                                            request, layout,
341                                                            layoutFriendlyURLCompositeFriendlyURL);
342    
343                                                    String redirect = PortalUtil.getLocalizedFriendlyURL(
344                                                            request, layout, locale, originalLocale);
345    
346                                                    return new Object[] {redirect, Boolean.TRUE};
347                                            }
348                                    }
349                            }
350                            catch (NoSuchLayoutException nsle) {
351                                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
352                                            group.getGroupId(), _private,
353                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
354    
355                                    for (Layout layout : layouts) {
356                                            if (layout.matches(request, friendlyURL)) {
357                                                    String redirect = PortalUtil.getLayoutActualURL(
358                                                            layout, mainPath);
359    
360                                                    return new Object[] {redirect, Boolean.FALSE};
361                                            }
362                                    }
363    
364                                    throw nsle;
365                            }
366                    }
367    
368                    String actualURL = PortalUtil.getActualURL(
369                            group.getGroupId(), _private, mainPath, friendlyURL, params,
370                            requestContext);
371    
372                    return new Object[] {actualURL, Boolean.FALSE};
373            }
374    
375            protected Locale setAlternativeLayoutFriendlyURL(
376                            HttpServletRequest request, Layout layout, String friendlyURL)
377                    throws Exception {
378    
379                    List<LayoutFriendlyURL> layoutFriendlyURLs =
380                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
381                                    layout.getPlid(), friendlyURL, 0, 1);
382    
383                    if (layoutFriendlyURLs.isEmpty()) {
384                            return null;
385                    }
386    
387                    LayoutFriendlyURL layoutFriendlyURL = layoutFriendlyURLs.get(0);
388    
389                    Locale locale = LocaleUtil.fromLanguageId(
390                            layoutFriendlyURL.getLanguageId());
391    
392                    String alternativeLayoutFriendlyURL =
393                            PortalUtil.getLocalizedFriendlyURL(request, layout, locale, locale);
394    
395                    SessionMessages.add(
396                            request, "alternativeLayoutFriendlyURL",
397                            alternativeLayoutFriendlyURL);
398    
399                    PortalMessages.add(
400                            request, PortalMessages.KEY_JSP_PATH,
401                            "/html/common/themes/layout_friendly_url_redirect.jsp");
402    
403                    return locale;
404            }
405    
406            private static final Log _log = LogFactoryUtil.getLog(
407                    FriendlyURLServlet.class);
408    
409            private String _friendlyURLPathPrefix;
410            private boolean _private;
411            private boolean _user;
412    
413    }