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(
070 _SORTABLE_TEXT_FIELD_SUFFIX);
071 }
072
073 public static boolean isSortableTextField(String name) {
074 return _defaultSortableTextFields.contains(name);
075 }
076
077 @Override
078 public void add(Field field) {
079 _fields.put(field.getName(), field);
080 }
081
082 @Override
083 public void addDate(String name, Date value) {
084 if (value == null) {
085 return;
086 }
087
088 addKeyword(name, _dateFormat.format(value));
089 }
090
091 @Override
092 public void addDate(String name, Date[] values) {
093 if (values == null) {
094 return;
095 }
096
097 String[] dates = new String[values.length];
098
099 for (int i = 0; i < values.length; i++) {
100 dates[i] = _dateFormat.format(values[i]);
101 }
102
103 addKeyword(name, dates);
104 }
105
106 @Override
107 public void addFile(String name, byte[] bytes, String fileExt) {
108 InputStream is = new UnsyncByteArrayInputStream(bytes);
109
110 addFile(name, is, fileExt);
111 }
112
113 @Override
114 public void addFile(String name, File file, String fileExt)
115 throws IOException {
116
117 InputStream is = new FileInputStream(file);
118
119 addFile(name, is, fileExt);
120 }
121
122 @Override
123 public void addFile(String name, InputStream is, String fileExt) {
124 addText(name, FileUtil.extractText(is, fileExt));
125 }
126
127 @Override
128 public void addKeyword(String name, boolean value) {
129 addKeyword(name, String.valueOf(value));
130 }
131
132 @Override
133 public void addKeyword(String name, Boolean value) {
134 addKeyword(name, String.valueOf(value));
135 }
136
137 @Override
138 public void addKeyword(String name, boolean[] values) {
139 if (values == null) {
140 return;
141 }
142
143 addKeyword(name, ArrayUtil.toStringArray(values));
144 }
145
146 @Override
147 public void addKeyword(String name, Boolean[] values) {
148 if (values == null) {
149 return;
150 }
151
152 addKeyword(name, ArrayUtil.toStringArray(values));
153 }
154
155 @Override
156 public void addKeyword(String name, double value) {
157 addKeyword(name, String.valueOf(value));
158 }
159
160 @Override
161 public void addKeyword(String name, Double value) {
162 addKeyword(name, String.valueOf(value));
163 }
164
165 @Override
166 public void addKeyword(String name, double[] values) {
167 if (values == null) {
168 return;
169 }
170
171 addKeyword(name, ArrayUtil.toStringArray(values));
172 }
173
174 @Override
175 public void addKeyword(String name, Double[] values) {
176 if (values == null) {
177 return;
178 }
179
180 addKeyword(name, ArrayUtil.toStringArray(values));
181 }
182
183 @Override
184 public void addKeyword(String name, float value) {
185 addKeyword(name, String.valueOf(value));
186 }
187
188 @Override
189 public void addKeyword(String name, Float value) {
190 addKeyword(name, String.valueOf(value));
191 }
192
193 @Override
194 public void addKeyword(String name, float[] 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, Float[] values) {
204 if (values == null) {
205 return;
206 }
207
208 addKeyword(name, ArrayUtil.toStringArray(values));
209 }
210
211 @Override
212 public void addKeyword(String name, int value) {
213 addKeyword(name, String.valueOf(value));
214 }
215
216 @Override
217 public void addKeyword(String name, int[] values) {
218 if (values == null) {
219 return;
220 }
221
222 addKeyword(name, ArrayUtil.toStringArray(values));
223 }
224
225 @Override
226 public void addKeyword(String name, Integer value) {
227 addKeyword(name, String.valueOf(value));
228 }
229
230 @Override
231 public void addKeyword(String name, Integer[] values) {
232 if (values == null) {
233 return;
234 }
235
236 addKeyword(name, ArrayUtil.toStringArray(values));
237 }
238
239 @Override
240 public void addKeyword(String name, long value) {
241 addKeyword(name, String.valueOf(value));
242 }
243
244 @Override
245 public void addKeyword(String name, Long value) {
246 addKeyword(name, String.valueOf(value));
247 }
248
249 @Override
250 public void addKeyword(String name, long[] 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, Long[] values) {
260 if (values == null) {
261 return;
262 }
263
264 addKeyword(name, ArrayUtil.toStringArray(values));
265 }
266
267 @Override
268 public void addKeyword(String name, short value) {
269 addKeyword(name, String.valueOf(value));
270 }
271
272 @Override
273 public void addKeyword(String name, Short value) {
274 addKeyword(name, String.valueOf(value));
275 }
276
277 @Override
278 public void addKeyword(String name, short[] 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, Short[] values) {
288 if (values == null) {
289 return;
290 }
291
292 addKeyword(name, ArrayUtil.toStringArray(values));
293 }
294
295 @Override
296 public void addKeyword(String name, String value) {
297 addKeyword(name, value, false);
298 }
299
300 @Override
301 public void addKeyword(String name, String value, boolean lowerCase) {
302 if (lowerCase && Validator.isNotNull(value)) {
303 value = StringUtil.toLowerCase(value);
304 }
305
306 Field field = new Field(name, value);
307
308 for (String fieldName : Field.UNSCORED_FIELD_NAMES) {
309 if (StringUtil.equalsIgnoreCase(name, fieldName)) {
310 field.setBoost(0);
311 }
312 }
313
314 _fields.put(name, field);
315 }
316
317 @Override
318 public void addKeyword(String name, String[] values) {
319 if (values == null) {
320 return;
321 }
322
323 Field field = new Field(name, values);
324
325 _fields.put(name, field);
326 }
327
328 @Override
329 public void addLocalizedKeyword(String name, Map<Locale, String> values) {
330 addLocalizedKeyword(name, values, false);
331 }
332
333 @Override
334 public void addLocalizedKeyword(
335 String name, Map<Locale, String> values, boolean lowerCase) {
336
337 if ((values == null) || values.isEmpty()) {
338 return;
339 }
340
341 if (lowerCase) {
342 Map<Locale, String> lowerCaseValues = new HashMap<Locale, String>(
343 values.size());
344
345 for (Map.Entry<Locale, String> entry : values.entrySet()) {
346 String value = GetterUtil.getString(entry.getValue());
347
348 lowerCaseValues.put(
349 entry.getKey(), StringUtil.toLowerCase(value));
350 }
351
352 values = lowerCaseValues;
353 }
354
355 Field field = new Field(name, values);
356
357 _fields.put(name, field);
358 }
359
360 @Override
361 public void addLocalizedText(String name, Map<Locale, String> values) {
362 if ((values == null) || values.isEmpty()) {
363 return;
364 }
365
366 Field field = new Field(name, values);
367
368 field.setTokenized(true);
369
370 _fields.put(name, field);
371 }
372
373
376 @Override
377 public void addModifiedDate() {
378 addModifiedDate(new Date());
379 }
380
381
384 @Override
385 public void addModifiedDate(Date modifiedDate) {
386 addDate(Field.MODIFIED, modifiedDate);
387 }
388
389 @Override
390 public void addNumber(String name, double value) {
391 addNumber(name, String.valueOf(value), Double.class);
392 }
393
394 @Override
395 public void addNumber(String name, Double value) {
396 addNumber(name, String.valueOf(value), Double.class);
397 }
398
399 @Override
400 public void addNumber(String name, double[] values) {
401 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
402 }
403
404 @Override
405 public void addNumber(String name, Double[] values) {
406 addNumber(name, ArrayUtil.toStringArray(values), Double.class);
407 }
408
409 @Override
410 public void addNumber(String name, float value) {
411 addNumber(name, String.valueOf(value), Float.class);
412 }
413
414 @Override
415 public void addNumber(String name, Float value) {
416 addNumber(name, String.valueOf(value), Float.class);
417 }
418
419 @Override
420 public void addNumber(String name, float[] values) {
421 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
422 }
423
424 @Override
425 public void addNumber(String name, Float[] values) {
426 addNumber(name, ArrayUtil.toStringArray(values), Float.class);
427 }
428
429 @Override
430 public void addNumber(String name, int value) {
431 addNumber(name, String.valueOf(value), Integer.class);
432 }
433
434 @Override
435 public void addNumber(String name, int[] values) {
436 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
437 }
438
439 @Override
440 public void addNumber(String name, Integer value) {
441 addNumber(name, String.valueOf(value), Integer.class);
442 }
443
444 @Override
445 public void addNumber(String name, Integer[] values) {
446 addNumber(name, ArrayUtil.toStringArray(values), Integer.class);
447 }
448
449 @Override
450 public void addNumber(String name, long value) {
451 addNumber(name, String.valueOf(value), Long.class);
452 }
453
454 @Override
455 public void addNumber(String name, Long value) {
456 addNumber(name, String.valueOf(value), Long.class);
457 }
458
459 @Override
460 public void addNumber(String name, long[] values) {
461 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
462 }
463
464 @Override
465 public void addNumber(String name, Long[] values) {
466 addNumber(name, ArrayUtil.toStringArray(values), Long.class);
467 }
468
469 @Override
470 public void addNumber(String name, String value) {
471 addNumber(name, value, Long.class);
472 }
473
474 public void addNumber(
475 String name, String value, Class<? extends Number> clazz) {
476
477 if (Validator.isNotNull(value)) {
478 Field field = new Field(name, value);
479
480 field.setNumeric(true);
481 field.setNumericClass(clazz);
482
483 _fields.put(name, field);
484 }
485 }
486
487 @Override
488 public void addNumber(String name, String[] values) {
489 addNumber(name, values, Long.class);
490 }
491
492 public void addNumber(
493 String name, String[] values, Class<? extends Number> clazz) {
494
495 if (values == null) {
496 return;
497 }
498
499 Field field = new Field(name, values);
500
501 field.setNumeric(true);
502 field.setNumericClass(clazz);
503
504 _fields.put(name, field);
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_TEXT_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 }