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