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 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 = StringUtil.toLowerCase(value);
303 }
304
305 Field field = new Field(name, value);
306
307 for (String fieldName : Field.UNSCORED_FIELD_NAMES) {
308 if (StringUtil.equalsIgnoreCase(name, 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(
348 entry.getKey(), StringUtil.toLowerCase(value));
349 }
350
351 values = lowerCaseValues;
352 }
353
354 Field field = new Field(name, values);
355
356 _fields.put(name, field);
357 }
358
359 @Override
360 public void addLocalizedText(String name, Map<Locale, String> values) {
361 if ((values == null) || values.isEmpty()) {
362 return;
363 }
364
365 Field field = new Field(name, values);
366
367 field.setTokenized(true);
368
369 _fields.put(name, field);
370 }
371
372
375 @Override
376 public void addModifiedDate() {
377 addModifiedDate(new Date());
378 }
379
380
383 @Override
384 public void addModifiedDate(Date modifiedDate) {
385 addDate(Field.MODIFIED, modifiedDate);
386 }
387
388 @Override
389 public void addNumber(String name, double value) {
390 addNumber(name, String.valueOf(value), Double.class);
391 }
392
393 @Override
394 public void addNumber(String name, Double value) {
395 addNumber(name, String.valueOf(value), Double.class);
396 }
397
398 @Override
399 public void addNumber(String name, double[] values) {
400 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
401 }
402
403 @Override
404 public void addNumber(String name, Double[] values) {
405 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
406 }
407
408 @Override
409 public void addNumber(String name, float value) {
410 addNumber(name, String.valueOf(value), Float.class);
411 }
412
413 @Override
414 public void addNumber(String name, Float value) {
415 addNumber(name, String.valueOf(value), Float.class);
416 }
417
418 @Override
419 public void addNumber(String name, float[] values) {
420 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
421 }
422
423 @Override
424 public void addNumber(String name, Float[] values) {
425 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
426 }
427
428 @Override
429 public void addNumber(String name, int value) {
430 addNumber(name, String.valueOf(value), Integer.class);
431 }
432
433 @Override
434 public void addNumber(String name, int[] values) {
435 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
436 }
437
438 @Override
439 public void addNumber(String name, Integer value) {
440 addNumber(name, String.valueOf(value), Integer.class);
441 }
442
443 @Override
444 public void addNumber(String name, Integer[] values) {
445 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
446 }
447
448 @Override
449 public void addNumber(String name, long value) {
450 addNumber(name, String.valueOf(value), Long.class);
451 }
452
453 @Override
454 public void addNumber(String name, Long value) {
455 addNumber(name, String.valueOf(value), Long.class);
456 }
457
458 @Override
459 public void addNumber(String name, long[] values) {
460 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
461 }
462
463 @Override
464 public void addNumber(String name, Long[] values) {
465 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
466 }
467
468 @Override
469 public void addNumber(String name, String value) {
470 addNumber(name, value, Long.class);
471 }
472
473 public void addNumber(
474 String name, String value, Class<? extends Number> clazz) {
475
476 if (Validator.isNull(value)) {
477 return;
478 }
479
480 addNumber(name, new String[] {value}, clazz);
481 }
482
483 @Override
484 public void addNumber(String name, String[] values) {
485 addNumber(name, values, Long.class);
486 }
487
488 public void addNumber(
489 String name, String[] values, Class<? extends Number> clazz) {
490
491 if (values == null) {
492 return;
493 }
494
495 String sortableFieldName = getSortableFieldName(name);
496
497 Field field = new Field(sortableFieldName, values);
498
499 field.setNumeric(true);
500 field.setNumericClass(clazz);
501
502 _fields.put(sortableFieldName, field);
503
504 addKeyword(name, values);
505 }
506
507 @Override
508 public void addText(String name, String value) {
509 if (Validator.isNull(value)) {
510 return;
511 }
512
513 Field field = new Field(name, value);
514
515 field.setTokenized(true);
516
517 _fields.put(name, field);
518
519 if (_sortableTextFields.contains(name)) {
520 String truncatedValue = value;
521
522 if (value.length() > _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH) {
523 truncatedValue = value.substring(
524 0, _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH);
525 }
526
527 addKeyword(getSortableFieldName(name), truncatedValue, true);
528 }
529 }
530
531 @Override
532 public void addText(String name, String[] values) {
533 if (values == null) {
534 return;
535 }
536
537 Field field = new Field(name, values);
538
539 field.setTokenized(true);
540
541 _fields.put(name, field);
542 }
543
544 @Override
545 public void addUID(String portletId, long field1) {
546 addUID(portletId, String.valueOf(field1));
547 }
548
549 @Override
550 public void addUID(String portletId, long field1, String field2) {
551 addUID(portletId, String.valueOf(field1), field2);
552 }
553
554 @Override
555 public void addUID(String portletId, Long field1) {
556 addUID(portletId, field1.longValue());
557 }
558
559 @Override
560 public void addUID(String portletId, Long field1, String field2) {
561 addUID(portletId, field1.longValue(), field2);
562 }
563
564 @Override
565 public void addUID(String portletId, String field1) {
566 addUID(portletId, field1, null);
567 }
568
569 @Override
570 public void addUID(String portletId, String field1, String field2) {
571 addUID(portletId, field1, field2, null);
572 }
573
574 @Override
575 public void addUID(
576 String portletId, String field1, String field2, String field3) {
577
578 addUID(portletId, field1, field2, field3, null);
579 }
580
581 @Override
582 public void addUID(
583 String portletId, String field1, String field2, String field3,
584 String field4) {
585
586 String uid = portletId + _UID_PORTLET + field1;
587
588 if (field2 != null) {
589 uid += _UID_FIELD + field2;
590 }
591
592 if (field3 != null) {
593 uid += _UID_FIELD + field3;
594 }
595
596 if (field4 != null) {
597 uid += _UID_FIELD + field4;
598 }
599
600 addKeyword(Field.UID, uid);
601 }
602
603 @Override
604 public Object clone() {
605 DocumentImpl documentImpl = new DocumentImpl();
606
607 documentImpl.setSortableTextFields(_sortableTextFields);
608
609 return documentImpl;
610 }
611
612 @Override
613 public String get(Locale locale, String name) {
614 if (locale == null) {
615 return get(name);
616 }
617
618 String localizedName = getLocalizedName(locale, name);
619
620 Field field = _fields.get(localizedName);
621
622 if (field == null) {
623 field = _fields.get(name);
624 }
625
626 if (field == null) {
627 return StringPool.BLANK;
628 }
629
630 return field.getValue();
631 }
632
633 @Override
634 public String get(Locale locale, String name, String defaultName) {
635 if (locale == null) {
636 return get(name, defaultName);
637 }
638
639 String localizedName = getLocalizedName(locale, name);
640
641 Field field = _fields.get(localizedName);
642
643 if (field == null) {
644 localizedName = getLocalizedName(locale, defaultName);
645
646 field = _fields.get(localizedName);
647 }
648
649 if (field == null) {
650 return StringPool.BLANK;
651 }
652
653 return field.getValue();
654 }
655
656 @Override
657 public String get(String name) {
658 Field field = _fields.get(name);
659
660 if (field == null) {
661 return StringPool.BLANK;
662 }
663
664 return field.getValue();
665 }
666
667 @Override
668 public String get(String name, String defaultName) {
669 Field field = _fields.get(name);
670
671 if (field == null) {
672 return get(defaultName);
673 }
674
675 return field.getValue();
676 }
677
678 @Override
679 public Date getDate(String name) throws ParseException {
680 DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
681 _INDEX_DATE_FORMAT_PATTERN);
682
683 return dateFormat.parse(get(name));
684 }
685
686 @Override
687 public Field getField(String name) {
688 return _fields.get(name);
689 }
690
691 @Override
692 public Map<String, Field> getFields() {
693 return _fields;
694 }
695
696 @Override
697 public String getPortletId() {
698 String uid = getUID();
699
700 int pos = uid.indexOf(_UID_PORTLET);
701
702 return uid.substring(0, pos);
703 }
704
705 @Override
706 public String getUID() {
707 Field field = _fields.get(Field.UID);
708
709 if (field == null) {
710 throw new RuntimeException("UID is not set");
711 }
712
713 return field.getValue();
714 }
715
716 @Override
717 public String[] getValues(String name) {
718 Field field = _fields.get(name);
719
720 if (field == null) {
721 return new String[] {StringPool.BLANK};
722 }
723
724 return field.getValues();
725 }
726
727 @Override
728 public boolean hasField(String name) {
729 if (_fields.containsKey(name)) {
730 return true;
731 }
732
733 return false;
734 }
735
736 @Override
737 public boolean isDocumentSortableTextField(String name) {
738 return _sortableTextFields.contains(name);
739 }
740
741 @Override
742 public void remove(String name) {
743 _fields.remove(name);
744 }
745
746 public void setFields(Map<String, Field> fields) {
747 _fields = fields;
748 }
749
750 @Override
751 public void setSortableTextFields(String[] sortableTextFields) {
752 _sortableTextFields = SetUtil.fromArray(sortableTextFields);
753 }
754
755 @Override
756 public String toString() {
757 StringBundler sb = new StringBundler();
758
759 sb.append(StringPool.OPEN_CURLY_BRACE);
760
761 boolean firstField = true;
762
763 for (Field field : _fields.values()) {
764 if (!firstField) {
765 sb.append(StringPool.COMMA);
766 sb.append(StringPool.SPACE);
767 }
768 else {
769 firstField = false;
770 }
771
772 sb.append(field.getName());
773 sb.append(StringPool.EQUAL);
774 sb.append(Arrays.toString(field.getValues()));
775 }
776
777 sb.append(StringPool.CLOSE_CURLY_BRACE);
778
779 return sb.toString();
780 }
781
782 protected void setSortableTextFields(Set<String> sortableTextFields) {
783 _sortableTextFields = sortableTextFields;
784 }
785
786 private static final String _INDEX_DATE_FORMAT_PATTERN = PropsUtil.get(
787 PropsKeys.INDEX_DATE_FORMAT_PATTERN);
788
789 private static final String _SORTABLE_FIELD_SUFFIX = "sortable";
790
791 private static final int _SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH =
792 GetterUtil.getInteger(
793 PropsUtil.get(
794 PropsKeys.INDEX_SORTABLE_TEXT_FIELDS_TRUNCATED_LENGTH));
795
796 private static final String _UID_FIELD = "_FIELD_";
797
798 private static final String _UID_PORTLET = "_PORTLET_";
799
800 private static Format _dateFormat =
801 FastDateFormatFactoryUtil.getSimpleDateFormat(
802 _INDEX_DATE_FORMAT_PATTERN);
803 private static Set<String> _defaultSortableTextFields = SetUtil.fromArray(
804 PropsUtil.getArray(PropsKeys.INDEX_SORTABLE_TEXT_FIELDS));
805
806 private Map<String, Field> _fields = new HashMap<String, Field>();
807 private Set<String> _sortableTextFields = _defaultSortableTextFields;
808
809 }