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