001
014
015 package com.liferay.portal.kernel.search;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
021 import com.liferay.portal.kernel.util.Base64;
022 import com.liferay.portal.kernel.util.Digester;
023 import com.liferay.portal.kernel.util.DigesterUtil;
024 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
025 import com.liferay.portal.kernel.util.PropsKeys;
026 import com.liferay.portal.kernel.util.PropsUtil;
027 import com.liferay.portal.kernel.util.StreamUtil;
028 import com.liferay.portal.kernel.util.StringBundler;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.Validator;
032 import com.liferay.portal.model.Group;
033 import com.liferay.portal.service.GroupLocalServiceUtil;
034 import com.liferay.portal.util.PortletKeys;
035
036 import java.io.InputStream;
037
038 import java.net.URL;
039
040 import java.nio.CharBuffer;
041 import java.nio.charset.CharsetEncoder;
042
043 import java.util.List;
044
045
048 public abstract class BaseSpellCheckIndexWriter
049 implements SpellCheckIndexWriter {
050
051 @Override
052 public void indexQuerySuggestionDictionaries(SearchContext searchContext)
053 throws SearchException {
054
055 try {
056 for (String languageId : _SUPPORTED_LOCALES) {
057 indexKeywords(
058 searchContext.getCompanyId(), languageId,
059 PropsKeys.INDEX_SEARCH_QUERY_SUGGESTION_DICTIONARY,
060 Field.KEYWORD_SEARCH, QUERY_SUGGESTION_TYPE, 0);
061 }
062 }
063 catch (Exception e) {
064 throw new SearchException(e);
065 }
066 }
067
068 @Override
069 public void indexQuerySuggestionDictionary(SearchContext searchContext)
070 throws SearchException {
071
072 try {
073 indexKeywords(
074 searchContext.getCompanyId(), searchContext.getLanguageId(),
075 PropsKeys.INDEX_SEARCH_QUERY_SUGGESTION_DICTIONARY,
076 Field.KEYWORD_SEARCH, QUERY_SUGGESTION_TYPE, 0);
077 }
078 catch (Exception e) {
079 throw new SearchException(e);
080 }
081 }
082
083 @Override
084 public void indexSpellCheckerDictionaries(SearchContext searchContext)
085 throws SearchException {
086
087 try {
088 for (String languageId : _SUPPORTED_LOCALES) {
089 indexKeywords(
090 searchContext.getCompanyId(), languageId,
091 PropsKeys.INDEX_SEARCH_SPELL_CHECKER_DICTIONARY,
092 Field.SPELL_CHECK_WORD, SPELL_CHECKER_TYPE, 0);
093 }
094 }
095 catch (Exception e) {
096 throw new SearchException(e);
097 }
098 }
099
100 @Override
101 public void indexSpellCheckerDictionary(SearchContext searchContext)
102 throws SearchException {
103
104 try {
105 indexKeywords(
106 searchContext.getCompanyId(), searchContext.getLanguageId(),
107 PropsKeys.INDEX_SEARCH_SPELL_CHECKER_DICTIONARY,
108 Field.SPELL_CHECK_WORD, SPELL_CHECKER_TYPE, 0);
109 }
110 catch (Exception e) {
111 throw new SearchException(e);
112 }
113 }
114
115 protected URL getResource(String name) {
116 ClassLoader contextClassLoader =
117 Thread.currentThread().getContextClassLoader();
118
119 URL url = contextClassLoader.getResource(name);
120
121 if (url == null) {
122 ClassLoader portalClassLoader =
123 PortalClassLoaderUtil.getClassLoader();
124
125 url = portalClassLoader.getResource(name);
126 }
127
128 return url;
129 }
130
131 protected String getUID(
132 long companyId, String languageId, String word, String... parameters) {
133
134 StringBundler uidSB = new StringBundler();
135
136 uidSB.append(String.valueOf(companyId));
137 uidSB.append(StringPool.UNDERLINE);
138 uidSB.append(PortletKeys.SEARCH);
139 uidSB.append(_PORTLET_SEPARATOR);
140
141 int length = 4;
142
143 if (parameters != null) {
144 length += parameters.length;
145 }
146
147 try {
148 CharsetEncoder charsetEncoder =
149 CharsetEncoderUtil.getCharsetEncoder(StringPool.UTF8);
150
151 StringBundler keySB = new StringBundler(length);
152
153 keySB.append(languageId);
154 keySB.append(StringPool.UNDERLINE);
155 keySB.append(word);
156 keySB.append(StringPool.UNDERLINE);
157
158 keySB.append(word.toLowerCase());
159
160 if (parameters != null) {
161 for (String parameter : parameters) {
162 keySB.append(parameter);
163 keySB.append(StringPool.UNDERLINE);
164 }
165 }
166
167 String key = keySB.toString();
168
169 byte[] bytes = DigesterUtil.digestRaw(
170 Digester.MD5, charsetEncoder.encode(CharBuffer.wrap(key)));
171
172 uidSB.append(Base64.encode(bytes));
173 }
174 catch (Exception e) {
175 throw new IllegalStateException(e);
176 }
177
178 return uidSB.toString();
179 }
180
181 protected abstract void indexKeywords(
182 long companyId, long groupId, String languageId,
183 InputStream inputStream, String keywordFieldName,
184 String typeFieldValue, int maxNGramLength)
185 throws Exception;
186
187 protected void indexKeywords(
188 long companyId, long groupId, String languageId,
189 String[] dictionaryFileNames, String keywordFieldName,
190 String typeFieldValue, int maxNGramLength)
191 throws Exception {
192
193 for (String dictionaryFileName : dictionaryFileNames) {
194 InputStream inputStream = null;
195
196 if (_log.isInfoEnabled()) {
197 _log.info(
198 "Start indexing dictionary for " + dictionaryFileName);
199 }
200
201 try {
202 URL url = getResource(dictionaryFileName);
203
204 if (url == null) {
205 if (_log.isWarnEnabled()) {
206 _log.warn("Unable to read " + dictionaryFileName);
207 }
208
209 continue;
210 }
211
212 inputStream = url.openStream();
213
214 if (inputStream == null) {
215 if (_log.isWarnEnabled()) {
216 _log.warn("Unable to read " + dictionaryFileName);
217 }
218
219 continue;
220 }
221
222 indexKeywords(
223 companyId, groupId, languageId, inputStream,
224 keywordFieldName, typeFieldValue, maxNGramLength);
225 }
226 finally {
227 StreamUtil.cleanUp(inputStream);
228 }
229
230 if (_log.isInfoEnabled()) {
231 _log.info(
232 "Finished indexing dictionary for " + dictionaryFileName);
233 }
234 }
235 }
236
237 protected void indexKeywords(
238 long companyId, String languageId, String propsKey,
239 String keywordFieldName, String typeFieldValue, int maxNGramLength)
240 throws Exception {
241
242 String[] dictionaryFileNames = PropsUtil.getArray(
243 propsKey, new Filter(languageId));
244
245 indexKeywords(
246 companyId, 0, languageId, dictionaryFileNames, keywordFieldName,
247 typeFieldValue, maxNGramLength);
248
249 List<Group> groups = GroupLocalServiceUtil.getLiveGroups();
250
251 for (Group group : groups) {
252 String[] groupDictionaryFileNames = PropsUtil.getArray(
253 PropsKeys.INDEX_SEARCH_SPELL_CHECKER_DICTIONARY,
254 new Filter(languageId, String.valueOf(group.getGroupId())));
255
256 if (Validator.isNull(groupDictionaryFileNames)) {
257 continue;
258 }
259
260 indexKeywords(
261 companyId, group.getGroupId(), languageId, dictionaryFileNames,
262 keywordFieldName, typeFieldValue, maxNGramLength);
263 }
264 }
265
266 protected static final String QUERY_SUGGESTION_TYPE = "querySuggestion";
267
268 protected static final String SPELL_CHECKER_TYPE = "spellChecker";
269
270 private static final String _PORTLET_SEPARATOR = "_PORTLET_";
271
272 private static final String[] _SUPPORTED_LOCALES = StringUtil.split(
273 PropsUtil.get(PropsKeys.INDEX_SEARCH_SPELL_CHECKER_SUPPORTED_LOCALES));
274
275 private static Log _log = LogFactoryUtil.getLog(
276 BaseSpellCheckIndexWriter.class);
277
278 }