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