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                    request.setAttribute(
103                            WebKeys.FRIENDLY_URL, _friendlyURLPathPrefix.concat(pathInfo));
104    
105                    Object[] redirectArray = null;
106    
107                    boolean forcePermanentRedirect = false;
108    
109                    try {
110                            redirectArray = getRedirect(
111                                    request, pathInfo, mainPath, request.getParameterMap());
112    
113                            redirect = (String)redirectArray[0];
114                            forcePermanentRedirect = (Boolean)redirectArray[1];
115    
116                            if (request.getAttribute(WebKeys.LAST_PATH) == null) {
117                                    LastPath lastPath = new LastPath(
118                                            _friendlyURLPathPrefix, pathInfo,
119                                            request.getParameterMap());
120    
121                                    request.setAttribute(WebKeys.LAST_PATH, lastPath);
122                            }
123                    }
124                    catch (NoSuchLayoutException nsle) {
125                            _log.warn(nsle);
126    
127                            PortalUtil.sendError(
128                                    HttpServletResponse.SC_NOT_FOUND, nsle, request, response);
129    
130                            return;
131                    }
132                    catch (Exception e) {
133                            if (_log.isWarnEnabled()) {
134                                    _log.warn(e);
135                            }
136                    }
137    
138                    if (Validator.isNull(redirect)) {
139                            redirect = mainPath;
140                    }
141    
142                    if (_log.isDebugEnabled()) {
143                            _log.debug("Redirect " + redirect);
144                    }
145    
146                    if ((redirect.charAt(0) == CharPool.SLASH) && !forcePermanentRedirect) {
147                            ServletContext servletContext = getServletContext();
148    
149                            RequestDispatcher requestDispatcher =
150                                    servletContext.getRequestDispatcher(redirect);
151    
152                            if (requestDispatcher != null) {
153                                    requestDispatcher.forward(request, response);
154                            }
155                    }
156                    else {
157                            if (forcePermanentRedirect) {
158                                    response.setHeader("Location", redirect);
159                                    response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
160                            }
161                            else {
162                                    response.sendRedirect(redirect);
163                            }
164                    }
165            }
166    
167            protected Object[] getRedirect(
168                            HttpServletRequest request, String path, String mainPath,
169                            Map<String, String[]> params)
170                    throws Exception {
171    
172                    if (Validator.isNull(path) || (path.charAt(0) != CharPool.SLASH)) {
173                            return new Object[] {mainPath, false};
174                    }
175    
176                    // Group friendly URL
177    
178                    String friendlyURL = null;
179    
180                    int pos = path.indexOf(CharPool.SLASH, 1);
181    
182                    if (pos != -1) {
183                            friendlyURL = path.substring(0, pos);
184                    }
185                    else if (path.length() > 1) {
186                            friendlyURL = path;
187                    }
188    
189                    if (Validator.isNull(friendlyURL)) {
190                            return new Object[] {mainPath, Boolean.FALSE};
191                    }
192    
193                    long companyId = PortalInstances.getCompanyId(request);
194    
195                    Group group = GroupLocalServiceUtil.fetchFriendlyURLGroup(
196                            companyId, friendlyURL);
197    
198                    if (group == null) {
199                            String screenName = friendlyURL.substring(1);
200    
201                            if (_user || !Validator.isNumber(screenName)) {
202                                    User user = UserLocalServiceUtil.fetchUserByScreenName(
203                                            companyId, screenName);
204    
205                                    if (user != null) {
206                                            group = user.getGroup();
207                                    }
208                                    else if (_log.isWarnEnabled()) {
209                                            _log.warn("No user exists with friendly URL " + screenName);
210                                    }
211                            }
212                            else {
213                                    long groupId = GetterUtil.getLong(screenName);
214    
215                                    group = GroupLocalServiceUtil.fetchGroup(groupId);
216    
217                                    if (group == null) {
218                                            if (_log.isDebugEnabled()) {
219                                                    _log.debug(
220                                                            "No group exists with friendly URL " + groupId +
221                                                                    ". Try fetching by screen name instead.");
222                                            }
223    
224                                            User user = UserLocalServiceUtil.fetchUserByScreenName(
225                                                    companyId, screenName);
226    
227                                            if (user != null) {
228                                                    group = user.getGroup();
229                                            }
230                                            else if (_log.isWarnEnabled()) {
231                                                    _log.warn(
232                                                            "No user or group exists with friendly URL " +
233                                                                    groupId);
234                                            }
235                                    }
236                            }
237                    }
238    
239                    if (group == null) {
240                            return new Object[] {mainPath, Boolean.FALSE};
241                    }
242    
243                    // Layout friendly URL
244    
245                    friendlyURL = null;
246    
247                    if ((pos != -1) && ((pos + 1) != path.length())) {
248                            friendlyURL = path.substring(pos);
249                    }
250    
251                    if (Validator.isNull(friendlyURL)) {
252                            request.setAttribute(
253                                    WebKeys.REDIRECT_TO_DEFAULT_LAYOUT, Boolean.TRUE);
254                    }
255    
256                    Map<String, Object> requestContext = new HashMap<String, Object>();
257    
258                    requestContext.put("request", request);
259    
260                    ServiceContext serviceContext =
261                            ServiceContextThreadLocal.getServiceContext();
262    
263                    if (serviceContext == null) {
264                            serviceContext = ServiceContextFactory.getInstance(request);
265    
266                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
267                    }
268    
269                    String actualURL = PortalUtil.getActualURL(
270                            group.getGroupId(), _private, mainPath, friendlyURL, params,
271                            requestContext);
272    
273                    if (Validator.isNotNull(friendlyURL)) {
274                            Locale locale = PortalUtil.getLocale(request);
275    
276                            LayoutFriendlyURLComposite layoutFriendlyURLComposite =
277                                    PortalUtil.getLayoutFriendlyURLComposite(
278                                            group.getGroupId(), _private, friendlyURL, params,
279                                            requestContext);
280    
281                            Layout layout = layoutFriendlyURLComposite.getLayout();
282    
283                            friendlyURL = layoutFriendlyURLComposite.getFriendlyURL();
284    
285                            pos = friendlyURL.indexOf(Portal.FRIENDLY_URL_SEPARATOR);
286    
287                            if (pos != 0) {
288                                    if (pos != -1) {
289                                            friendlyURL = friendlyURL.substring(0, pos);
290                                    }
291    
292                                    if (!friendlyURL.equals(layout.getFriendlyURL(locale))) {
293                                            setAlternativeLayoutFriendlyURL(
294                                                    request, layout, friendlyURL);
295    
296                                            String redirect = PortalUtil.getLocalizedFriendlyURL(
297                                                    request, layout, locale);
298    
299                                            return new Object[] {redirect, Boolean.TRUE};
300                                    }
301                            }
302                    }
303    
304                    return new Object[] {actualURL, Boolean.FALSE};
305            }
306    
307            protected void setAlternativeLayoutFriendlyURL(
308                            HttpServletRequest request, Layout layout, String friendlyURL)
309                    throws Exception {
310    
311                    List<LayoutFriendlyURL> layoutFriendlyURLs =
312                            LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
313                                    layout.getPlid(), friendlyURL, 0, 1);
314    
315                    if (layoutFriendlyURLs.isEmpty()) {
316                            return;
317                    }
318    
319                    LayoutFriendlyURL layoutFriendlyURL = layoutFriendlyURLs.get(0);
320    
321                    Locale locale = LocaleUtil.fromLanguageId(
322                            layoutFriendlyURL.getLanguageId());
323    
324                    String alternativeLayoutFriendlyURL =
325                            PortalUtil.getLocalizedFriendlyURL(request, layout, locale);
326    
327                    SessionMessages.add(
328                            request, "alternativeLayoutFriendlyURL",
329                            alternativeLayoutFriendlyURL);
330    
331                    PortalMessages.add(
332                            request, PortalMessages.KEY_JSP_PATH,
333                            "/html/common/themes/layout_friendly_url_redirect.jsp");
334            }
335    
336            private static Log _log = LogFactoryUtil.getLog(FriendlyURLServlet.class);
337    
338            private String _friendlyURLPathPrefix;
339            private boolean _private;
340            private boolean _user;
341    
342    }