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