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