001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.search.lucene;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.search.BaseIndexWriter;
020    import com.liferay.portal.kernel.search.Document;
021    import com.liferay.portal.kernel.search.DocumentImpl;
022    import com.liferay.portal.kernel.search.Field;
023    import com.liferay.portal.kernel.search.SearchContext;
024    import com.liferay.portal.kernel.search.SearchException;
025    import com.liferay.portal.kernel.util.LocaleUtil;
026    import com.liferay.portal.kernel.util.Validator;
027    
028    import java.io.IOException;
029    
030    import java.util.Collection;
031    import java.util.Locale;
032    import java.util.Map;
033    
034    import org.apache.lucene.index.Term;
035    
036    /**
037     * @author Bruno Farache
038     * @author Brian Wing Shun Chan
039     * @author Allen Chiang
040     * @author Alex Wallace
041     */
042    public class LuceneIndexWriter extends BaseIndexWriter {
043    
044            @Override
045            public void addDocument(SearchContext searchContext, Document document)
046                    throws SearchException {
047    
048                    try {
049                            LuceneHelperUtil.addDocument(
050                                    searchContext.getCompanyId(), _getLuceneDocument(document));
051    
052                            if (_log.isDebugEnabled()) {
053                                    _log.debug("Added document " + document.get(Field.UID));
054                            }
055                    }
056                    catch (IOException ioe) {
057                            throw new SearchException(ioe);
058                    }
059            }
060    
061            @Override
062            public void addDocuments(
063                            SearchContext searchContext, Collection<Document> documents)
064                    throws SearchException {
065    
066                    for (Document document : documents) {
067                            addDocument(searchContext, document);
068                    }
069            }
070    
071            @Override
072            public void deleteDocument(SearchContext searchContext, String uid)
073                    throws SearchException {
074    
075                    try {
076                            LuceneHelperUtil.deleteDocuments(
077                                    searchContext.getCompanyId(), new Term(Field.UID, uid));
078    
079                            if (_log.isDebugEnabled()) {
080                                    _log.debug("Deleted document " + uid);
081                            }
082                    }
083                    catch (IOException ioe) {
084                            throw new SearchException(ioe);
085                    }
086            }
087    
088            @Override
089            public void deleteDocuments(
090                            SearchContext searchContext, Collection<String> uids)
091                    throws SearchException {
092    
093                    for (String uid : uids) {
094                            deleteDocument(searchContext, uid);
095                    }
096            }
097    
098            @Override
099            public void deletePortletDocuments(
100                            SearchContext searchContext, String portletId)
101                    throws SearchException {
102    
103                    try {
104                            LuceneHelperUtil.deleteDocuments(
105                                    searchContext.getCompanyId(), new Term(Field.PORTLET_ID,
106                                    portletId));
107                    }
108                    catch (IOException ioe) {
109                            throw new SearchException(ioe);
110                    }
111            }
112    
113            @Override
114            public void updateDocument(SearchContext searchContext, Document document)
115                    throws SearchException {
116    
117                    try {
118                            LuceneHelperUtil.updateDocument(
119                                    searchContext.getCompanyId(),
120                                    new Term(Field.UID, document.getUID()),
121                                    _getLuceneDocument(document));
122    
123                            if (_log.isDebugEnabled()) {
124                                    _log.debug("Updated document " + document.get(Field.UID));
125                            }
126                    }
127                    catch (IOException ioe) {
128                            throw new SearchException(ioe);
129                    }
130            }
131    
132            @Override
133            public void updateDocuments(
134                            SearchContext searchContext, Collection<Document> documents)
135                    throws SearchException {
136    
137                    for (Document document : documents) {
138                            updateDocument(searchContext, document);
139                    }
140            }
141    
142            private void _addLuceneFieldable(
143                    org.apache.lucene.document.Document luceneDocument, String name,
144                    boolean numeric, Class<? extends Number> numericClass,
145                    boolean tokenized, boolean sortable, float boost, String value) {
146    
147                    org.apache.lucene.document.Fieldable luceneFieldable = null;
148    
149                    if (numeric) {
150                            luceneFieldable = LuceneFields.getNumber(name, value, numericClass);
151                    }
152                    else {
153                            if (tokenized) {
154                                    luceneFieldable = LuceneFields.getText(name, value);
155                            }
156                            else {
157                                    luceneFieldable = LuceneFields.getKeyword(name, value);
158                            }
159                    }
160    
161                    if (sortable) {
162                            String sortableFieldName = DocumentImpl.getSortableFieldName(name);
163    
164                            luceneFieldable = LuceneFields.getKeyword(sortableFieldName, value);
165                    }
166    
167                    luceneFieldable.setBoost(boost);
168    
169                    luceneDocument.add(luceneFieldable);
170            }
171    
172            private org.apache.lucene.document.Document _getLuceneDocument(
173                    Document document) {
174    
175                    org.apache.lucene.document.Document luceneDocument =
176                            new org.apache.lucene.document.Document();
177    
178                    Collection<Field> fields = document.getFields().values();
179    
180                    for (Field field : fields) {
181                            String name = field.getName();
182                            boolean numeric = field.isNumeric();
183                            Class<? extends Number> numericClass = field.getNumericClass();
184                            boolean tokenized = field.isTokenized();
185                            float boost = field.getBoost();
186    
187                            if (!field.isLocalized()) {
188                                    for (String value : field.getValues()) {
189                                            if (Validator.isNull(value)) {
190                                                    continue;
191                                            }
192    
193                                            _addLuceneFieldable(
194                                                    luceneDocument, name, numeric, numericClass, tokenized,
195                                                    field.isSortable(), boost, value);
196                                    }
197                            }
198                            else {
199                                    Map<Locale, String> localizedValues =
200                                            field.getLocalizedValues();
201    
202                                    for (Map.Entry<Locale, String> entry :
203                                                    localizedValues.entrySet()) {
204    
205                                            String value = entry.getValue();
206    
207                                            if (Validator.isNull(value)) {
208                                                    continue;
209                                            }
210    
211                                            Locale locale = entry.getKey();
212    
213                                            String languageId = LocaleUtil.toLanguageId(locale);
214    
215                                            String defaultLanguageId = LocaleUtil.toLanguageId(
216                                                    LocaleUtil.getDefault());
217    
218                                            if (languageId.equals(defaultLanguageId)) {
219                                                    _addLuceneFieldable(
220                                                            luceneDocument, name, numeric, numericClass,
221                                                            tokenized, field.isSortable(), boost, value);
222                                            }
223    
224                                            String localizedName = DocumentImpl.getLocalizedName(
225                                                    locale, name);
226    
227                                            _addLuceneFieldable(
228                                                    luceneDocument, localizedName, numeric, numericClass,
229                                                    tokenized, field.isSortable(), boost, value);
230                                    }
231                            }
232                    }
233    
234                    return luceneDocument;
235            }
236    
237            private static Log _log = LogFactoryUtil.getLog(LuceneIndexWriter.class);
238    
239    }