001    /**
002     * Copyright (c) 2000-2013 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.portlet.documentlibrary.lar;
016    
017    import com.liferay.portal.kernel.lar.BaseStagedModelDataHandler;
018    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
019    import com.liferay.portal.kernel.lar.PortletDataContext;
020    import com.liferay.portal.kernel.lar.PortletDataException;
021    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.repository.model.FileEntry;
025    import com.liferay.portal.kernel.repository.model.FileVersion;
026    import com.liferay.portal.kernel.repository.model.Folder;
027    import com.liferay.portal.kernel.search.Indexer;
028    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.MapUtil;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.xml.Element;
035    import com.liferay.portal.model.Group;
036    import com.liferay.portal.model.Repository;
037    import com.liferay.portal.model.StagedModel;
038    import com.liferay.portal.repository.liferayrepository.model.LiferayFileEntry;
039    import com.liferay.portal.service.GroupLocalServiceUtil;
040    import com.liferay.portal.service.ServiceContext;
041    import com.liferay.portal.service.persistence.RepositoryUtil;
042    import com.liferay.portlet.documentlibrary.DuplicateFileException;
043    import com.liferay.portlet.documentlibrary.NoSuchFileException;
044    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
045    import com.liferay.portlet.documentlibrary.model.DLFileEntryMetadata;
046    import com.liferay.portlet.documentlibrary.model.DLFileEntryType;
047    import com.liferay.portlet.documentlibrary.model.DLFileRank;
048    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
049    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
050    import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
051    import com.liferay.portlet.documentlibrary.service.DLAppServiceUtil;
052    import com.liferay.portlet.documentlibrary.service.DLFileEntryMetadataLocalServiceUtil;
053    import com.liferay.portlet.documentlibrary.service.DLFileEntryTypeLocalServiceUtil;
054    import com.liferay.portlet.documentlibrary.service.DLFileVersionLocalServiceUtil;
055    import com.liferay.portlet.documentlibrary.service.persistence.DLFileEntryTypeUtil;
056    import com.liferay.portlet.documentlibrary.service.persistence.DLFileRankUtil;
057    import com.liferay.portlet.documentlibrary.util.DLProcessorRegistryUtil;
058    import com.liferay.portlet.documentlibrary.util.DLProcessorThreadLocal;
059    import com.liferay.portlet.documentlibrary.util.DLUtil;
060    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
061    import com.liferay.portlet.dynamicdatamapping.storage.Fields;
062    import com.liferay.portlet.dynamicdatamapping.storage.StorageEngineUtil;
063    import com.liferay.util.PwdGenerator;
064    
065    import java.io.IOException;
066    import java.io.InputStream;
067    
068    import java.util.List;
069    import java.util.Map;
070    
071    /**
072     * @author Mate Thurzo
073     */
074    public class FileEntryStagedModelDataHandler
075            extends BaseStagedModelDataHandler<FileEntry> {
076    
077            public static final String[] CLASS_NAMES = {
078                    DLFileEntry.class.getName(), FileEntry.class.getName(),
079                    LiferayFileEntry.class.getName()
080            };
081    
082            @Override
083            public String[] getClassNames() {
084                    return CLASS_NAMES;
085            }
086    
087            @Override
088            public void importStagedModel(
089                            PortletDataContext portletDataContext, FileEntry fileEntry)
090                    throws PortletDataException {
091    
092                    boolean dlProcessorEnabled = DLProcessorThreadLocal.isEnabled();
093    
094                    try {
095                            DLProcessorThreadLocal.setEnabled(false);
096    
097                            super.importStagedModel(portletDataContext, fileEntry);
098                    }
099                    finally {
100                            DLProcessorThreadLocal.setEnabled(dlProcessorEnabled);
101                    }
102            }
103    
104            @Override
105            protected void doExportStagedModel(
106                            PortletDataContext portletDataContext, FileEntry fileEntry)
107                    throws Exception {
108    
109                    Element fileEntryGroupElement =
110                            portletDataContext.getExportDataGroupElement(FileEntry.class);
111    
112                    Element fileEntryElement = fileEntryGroupElement.addElement(
113                            "staged-model");
114    
115                    String fileEntryPath = ExportImportPathUtil.getModelPath(
116                            fileEntry.getGroupId(), FileEntry.class.getName(),
117                            fileEntry.getFileEntryId());
118    
119                    if (!fileEntry.isDefaultRepository()) {
120                            Repository repository = RepositoryUtil.findByPrimaryKey(
121                                    fileEntry.getRepositoryId());
122    
123                            StagedModelDataHandlerUtil.exportStagedModel(
124                                    portletDataContext, repository);
125    
126                            portletDataContext.addReferenceElement(
127                                    fileEntryElement, repository);
128                    }
129    
130                    FileVersion fileVersion = fileEntry.getFileVersion();
131    
132                    if (!fileVersion.isApproved() && !fileVersion.isInTrash()) {
133                            return;
134                    }
135    
136                    if (fileEntry.getFolderId() !=
137                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
138    
139                            StagedModelDataHandlerUtil.exportStagedModel(
140                                    portletDataContext, fileEntry.getFolder());
141                    }
142    
143                    LiferayFileEntry liferayFileEntry = (LiferayFileEntry)fileEntry;
144    
145                    liferayFileEntry.setCachedFileVersion(fileVersion);
146    
147                    if (!portletDataContext.isPerformDirectBinaryImport()) {
148                            InputStream is = null;
149    
150                            try {
151                                    is = FileEntryUtil.getContentStream(fileEntry);
152                            }
153                            catch (NoSuchFileException nsfe) {
154                            }
155    
156                            if (is == null) {
157                                    if (_log.isWarnEnabled()) {
158                                            _log.warn(
159                                                    "No file found for file entry " +
160                                                            fileEntry.getFileEntryId());
161                                    }
162    
163                                    fileEntryElement.detach();
164    
165                                    return;
166                            }
167    
168                            try {
169                                    String binPath = ExportImportPathUtil.getModelPath(
170                                            fileEntry, fileEntry.getVersion());
171    
172                                    portletDataContext.addZipEntry(binPath, is);
173    
174                                    fileEntryElement.addAttribute("bin-path", binPath);
175                            }
176                            finally {
177                                    try {
178                                            is.close();
179                                    }
180                                    catch (IOException ioe) {
181                                            _log.error(ioe, ioe);
182                                    }
183                            }
184                    }
185    
186                    if (portletDataContext.getBooleanParameter(
187                                    DLPortletDataHandler.NAMESPACE, "ranks")) {
188    
189                            List<DLFileRank> fileRanks = DLFileRankUtil.findByFileEntryId(
190                                    fileEntry.getFileEntryId());
191    
192                            for (DLFileRank fileRank : fileRanks) {
193                                    StagedModelDataHandlerUtil.exportStagedModel(
194                                            portletDataContext, fileRank);
195    
196                                    portletDataContext.addReferenceElement(
197                                            fileEntryElement, fileRank);
198                            }
199                    }
200    
201                    if (portletDataContext.getBooleanParameter(
202                                    DLPortletDataHandler.NAMESPACE, "previews-and-thumbnails")) {
203    
204                            DLProcessorRegistryUtil.exportGeneratedFiles(
205                                    portletDataContext, fileEntry, fileEntryElement);
206                    }
207    
208                    exportMetaData(portletDataContext, fileEntryElement, fileEntry);
209    
210                    portletDataContext.addClassedModel(
211                            fileEntryElement, fileEntryPath, fileEntry,
212                            DLPortletDataHandler.NAMESPACE);
213            }
214    
215            @Override
216            protected void doImportStagedModel(
217                            PortletDataContext portletDataContext, FileEntry fileEntry)
218                    throws Exception {
219    
220                    long userId = portletDataContext.getUserId(fileEntry.getUserUuid());
221    
222                    String path = ExportImportPathUtil.getModelPath(
223                            portletDataContext, FileEntry.class.getName(),
224                            fileEntry.getFileEntryId());
225    
226                    Element fileEntryElement =
227                            portletDataContext.getImportDataStagedModelElement(
228                                    FileEntry.class.getSimpleName(), "path", path);
229    
230                    Element referencesElement = fileEntryElement.element("references");
231    
232                    if (referencesElement != null) {
233                            List<Element> referenceElements = referencesElement.elements();
234    
235                            for (Element referenceElement : referenceElements) {
236                                    String className = referenceElement.attributeValue(
237                                            "class-name");
238                                    String classPK = referenceElement.attributeValue("class-pk");
239    
240                                    String referencePath = ExportImportPathUtil.getModelPath(
241                                            portletDataContext, className, GetterUtil.getLong(classPK));
242    
243                                    StagedModel referenceStagedModel =
244                                            (StagedModel)portletDataContext.getZipEntryAsObject(
245                                                    referencePath);
246    
247                                    StagedModelDataHandlerUtil.importStagedModel(
248                                            portletDataContext, referenceStagedModel);
249                            }
250                    }
251    
252                    if ((fileEntry.getFolderId() !=
253                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) &&
254                            (fileEntry.getFolderId() == fileEntry.getFolderId())) {
255    
256                            String folderPath = ExportImportPathUtil.getModelPath(
257                                    portletDataContext, Folder.class.getName(),
258                                    fileEntry.getFolderId());
259    
260                            Folder folder = (Folder)portletDataContext.getZipEntryAsObject(
261                                    folderPath);
262    
263                            StagedModelDataHandlerUtil.importStagedModel(
264                                    portletDataContext, folder);
265                    }
266    
267                    Map<Long, Long> folderIds =
268                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
269                                    Folder.class);
270    
271                    long folderId = MapUtil.getLong(
272                            folderIds, fileEntry.getFolderId(), fileEntry.getFolderId());
273    
274                    long[] assetCategoryIds = null;
275                    String[] assetTagNames = null;
276    
277                    if (portletDataContext.getBooleanParameter(
278                                    DLPortletDataHandler.NAMESPACE, "categories")) {
279    
280                            assetCategoryIds = portletDataContext.getAssetCategoryIds(
281                                    DLFileEntry.class, fileEntry.getFileEntryId());
282                    }
283    
284                    if (portletDataContext.getBooleanParameter(
285                                    DLPortletDataHandler.NAMESPACE, "tags")) {
286    
287                            assetTagNames = portletDataContext.getAssetTagNames(
288                                    DLFileEntry.class, fileEntry.getFileEntryId());
289                    }
290    
291                    ServiceContext serviceContext = portletDataContext.createServiceContext(
292                            fileEntry, DLPortletDataHandler.NAMESPACE);
293    
294                    serviceContext.setAttribute(
295                            "sourceFileName", "A." + fileEntry.getExtension());
296                    serviceContext.setUserId(userId);
297    
298                    String binPath = fileEntryElement.attributeValue("bin-path");
299    
300                    InputStream is = null;
301    
302                    if (Validator.isNull(binPath) &&
303                            portletDataContext.isPerformDirectBinaryImport()) {
304    
305                            try {
306                                    is = FileEntryUtil.getContentStream(fileEntry);
307                            }
308                            catch (NoSuchFileException nsfe) {
309                            }
310                    }
311                    else {
312                            is = portletDataContext.getZipEntryAsInputStream(binPath);
313                    }
314    
315                    if (is == null) {
316                            if (_log.isWarnEnabled()) {
317                                    _log.warn(
318                                            "No file found for file entry " +
319                                                    fileEntry.getFileEntryId());
320                            }
321    
322                            return;
323                    }
324    
325                    importMetaData(portletDataContext, fileEntryElement, serviceContext);
326    
327                    FileEntry importedFileEntry = null;
328    
329                    String titleWithExtension = DLUtil.getTitleWithExtension(fileEntry);
330                    String extension = fileEntry.getExtension();
331    
332                    String dotExtension = StringPool.PERIOD + extension;
333    
334                    if (portletDataContext.isDataStrategyMirror()) {
335                            FileEntry existingFileEntry = FileEntryUtil.fetchByUUID_R(
336                                    fileEntry.getUuid(), portletDataContext.getScopeGroupId());
337    
338                            FileVersion fileVersion = fileEntry.getFileVersion();
339    
340                            if (existingFileEntry == null) {
341                                    String fileEntryTitle = fileEntry.getTitle();
342    
343                                    FileEntry existingTitleFileEntry = FileEntryUtil.fetchByR_F_T(
344                                            portletDataContext.getScopeGroupId(), folderId,
345                                            fileEntryTitle);
346    
347                                    if (existingTitleFileEntry != null) {
348                                            if ((fileEntry.getGroupId() ==
349                                                            portletDataContext.getSourceGroupId()) &&
350                                                    portletDataContext.
351                                                            isDataStrategyMirrorWithOverwriting()) {
352    
353                                                    DLAppLocalServiceUtil.deleteFileEntry(
354                                                            existingTitleFileEntry.getFileEntryId());
355                                            }
356                                            else {
357                                                    boolean titleHasExtension = false;
358    
359                                                    if (fileEntryTitle.endsWith(dotExtension)) {
360                                                            fileEntryTitle = FileUtil.stripExtension(
361                                                                    fileEntryTitle);
362    
363                                                            titleHasExtension = true;
364                                                    }
365    
366                                                    for (int i = 1;; i++) {
367                                                            fileEntryTitle += StringPool.SPACE + i;
368    
369                                                            titleWithExtension = fileEntryTitle + dotExtension;
370    
371                                                            existingTitleFileEntry = FileEntryUtil.fetchByR_F_T(
372                                                                    portletDataContext.getScopeGroupId(), folderId,
373                                                                    titleWithExtension);
374    
375                                                            if (existingTitleFileEntry == null) {
376                                                                    if (titleHasExtension) {
377                                                                            fileEntryTitle += dotExtension;
378                                                                    }
379    
380                                                                    break;
381                                                            }
382                                                    }
383                                            }
384                                    }
385    
386                                    serviceContext.setAttribute(
387                                            "fileVersionUuid", fileVersion.getUuid());
388                                    serviceContext.setUuid(fileEntry.getUuid());
389    
390                                    importedFileEntry = DLAppLocalServiceUtil.addFileEntry(
391                                            userId, portletDataContext.getScopeGroupId(), folderId,
392                                            titleWithExtension, fileEntry.getMimeType(), fileEntryTitle,
393                                            fileEntry.getDescription(), null, is, fileEntry.getSize(),
394                                            serviceContext);
395    
396                                    if (fileVersion.isInTrash()) {
397                                            importedFileEntry = DLAppServiceUtil.moveFileEntryToTrash(
398                                                    importedFileEntry.getFileEntryId());
399                                    }
400                            }
401                            else {
402                                    FileVersion latestExistingFileVersion =
403                                            existingFileEntry.getLatestFileVersion();
404    
405                                    boolean indexEnabled = serviceContext.isIndexingEnabled();
406    
407                                    try {
408                                            serviceContext.setIndexingEnabled(false);
409    
410                                            if (!fileVersion.getUuid().equals(
411                                                            latestExistingFileVersion.getUuid())) {
412    
413                                                    DLFileVersion alreadyExistingFileVersion =
414                                                            DLFileVersionLocalServiceUtil.
415                                                                    getFileVersionByUuidAndGroupId(
416                                                                            fileVersion.getUuid(),
417                                                                            existingFileEntry.getGroupId());
418    
419                                                    if (alreadyExistingFileVersion != null) {
420                                                            serviceContext.setAttribute(
421                                                                    "existingDLFileVersionId",
422                                                                    alreadyExistingFileVersion.getFileVersionId());
423                                                    }
424    
425                                                    serviceContext.setUuid(fileVersion.getUuid());
426    
427                                                    importedFileEntry =
428                                                            DLAppLocalServiceUtil.updateFileEntry(
429                                                                    userId, existingFileEntry.getFileEntryId(),
430                                                                    fileEntry.getTitle(), fileEntry.getMimeType(),
431                                                                    fileEntry.getTitle(),
432                                                                    fileEntry.getDescription(), null, false, is,
433                                                                    fileEntry.getSize(), serviceContext);
434                                            }
435                                            else {
436                                                    DLAppLocalServiceUtil.updateAsset(
437                                                            userId, existingFileEntry,
438                                                            latestExistingFileVersion, assetCategoryIds,
439                                                            assetTagNames, null);
440    
441                                                    importedFileEntry = existingFileEntry;
442                                            }
443    
444                                            if (importedFileEntry.getFolderId() != folderId) {
445                                                    importedFileEntry = DLAppLocalServiceUtil.moveFileEntry(
446                                                            userId, importedFileEntry.getFileEntryId(),
447                                                            folderId, serviceContext);
448                                            }
449    
450                                            if (importedFileEntry instanceof LiferayFileEntry) {
451                                                    LiferayFileEntry liferayFileEntry =
452                                                            (LiferayFileEntry)importedFileEntry;
453    
454                                                    Indexer indexer = IndexerRegistryUtil.getIndexer(
455                                                            DLFileEntry.class);
456    
457                                                    indexer.reindex(liferayFileEntry.getModel());
458                                            }
459                                    }
460                                    finally {
461                                            serviceContext.setIndexingEnabled(indexEnabled);
462                                    }
463                            }
464                    }
465                    else {
466                            try {
467                                    importedFileEntry = DLAppLocalServiceUtil.addFileEntry(
468                                            userId, portletDataContext.getScopeGroupId(), folderId,
469                                            titleWithExtension, fileEntry.getMimeType(),
470                                            fileEntry.getTitle(), fileEntry.getDescription(), null, is,
471                                            fileEntry.getSize(), serviceContext);
472                            }
473                            catch (DuplicateFileException dfe) {
474                                    String title = fileEntry.getTitle();
475    
476                                    String[] titleParts = title.split("\\.", 2);
477    
478                                    title = titleParts[0] + PwdGenerator.getPassword();
479    
480                                    if (titleParts.length > 1) {
481                                            title += StringPool.PERIOD + titleParts[1];
482                                    }
483    
484                                    if (!title.endsWith(dotExtension)) {
485                                            title += dotExtension;
486                                    }
487    
488                                    importedFileEntry = DLAppLocalServiceUtil.addFileEntry(
489                                            userId, portletDataContext.getScopeGroupId(), folderId,
490                                            title, fileEntry.getMimeType(), title,
491                                            fileEntry.getDescription(), null, is, fileEntry.getSize(),
492                                            serviceContext);
493                            }
494                    }
495    
496                    if (portletDataContext.getBooleanParameter(
497                                    DLPortletDataHandler.NAMESPACE, "previews-and-thumbnails")) {
498    
499                            DLProcessorRegistryUtil.importGeneratedFiles(
500                                    portletDataContext, fileEntry, importedFileEntry,
501                                    fileEntryElement);
502                    }
503    
504                    Map<String, String> fileEntryTitles =
505                            (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
506                                    DLFileEntry.class.getName() + ".title");
507    
508                    fileEntryTitles.put(fileEntry.getTitle(), importedFileEntry.getTitle());
509    
510                    portletDataContext.importClassedModel(
511                            fileEntry, importedFileEntry, DLPortletDataHandler.NAMESPACE);
512            }
513    
514            protected void exportMetaData(
515                            PortletDataContext portletDataContext, Element fileEntryElement,
516                            FileEntry fileEntry)
517                    throws Exception {
518    
519                    LiferayFileEntry liferayFileEntry = (LiferayFileEntry)fileEntry;
520    
521                    DLFileEntry dlFileEntry = liferayFileEntry.getDLFileEntry();
522    
523                    long fileEntryTypeId = dlFileEntry.getFileEntryTypeId();
524    
525                    DLFileEntryType dlFileEntryType =
526                            DLFileEntryTypeLocalServiceUtil.fetchFileEntryType(fileEntryTypeId);
527    
528                    if ((dlFileEntryType == null) || !dlFileEntryType.isExportable()) {
529                            return;
530                    }
531    
532                    StagedModelDataHandlerUtil.exportStagedModel(
533                            portletDataContext, dlFileEntryType);
534    
535                    List<DDMStructure> ddmStructures = dlFileEntryType.getDDMStructures();
536    
537                    for (DDMStructure ddmStructure : ddmStructures) {
538                            Element structureFields = fileEntryElement.addElement(
539                                    "structure-fields");
540    
541                            String path = ExportImportPathUtil.getModelPath(
542                                    ddmStructure, String.valueOf(ddmStructure.getStructureId()));
543    
544                            structureFields.addAttribute("path", path);
545    
546                            structureFields.addAttribute(
547                                    "structureUuid", ddmStructure.getUuid());
548    
549                            FileVersion fileVersion = fileEntry.getFileVersion();
550    
551                            DLFileEntryMetadata dlFileEntryMetadata =
552                                    DLFileEntryMetadataLocalServiceUtil.getFileEntryMetadata(
553                                            ddmStructure.getStructureId(),
554                                            fileVersion.getFileVersionId());
555    
556                            Fields fields = StorageEngineUtil.getFields(
557                                    dlFileEntryMetadata.getDDMStorageId());
558    
559                            portletDataContext.addZipEntry(path, fields);
560                    }
561            }
562    
563            protected void importMetaData(
564                            PortletDataContext portletDataContext, Element fileEntryElement,
565                            ServiceContext serviceContext)
566                    throws Exception {
567    
568                    String fileEntryTypeUuid = fileEntryElement.attributeValue(
569                            "fileEntryTypeUuid");
570    
571                    if (Validator.isNull(fileEntryTypeUuid)) {
572                            return;
573                    }
574    
575                    DLFileEntryType dlFileEntryType = DLFileEntryTypeUtil.fetchByUUID_G(
576                            fileEntryTypeUuid, portletDataContext.getScopeGroupId());
577    
578                    if (dlFileEntryType == null) {
579                            Group group = GroupLocalServiceUtil.getCompanyGroup(
580                                    portletDataContext.getCompanyId());
581    
582                            dlFileEntryType = DLFileEntryTypeUtil.fetchByUUID_G(
583                                    fileEntryTypeUuid, group.getGroupId());
584    
585                            if (dlFileEntryType == null) {
586                                    serviceContext.setAttribute("fileEntryTypeId", -1);
587    
588                                    return;
589                            }
590                    }
591    
592                    serviceContext.setAttribute(
593                            "fileEntryTypeId", dlFileEntryType.getFileEntryTypeId());
594    
595                    List<DDMStructure> ddmStructures = dlFileEntryType.getDDMStructures();
596    
597                    for (DDMStructure ddmStructure : ddmStructures) {
598                            Element structureFieldsElement =
599                                    (Element)fileEntryElement.selectSingleNode(
600                                            "structure-fields[@structureUuid='".concat(
601                                                    ddmStructure.getUuid()).concat("']"));
602    
603                            if (structureFieldsElement == null) {
604                                    continue;
605                            }
606    
607                            String path = structureFieldsElement.attributeValue("path");
608    
609                            Fields fields = (Fields)portletDataContext.getZipEntryAsObject(
610                                    path);
611    
612                            serviceContext.setAttribute(
613                                    Fields.class.getName() + ddmStructure.getStructureId(), fields);
614                    }
615            }
616    
617            private static Log _log = LogFactoryUtil.getLog(
618                    FileEntryStagedModelDataHandler.class);
619    
620    }