001    /**
002     * Copyright (c) 2000-2012 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.exception.SystemException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.search.Indexer;
021    import com.liferay.portal.kernel.util.ListUtil;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.workflow.WorkflowConstants;
026    import com.liferay.portal.model.CompanyConstants;
027    import com.liferay.portal.model.Image;
028    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
029    import com.liferay.portal.service.ImageLocalServiceUtil;
030    import com.liferay.portal.util.MaintenanceUtil;
031    import com.liferay.portal.util.PropsValues;
032    import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
033    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
034    import com.liferay.portlet.documentlibrary.model.DLFileVersion;
035    import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
036    import com.liferay.portlet.documentlibrary.store.AdvancedFileSystemStore;
037    import com.liferay.portlet.documentlibrary.store.CMISStore;
038    import com.liferay.portlet.documentlibrary.store.FileSystemStore;
039    import com.liferay.portlet.documentlibrary.store.JCRStore;
040    import com.liferay.portlet.documentlibrary.store.S3Store;
041    import com.liferay.portlet.documentlibrary.store.Store;
042    import com.liferay.portlet.documentlibrary.store.StoreFactory;
043    import com.liferay.portlet.documentlibrary.util.comparator.FileVersionVersionComparator;
044    import com.liferay.portlet.messageboards.model.MBMessage;
045    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
046    import com.liferay.portlet.wiki.model.WikiPage;
047    import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
048    
049    import java.io.InputStream;
050    
051    import java.util.List;
052    
053    /**
054     * @author Minhchau Dang
055     * @author Alexander Chow
056     */
057    public class ConvertDocumentLibrary extends ConvertProcess {
058    
059            @Override
060            public String getDescription() {
061                    return "migrate-documents-from-one-repository-to-another";
062            }
063    
064            @Override
065            public String getParameterDescription() {
066                    return "please-select-a-new-repository-hook";
067            }
068    
069            @Override
070            public String[] getParameterNames() {
071                    StringBundler sb = new StringBundler(_HOOKS.length * 2 + 2);
072    
073                    sb.append(PropsKeys.DL_STORE_IMPL);
074                    sb.append(StringPool.EQUAL);
075    
076                    for (String hook : _HOOKS) {
077                            if (!hook.equals(PropsValues.DL_STORE_IMPL)) {
078                                    sb.append(hook);
079                                    sb.append(StringPool.SEMICOLON);
080                            }
081                    }
082    
083                    return new String[] {sb.toString()};
084            }
085    
086            @Override
087            public boolean isEnabled() {
088                    return true;
089            }
090    
091            @Override
092            protected void doConvert() throws Exception {
093                    _sourceStore = StoreFactory.getInstance();
094    
095                    String[] values = getParameterValues();
096    
097                    String targetStoreClassName = values[0];
098    
099                    ClassLoader classLoader = PACLClassLoaderUtil.getPortalClassLoader();
100    
101                    _targetStore = (Store)classLoader.loadClass(
102                            targetStoreClassName).newInstance();
103    
104                    migratePortlets();
105    
106                    StoreFactory.setInstance(_targetStore);
107    
108                    MaintenanceUtil.appendStatus(
109                            "Please set " + PropsKeys.DL_STORE_IMPL +
110                                    " in your portal-ext.properties to use " +
111                                            targetStoreClassName);
112    
113                    PropsValues.DL_STORE_IMPL = targetStoreClassName;
114            }
115    
116            protected List<DLFileVersion> getDLFileVersions(DLFileEntry dlFileEntry)
117                    throws SystemException {
118    
119                    List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
120                            WorkflowConstants.STATUS_ANY);
121    
122                    return ListUtil.sort(
123                            dlFileVersions, new FileVersionVersionComparator(true));
124            }
125    
126            protected void migrateDL() throws Exception {
127                    int count = DLFileEntryLocalServiceUtil.getFileEntriesCount();
128    
129                    MaintenanceUtil.appendStatus(
130                            "Migrating " + count + " documents and media files");
131    
132                    int pages = count / Indexer.DEFAULT_INTERVAL;
133    
134                    for (int i = 0; i <= pages; i++) {
135                            int start = (i * Indexer.DEFAULT_INTERVAL);
136                            int end = start + Indexer.DEFAULT_INTERVAL;
137    
138                            List<DLFileEntry> dlFileEntries =
139                                    DLFileEntryLocalServiceUtil.getFileEntries(start, end);
140    
141                            for (DLFileEntry dlFileEntry : dlFileEntries) {
142                                    long companyId = dlFileEntry.getCompanyId();
143                                    long repositoryId = dlFileEntry.getDataRepositoryId();
144    
145                                    migrateDLFileEntry(companyId, repositoryId, dlFileEntry);
146                            }
147                    }
148            }
149    
150            protected void migrateDLFileEntry(
151                            long companyId, long repositoryId, DLFileEntry fileEntry)
152                    throws Exception {
153    
154                    String fileName = fileEntry.getName();
155    
156                    List<DLFileVersion> dlFileVersions = getDLFileVersions(fileEntry);
157    
158                    if (dlFileVersions.isEmpty()) {
159                            String versionNumber = Store.VERSION_DEFAULT;
160    
161                            migrateFile(companyId, repositoryId, fileName, versionNumber);
162    
163                            return;
164                    }
165    
166                    for (DLFileVersion dlFileVersion : dlFileVersions) {
167                            String versionNumber = dlFileVersion.getVersion();
168    
169                            migrateFile(companyId, repositoryId, fileName, versionNumber);
170                    }
171            }
172    
173            protected void migrateFile(
174                    long companyId, long repositoryId, String fileName,
175                    String versionNumber) {
176    
177                    try {
178                            InputStream is = _sourceStore.getFileAsStream(
179                                    companyId, repositoryId, fileName, versionNumber);
180    
181                            if (versionNumber.equals(Store.VERSION_DEFAULT)) {
182                                    _targetStore.addFile(companyId, repositoryId, fileName, is);
183                            }
184                            else {
185                                    _targetStore.updateFile(
186                                            companyId, repositoryId, fileName, versionNumber, is);
187                            }
188                    }
189                    catch (Exception e) {
190                            _log.error("Migration failed for " + fileName, e);
191                    }
192            }
193    
194            protected void migrateFiles(
195                            long companyId, String dirName, String[] fileNames)
196                    throws Exception {
197    
198                    long repositoryId = CompanyConstants.SYSTEM;
199                    String versionNumber = Store.VERSION_DEFAULT;
200    
201                    try {
202                            _targetStore.addDirectory(companyId, repositoryId, dirName);
203                    }
204                    catch (DuplicateDirectoryException dde) {
205                    }
206    
207                    for (String fileName : fileNames) {
208                            if (fileName.startsWith(StringPool.SLASH)) {
209                                    fileName = fileName.substring(1);
210                            }
211    
212                            migrateFile(companyId, repositoryId, fileName, versionNumber);
213                    }
214            }
215    
216            protected void migrateImages() throws Exception {
217                    int count = ImageLocalServiceUtil.getImagesCount();
218    
219                    MaintenanceUtil.appendStatus("Migrating " + count + " images");
220    
221                    int pages = count / Indexer.DEFAULT_INTERVAL;
222    
223                    for (int i = 0; i <= pages; i++) {
224                            int start = (i * Indexer.DEFAULT_INTERVAL);
225                            int end = start + Indexer.DEFAULT_INTERVAL;
226    
227                            List<Image> images = ImageLocalServiceUtil.getImages(start, end);
228    
229                            for (Image image : images) {
230                                    String fileName =
231                                            image.getImageId() + StringPool.PERIOD + image.getType();
232    
233                                    migrateFile(0, 0, fileName, Store.VERSION_DEFAULT);
234                            }
235                    }
236            }
237    
238            protected void migrateMB() throws Exception {
239                    int count = MBMessageLocalServiceUtil.getMBMessagesCount();
240    
241                    MaintenanceUtil.appendStatus(
242                            "Migrating message boards attachments in " + count + " messages");
243    
244                    int pages = count / Indexer.DEFAULT_INTERVAL;
245    
246                    for (int i = 0; i <= pages; i++) {
247                            int start = (i * Indexer.DEFAULT_INTERVAL);
248                            int end = start + Indexer.DEFAULT_INTERVAL;
249    
250                            List<MBMessage> messages = MBMessageLocalServiceUtil.getMBMessages(
251                                    start, end);
252    
253                            for (MBMessage message : messages) {
254                                    migrateFiles(
255                                            message.getCompanyId(), message.getAttachmentsDir(),
256                                            message.getAttachmentsFiles());
257                            }
258                    }
259            }
260    
261            protected void migratePortlets() throws Exception {
262                    migrateImages();
263                    migrateDL();
264                    migrateMB();
265                    migrateWiki();
266            }
267    
268            protected void migrateWiki() throws Exception {
269                    int count = WikiPageLocalServiceUtil.getWikiPagesCount();
270    
271                    MaintenanceUtil.appendStatus(
272                            "Migrating wiki page attachments in " + count + " pages");
273    
274                    int pages = count / Indexer.DEFAULT_INTERVAL;
275    
276                    for (int i = 0; i <= pages; i++) {
277                            int start = (i * Indexer.DEFAULT_INTERVAL);
278                            int end = start + Indexer.DEFAULT_INTERVAL;
279    
280                            List<WikiPage> wikiPages = WikiPageLocalServiceUtil.getWikiPages(
281                                    start, end);
282    
283                            for (WikiPage wikiPage : wikiPages) {
284                                    if (!wikiPage.isHead()) {
285                                            continue;
286                                    }
287    
288                                    migrateFiles(
289                                            wikiPage.getCompanyId(), wikiPage.getAttachmentsDir(),
290                                            wikiPage.getAttachmentsFiles());
291                            }
292                    }
293            }
294    
295            private static final String[] _HOOKS = new String[] {
296                    AdvancedFileSystemStore.class.getName(), CMISStore.class.getName(),
297                    FileSystemStore.class.getName(), JCRStore.class.getName(),
298                    S3Store.class.getName()
299            };
300    
301            private static Log _log = LogFactoryUtil.getLog(
302                    ConvertDocumentLibrary.class);
303    
304            private Store _sourceStore;
305            private Store _targetStore;
306    
307    }