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