001    /**
002     * Copyright (c) 2000-2012 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.kernel.search;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
018    import com.liferay.portal.kernel.util.ArrayUtil;
019    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
020    import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
021    import com.liferay.portal.kernel.util.FileUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.LocaleUtil;
024    import com.liferay.portal.kernel.util.PropsKeys;
025    import com.liferay.portal.kernel.util.PropsUtil;
026    import com.liferay.portal.kernel.util.SetUtil;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.Validator;
030    
031    import java.io.File;
032    import java.io.FileInputStream;
033    import java.io.IOException;
034    import java.io.InputStream;
035    
036    import java.text.DateFormat;
037    import java.text.Format;
038    import java.text.ParseException;
039    
040    import java.util.Arrays;
041    import java.util.Date;
042    import java.util.HashMap;
043    import java.util.Locale;
044    import java.util.Map;
045    import java.util.Set;
046    
047    /**
048     * @author Brian Wing Shun Chan
049     * @author Bruno Farache
050     */
051    public class DocumentImpl implements Document {
052    
053            public static String getLocalizedName(Locale locale, String name) {
054                    String languageId = LocaleUtil.toLanguageId(locale);
055    
056                    String localizedName = name.concat(StringPool.UNDERLINE).concat(
057                            languageId);
058    
059                    return localizedName;
060            }
061    
062            public static String getSortableFieldName(String name) {
063                    return name.concat(StringPool.UNDERLINE).concat(
064                            _SORTABLE_TEXT_FIELD_SUFFIX);
065            }
066    
067            public static boolean isSortableTextField(String name) {
068                    return _sortableTextFields.contains(name);
069            }
070    
071            public void add(Field field) {
072                    _fields.put(field.getName(), field);
073            }
074    
075            public void addDate(String name, Date value) {
076                    if (value == null) {
077                            return;
078                    }
079    
080                    addKeyword(name, _dateFormat.format(value));
081            }
082    
083            public void addFile(String name, byte[] bytes, String fileExt) {
084                    InputStream is = new UnsyncByteArrayInputStream(bytes);
085    
086                    addFile(name, is, fileExt);
087            }
088    
089            public void addFile(String name, File file, String fileExt)
090                    throws IOException {
091    
092                    InputStream is = new FileInputStream(file);
093    
094                    addFile(name, is, fileExt);
095            }
096    
097            public void addFile(String name, InputStream is, String fileExt) {
098                    addText(name, FileUtil.extractText(is, fileExt));
099            }
100    
101            public void addKeyword(String name, boolean value) {
102                    addKeyword(name, String.valueOf(value));
103            }
104    
105            public void addKeyword(String name, Boolean value) {
106                    addKeyword(name, String.valueOf(value));
107            }
108    
109            public void addKeyword(String name, boolean[] values) {
110                    if (values == null) {
111                            return;
112                    }
113    
114                    addKeyword(name, ArrayUtil.toStringArray(values));
115            }
116    
117            public void addKeyword(String name, Boolean[] values) {
118                    if (values == null) {
119                            return;
120                    }
121    
122                    addKeyword(name, ArrayUtil.toStringArray(values));
123            }
124    
125            public void addKeyword(String name, double value) {
126                    addKeyword(name, String.valueOf(value));
127            }
128    
129            public void addKeyword(String name, Double value) {
130                    addKeyword(name, String.valueOf(value));
131            }
132    
133            public void addKeyword(String name, double[] values) {
134                    if (values == null) {
135                            return;
136                    }
137    
138                    addKeyword(name, ArrayUtil.toStringArray(values));
139            }
140    
141            public void addKeyword(String name, Double[] values) {
142                    if (values == null) {
143                            return;
144                    }
145    
146                    addKeyword(name, ArrayUtil.toStringArray(values));
147            }
148    
149            public void addKeyword(String name, float value) {
150                    addKeyword(name, String.valueOf(value));
151            }
152    
153            public void addKeyword(String name, Float value) {
154                    addKeyword(name, String.valueOf(value));
155            }
156    
157            public void addKeyword(String name, float[] values) {
158                    if (values == null) {
159                            return;
160                    }
161    
162                    addKeyword(name, ArrayUtil.toStringArray(values));
163            }
164    
165            public void addKeyword(String name, Float[] values) {
166                    if (values == null) {
167                            return;
168                    }
169    
170                    addKeyword(name, ArrayUtil.toStringArray(values));
171            }
172    
173            public void addKeyword(String name, int value) {
174                    addKeyword(name, String.valueOf(value));
175            }
176    
177            public void addKeyword(String name, int[] values) {
178                    if (values == null) {
179                            return;
180                    }
181    
182                    addKeyword(name, ArrayUtil.toStringArray(values));
183            }
184    
185            public void addKeyword(String name, Integer value) {
186                    addKeyword(name, String.valueOf(value));
187            }
188    
189            public void addKeyword(String name, Integer[] values) {
190                    if (values == null) {
191                            return;
192                    }
193    
194                    addKeyword(name, ArrayUtil.toStringArray(values));
195            }
196    
197            public void addKeyword(String name, long value) {
198                    addKeyword(name, String.valueOf(value));
199            }
200    
201            public void addKeyword(String name, Long value) {
202                    addKeyword(name, String.valueOf(value));
203            }
204    
205            public void addKeyword(String name, long[] values) {
206                    if (values == null) {
207                            return;
208                    }
209    
210                    addKeyword(name, ArrayUtil.toStringArray(values));
211            }
212    
213            public void addKeyword(String name, Long[] values) {
214                    if (values == null) {
215                            return;
216                    }
217    
218                    addKeyword(name, ArrayUtil.toStringArray(values));
219            }
220    
221            public void addKeyword(String name, short value) {
222                    addKeyword(name, String.valueOf(value));
223            }
224    
225            public void addKeyword(String name, Short value) {
226                    addKeyword(name, String.valueOf(value));
227            }
228    
229            public void addKeyword(String name, short[] values) {
230                    if (values == null) {
231                            return;
232                    }
233    
234                    addKeyword(name, ArrayUtil.toStringArray(values));
235            }
236    
237            public void addKeyword(String name, Short[] values) {
238                    if (values == null) {
239                            return;
240                    }
241    
242                    addKeyword(name, ArrayUtil.toStringArray(values));
243            }
244    
245            public void addKeyword(String name, String value) {
246                    addKeyword(name, value, false);
247            }
248    
249            public void addKeyword(String name, String value, boolean lowerCase) {
250                    if (lowerCase && Validator.isNotNull(value)) {
251                            value = value.toLowerCase();
252                    }
253    
254                    Field field = new Field(name, value);
255    
256                    for (String fieldName : Field.UNSCORED_FIELD_NAMES) {
257                            if (name.equalsIgnoreCase(fieldName)) {
258                                    field.setBoost(0);
259                            }
260                    }
261    
262                    _fields.put(name, field);
263            }
264    
265            public void addKeyword(String name, String[] values) {
266                    if (values == null) {
267                            return;
268                    }
269    
270                    Field field = new Field(name, values);
271    
272                    _fields.put(name, field);
273            }
274    
275            public void addLocalizedKeyword(String name, Map<Locale, String> values) {
276                    if ((values == null) || values.isEmpty()) {
277                            return;
278                    }
279    
280                    Field field = new Field(name, values);
281    
282                    _fields.put(name, field);
283            }
284    
285            public void addLocalizedText(String name, Map<Locale, String> values) {
286                    if ((values == null) || values.isEmpty()) {
287                            return;
288                    }
289    
290                    Field field = new Field(name, values);
291    
292                    field.setTokenized(true);
293    
294                    _fields.put(name, field);
295            }
296    
297            /**
298             * @deprecated
299             */
300            public void addModifiedDate() {
301                    addModifiedDate(new Date());
302            }
303    
304            /**
305             * @deprecated
306             */
307            public void addModifiedDate(Date modifiedDate) {
308                    addDate(Field.MODIFIED, modifiedDate);
309            }
310    
311            public void addNumber(String name, double value) {
312                    addNumber(name, String.valueOf(value));
313            }
314    
315            public void addNumber(String name, Double value) {
316                    addNumber(name, String.valueOf(value));
317            }
318    
319            public void addNumber(String name, double[] values) {
320                    addNumber(name, ArrayUtil.toStringArray(values));
321            }
322    
323            public void addNumber(String name, Double[] values) {
324                    addNumber(name, String.valueOf(ArrayUtil.toStringArray(values)));
325            }
326    
327            public void addNumber(String name, float value) {
328                    addNumber(name, String.valueOf(value));
329            }
330    
331            public void addNumber(String name, Float value) {
332                    addNumber(name, String.valueOf(value));
333            }
334    
335            public void addNumber(String name, float[] values) {
336                    addNumber(name, ArrayUtil.toStringArray(values));
337            }
338    
339            public void addNumber(String name, Float[] values) {
340                    addNumber(name, ArrayUtil.toStringArray(values));
341            }
342    
343            public void addNumber(String name, int value) {
344                    addNumber(name, String.valueOf(value));
345            }
346    
347            public void addNumber(String name, int[] values) {
348                    addNumber(name, ArrayUtil.toStringArray(values));
349            }
350    
351            public void addNumber(String name, Integer value) {
352                    addNumber(name, String.valueOf(value));
353            }
354    
355            public void addNumber(String name, Integer[] values) {
356                    addNumber(name, ArrayUtil.toStringArray(values));
357            }
358    
359            public void addNumber(String name, long value) {
360                    addNumber(name, String.valueOf(value));
361            }
362    
363            public void addNumber(String name, Long value) {
364                    addNumber(name, String.valueOf(value));
365            }
366    
367            public void addNumber(String name, long[] values) {
368                    addNumber(name, ArrayUtil.toStringArray(values));
369            }
370    
371            public void addNumber(String name, Long[] values) {
372                    addNumber(name, ArrayUtil.toStringArray(values));
373            }
374    
375            public void addNumber(String name, String value) {
376                    if (Validator.isNotNull(value)) {
377                            Field field = new Field(name, value);
378    
379                            field.setNumeric(true);
380    
381                            _fields.put(name, field);
382                    }
383            }
384    
385            public void addNumber(String name, String[] values) {
386                    if (values == null) {
387                            return;
388                    }
389    
390                    Field field = new Field(name, values);
391    
392                    field.setNumeric(true);
393    
394                    _fields.put(name, field);
395            }
396    
397            public void addText(String name, String value) {
398                    if (Validator.isNull(value)) {
399                            return;
400                    }
401    
402                    Field field = new Field(name, value);
403    
404                    field.setTokenized(true);
405    
406                    _fields.put(name, field);
407    
408                    if (_sortableTextFields.contains(name)) {
409                            String truncatedValue = value;
410    
411                            if (value.length() > _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH) {
412                                    truncatedValue = value.substring(
413                                            0, _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH);
414                            }
415    
416                            addKeyword(getSortableFieldName(name), truncatedValue);
417                    }
418            }
419    
420            public void addText(String name, String[] values) {
421                    if (values == null) {
422                            return;
423                    }
424    
425                    Field field = new Field(name, values);
426    
427                    field.setTokenized(true);
428    
429                    _fields.put(name, field);
430            }
431    
432            public void addUID(String portletId, long field1) {
433                    addUID(portletId, String.valueOf(field1));
434            }
435    
436            public void addUID(String portletId, long field1, String field2) {
437                    addUID(portletId, String.valueOf(field1), field2);
438            }
439    
440            public void addUID(String portletId, Long field1) {
441                    addUID(portletId, field1.longValue());
442            }
443    
444            public void addUID(String portletId, Long field1, String field2) {
445                    addUID(portletId, field1.longValue(), field2);
446            }
447    
448            public void addUID(String portletId, String field1) {
449                    addUID(portletId, field1, null);
450            }
451    
452            public void addUID(String portletId, String field1, String field2) {
453                    addUID(portletId, field1, field2, null);
454            }
455    
456            public void addUID(
457                    String portletId, String field1, String field2, String field3) {
458    
459                    addUID(portletId, field1, field2, field3, null);
460            }
461    
462            public void addUID(
463                    String portletId, String field1, String field2, String field3,
464                    String field4) {
465    
466                    String uid = portletId + _UID_PORTLET + field1;
467    
468                    if (field2 != null) {
469                            uid += _UID_FIELD + field2;
470                    }
471    
472                    if (field3 != null) {
473                            uid += _UID_FIELD + field3;
474                    }
475    
476                    if (field4 != null) {
477                            uid += _UID_FIELD + field4;
478                    }
479    
480                    addKeyword(Field.UID, uid);
481            }
482    
483            public String get(Locale locale, String name) {
484                    String localizedName = getLocalizedName(locale, name);
485    
486                    Field field = _fields.get(localizedName);
487    
488                    if (field == null) {
489                            field = _fields.get(name);
490                    }
491    
492                    if (field == null) {
493                            return StringPool.BLANK;
494                    }
495    
496                    return field.getValue();
497            }
498    
499            public String get(String name) {
500                    Field field = _fields.get(name);
501    
502                    if (field == null) {
503                            return StringPool.BLANK;
504                    }
505    
506                    return field.getValue();
507            }
508    
509            public Date getDate(String name) throws ParseException {
510                    DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
511                            _INDEX_DATE_FORMAT_PATTERN);
512    
513                    return dateFormat.parse(get(name));
514            }
515    
516            public Map<String, Field> getFields() {
517                    return _fields;
518            }
519    
520            public String getPortletId() {
521                    String uid = getUID();
522    
523                    int pos = uid.indexOf(_UID_PORTLET);
524    
525                    return uid.substring(0, pos);
526            }
527    
528            public String getUID() {
529                    Field field = _fields.get(Field.UID);
530    
531                    if (field == null) {
532                            throw new RuntimeException("UID is not set");
533                    }
534    
535                    return field.getValue();
536            }
537    
538            public String[] getValues(String name) {
539                    Field field = _fields.get(name);
540    
541                    if (field == null) {
542                            return new String[] {StringPool.BLANK};
543                    }
544    
545                    return field.getValues();
546            }
547    
548            public void remove(String name) {
549                    _fields.remove(name);
550            }
551    
552            public void setFields(Map<String, Field> fields) {
553                    _fields = fields;
554            }
555    
556            @Override
557            public String toString() {
558                    StringBundler sb = new StringBundler();
559    
560                    sb.append(StringPool.OPEN_CURLY_BRACE);
561    
562                    boolean firstField = true;
563    
564                    for (Field field : _fields.values()) {
565                            if (!firstField) {
566                                    sb.append(StringPool.COMMA);
567                                    sb.append(StringPool.SPACE);
568                            }
569                            else {
570                                    firstField = false;
571                            }
572    
573                            sb.append(field.getName());
574                            sb.append(StringPool.EQUAL);
575                            sb.append(Arrays.toString(field.getValues()));
576                    }
577    
578                    sb.append(StringPool.CLOSE_CURLY_BRACE);
579    
580                    return sb.toString();
581            }
582    
583            private static final String _INDEX_DATE_FORMAT_PATTERN = PropsUtil.get(
584                    PropsKeys.INDEX_DATE_FORMAT_PATTERN);
585    
586            private static final String _SORTABLE_TEXT_FIELD_SUFFIX = "sortable";
587    
588            private static final int _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH =
589                    GetterUtil.getInteger(
590                            PropsUtil.get(
591                                    PropsKeys.INDEX_SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH));
592    
593            private static final String _UID_FIELD = "_FIELD_";
594    
595            private static final String _UID_PORTLET = "_PORTLET_";
596    
597            private static Format _dateFormat =
598                    FastDateFormatFactoryUtil.getSimpleDateFormat(
599                            _INDEX_DATE_FORMAT_PATTERN);
600            private static Set<String> _sortableTextFields = SetUtil.fromArray(
601                    PropsUtil.getArray(PropsKeys.INDEX_SORTABLE_TEXT_FIELDS));
602    
603            private Map<String, Field> _fields = new HashMap<String, Field>();
604    
605    }