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