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