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.convert.documentlibrary;
016    
017    import com.liferay.document.library.kernel.model.DLFileEntry;
018    import com.liferay.document.library.kernel.model.DLFolderConstants;
019    import com.liferay.document.library.kernel.service.DLFileEntryLocalServiceUtil;
020    import com.liferay.document.library.kernel.store.Store;
021    import com.liferay.document.library.kernel.util.DLPreviewableProcessor;
022    import com.liferay.document.library.kernel.util.comparator.FileVersionVersionComparator;
023    import com.liferay.message.boards.kernel.model.MBMessage;
024    import com.liferay.message.boards.kernel.service.MBMessageLocalServiceUtil;
025    import com.liferay.portal.convert.BaseConvertProcess;
026    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
027    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
028    import com.liferay.portal.kernel.dao.orm.Property;
029    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
030    import com.liferay.portal.kernel.exception.PortalException;
031    import com.liferay.portal.kernel.exception.SystemException;
032    import com.liferay.portal.kernel.log.Log;
033    import com.liferay.portal.kernel.log.LogFactoryUtil;
034    import com.liferay.portal.kernel.model.Image;
035    import com.liferay.portal.kernel.repository.model.FileEntry;
036    import com.liferay.portal.kernel.repository.model.FileVersion;
037    import com.liferay.portal.kernel.service.ImageLocalServiceUtil;
038    import com.liferay.portal.kernel.util.GetterUtil;
039    import com.liferay.portal.kernel.util.ListUtil;
040    import com.liferay.portal.kernel.util.PropsKeys;
041    import com.liferay.portal.kernel.util.StringBundler;
042    import com.liferay.portal.kernel.util.StringPool;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.repository.liferayrepository.model.LiferayFileEntry;
045    import com.liferay.portal.util.MaintenanceUtil;
046    import com.liferay.portal.util.PropsValues;
047    import com.liferay.portlet.documentlibrary.store.StoreFactory;
048    import com.liferay.registry.Registry;
049    import com.liferay.registry.RegistryUtil;
050    
051    import java.io.InputStream;
052    
053    import java.util.Collection;
054    import java.util.List;
055    
056    /**
057     * @author Minhchau Dang
058     * @author Alexander Chow
059     * @author László Csontos
060     */
061    public class DocumentLibraryConvertProcess
062            extends BaseConvertProcess implements DLStoreConverter {
063    
064            @Override
065            public String getConfigurationErrorMessage() {
066                    return "there-are-no-stores-configured";
067            }
068    
069            @Override
070            public String getDescription() {
071                    return "migrate-documents-from-one-repository-to-another";
072            }
073    
074            @Override
075            public String getParameterDescription() {
076                    return "please-select-a-new-repository-hook";
077            }
078    
079            @Override
080            public String[] getParameterNames() {
081                    StoreFactory storeFactory = StoreFactory.getInstance();
082    
083                    Store store = storeFactory.getStore();
084    
085                    if (store == null) {
086                            return null;
087                    }
088    
089                    String[] storeTypes = storeFactory.getStoreTypes();
090    
091                    StringBundler sb = new StringBundler(storeTypes.length * 2 + 2);
092    
093                    sb.append(PropsKeys.DL_STORE_IMPL);
094                    sb.append(StringPool.EQUAL);
095    
096                    for (String storeType : storeTypes) {
097                            Class<?> clazz = store.getClass();
098    
099                            if (!storeType.equals(clazz.getName())) {
100                                    sb.append(storeType);
101                                    sb.append(StringPool.SEMICOLON);
102                            }
103                    }
104    
105                    return new String[] {
106                            sb.toString(), "delete-files-from-previous-repository=checkbox"
107                    };
108            }
109    
110            @Override
111            public boolean isEnabled() {
112                    return true;
113            }
114    
115            @Override
116            public void migrateDLFileEntry(
117                    long companyId, long repositoryId, FileEntry fileEntry) {
118    
119                    Object model = fileEntry.getModel();
120    
121                    if (!(model instanceof DLFileEntry)) {
122                            throw new IllegalArgumentException(
123                                    "Unsupported file entry model " + model.getClass());
124                    }
125    
126                    String fileName = ((DLFileEntry)model).getName();
127    
128                    List<FileVersion> fileVersions = getFileVersions(fileEntry);
129    
130                    if (fileVersions.isEmpty()) {
131                            String versionNumber = Store.VERSION_DEFAULT;
132    
133                            migrateFile(companyId, repositoryId, fileName, versionNumber);
134    
135                            return;
136                    }
137    
138                    for (FileVersion fileVersion : fileVersions) {
139                            String versionNumber = fileVersion.getVersion();
140    
141                            migrateFile(companyId, repositoryId, fileName, versionNumber);
142                    }
143            }
144    
145            @Override
146            public void validate() {
147                    String sourceStoreClassName = getSourceStoreClassName();
148    
149                    if (!sourceStoreClassName.endsWith(_FILE_SYSTEM_STORE_SUFFIX)) {
150                            return;
151                    }
152    
153                    String targetStoreClassName = getTargetStoreClassName();
154    
155                    if (!targetStoreClassName.endsWith(_FILE_SYSTEM_STORE_SUFFIX)) {
156                            return;
157                    }
158            }
159    
160            @Override
161            protected void doConvert() throws Exception {
162                    StoreFactory storeFactory = StoreFactory.getInstance();
163    
164                    _sourceStore = storeFactory.getStore();
165    
166                    String targetStoreClassName = getTargetStoreClassName();
167    
168                    _targetStore = storeFactory.getStore(targetStoreClassName);
169    
170                    migratePortlets();
171    
172                    storeFactory.setStore(targetStoreClassName);
173    
174                    MaintenanceUtil.appendStatus(
175                            "Please set " + PropsKeys.DL_STORE_IMPL +
176                                    " in your portal-ext.properties to use " +
177                                            targetStoreClassName);
178    
179                    PropsValues.DL_STORE_IMPL = targetStoreClassName;
180            }
181    
182            protected List<FileVersion> getFileVersions(FileEntry fileEntry) {
183                    List<FileVersion> fileVersions = fileEntry.getFileVersions(
184                            WorkflowConstants.STATUS_ANY);
185    
186                    return ListUtil.sort(
187                            fileVersions, new FileVersionVersionComparator(true));
188            }
189    
190            protected String getSourceStoreClassName() {
191                    StoreFactory storeFactory = StoreFactory.getInstance();
192    
193                    Store sourceStore = storeFactory.getStore();
194    
195                    Class<?> clazz = sourceStore.getClass();
196    
197                    return clazz.getName();
198            }
199    
200            protected String getTargetStoreClassName() {
201                    String[] values = getParameterValues();
202    
203                    return values[0];
204            }
205    
206            protected boolean isDeleteFilesFromSourceStore() {
207                    String[] values = getParameterValues();
208    
209                    return GetterUtil.getBoolean(values[1]);
210            }
211    
212            protected void migrateDL() throws PortalException {
213                    int count = DLFileEntryLocalServiceUtil.getFileEntriesCount();
214    
215                    MaintenanceUtil.appendStatus(
216                            "Migrating " + count + " documents and media files");
217    
218                    ActionableDynamicQuery actionableDynamicQuery =
219                            DLFileEntryLocalServiceUtil.getActionableDynamicQuery();
220    
221                    actionableDynamicQuery.setAddCriteriaMethod(
222                            new ActionableDynamicQuery.AddCriteriaMethod() {
223    
224                                    @Override
225                                    public void addCriteria(DynamicQuery dynamicQuery) {
226                                            Property classNameIdProperty = PropertyFactoryUtil.forName(
227                                                    "classNameId");
228    
229                                            dynamicQuery.add(classNameIdProperty.eq(0L));
230                                    }
231    
232                            });
233                    actionableDynamicQuery.setPerformActionMethod(
234                            new ActionableDynamicQuery.PerformActionMethod<DLFileEntry>() {
235    
236                                    @Override
237                                    public void performAction(DLFileEntry dlFileEntry) {
238                                            migrateDLFileEntry(
239                                                    dlFileEntry.getCompanyId(),
240                                                    dlFileEntry.getDataRepositoryId(),
241                                                    new LiferayFileEntry(dlFileEntry));
242                                    }
243    
244                            });
245    
246                    actionableDynamicQuery.performActions();
247    
248                    if (isDeleteFilesFromSourceStore()) {
249                            DLPreviewableProcessor.deleteFiles();
250                    }
251            }
252    
253            protected void migrateFile(
254                    long companyId, long repositoryId, String fileName,
255                    String versionNumber) {
256    
257                    try {
258                            InputStream is = _sourceStore.getFileAsStream(
259                                    companyId, repositoryId, fileName, versionNumber);
260    
261                            if (versionNumber.equals(Store.VERSION_DEFAULT)) {
262                                    _targetStore.addFile(companyId, repositoryId, fileName, is);
263                            }
264                            else {
265                                    _targetStore.updateFile(
266                                            companyId, repositoryId, fileName, versionNumber, is);
267                            }
268    
269                            if (isDeleteFilesFromSourceStore()) {
270                                    _sourceStore.deleteFile(
271                                            companyId, repositoryId, fileName, versionNumber);
272                            }
273                    }
274                    catch (Exception e) {
275                            _log.error("Migration failed for " + fileName, e);
276                    }
277            }
278    
279            protected void migrateImages() throws PortalException {
280                    int count = ImageLocalServiceUtil.getImagesCount();
281    
282                    MaintenanceUtil.appendStatus("Migrating " + count + " images");
283    
284                    ActionableDynamicQuery actionableDynamicQuery =
285                            ImageLocalServiceUtil.getActionableDynamicQuery();
286    
287                    actionableDynamicQuery.setPerformActionMethod(
288                            new ActionableDynamicQuery.PerformActionMethod<Image>() {
289    
290                                    @Override
291                                    public void performAction(Image image) {
292                                            String fileName =
293                                                    image.getImageId() + StringPool.PERIOD +
294                                                            image.getType();
295    
296                                            migrateFile(0, 0, fileName, Store.VERSION_DEFAULT);
297                                    }
298    
299                            });
300    
301                    actionableDynamicQuery.performActions();
302            }
303    
304            protected void migrateMB() throws PortalException {
305                    int count = MBMessageLocalServiceUtil.getMBMessagesCount();
306    
307                    MaintenanceUtil.appendStatus(
308                            "Migrating message boards attachments in " + count + " messages");
309    
310                    ActionableDynamicQuery actionableDynamicQuery =
311                            MBMessageLocalServiceUtil.getActionableDynamicQuery();
312    
313                    actionableDynamicQuery.setPerformActionMethod(
314                            new ActionableDynamicQuery.PerformActionMethod<MBMessage>() {
315    
316                                    @Override
317                                    public void performAction(MBMessage mbMessage)
318                                            throws PortalException {
319    
320                                            for (FileEntry fileEntry :
321                                                            mbMessage.getAttachmentsFileEntries()) {
322    
323                                                    DLFileEntry dlFileEntry =
324                                                            (DLFileEntry)fileEntry.getModel();
325    
326                                                    migrateDLFileEntry(
327                                                            mbMessage.getCompanyId(),
328                                                            DLFolderConstants.getDataRepositoryId(
329                                                                    dlFileEntry.getRepositoryId(),
330                                                                    dlFileEntry.getFolderId()),
331                                                            new LiferayFileEntry(dlFileEntry));
332                                            }
333                                    }
334    
335                            });
336    
337                    actionableDynamicQuery.performActions();
338            }
339    
340            protected void migratePortlets() throws Exception {
341                    migrateImages();
342                    migrateDL();
343                    migrateMB();
344    
345                    Collection<DLStoreConvertProcess> dlStoreConvertProcesses =
346                            _getDLStoreConvertProcesses();
347    
348                    for (DLStoreConvertProcess dlStoreConvertProcess :
349                                    dlStoreConvertProcesses) {
350    
351                            dlStoreConvertProcess.migrate(this);
352                    }
353            }
354    
355            private Collection<DLStoreConvertProcess> _getDLStoreConvertProcesses() {
356                    try {
357                            Registry registry = RegistryUtil.getRegistry();
358    
359                            return registry.getServices(DLStoreConvertProcess.class, null);
360                    }
361                    catch (Exception e) {
362                            throw new SystemException(e);
363                    }
364            }
365    
366            private static final String _FILE_SYSTEM_STORE_SUFFIX = "FileSystemStore";
367    
368            private static final Log _log = LogFactoryUtil.getLog(
369                    DocumentLibraryConvertProcess.class);
370    
371            private Store _sourceStore;
372            private Store _targetStore;
373    
374    }