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