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