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