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