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.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.util.InstanceFactory;
027    import com.liferay.portal.kernel.util.ListUtil;
028    import com.liferay.portal.kernel.util.PropsKeys;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.workflow.WorkflowConstants;
032    import com.liferay.portal.model.Image;
033    import com.liferay.portal.service.ImageLocalServiceUtil;
034    import com.liferay.portal.service.persistence.ImageActionableDynamicQuery;
035    import com.liferay.portal.util.ClassLoaderUtil;
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.DLFileVersion;
040    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
041    import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
042    import com.liferay.portlet.documentlibrary.service.persistence.DLFileEntryActionableDynamicQuery;
043    import com.liferay.portlet.documentlibrary.store.AdvancedFileSystemStore;
044    import com.liferay.portlet.documentlibrary.store.CMISStore;
045    import com.liferay.portlet.documentlibrary.store.DBStore;
046    import com.liferay.portlet.documentlibrary.store.FileSystemStore;
047    import com.liferay.portlet.documentlibrary.store.JCRStore;
048    import com.liferay.portlet.documentlibrary.store.S3Store;
049    import com.liferay.portlet.documentlibrary.store.Store;
050    import com.liferay.portlet.documentlibrary.store.StoreFactory;
051    import com.liferay.portlet.documentlibrary.util.comparator.FileVersionVersionComparator;
052    import com.liferay.portlet.messageboards.model.MBMessage;
053    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
054    import com.liferay.portlet.messageboards.service.persistence.MBMessageActionableDynamicQuery;
055    import com.liferay.portlet.wiki.model.WikiPage;
056    import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
057    import com.liferay.portlet.wiki.service.persistence.WikiPageActionableDynamicQuery;
058    
059    import java.io.InputStream;
060    
061    import java.util.List;
062    
063    /**
064     * @author Minhchau Dang
065     * @author Alexander Chow
066     */
067    public class ConvertDocumentLibrary extends ConvertProcess {
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                    StringBundler sb = new StringBundler(_HOOKS.length * 2 + 2);
082    
083                    sb.append(PropsKeys.DL_STORE_IMPL);
084                    sb.append(StringPool.EQUAL);
085    
086                    for (String hook : _HOOKS) {
087                            if (!hook.equals(PropsValues.DL_STORE_IMPL)) {
088                                    sb.append(hook);
089                                    sb.append(StringPool.SEMICOLON);
090                            }
091                    }
092    
093                    return new String[] {sb.toString()};
094            }
095    
096            @Override
097            public boolean isEnabled() {
098                    return true;
099            }
100    
101            @Override
102            protected void doConvert() throws Exception {
103                    _sourceStore = StoreFactory.getInstance();
104    
105                    String[] values = getParameterValues();
106    
107                    String targetStoreClassName = values[0];
108    
109                    _targetStore = (Store)InstanceFactory.newInstance(
110                            ClassLoaderUtil.getPortalClassLoader(), targetStoreClassName);
111    
112                    migratePortlets();
113    
114                    StoreFactory.setInstance(_targetStore);
115    
116                    MaintenanceUtil.appendStatus(
117                            "Please set " + PropsKeys.DL_STORE_IMPL +
118                                    " in your portal-ext.properties to use " +
119                                            targetStoreClassName);
120    
121                    PropsValues.DL_STORE_IMPL = targetStoreClassName;
122            }
123    
124            protected List<DLFileVersion> getDLFileVersions(DLFileEntry dlFileEntry)
125                    throws SystemException {
126    
127                    List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
128                            WorkflowConstants.STATUS_ANY);
129    
130                    return ListUtil.sort(
131                            dlFileVersions, new FileVersionVersionComparator(true));
132            }
133    
134            protected void migrateDL() throws PortalException, SystemException {
135                    int count = DLFileEntryLocalServiceUtil.getFileEntriesCount();
136    
137                    MaintenanceUtil.appendStatus(
138                            "Migrating " + count + " documents and media files");
139    
140                    ActionableDynamicQuery actionableDynamicQuery =
141                            new DLFileEntryActionableDynamicQuery() {
142    
143                            @Override
144                            protected void addCriteria(DynamicQuery dynamicQuery) {
145                                    Property classNameIdProperty = PropertyFactoryUtil.forName(
146                                            "classNameId");
147    
148                                    dynamicQuery.add(classNameIdProperty.eq(0L));
149                            }
150    
151                            @Override
152                            protected void performAction(Object object) throws SystemException {
153                                    DLFileEntry dlFileEntry = (DLFileEntry)object;
154    
155                                    migrateDLFileEntry(
156                                            dlFileEntry.getCompanyId(),
157                                            dlFileEntry.getDataRepositoryId(), dlFileEntry);
158                            }
159    
160                    };
161    
162                    actionableDynamicQuery.performActions();
163            }
164    
165            protected void migrateDLFileEntry(
166                            long companyId, long repositoryId, DLFileEntry dlFileEntry)
167                    throws SystemException {
168    
169                    String fileName = dlFileEntry.getName();
170    
171                    List<DLFileVersion> dlFileVersions = getDLFileVersions(dlFileEntry);
172    
173                    if (dlFileVersions.isEmpty()) {
174                            String versionNumber = Store.VERSION_DEFAULT;
175    
176                            migrateFile(companyId, repositoryId, fileName, versionNumber);
177    
178                            return;
179                    }
180    
181                    for (DLFileVersion dlFileVersion : dlFileVersions) {
182                            String versionNumber = dlFileVersion.getVersion();
183    
184                            migrateFile(companyId, repositoryId, fileName, versionNumber);
185                    }
186            }
187    
188            protected void migrateFile(
189                    long companyId, long repositoryId, String fileName,
190                    String versionNumber) {
191    
192                    try {
193                            InputStream is = _sourceStore.getFileAsStream(
194                                    companyId, repositoryId, fileName, versionNumber);
195    
196                            if (versionNumber.equals(Store.VERSION_DEFAULT)) {
197                                    _targetStore.addFile(companyId, repositoryId, fileName, is);
198                            }
199                            else {
200                                    _targetStore.updateFile(
201                                            companyId, repositoryId, fileName, versionNumber, is);
202                            }
203                    }
204                    catch (Exception e) {
205                            _log.error("Migration failed for " + fileName, e);
206                    }
207            }
208    
209            protected void migrateImages() throws PortalException, SystemException {
210                    int count = ImageLocalServiceUtil.getImagesCount();
211    
212                    MaintenanceUtil.appendStatus("Migrating " + count + " images");
213    
214                    ActionableDynamicQuery actionableDynamicQuery =
215                            new ImageActionableDynamicQuery() {
216    
217                            @Override
218                            protected void performAction(Object object) {
219                                    Image image = (Image)object;
220    
221                                    String fileName =
222                                            image.getImageId() + StringPool.PERIOD + image.getType();
223    
224                                    migrateFile(0, 0, fileName, Store.VERSION_DEFAULT);
225                            }
226    
227                    };
228    
229                    actionableDynamicQuery.performActions();
230            }
231    
232            protected void migrateMB() throws PortalException, SystemException {
233                    int count = MBMessageLocalServiceUtil.getMBMessagesCount();
234    
235                    MaintenanceUtil.appendStatus(
236                            "Migrating message boards attachments in " + count + " messages");
237    
238                    ActionableDynamicQuery actionableDynamicQuery =
239                            new MBMessageActionableDynamicQuery() {
240    
241                            @Override
242                            protected void performAction(Object object)
243                                    throws PortalException, SystemException {
244    
245                                    MBMessage mbMessage = (MBMessage)object;
246    
247                                    for (FileEntry fileEntry :
248                                                    mbMessage.getAttachmentsFileEntries()) {
249    
250                                            DLFileEntry dlFileEntry = (DLFileEntry)fileEntry.getModel();
251    
252                                            migrateDLFileEntry(
253                                                    mbMessage.getCompanyId(),
254                                                    DLFolderConstants.getDataRepositoryId(
255                                                            dlFileEntry.getRepositoryId(),
256                                                            dlFileEntry.getFolderId()),
257                                                    dlFileEntry);
258                                    }
259                            }
260    
261                    };
262    
263                    actionableDynamicQuery.performActions();
264            }
265    
266            protected void migratePortlets() throws Exception {
267                    migrateImages();
268                    migrateDL();
269                    migrateMB();
270                    migrateWiki();
271            }
272    
273            protected void migrateWiki() throws PortalException, SystemException {
274                    int count = WikiPageLocalServiceUtil.getWikiPagesCount();
275    
276                    MaintenanceUtil.appendStatus(
277                            "Migrating wiki page attachments in " + count + " pages");
278    
279                    ActionableDynamicQuery actionableDynamicQuery =
280                            new WikiPageActionableDynamicQuery() {
281    
282                            @Override
283                            protected void addCriteria(DynamicQuery dynamicQuery) {
284                                    Property property = PropertyFactoryUtil.forName("head");
285    
286                                    dynamicQuery.add(property.eq(true));
287                            }
288    
289                            @Override
290                            protected void performAction(Object object) throws SystemException {
291                                    WikiPage wikiPage = (WikiPage)object;
292    
293                                    for (FileEntry fileEntry :
294                                                    wikiPage.getAttachmentsFileEntries()) {
295    
296                                            DLFileEntry dlFileEntry = (DLFileEntry)fileEntry.getModel();
297    
298                                            migrateDLFileEntry(
299                                                    wikiPage.getCompanyId(),
300                                                    DLFolderConstants.getDataRepositoryId(
301                                                            dlFileEntry.getRepositoryId(),
302                                                            dlFileEntry.getFolderId()),
303                                                    dlFileEntry);
304                                    }
305                            }
306    
307                    };
308    
309                    actionableDynamicQuery.performActions();
310            }
311    
312            private static final String[] _HOOKS = new String[] {
313                    AdvancedFileSystemStore.class.getName(), CMISStore.class.getName(),
314                    DBStore.class.getName(), FileSystemStore.class.getName(),
315                    JCRStore.class.getName(), S3Store.class.getName()
316            };
317    
318            private static Log _log = LogFactoryUtil.getLog(
319                    ConvertDocumentLibrary.class);
320    
321            private Store _sourceStore;
322            private Store _targetStore;
323    
324    }