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.filters.i18n;
016    
017    import com.liferay.portal.kernel.language.LanguageUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.servlet.HttpMethods;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.LocaleUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.model.Group;
027    import com.liferay.portal.model.LayoutSet;
028    import com.liferay.portal.model.User;
029    import com.liferay.portal.servlet.filters.BasePortalFilter;
030    import com.liferay.portal.util.CookieKeys;
031    import com.liferay.portal.util.PortalUtil;
032    import com.liferay.portal.util.PropsValues;
033    import com.liferay.portal.util.WebKeys;
034    
035    import java.util.Collections;
036    import java.util.HashSet;
037    import java.util.Locale;
038    import java.util.Set;
039    
040    import javax.servlet.FilterChain;
041    import javax.servlet.http.HttpServletRequest;
042    import javax.servlet.http.HttpServletResponse;
043    
044    /**
045     * @author Brian Wing Shun Chan
046     */
047    public class I18nFilter extends BasePortalFilter {
048    
049            public static final String SKIP_FILTER =
050                    I18nFilter.class.getName() + "SKIP_FILTER";
051    
052            public static Set<String> getLanguageIds() {
053                    return _languageIds;
054            }
055    
056            public static void setLanguageIds(Set<String> languageIds) {
057                    _languageIds = new HashSet<String>();
058    
059                    for (String languageId : languageIds) {
060                            languageId = languageId.substring(1);
061    
062                            _languageIds.add(languageId);
063                    }
064    
065                    _languageIds = Collections.unmodifiableSet(_languageIds);
066            }
067    
068            @Override
069            public boolean isFilterEnabled(
070                    HttpServletRequest request, HttpServletResponse response) {
071    
072                    if (!isAlreadyFiltered(request) && !isForwardedByI18nServlet(request)) {
073                            return true;
074                    }
075                    else {
076                            return false;
077                    }
078            }
079    
080            protected String getRedirect(HttpServletRequest request) throws Exception {
081                    if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 0) {
082                            return null;
083                    }
084    
085                    String method = request.getMethod();
086    
087                    if (method.equals(HttpMethods.POST)) {
088                            return null;
089                    }
090    
091                    String contextPath = PortalUtil.getPathContext();
092    
093                    String requestURI = request.getRequestURI();
094    
095                    if (Validator.isNotNull(contextPath) &&
096                            requestURI.contains(contextPath)) {
097    
098                            requestURI = requestURI.substring(contextPath.length());
099                    }
100    
101                    requestURI = StringUtil.replace(
102                            requestURI, StringPool.DOUBLE_SLASH, StringPool.SLASH);
103    
104                    String i18nLanguageId = requestURI.substring(1);
105    
106                    int pos = requestURI.indexOf(CharPool.SLASH, 1);
107    
108                    if (pos != -1) {
109                            i18nLanguageId = i18nLanguageId.substring(0, pos - 1);
110                    }
111    
112                    if (_languageIds.contains(i18nLanguageId)) {
113                            return null;
114                    }
115    
116                    String guestLanguageId = null;
117    
118                    User user = (User)request.getAttribute(WebKeys.USER);
119    
120                    if (user != null) {
121                            guestLanguageId = user.getLanguageId();
122                    }
123    
124                    if (Validator.isNull(guestLanguageId)) {
125                            guestLanguageId = CookieKeys.getCookie(
126                                    request, CookieKeys.GUEST_LANGUAGE_ID, false);
127                    }
128    
129                    String defaultLanguageId = LocaleUtil.toLanguageId(
130                            LocaleUtil.getDefault());
131    
132                    if (Validator.isNull(guestLanguageId)) {
133                            guestLanguageId = defaultLanguageId;
134                    }
135    
136                    if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 1) {
137                            if (!defaultLanguageId.equals(guestLanguageId)) {
138                                    i18nLanguageId = guestLanguageId;
139                            }
140                            else {
141                                    return null;
142                            }
143                    }
144                    else if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 2) {
145                            i18nLanguageId = LocaleUtil.toLanguageId(
146                                    PortalUtil.getLocale(request));
147                    }
148    
149                    if (i18nLanguageId == null) {
150                            return null;
151                    }
152    
153                    Locale locale = LocaleUtil.fromLanguageId(i18nLanguageId);
154    
155                    if (!LanguageUtil.isAvailableLocale(locale)) {
156                            return null;
157                    }
158    
159                    String i18nPathLanguageId = i18nLanguageId;
160    
161                    if (!LanguageUtil.isDuplicateLanguageCode(locale.getLanguage())) {
162                            i18nPathLanguageId = locale.getLanguage();
163                    }
164                    else {
165                            Locale priorityLocale = LanguageUtil.getLocale(
166                                    locale.getLanguage());
167    
168                            if (locale.equals(priorityLocale)) {
169                                    i18nPathLanguageId = locale.getLanguage();
170                            }
171                    }
172    
173                    String i18nPath = StringPool.SLASH.concat(i18nPathLanguageId);
174    
175                    if (requestURI.contains(i18nPath.concat(StringPool.SLASH))) {
176                            return null;
177                    }
178    
179                    String redirect = contextPath + i18nPath + requestURI;
180    
181                    LayoutSet layoutSet = (LayoutSet)request.getAttribute(
182                            WebKeys.VIRTUAL_HOST_LAYOUT_SET);
183    
184                    if ((layoutSet != null) &&
185                            (requestURI.startsWith(_PRIVATE_GROUP_SERVLET_MAPPING) ||
186                             requestURI.startsWith(_PRIVATE_USER_SERVLET_MAPPING) ||
187                             requestURI.startsWith(_PUBLIC_GROUP_SERVLET_MAPPING))) {
188    
189                            int x = requestURI.indexOf(StringPool.SLASH, 1);
190    
191                            if (x == -1) {
192    
193                                    // /web
194    
195                                    requestURI += StringPool.SLASH;
196    
197                                    x = requestURI.indexOf(CharPool.SLASH, 1);
198                            }
199    
200                            int y = requestURI.indexOf(CharPool.SLASH, x + 1);
201    
202                            if (y == -1) {
203    
204                                    // /web/alpha
205    
206                                    requestURI += StringPool.SLASH;
207    
208                                    y = requestURI.indexOf(CharPool.SLASH, x + 1);
209                            }
210    
211                            String groupFriendlyURL = requestURI.substring(x, y);
212    
213                            Group group = layoutSet.getGroup();
214    
215                            if (group.getFriendlyURL().equals(groupFriendlyURL)) {
216                                    redirect = contextPath + i18nPath + requestURI.substring(y);
217                            }
218                    }
219    
220                    String queryString = request.getQueryString();
221    
222                    if (Validator.isNotNull(queryString)) {
223                            redirect += StringPool.QUESTION + request.getQueryString();
224                    }
225    
226                    return redirect;
227            }
228    
229            protected boolean isAlreadyFiltered(HttpServletRequest request) {
230                    if (request.getAttribute(SKIP_FILTER) != null) {
231                            return true;
232                    }
233                    else {
234                            return false;
235                    }
236            }
237    
238            protected boolean isForwardedByI18nServlet(HttpServletRequest request) {
239                    if ((request.getAttribute(WebKeys.I18N_LANGUAGE_ID) != null) ||
240                            (request.getAttribute(WebKeys.I18N_PATH) != null)) {
241    
242                            return true;
243                    }
244                    else {
245                            return false;
246                    }
247            }
248    
249            @Override
250            protected void processFilter(
251                            HttpServletRequest request, HttpServletResponse response,
252                            FilterChain filterChain)
253                    throws Exception {
254    
255                    request.setAttribute(SKIP_FILTER, Boolean.TRUE);
256    
257                    String redirect = getRedirect(request);
258    
259                    if (redirect == null) {
260                            processFilter(I18nFilter.class, request, response, filterChain);
261    
262                            return;
263                    }
264    
265                    if (_log.isDebugEnabled()) {
266                            _log.debug("Redirect " + redirect);
267                    }
268    
269                    response.sendRedirect(redirect);
270            }
271    
272            private static final String _PRIVATE_GROUP_SERVLET_MAPPING =
273                    PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
274    
275            private static final String _PRIVATE_USER_SERVLET_MAPPING =
276                    PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
277    
278            private static final String _PUBLIC_GROUP_SERVLET_MAPPING =
279                    PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
280    
281            private static Log _log = LogFactoryUtil.getLog(I18nFilter.class);
282    
283            private static Set<String> _languageIds;
284    
285    }