1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.servlet.filters.i18n;
16  
17  import com.liferay.portal.kernel.language.LanguageUtil;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.util.CharPool;
21  import com.liferay.portal.kernel.util.LocaleUtil;
22  import com.liferay.portal.kernel.util.StringPool;
23  import com.liferay.portal.kernel.util.StringUtil;
24  import com.liferay.portal.kernel.util.Validator;
25  import com.liferay.portal.model.Group;
26  import com.liferay.portal.model.LayoutSet;
27  import com.liferay.portal.servlet.filters.BasePortalFilter;
28  import com.liferay.portal.util.CookieKeys;
29  import com.liferay.portal.util.PortalUtil;
30  import com.liferay.portal.util.PropsValues;
31  import com.liferay.portal.util.WebKeys;
32  
33  import java.util.Collections;
34  import java.util.HashSet;
35  import java.util.Locale;
36  import java.util.Set;
37  
38  import javax.servlet.FilterChain;
39  import javax.servlet.http.HttpServletRequest;
40  import javax.servlet.http.HttpServletResponse;
41  
42  /**
43   * <a href="I18nFilter.java.html"><b><i>View Source</i></b></a>
44   *
45   * @author Brian Wing Shun Chan
46   */
47  public class I18nFilter extends BasePortalFilter {
48  
49      public static final String SKIP_FILTER =
50          I18nFilter.class.getName() + "SKIP_FILTER";
51  
52      public static Set<String> getLanguageIds() {
53          return _languageIds;
54      }
55  
56      public static void setLanguageIds(Set<String> languageIds) {
57          for (String languageId : languageIds) {
58              languageId = languageId.substring(1);
59  
60              _languageIds.add(languageId);
61          }
62  
63          _languageIds = Collections.unmodifiableSet(_languageIds);
64      }
65  
66      protected String getRedirect(HttpServletRequest request) {
67          if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 0) {
68              return null;
69          }
70  
71          String contextPath = PortalUtil.getPathContext();
72  
73          String requestURI = request.getRequestURI();
74  
75          if ((Validator.isNotNull(contextPath)) &&
76              (requestURI.indexOf(contextPath) != -1)) {
77  
78              requestURI = requestURI.substring(contextPath.length());
79          }
80  
81          requestURI = StringUtil.replace(
82              requestURI, StringPool.DOUBLE_SLASH, StringPool.SLASH);
83  
84          String i18nLanguageId = requestURI.substring(1);
85  
86          int pos = requestURI.indexOf(CharPool.SLASH, 1);
87  
88          if (pos != -1) {
89              i18nLanguageId = i18nLanguageId.substring(0, pos - 1);
90          }
91  
92          if (_languageIds.contains(i18nLanguageId)) {
93              return null;
94          }
95  
96          String defaultLanguageId = LocaleUtil.toLanguageId(
97              LocaleUtil.getDefault());
98  
99          String guestLanguageId = CookieKeys.getCookie(
100             request, CookieKeys.GUEST_LANGUAGE_ID);
101 
102         if (Validator.isNull(guestLanguageId)) {
103             guestLanguageId = defaultLanguageId;
104         }
105 
106         if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 1) {
107             if (!defaultLanguageId.equals(guestLanguageId)) {
108                 i18nLanguageId = guestLanguageId;
109             }
110             else {
111                 return null;
112             }
113         }
114         else if (PropsValues.LOCALE_PREPEND_FRIENDLY_URL_STYLE == 2) {
115             i18nLanguageId = guestLanguageId;
116         }
117 
118         if (i18nLanguageId == null) {
119             return null;
120         }
121 
122         String i18nPath = StringPool.SLASH + i18nLanguageId;
123 
124         Locale locale = LocaleUtil.fromLanguageId(i18nLanguageId);
125 
126         if (!LanguageUtil.isDuplicateLanguageCode(locale.getLanguage())) {
127             i18nPath = StringPool.SLASH + locale.getLanguage();
128         }
129         else {
130             Locale priorityLocale = LanguageUtil.getLocale(
131                 locale.getLanguage());
132 
133             if (locale.equals(priorityLocale)) {
134                 i18nPath = StringPool.SLASH + locale.getLanguage();
135             }
136         }
137 
138         String redirect = contextPath + i18nPath + requestURI;
139 
140         LayoutSet layoutSet = (LayoutSet)request.getAttribute(
141             WebKeys.VIRTUAL_HOST_LAYOUT_SET);
142 
143         if ((layoutSet != null) &&
144             (requestURI.startsWith(_PRIVATE_GROUP_SERVLET_MAPPING) ||
145              requestURI.startsWith(_PRIVATE_USER_SERVLET_MAPPING) ||
146              requestURI.startsWith(_PUBLIC_GROUP_SERVLET_MAPPING))) {
147 
148             int x = requestURI.indexOf(StringPool.SLASH, 1);
149 
150             if (x == -1) {
151 
152                 // /web
153 
154                 requestURI += StringPool.SLASH;
155 
156                 x = requestURI.indexOf(CharPool.SLASH, 1);
157             }
158 
159             int y = requestURI.indexOf(CharPool.SLASH, x + 1);
160 
161             if (y == -1) {
162 
163                 // /web/alpha
164 
165                 requestURI += StringPool.SLASH;
166 
167                 y = requestURI.indexOf(CharPool.SLASH, x + 1);
168             }
169 
170             String groupFriendlyURL = requestURI.substring(x, y);
171 
172             Group group = layoutSet.getGroup();
173 
174             if (group.getFriendlyURL().equals(groupFriendlyURL)) {
175                 redirect = contextPath + i18nPath + requestURI.substring(y);
176             }
177         }
178 
179         String queryString = request.getQueryString();
180 
181         if (Validator.isNotNull(queryString)) {
182             redirect += StringPool.QUESTION + request.getQueryString();
183         }
184 
185         return redirect;
186     }
187 
188     protected boolean isAlreadyFiltered(HttpServletRequest request) {
189         if (request.getAttribute(SKIP_FILTER) != null) {
190             return true;
191         }
192         else {
193             return false;
194         }
195     }
196 
197     protected boolean isForwardedByI18nServlet(HttpServletRequest request) {
198         if ((request.getAttribute(WebKeys.I18N_LANGUAGE_ID) != null) ||
199             (request.getAttribute(WebKeys.I18N_PATH) != null)) {
200 
201             return true;
202         }
203         else {
204             return false;
205         }
206     }
207 
208     protected void processFilter(
209             HttpServletRequest request, HttpServletResponse response,
210             FilterChain filterChain)
211         throws Exception {
212 
213         if (isAlreadyFiltered(request) || isForwardedByI18nServlet(request)) {
214             processFilter(I18nFilter.class, request, response, filterChain);
215 
216             return;
217         }
218 
219         request.setAttribute(SKIP_FILTER, Boolean.TRUE);
220 
221         String redirect = getRedirect(request);
222 
223         if (redirect == null) {
224             processFilter(I18nFilter.class, request, response, filterChain);
225 
226             return;
227         }
228 
229         if (_log.isDebugEnabled()) {
230             _log.debug("Redirect " + redirect);
231         }
232 
233         response.sendRedirect(redirect);
234     }
235 
236     private static Log _log = LogFactoryUtil.getLog(I18nFilter.class);
237 
238     private static final String  _PRIVATE_GROUP_SERVLET_MAPPING =
239         PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
240 
241     private static final String _PRIVATE_USER_SERVLET_MAPPING =
242         PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
243 
244     private static final String _PUBLIC_GROUP_SERVLET_MAPPING =
245         PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
246 
247     private static Set<String> _languageIds = new HashSet<String>();
248 
249 }