001
014
015 package com.liferay.portlet.documentlibrary.util;
016
017 import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
018 import com.liferay.portal.kernel.dao.orm.DynamicQuery;
019 import com.liferay.portal.kernel.dao.orm.Property;
020 import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
021 import com.liferay.portal.kernel.exception.PortalException;
022 import com.liferay.portal.kernel.exception.SystemException;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.portlet.LiferayPortletURL;
026 import com.liferay.portal.kernel.portlet.LiferayWindowState;
027 import com.liferay.portal.kernel.search.BaseIndexer;
028 import com.liferay.portal.kernel.search.BooleanClauseOccur;
029 import com.liferay.portal.kernel.search.BooleanQuery;
030 import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
031 import com.liferay.portal.kernel.search.Document;
032 import com.liferay.portal.kernel.search.DocumentImpl;
033 import com.liferay.portal.kernel.search.Field;
034 import com.liferay.portal.kernel.search.Indexer;
035 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
036 import com.liferay.portal.kernel.search.SearchContext;
037 import com.liferay.portal.kernel.search.SearchEngineUtil;
038 import com.liferay.portal.kernel.search.SearchException;
039 import com.liferay.portal.kernel.search.Summary;
040 import com.liferay.portal.kernel.util.ArrayUtil;
041 import com.liferay.portal.kernel.util.CharPool;
042 import com.liferay.portal.kernel.util.GetterUtil;
043 import com.liferay.portal.kernel.util.LocaleUtil;
044 import com.liferay.portal.kernel.util.PropsKeys;
045 import com.liferay.portal.kernel.util.StringPool;
046 import com.liferay.portal.kernel.util.StringUtil;
047 import com.liferay.portal.kernel.util.Validator;
048 import com.liferay.portal.kernel.workflow.WorkflowConstants;
049 import com.liferay.portal.model.Group;
050 import com.liferay.portal.model.Repository;
051 import com.liferay.portal.security.permission.ActionKeys;
052 import com.liferay.portal.security.permission.PermissionChecker;
053 import com.liferay.portal.service.GroupLocalServiceUtil;
054 import com.liferay.portal.service.RepositoryLocalServiceUtil;
055 import com.liferay.portal.service.persistence.GroupActionableDynamicQuery;
056 import com.liferay.portal.util.PortalUtil;
057 import com.liferay.portal.util.PortletKeys;
058 import com.liferay.portal.util.PrefsPropsUtil;
059 import com.liferay.portal.util.PropsValues;
060 import com.liferay.portlet.documentlibrary.asset.DLFileEntryAssetRendererFactory;
061 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
062 import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
063 import com.liferay.portlet.documentlibrary.model.DLFileEntryType;
064 import com.liferay.portlet.documentlibrary.model.DLFileVersion;
065 import com.liferay.portlet.documentlibrary.model.DLFolder;
066 import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
067 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
068 import com.liferay.portlet.documentlibrary.service.DLFileEntryMetadataLocalServiceUtil;
069 import com.liferay.portlet.documentlibrary.service.DLFileEntryTypeLocalServiceUtil;
070 import com.liferay.portlet.documentlibrary.service.DLFolderServiceUtil;
071 import com.liferay.portlet.documentlibrary.service.permission.DLFileEntryPermission;
072 import com.liferay.portlet.documentlibrary.service.persistence.DLFileEntryActionableDynamicQuery;
073 import com.liferay.portlet.documentlibrary.service.persistence.DLFolderActionableDynamicQuery;
074 import com.liferay.portlet.dynamicdatamapping.StructureFieldException;
075 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
076 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
077 import com.liferay.portlet.dynamicdatamapping.storage.Fields;
078 import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
079 import com.liferay.portlet.dynamicdatamapping.util.DDMIndexerUtil;
080 import com.liferay.portlet.dynamicdatamapping.util.DDMUtil;
081 import com.liferay.portlet.expando.model.ExpandoBridge;
082 import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
083 import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
084 import com.liferay.portlet.messageboards.model.MBMessage;
085
086 import java.io.IOException;
087 import java.io.InputStream;
088 import java.io.Serializable;
089
090 import java.util.ArrayList;
091 import java.util.Collection;
092 import java.util.LinkedHashMap;
093 import java.util.List;
094 import java.util.Locale;
095 import java.util.Set;
096 import java.util.TreeSet;
097
098 import javax.portlet.PortletRequest;
099 import javax.portlet.PortletURL;
100 import javax.portlet.WindowStateException;
101
102
107 public class DLFileEntryIndexer extends BaseIndexer {
108
109 public static final String[] CLASS_NAMES = {DLFileEntry.class.getName()};
110
111 public static final String PORTLET_ID = PortletKeys.DOCUMENT_LIBRARY;
112
113 public DLFileEntryIndexer() {
114 setFilterSearch(true);
115 setPermissionAware(true);
116 }
117
118 @Override
119 public void addRelatedEntryFields(Document document, Object obj)
120 throws Exception {
121
122 MBMessage message = (MBMessage)obj;
123
124 DLFileEntry dlFileEntry = DLFileEntryLocalServiceUtil.getDLFileEntry(
125 message.getClassPK());
126
127 document.addKeyword(Field.FOLDER_ID, dlFileEntry.getFolderId());
128 document.addKeyword(Field.HIDDEN, dlFileEntry.isInHiddenFolder());
129 document.addKeyword(Field.RELATED_ENTRY, true);
130 }
131
132 @Override
133 public String[] getClassNames() {
134 return CLASS_NAMES;
135 }
136
137 @Override
138 public String getPortletId() {
139 return PORTLET_ID;
140 }
141
142 @Override
143 public boolean hasPermission(
144 PermissionChecker permissionChecker, String entryClassName,
145 long entryClassPK, String actionId)
146 throws Exception {
147
148 return DLFileEntryPermission.contains(
149 permissionChecker, entryClassPK, ActionKeys.VIEW);
150 }
151
152 @Override
153 public void postProcessContextQuery(
154 BooleanQuery contextQuery, SearchContext searchContext)
155 throws Exception {
156
157 addStatus(contextQuery, searchContext);
158
159 if (searchContext.isIncludeAttachments()) {
160 addRelatedClassNames(contextQuery, searchContext);
161 }
162
163 contextQuery.addRequiredTerm(
164 Field.HIDDEN, searchContext.isIncludeAttachments());
165
166 addSearchClassTypeIds(contextQuery, searchContext);
167
168 String ddmStructureFieldName = (String)searchContext.getAttribute(
169 "ddmStructureFieldName");
170 Serializable ddmStructureFieldValue = searchContext.getAttribute(
171 "ddmStructureFieldValue");
172
173 if (Validator.isNotNull(ddmStructureFieldName) &&
174 Validator.isNotNull(ddmStructureFieldValue)) {
175
176 String[] ddmStructureFieldNameParts = StringUtil.split(
177 ddmStructureFieldName, StringPool.SLASH);
178
179 DDMStructure structure = DDMStructureLocalServiceUtil.getStructure(
180 GetterUtil.getLong(ddmStructureFieldNameParts[1]));
181
182 String fieldName = StringUtil.replaceLast(
183 ddmStructureFieldNameParts[2],
184 StringPool.UNDERLINE.concat(
185 LocaleUtil.toLanguageId(searchContext.getLocale())),
186 StringPool.BLANK);
187
188 try {
189 ddmStructureFieldValue = DDMUtil.getIndexedFieldValue(
190 ddmStructureFieldValue, structure.getFieldType(fieldName));
191 }
192 catch (StructureFieldException sfe) {
193 }
194
195 contextQuery.addRequiredTerm(
196 ddmStructureFieldName,
197 StringPool.QUOTE + ddmStructureFieldValue + StringPool.QUOTE);
198 }
199
200 long[] folderIds = searchContext.getFolderIds();
201
202 if ((folderIds != null) && (folderIds.length > 0) &&
203 (folderIds[0] !=
204 DLFolderConstants.DEFAULT_PARENT_FOLDER_ID)) {
205
206 BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create(
207 searchContext);
208
209 for (long folderId : folderIds) {
210 try {
211 DLFolderServiceUtil.getFolder(folderId);
212 }
213 catch (Exception e) {
214 continue;
215 }
216
217 folderIdsQuery.addTerm(Field.FOLDER_ID, folderId);
218 }
219
220 contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
221 }
222
223 String[] mimeTypes = (String[])searchContext.getAttribute("mimeTypes");
224
225 if (ArrayUtil.isNotEmpty(mimeTypes)) {
226 BooleanQuery mimeTypesQuery = BooleanQueryFactoryUtil.create(
227 searchContext);
228
229 for (String mimeType : mimeTypes) {
230 mimeTypesQuery.addTerm(
231 "mimeType",
232 StringUtil.replace(
233 mimeType, CharPool.FORWARD_SLASH, CharPool.UNDERLINE));
234 }
235
236 contextQuery.add(mimeTypesQuery, BooleanClauseOccur.MUST);
237 }
238 }
239
240 @Override
241 public void postProcessSearchQuery(
242 BooleanQuery searchQuery, SearchContext searchContext)
243 throws Exception {
244
245 Set<DDMStructure> ddmStructuresSet = new TreeSet<DDMStructure>();
246
247 long[] groupIds = searchContext.getGroupIds();
248
249 if (ArrayUtil.isNotEmpty(groupIds)) {
250 List<DLFileEntryType> dlFileEntryTypes =
251 DLFileEntryTypeLocalServiceUtil.getFileEntryTypes(groupIds);
252
253 for (DLFileEntryType dlFileEntryType : dlFileEntryTypes) {
254 ddmStructuresSet.addAll(dlFileEntryType.getDDMStructures());
255 }
256 }
257
258 Group group = GroupLocalServiceUtil.getCompanyGroup(
259 searchContext.getCompanyId());
260
261 DDMStructure tikaRawMetadataStructure =
262 DDMStructureLocalServiceUtil.fetchStructure(
263 group.getGroupId(),
264 PortalUtil.getClassNameId(RawMetadataProcessor.class),
265 "TikaRawMetadata");
266
267 if (tikaRawMetadataStructure != null) {
268 ddmStructuresSet.add(tikaRawMetadataStructure);
269 }
270
271 for (DDMStructure ddmStructure : ddmStructuresSet) {
272 addSearchDDMStruture(searchQuery, searchContext, ddmStructure);
273 }
274
275 String keywords = searchContext.getKeywords();
276
277 if (Validator.isNull(keywords)) {
278 addSearchTerm(searchQuery, searchContext, Field.DESCRIPTION, false);
279 addSearchTerm(searchQuery, searchContext, Field.TITLE, false);
280 addSearchTerm(searchQuery, searchContext, Field.USER_NAME, false);
281 }
282
283 addSearchTerm(searchQuery, searchContext, "extension", false);
284 addSearchTerm(searchQuery, searchContext, "fileEntryTypeId", false);
285 addSearchTerm(searchQuery, searchContext, "path", false);
286
287 LinkedHashMap<String, Object> params =
288 (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
289
290 if (params != null) {
291 String expandoAttributes = (String)params.get("expandoAttributes");
292
293 if (Validator.isNotNull(expandoAttributes)) {
294 addSearchExpando(searchQuery, searchContext, expandoAttributes);
295 }
296 }
297 }
298
299 protected void addFileEntryTypeAttributes(
300 Document document, DLFileVersion dlFileVersion)
301 throws PortalException, SystemException {
302
303 DLFileEntryType dlFileEntryType =
304 DLFileEntryTypeLocalServiceUtil.getDLFileEntryType(
305 dlFileVersion.getFileEntryTypeId());
306
307 List<DDMStructure> ddmStructures = dlFileEntryType.getDDMStructures();
308
309 for (DDMStructure ddmStructure : ddmStructures) {
310 Fields fields = null;
311
312 try {
313 DLFileEntryMetadata fileEntryMetadata =
314 DLFileEntryMetadataLocalServiceUtil.getFileEntryMetadata(
315 ddmStructure.getStructureId(),
316 dlFileVersion.getFileVersionId());
317
318 fields = StorageEngineUtil.getFields(
319 fileEntryMetadata.getDDMStorageId());
320 }
321 catch (Exception e) {
322 }
323
324 if (fields != null) {
325 DDMIndexerUtil.addAttributes(document, ddmStructure, fields);
326 }
327 }
328 }
329
330 @Override
331 protected void doDelete(Object obj) throws Exception {
332 DLFileEntry dlFileEntry = (DLFileEntry)obj;
333
334 Document document = new DocumentImpl();
335
336 document.addUID(PORTLET_ID, dlFileEntry.getFileEntryId());
337
338 SearchEngineUtil.deleteDocument(
339 getSearchEngineId(), dlFileEntry.getCompanyId(),
340 document.get(Field.UID));
341 }
342
343 @Override
344 protected Document doGetDocument(Object obj) throws Exception {
345 DLFileEntry dlFileEntry = (DLFileEntry)obj;
346
347 if (_log.isDebugEnabled()) {
348 _log.debug("Indexing document " + dlFileEntry);
349 }
350
351 boolean indexContent = true;
352
353 InputStream is = null;
354
355 try {
356 if (PropsValues.DL_FILE_INDEXING_MAX_SIZE == 0) {
357 indexContent = false;
358 }
359 else if (PropsValues.DL_FILE_INDEXING_MAX_SIZE != -1) {
360 if (dlFileEntry.getSize() >
361 PropsValues.DL_FILE_INDEXING_MAX_SIZE) {
362
363 indexContent = false;
364 }
365 }
366
367 if (indexContent) {
368 String[] ignoreExtensions = PrefsPropsUtil.getStringArray(
369 PropsKeys.DL_FILE_INDEXING_IGNORE_EXTENSIONS,
370 StringPool.COMMA);
371
372 if (ArrayUtil.contains(
373 ignoreExtensions,
374 StringPool.PERIOD + dlFileEntry.getExtension())) {
375
376 indexContent = false;
377 }
378 }
379
380 if (indexContent) {
381 is = dlFileEntry.getFileVersion().getContentStream(false);
382 }
383 }
384 catch (Exception e) {
385 }
386
387 DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
388
389 try {
390 Document document = getBaseModelDocument(
391 PORTLET_ID, dlFileEntry, dlFileVersion);
392
393 if (indexContent) {
394 if (is != null) {
395 try {
396 document.addFile(
397 Field.CONTENT, is, dlFileEntry.getTitle());
398 }
399 catch (IOException ioe) {
400 throw new SearchException(
401 "Cannot extract text from file" + dlFileEntry);
402 }
403 }
404 else if (_log.isDebugEnabled()) {
405 _log.debug(
406 "Document " + dlFileEntry +
407 " does not have any content");
408 }
409 }
410
411 document.addKeyword(
412 Field.CLASS_TYPE_ID, dlFileEntry.getFileEntryTypeId());
413 document.addText(Field.DESCRIPTION, dlFileEntry.getDescription());
414 document.addKeyword(Field.FOLDER_ID, dlFileEntry.getFolderId());
415 document.addKeyword(Field.HIDDEN, dlFileEntry.isInHiddenFolder());
416 document.addText(
417 Field.PROPERTIES, dlFileEntry.getLuceneProperties());
418 document.addText(Field.TITLE, dlFileEntry.getTitle());
419
420 document.addKeyword(
421 "dataRepositoryId", dlFileEntry.getDataRepositoryId());
422 document.addKeyword("extension", dlFileEntry.getExtension());
423 document.addKeyword(
424 "fileEntryTypeId", dlFileEntry.getFileEntryTypeId());
425 document.addKeyword(
426 "mimeType",
427 StringUtil.replace(
428 dlFileEntry.getMimeType(), CharPool.FORWARD_SLASH,
429 CharPool.UNDERLINE));
430 document.addKeyword("path", dlFileEntry.getTitle());
431 document.addKeyword("readCount", dlFileEntry.getReadCount());
432 document.addKeyword("size", dlFileEntry.getSize());
433
434 ExpandoBridge expandoBridge =
435 ExpandoBridgeFactoryUtil.getExpandoBridge(
436 dlFileEntry.getCompanyId(), DLFileEntry.class.getName(),
437 dlFileVersion.getFileVersionId());
438
439 ExpandoBridgeIndexerUtil.addAttributes(document, expandoBridge);
440
441 addFileEntryTypeAttributes(document, dlFileVersion);
442
443 if (dlFileEntry.isInHiddenFolder()) {
444 try {
445 Repository repository =
446 RepositoryLocalServiceUtil.getRepository(
447 dlFileEntry.getRepositoryId());
448
449 String portletId = repository.getPortletId();
450
451 for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
452 if (portletId.equals(indexer.getPortletId())) {
453 indexer.addRelatedEntryFields(document, obj);
454 }
455 }
456 }
457 catch (Exception e) {
458 }
459 }
460
461 if (!dlFileVersion.isInTrash() &&
462 dlFileVersion.isInTrashContainer()) {
463
464 DLFolder folder = dlFileVersion.getTrashContainer();
465
466 addTrashFields(
467 document, DLFolder.class.getName(), folder.getFolderId(),
468 null, null, DLFileEntryAssetRendererFactory.TYPE);
469
470 document.addKeyword(
471 Field.ROOT_ENTRY_CLASS_NAME, DLFolder.class.getName());
472 document.addKeyword(
473 Field.ROOT_ENTRY_CLASS_PK, folder.getFolderId());
474 document.addKeyword(
475 Field.STATUS, WorkflowConstants.STATUS_IN_TRASH);
476 }
477
478 if (_log.isDebugEnabled()) {
479 _log.debug("Document " + dlFileEntry + " indexed successfully");
480 }
481
482 return document;
483 }
484 finally {
485 if (is != null) {
486 try {
487 is.close();
488 }
489 catch (IOException ioe) {
490 }
491 }
492 }
493 }
494
495 @Override
496 protected Summary doGetSummary(
497 Document document, Locale locale, String snippet,
498 PortletURL portletURL) {
499
500 LiferayPortletURL liferayPortletURL = (LiferayPortletURL)portletURL;
501
502 liferayPortletURL.setLifecycle(PortletRequest.ACTION_PHASE);
503
504 try {
505 liferayPortletURL.setWindowState(LiferayWindowState.EXCLUSIVE);
506 }
507 catch (WindowStateException wse) {
508 }
509
510 String fileEntryId = document.get(Field.ENTRY_CLASS_PK);
511
512 portletURL.setParameter("struts_action", "/document_library/get_file");
513 portletURL.setParameter("fileEntryId", fileEntryId);
514
515 Summary summary = createSummary(document, Field.TITLE, Field.CONTENT);
516
517 summary.setMaxContentLength(200);
518 summary.setPortletURL(portletURL);
519
520 return summary;
521 }
522
523 @Override
524 protected void doReindex(Object obj) throws Exception {
525 DLFileEntry dlFileEntry = (DLFileEntry)obj;
526
527 DLFileVersion dlFileVersion = dlFileEntry.getFileVersion();
528
529 if (!dlFileVersion.isApproved() && !dlFileVersion.isInTrash()) {
530 return;
531 }
532
533 Document document = getDocument(dlFileEntry);
534
535 if (document != null) {
536 SearchEngineUtil.updateDocument(
537 getSearchEngineId(), dlFileEntry.getCompanyId(), document);
538 }
539 }
540
541 @Override
542 protected void doReindex(String className, long classPK) throws Exception {
543 DLFileEntry dlFileEntry = DLFileEntryLocalServiceUtil.getFileEntry(
544 classPK);
545
546 doReindex(dlFileEntry);
547 }
548
549 @Override
550 protected void doReindex(String[] ids) throws Exception {
551 if (ids.length == 1) {
552 long companyId = GetterUtil.getLong(ids[0]);
553
554 reindexFolders(companyId);
555 reindexRoot(companyId);
556 }
557 else {
558 long companyId = GetterUtil.getLong(ids[0]);
559 long groupId = GetterUtil.getLong(ids[2]);
560 long dataRepositoryId = GetterUtil.getLong(ids[3]);
561
562 reindexFileEntries(companyId, groupId, dataRepositoryId);
563 }
564 }
565
566 @Override
567 protected void doReindexDDMStructures(List<Long> ddmStructureIds)
568 throws Exception {
569
570 List<DLFileEntry> dlFileEntries =
571 DLFileEntryLocalServiceUtil.getDDMStructureFileEntries(
572 ArrayUtil.toLongArray(ddmStructureIds));
573
574 for (DLFileEntry dlFileEntry : dlFileEntries) {
575 doReindex(dlFileEntry);
576 }
577 }
578
579 @Override
580 protected String getPortletId(SearchContext searchContext) {
581 return PORTLET_ID;
582 }
583
584 protected void reindexFileEntries(
585 long companyId, final long groupId, final long dataRepositoryId)
586 throws PortalException, SystemException {
587
588 final Collection<Document> documents = new ArrayList<Document>();
589
590 ActionableDynamicQuery actionableDynamicQuery =
591 new DLFileEntryActionableDynamicQuery() {
592
593 @Override
594 protected void addCriteria(DynamicQuery dynamicQuery) {
595 Property property = PropertyFactoryUtil.forName("folderId");
596
597 long folderId = DLFolderConstants.getFolderId(
598 groupId, dataRepositoryId);
599
600 dynamicQuery.add(property.eq(folderId));
601 }
602
603 @Override
604 protected void performAction(Object object) throws PortalException {
605 DLFileEntry dlFileEntry = (DLFileEntry)object;
606
607 Document document = getDocument(dlFileEntry);
608
609 if (document != null) {
610 documents.add(document);
611 }
612 }
613
614 };
615
616 actionableDynamicQuery.setGroupId(groupId);
617
618 actionableDynamicQuery.performActions();
619
620 SearchEngineUtil.updateDocuments(
621 getSearchEngineId(), companyId, documents);
622 }
623
624 protected void reindexFolders(final long companyId)
625 throws PortalException, SystemException {
626
627 ActionableDynamicQuery actionableDynamicQuery =
628 new DLFolderActionableDynamicQuery() {
629
630 @Override
631 protected void performAction(Object object) throws PortalException {
632 DLFolder dlFolder = (DLFolder)object;
633
634 String portletId = PortletKeys.DOCUMENT_LIBRARY;
635 long groupId = dlFolder.getGroupId();
636 long folderId = dlFolder.getFolderId();
637
638 String[] newIds = {
639 String.valueOf(companyId), portletId,
640 String.valueOf(groupId), String.valueOf(folderId)
641 };
642
643 reindex(newIds);
644 }
645
646 };
647
648 actionableDynamicQuery.setCompanyId(companyId);
649
650 actionableDynamicQuery.performActions();
651 }
652
653 protected void reindexRoot(final long companyId)
654 throws PortalException, SystemException {
655
656 ActionableDynamicQuery actionableDynamicQuery =
657 new GroupActionableDynamicQuery() {
658
659 @Override
660 protected void performAction(Object object) throws PortalException {
661 Group group = (Group)object;
662
663 String portletId = PortletKeys.DOCUMENT_LIBRARY;
664 long groupId = group.getGroupId();
665 long folderId = groupId;
666
667 String[] newIds = {
668 String.valueOf(companyId), portletId,
669 String.valueOf(groupId), String.valueOf(folderId)
670 };
671
672 reindex(newIds);
673 }
674
675 };
676
677 actionableDynamicQuery.setCompanyId(companyId);
678
679 actionableDynamicQuery.performActions();
680 }
681
682 private static Log _log = LogFactoryUtil.getLog(DLFileEntryIndexer.class);
683
684 }