001
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.StringUtil;
030 import com.liferay.portal.kernel.util.Validator;
031
032 import java.io.File;
033 import java.io.FileInputStream;
034 import java.io.IOException;
035 import java.io.InputStream;
036
037 import java.text.DateFormat;
038 import java.text.Format;
039 import java.text.ParseException;
040
041 import java.util.Arrays;
042 import java.util.Date;
043 import java.util.HashMap;
044 import java.util.Locale;
045 import java.util.Map;
046 import java.util.Set;
047
048
052 public class DocumentImpl implements Document {
053
054 public static String getLocalizedName(Locale locale, String name) {
055 if (locale == null) {
056 return name;
057 }
058
059 String languageId = LocaleUtil.toLanguageId(locale);
060
061 return getLocalizedName(languageId, name);
062 }
063
064 public static String getLocalizedName(String languageId, String name) {
065 return name.concat(StringPool.UNDERLINE).concat(languageId);
066 }
067
068 public static String getSortableFieldName(String name) {
069 return name.concat(StringPool.UNDERLINE).concat(_SORTABLE_FIELD_SUFFIX);
070 }
071
072 public static String getSortFieldName(Sort sort, String scoreFieldName) {
073 if (sort.getType() == Sort.SCORE_TYPE) {
074 return scoreFieldName;
075 }
076
077 String fieldName = sort.getFieldName();
078
079 if (fieldName.endsWith(_SORTABLE_FIELD_SUFFIX)) {
080 return fieldName;
081 }
082
083 String sortFieldName = null;
084
085 if (DocumentImpl.isSortableTextField(fieldName) ||
086 (sort.getType() != Sort.STRING_TYPE)) {
087
088 sortFieldName = DocumentImpl.getSortableFieldName(fieldName);
089 }
090
091 if (Validator.isNull(sortFieldName)) {
092 sortFieldName = scoreFieldName;
093 }
094
095 return sortFieldName;
096 }
097
098 public static boolean isSortableFieldName(String name) {
099 return name.endsWith(_SORTABLE_FIELD_SUFFIX);
100 }
101
102 public static boolean isSortableTextField(String name) {
103 return _defaultSortableTextFields.contains(name);
104 }
105
106 @Override
107 public void add(Field field) {
108 _fields.put(field.getName(), field);
109 }
110
111 @Override
112 public void addDate(String name, Date value) {
113 if (value == null) {
114 return;
115 }
116
117 addDate(name, new Date[] {value});
118 }
119
120 @Override
121 public void addDate(String name, Date[] values) {
122 if (values == null) {
123 return;
124 }
125
126 String[] dates = new String[values.length];
127 String[] datesTime = new String[values.length];
128
129 for (int i = 0; i < values.length; i++) {
130 dates[i] = _dateFormat.format(values[i]);
131 datesTime[i] = String.valueOf(values[i].getTime());
132 }
133
134 String sortableFieldName = getSortableFieldName(name);
135
136 Field field = new Field(sortableFieldName, datesTime);
137
138 field.setNumeric(true);
139 field.setNumericClass(Long.class);
140
141 _fields.put(sortableFieldName, field);
142
143 addKeyword(name, dates);
144 }
145
146 @Override
147 public void addFile(String name, byte[] bytes, String fileExt) {
148 InputStream is = new UnsyncByteArrayInputStream(bytes);
149
150 addFile(name, is, fileExt);
151 }
152
153 @Override
154 public void addFile(String name, File file, String fileExt)
155 throws IOException {
156
157 InputStream is = new FileInputStream(file);
158
159 addFile(name, is, fileExt);
160 }
161
162 @Override
163 public void addFile(String name, InputStream is, String fileExt) {
164 addText(name, FileUtil.extractText(is, fileExt));
165 }
166
167 @Override
168 public void addFile(
169 String name, InputStream is, String fileExt, int maxStringLength) {
170
171 addText(name, FileUtil.extractText(is, fileExt, maxStringLength));
172 }
173
174 @Override
175 public void addKeyword(String name, boolean value) {
176 addKeyword(name, String.valueOf(value));
177 }
178
179 @Override
180 public void addKeyword(String name, Boolean value) {
181 addKeyword(name, String.valueOf(value));
182 }
183
184 @Override
185 public void addKeyword(String name, boolean[] values) {
186 if (values == null) {
187 return;
188 }
189
190 addKeyword(name, ArrayUtil.toStringArray(values));
191 }
192
193 @Override
194 public void addKeyword(String name, Boolean[] values) {
195 if (values == null) {
196 return;
197 }
198
199 addKeyword(name, ArrayUtil.toStringArray(values));
200 }
201
202 @Override
203 public void addKeyword(String name, double value) {
204 addKeyword(name, String.valueOf(value));
205 }
206
207 @Override
208 public void addKeyword(String name, Double value) {
209 addKeyword(name, String.valueOf(value));
210 }
211
212 @Override
213 public void addKeyword(String name, double[] values) {
214 if (values == null) {
215 return;
216 }
217
218 addKeyword(name, ArrayUtil.toStringArray(values));
219 }
220
221 @Override
222 public void addKeyword(String name, Double[] values) {
223 if (values == null) {
224 return;
225 }
226
227 addKeyword(name, ArrayUtil.toStringArray(values));
228 }
229
230 @Override
231 public void addKeyword(String name, float value) {
232 addKeyword(name, String.valueOf(value));
233 }
234
235 @Override
236 public void addKeyword(String name, Float value) {
237 addKeyword(name, String.valueOf(value));
238 }
239
240 @Override
241 public void addKeyword(String name, float[] values) {
242 if (values == null) {
243 return;
244 }
245
246 addKeyword(name, ArrayUtil.toStringArray(values));
247 }
248
249 @Override
250 public void addKeyword(String name, Float[] values) {
251 if (values == null) {
252 return;
253 }
254
255 addKeyword(name, ArrayUtil.toStringArray(values));
256 }
257
258 @Override
259 public void addKeyword(String name, int value) {
260 addKeyword(name, String.valueOf(value));
261 }
262
263 @Override
264 public void addKeyword(String name, int[] values) {
265 if (values == null) {
266 return;
267 }
268
269 addKeyword(name, ArrayUtil.toStringArray(values));
270 }
271
272 @Override
273 public void addKeyword(String name, Integer value) {
274 addKeyword(name, String.valueOf(value));
275 }
276
277 @Override
278 public void addKeyword(String name, Integer[] values) {
279 if (values == null) {
280 return;
281 }
282
283 addKeyword(name, ArrayUtil.toStringArray(values));
284 }
285
286 @Override
287 public void addKeyword(String name, long value) {
288 addKeyword(name, String.valueOf(value));
289 }
290
291 @Override
292 public void addKeyword(String name, Long value) {
293 addKeyword(name, String.valueOf(value));
294 }
295
296 @Override
297 public void addKeyword(String name, long[] values) {
298 if (values == null) {
299 return;
300 }
301
302 addKeyword(name, ArrayUtil.toStringArray(values));
303 }
304
305 @Override
306 public void addKeyword(String name, Long[] values) {
307 if (values == null) {
308 return;
309 }
310
311 addKeyword(name, ArrayUtil.toStringArray(values));
312 }
313
314 @Override
315 public void addKeyword(String name, short value) {
316 addKeyword(name, String.valueOf(value));
317 }
318
319 @Override
320 public void addKeyword(String name, Short value) {
321 addKeyword(name, String.valueOf(value));
322 }
323
324 @Override
325 public void addKeyword(String name, short[] values) {
326 if (values == null) {
327 return;
328 }
329
330 addKeyword(name, ArrayUtil.toStringArray(values));
331 }
332
333 @Override
334 public void addKeyword(String name, Short[] values) {
335 if (values == null) {
336 return;
337 }
338
339 addKeyword(name, ArrayUtil.toStringArray(values));
340 }
341
342 @Override
343 public void addKeyword(String name, String value) {
344 addKeyword(name, value, false);
345 }
346
347 @Override
348 public void addKeyword(String name, String value, boolean lowerCase) {
349 if (lowerCase && Validator.isNotNull(value)) {
350 value = StringUtil.toLowerCase(value);
351 }
352
353 Field field = new Field(name, value);
354
355 for (String fieldName : Field.UNSCORED_FIELD_NAMES) {
356 if (StringUtil.equalsIgnoreCase(name, fieldName)) {
357 field.setBoost(0);
358 }
359 }
360
361 _fields.put(name, field);
362 }
363
364 @Override
365 public void addKeyword(String name, String[] values) {
366 if (values == null) {
367 return;
368 }
369
370 Field field = new Field(name, values);
371
372 _fields.put(name, field);
373 }
374
375 @Override
376 public void addLocalizedKeyword(String name, Map<Locale, String> values) {
377 addLocalizedKeyword(name, values, false);
378 }
379
380 @Override
381 public void addLocalizedKeyword(
382 String name, Map<Locale, String> values, boolean lowerCase) {
383
384 if ((values == null) || values.isEmpty()) {
385 return;
386 }
387
388 if (lowerCase) {
389 Map<Locale, String> lowerCaseValues = new HashMap<Locale, String>(
390 values.size());
391
392 for (Map.Entry<Locale, String> entry : values.entrySet()) {
393 String value = GetterUtil.getString(entry.getValue());
394
395 lowerCaseValues.put(
396 entry.getKey(), StringUtil.toLowerCase(value));
397 }
398
399 values = lowerCaseValues;
400 }
401
402 Field field = new Field(name, values);
403
404 _fields.put(name, field);
405 }
406
407 @Override
408 public void addLocalizedKeyword(
409 String name, Map<Locale, String> values, boolean lowerCase,
410 boolean sortable) {
411
412 if ((values == null) || values.isEmpty()) {
413 return;
414 }
415
416 if (lowerCase) {
417 Map<Locale, String> lowerCaseValues = new HashMap<Locale, String>(
418 values.size());
419
420 for (Map.Entry<Locale, String> entry : values.entrySet()) {
421 String value = GetterUtil.getString(entry.getValue());
422
423 lowerCaseValues.put(
424 entry.getKey(), StringUtil.toLowerCase(value));
425 }
426
427 values = lowerCaseValues;
428 }
429
430 Field field = new Field(name, values);
431
432 field.setSortable(sortable);
433
434 _fields.put(name, field);
435 }
436
437 @Override
438 public void addLocalizedText(String name, Map<Locale, String> values) {
439 if ((values == null) || values.isEmpty()) {
440 return;
441 }
442
443 Field field = new Field(name, values);
444
445 field.setTokenized(true);
446
447 _fields.put(name, field);
448 }
449
450
453 @Override
454 public void addModifiedDate() {
455 addModifiedDate(new Date());
456 }
457
458
461 @Override
462 public void addModifiedDate(Date modifiedDate) {
463 addDate(Field.MODIFIED, modifiedDate);
464 }
465
466 @Override
467 public void addNumber(String name, double value) {
468 addNumber(name, String.valueOf(value), Double.class);
469 }
470
471 @Override
472 public void addNumber(String name, Double value) {
473 addNumber(name, String.valueOf(value), Double.class);
474 }
475
476 @Override
477 public void addNumber(String name, double[] values) {
478 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
479 }
480
481 @Override
482 public void addNumber(String name, Double[] values) {
483 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
484 }
485
486 @Override
487 public void addNumber(String name, float value) {
488 addNumber(name, String.valueOf(value), Float.class);
489 }
490
491 @Override
492 public void addNumber(String name, Float value) {
493 addNumber(name, String.valueOf(value), Float.class);
494 }
495
496 @Override
497 public void addNumber(String name, float[] values) {
498 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
499 }
500
501 @Override
502 public void addNumber(String name, Float[] values) {
503 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
504 }
505
506 @Override
507 public void addNumber(String name, int value) {
508 addNumber(name, String.valueOf(value), Integer.class);
509 }
510
511 @Override
512 public void addNumber(String name, int[] values) {
513 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
514 }
515
516 @Override
517 public void addNumber(String name, Integer value) {
518 addNumber(name, String.valueOf(value), Integer.class);
519 }
520
521 @Override
522 public void addNumber(String name, Integer[] values) {
523 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
524 }
525
526 @Override
527 public void addNumber(String name, long value) {
528 addNumber(name, String.valueOf(value), Long.class);
529 }
530
531 @Override
532 public void addNumber(String name, Long value) {
533 addNumber(name, String.valueOf(value), Long.class);
534 }
535
536 @Override
537 public void addNumber(String name, long[] values) {
538 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
539 }
540
541 @Override
542 public void addNumber(String name, Long[] values) {
543 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
544 }
545
546 @Override
547 public void addNumber(String name, String value) {
548 addNumber(name, value, Long.class);
549 }
550
551 public void addNumber(
552 String name, String value, Class<? extends Number> clazz) {
553
554 if (Validator.isNull(value)) {
555 return;
556 }
557
558 addNumber(name, new String[] {value}, clazz);
559 }
560
561 @Override
562 public void addNumber(String name, String[] values) {
563 addNumber(name, values, Long.class);
564 }
565
566 public void addNumber(
567 String name, String[] values, Class<? extends Number> clazz) {
568
569 if (values == null) {
570 return;
571 }
572
573 String sortableFieldName = getSortableFieldName(name);
574
575 Field field = new Field(sortableFieldName, values);
576
577 field.setNumeric(true);
578 field.setNumericClass(clazz);
579
580 _fields.put(sortableFieldName, field);
581
582 addKeyword(name, values);
583 }
584
585 @Override
586 public void addText(String name, String value) {
587 if (Validator.isNull(value)) {
588 return;
589 }
590
591 Field field = new Field(name, value);
592
593 field.setTokenized(true);
594
595 _fields.put(name, field);
596
597 if (_sortableTextFields.contains(name)) {
598 String truncatedValue = value;
599
600 if (value.length() > _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH) {
601 truncatedValue = value.substring(
602 0, _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH);
603 }
604
605 addKeyword(getSortableFieldName(name), truncatedValue, true);
606 }
607 }
608
609 @Override
610 public void addText(String name, String[] values) {
611 if (values == null) {
612 return;
613 }
614
615 Field field = new Field(name, values);
616
617 field.setTokenized(true);
618
619 _fields.put(name, field);
620 }
621
622 @Override
623 public void addUID(String portletId, long field1) {
624 addUID(portletId, String.valueOf(field1));
625 }
626
627 @Override
628 public void addUID(String portletId, long field1, String field2) {
629 addUID(portletId, String.valueOf(field1), field2);
630 }
631
632 @Override
633 public void addUID(String portletId, Long field1) {
634 addUID(portletId, field1.longValue());
635 }
636
637 @Override
638 public void addUID(String portletId, Long field1, String field2) {
639 addUID(portletId, field1.longValue(), field2);
640 }
641
642 @Override
643 public void addUID(String portletId, String field1) {
644 addUID(portletId, field1, null);
645 }
646
647 @Override
648 public void addUID(String portletId, String field1, String field2) {
649 addUID(portletId, field1, field2, null);
650 }
651
652 @Override
653 public void addUID(
654 String portletId, String field1, String field2, String field3) {
655
656 addUID(portletId, field1, field2, field3, null);
657 }
658
659 @Override
660 public void addUID(
661 String portletId, String field1, String field2, String field3,
662 String field4) {
663
664 String uid = portletId + _UID_PORTLET + field1;
665
666 if (field2 != null) {
667 uid += _UID_FIELD + field2;
668 }
669
670 if (field3 != null) {
671 uid += _UID_FIELD + field3;
672 }
673
674 if (field4 != null) {
675 uid += _UID_FIELD + field4;
676 }
677
678 addKeyword(Field.UID, uid);
679 }
680
681 @Override
682 public Object clone() {
683 DocumentImpl documentImpl = new DocumentImpl();
684
685 documentImpl.setSortableTextFields(_sortableTextFields);
686
687 return documentImpl;
688 }
689
690 @Override
691 public String get(Locale locale, String name) {
692 if (locale == null) {
693 return get(name);
694 }
695
696 String localizedName = getLocalizedName(locale, name);
697
698 Field field = _fields.get(localizedName);
699
700 if (field == null) {
701 field = _fields.get(name);
702 }
703
704 if (field == null) {
705 return StringPool.BLANK;
706 }
707
708 return field.getValue();
709 }
710
711 @Override
712 public String get(Locale locale, String name, String defaultName) {
713 if (locale == null) {
714 return get(name, defaultName);
715 }
716
717 String localizedName = getLocalizedName(locale, name);
718
719 Field field = _fields.get(localizedName);
720
721 if (field == null) {
722 localizedName = getLocalizedName(locale, defaultName);
723
724 field = _fields.get(localizedName);
725 }
726
727 if (field == null) {
728 return StringPool.BLANK;
729 }
730
731 return field.getValue();
732 }
733
734 @Override
735 public String get(String name) {
736 Field field = _fields.get(name);
737
738 if (field == null) {
739 return StringPool.BLANK;
740 }
741
742 return field.getValue();
743 }
744
745 @Override
746 public String get(String name, String defaultName) {
747 Field field = _fields.get(name);
748
749 if (field == null) {
750 return get(defaultName);
751 }
752
753 return field.getValue();
754 }
755
756 @Override
757 public Date getDate(String name) throws ParseException {
758 DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
759 _INDEX_DATE_FORMAT_PATTERN);
760
761 return dateFormat.parse(get(name));
762 }
763
764 @Override
765 public Field getField(String name) {
766 return _fields.get(name);
767 }
768
769 @Override
770 public Map<String, Field> getFields() {
771 return _fields;
772 }
773
774 @Override
775 public String getPortletId() {
776 String uid = getUID();
777
778 int pos = uid.indexOf(_UID_PORTLET);
779
780 return uid.substring(0, pos);
781 }
782
783 @Override
784 public String getUID() {
785 Field field = _fields.get(Field.UID);
786
787 if (field == null) {
788 throw new RuntimeException("UID is not set");
789 }
790
791 return field.getValue();
792 }
793
794 @Override
795 public String[] getValues(String name) {
796 Field field = _fields.get(name);
797
798 if (field == null) {
799 return new String[] {StringPool.BLANK};
800 }
801
802 return field.getValues();
803 }
804
805 @Override
806 public boolean hasField(String name) {
807 if (_fields.containsKey(name)) {
808 return true;
809 }
810
811 return false;
812 }
813
814 @Override
815 public boolean isDocumentSortableTextField(String name) {
816 return _sortableTextFields.contains(name);
817 }
818
819 @Override
820 public void remove(String name) {
821 _fields.remove(name);
822 }
823
824 public void setFields(Map<String, Field> fields) {
825 _fields = fields;
826 }
827
828 @Override
829 public void setSortableTextFields(String[] sortableTextFields) {
830 _sortableTextFields = SetUtil.fromArray(sortableTextFields);
831 }
832
833 @Override
834 public String toString() {
835 StringBundler sb = new StringBundler();
836
837 sb.append(StringPool.OPEN_CURLY_BRACE);
838
839 boolean firstField = true;
840
841 for (Field field : _fields.values()) {
842 if (!firstField) {
843 sb.append(StringPool.COMMA);
844 sb.append(StringPool.SPACE);
845 }
846 else {
847 firstField = false;
848 }
849
850 sb.append(field.getName());
851 sb.append(StringPool.EQUAL);
852 sb.append(Arrays.toString(field.getValues()));
853 }
854
855 sb.append(StringPool.CLOSE_CURLY_BRACE);
856
857 return sb.toString();
858 }
859
860 protected void setSortableTextFields(Set<String> sortableTextFields) {
861 _sortableTextFields = sortableTextFields;
862 }
863
864 private static final String _INDEX_DATE_FORMAT_PATTERN = PropsUtil.get(
865 PropsKeys.INDEX_DATE_FORMAT_PATTERN);
866
867 private static final String _SORTABLE_FIELD_SUFFIX = "sortable";
868
869 private static final int _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH =
870 GetterUtil.getInteger(
871 PropsUtil.get(
872 PropsKeys.INDEX_SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH));
873
874 private static final String _UID_FIELD = "_FIELD_";
875
876 private static final String _UID_PORTLET = "_PORTLET_";
877
878 private static Format _dateFormat =
879 FastDateFormatFactoryUtil.getSimpleDateFormat(
880 _INDEX_DATE_FORMAT_PATTERN);
881 private static Set<String> _defaultSortableTextFields = SetUtil.fromArray(
882 PropsUtil.getArray(PropsKeys.INDEX_SORTABLE_TEXT_FIELDS));
883
884 private Map<String, Field> _fields = new HashMap<String, Field>();
885 private Set<String> _sortableTextFields = _defaultSortableTextFields;
886
887 }