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