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