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                                    request.setAttribute(WebKeys.LAYOUT, layout);
319    
320                                    String layoutFriendlyURLCompositeFriendlyURL =
321                                            layoutFriendlyURLComposite.getFriendlyURL();
322    
323                                    pos = layoutFriendlyURLCompositeFriendlyURL.indexOf(
324                                            Portal.FRIENDLY_URL_SEPARATOR);
325    
326                                    if (pos != 0) {
327                                            if (pos != -1) {
328                                                    layoutFriendlyURLCompositeFriendlyURL =
329                                                            layoutFriendlyURLCompositeFriendlyURL.substring(
330                                                                    0, pos);
331                                            }
332    
333                                            Locale locale = PortalUtil.getLocale(request);
334    
335                                            boolean i18nRedirect = false;
336    
337                                            String i18nLanguageId = (String)request.getAttribute(
338                                                    WebKeys.I18N_LANGUAGE_ID);
339    
340                                            if (Validator.isNotNull(i18nLanguageId)) {
341                                                    Locale i18nLocale = LocaleUtil.fromLanguageId(
342                                                            i18nLanguageId);
343    
344                                                    if (!LanguageUtil.isAvailableLocale(
345                                                                    group.getGroupId(), i18nLocale)) {
346    
347                                                            i18nRedirect = true;
348                                                    }
349                                            }
350    
351                                            if (i18nRedirect ||
352                                                    !StringUtil.equalsIgnoreCase(
353                                                            layoutFriendlyURLCompositeFriendlyURL,
354                                                            layout.getFriendlyURL(locale))) {
355    
356                                                    Locale originalLocale = setAlternativeLayoutFriendlyURL(
357                                                            request, layout,
358                                                            layoutFriendlyURLCompositeFriendlyURL);
359    
360                                                    String redirect = PortalUtil.getLocalizedFriendlyURL(
361                                                            request, layout, locale, originalLocale);
362    
363                                                    return new Object[] {redirect, Boolean.TRUE};
364                                            }
365                                    }
366                            }
367                            catch (NoSuchLayoutException nsle) {
368                                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
369                                            group.getGroupId(), _private,
370                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
371    
372                                    for (Layout layout : layouts) {
373                                            if (layout.matches(request, friendlyURL)) {
374                                                    String redirect = PortalUtil.getLayoutActualURL(
375                                                            layout, mainPath);
376    
377                                                    return new Object[] {redirect, Boolean.FALSE};
378                                            }
379                                    }
380    
381                                    throw nsle;
382                            }
383                    }
384    
385                    String actualURL = PortalUtil.getActualURL(
386                            group.getGroupId(), _private, mainPath, friendlyURL, params,
387                            requestContext);
388    
389                    return new Object[] {actualURL, Boolean.FALSE};
390            }
391    
392            protected Locale setAlternativeLayoutFriendlyURL(
393                            HttpServletRequest request, Layout layout, String friendlyURL)
394                    throws Exception {
395    
396                    List<LayoutFriendlyURL> layoutFriendlyURLs =
397                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
398                                    layout.getPlid(), friendlyURL, 0, 1);
399    
400                    if (layoutFriendlyURLs.isEmpty()) {
401                            return null;
402                    }
403    
404                    LayoutFriendlyURL layoutFriendlyURL = layoutFriendlyURLs.get(0);
405    
406                    Locale locale = LocaleUtil.fromLanguageId(
407                            layoutFriendlyURL.getLanguageId());
408    
409                    String alternativeLayoutFriendlyURL =
410                            PortalUtil.getLocalizedFriendlyURL(request, layout, locale, locale);
411    
412                    SessionMessages.add(
413                            request, "alternativeLayoutFriendlyURL",
414                            alternativeLayoutFriendlyURL);
415    
416                    PortalMessages.add(
417                            request, PortalMessages.KEY_JSP_PATH,
418                            "/html/common/themes/layout_friendly_url_redirect.jsp");
419    
420                    return locale;
421            }
422    
423            private static final Log _log = LogFactoryUtil.getLog(
424                    FriendlyURLServlet.class);
425    
426            private String _friendlyURLPathPrefix;
427            private boolean _private;
428            private boolean _user;
429    
430    }