001
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.GetterUtil;
027 import com.liferay.portal.kernel.util.InstanceFactory;
028 import com.liferay.portal.kernel.util.ListUtil;
029 import com.liferay.portal.kernel.util.PropsKeys;
030 import com.liferay.portal.kernel.util.StringBundler;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.kernel.workflow.WorkflowConstants;
034 import com.liferay.portal.model.Image;
035 import com.liferay.portal.service.ImageLocalServiceUtil;
036 import com.liferay.portal.util.ClassLoaderUtil;
037 import com.liferay.portal.util.MaintenanceUtil;
038 import com.liferay.portal.util.PropsValues;
039 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
040 import com.liferay.portlet.documentlibrary.model.DLFileVersion;
041 import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
042 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
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.DLPreviewableProcessor;
052 import com.liferay.portlet.documentlibrary.util.comparator.FileVersionVersionComparator;
053 import com.liferay.portlet.messageboards.model.MBMessage;
054 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
055 import com.liferay.registry.Registry;
056 import com.liferay.registry.RegistryUtil;
057
058 import java.io.InputStream;
059
060 import java.util.Collection;
061 import java.util.List;
062
063
068 public class ConvertDocumentLibrary
069 extends BaseConvertProcess implements DLStoreConverter {
070
071 @Override
072 public String getDescription() {
073 return "migrate-documents-from-one-repository-to-another";
074 }
075
076 @Override
077 public String getParameterDescription() {
078 return "please-select-a-new-repository-hook";
079 }
080
081 @Override
082 public String[] getParameterNames() {
083 StringBundler sb = new StringBundler(_HOOKS.length * 2 + 2);
084
085 sb.append(PropsKeys.DL_STORE_IMPL);
086 sb.append(StringPool.EQUAL);
087
088 for (String hook : _HOOKS) {
089 if (!hook.equals(PropsValues.DL_STORE_IMPL)) {
090 sb.append(hook);
091 sb.append(StringPool.SEMICOLON);
092 }
093 }
094
095 return new String[] {
096 sb.toString(), "delete-files-from-previous-repository=checkbox"
097 };
098 }
099
100 @Override
101 public boolean isEnabled() {
102 return true;
103 }
104
105 @Override
106 public void migrateDLFileEntry(
107 long companyId, long repositoryId, DLFileEntry dlFileEntry) {
108
109 String fileName = dlFileEntry.getName();
110
111 List<DLFileVersion> dlFileVersions = getDLFileVersions(dlFileEntry);
112
113 if (dlFileVersions.isEmpty()) {
114 String versionNumber = Store.VERSION_DEFAULT;
115
116 migrateFile(companyId, repositoryId, fileName, versionNumber);
117
118 return;
119 }
120
121 for (DLFileVersion dlFileVersion : dlFileVersions) {
122 String versionNumber = dlFileVersion.getVersion();
123
124 migrateFile(companyId, repositoryId, fileName, versionNumber);
125 }
126 }
127
128 @Override
129 public void validate() throws FileSystemStoreRootDirException {
130 String sourceStoreClassName = getSourceStoreClassName();
131
132 if (!sourceStoreClassName.endsWith(_FILE_SYSTEM_STORE_SUFFIX)) {
133 return;
134 }
135
136 String targetStoreClassName = getTargetStoreClassName();
137
138 if (!targetStoreClassName.endsWith(_FILE_SYSTEM_STORE_SUFFIX)) {
139 return;
140 }
141
142 if (Validator.isBlank(
143 PropsValues.DL_STORE_ADVANCED_FILE_SYSTEM_ROOT_DIR)) {
144
145 if (_log.isWarnEnabled()) {
146 _log.warn(
147 "Property \"" +
148 PropsKeys.DL_STORE_ADVANCED_FILE_SYSTEM_ROOT_DIR +
149 " is not set");
150 }
151
152 throw new FileSystemStoreRootDirException();
153 }
154
155 if (Validator.isBlank(PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR)) {
156 if (_log.isWarnEnabled()) {
157 _log.warn(
158 "Property \"" +
159 PropsKeys.DL_STORE_FILE_SYSTEM_ROOT_DIR +
160 " is not set");
161 }
162
163 throw new FileSystemStoreRootDirException();
164 }
165
166 if (PropsValues.DL_STORE_ADVANCED_FILE_SYSTEM_ROOT_DIR.equals(
167 PropsValues.DL_STORE_FILE_SYSTEM_ROOT_DIR)) {
168
169 if (_log.isWarnEnabled()) {
170 StringBundler sb = new StringBundler(5);
171
172 sb.append("Both properties \"");
173 sb.append(PropsKeys.DL_STORE_ADVANCED_FILE_SYSTEM_ROOT_DIR);
174 sb.append("\" and \"");
175 sb.append(PropsKeys.DL_STORE_FILE_SYSTEM_ROOT_DIR);
176 sb.append("\" have the same value");
177
178 _log.warn(sb.toString());
179 }
180
181 throw new FileSystemStoreRootDirException();
182 }
183 }
184
185 @Override
186 protected void doConvert() throws Exception {
187 _sourceStore = StoreFactory.getInstance();
188
189 String targetStoreClassName = getTargetStoreClassName();
190
191 _targetStore = (Store)InstanceFactory.newInstance(
192 ClassLoaderUtil.getPortalClassLoader(), targetStoreClassName);
193
194 migratePortlets();
195
196 StoreFactory.setInstance(_targetStore);
197
198 MaintenanceUtil.appendStatus(
199 "Please set " + PropsKeys.DL_STORE_IMPL +
200 " in your portal-ext.properties to use " +
201 targetStoreClassName);
202
203 PropsValues.DL_STORE_IMPL = targetStoreClassName;
204 }
205
206 protected List<DLFileVersion> getDLFileVersions(DLFileEntry dlFileEntry) {
207 List<DLFileVersion> dlFileVersions = dlFileEntry.getFileVersions(
208 WorkflowConstants.STATUS_ANY);
209
210 return ListUtil.sort(
211 dlFileVersions, new FileVersionVersionComparator(true));
212 }
213
214 protected String getSourceStoreClassName() {
215 Store sourceStore = StoreFactory.getInstance();
216
217 return sourceStore.getClass().getName();
218 }
219
220 protected String getTargetStoreClassName() {
221 String[] values = getParameterValues();
222
223 return values[0];
224 }
225
226 protected boolean isDeleteFilesFromSourceStore() {
227 String[] values = getParameterValues();
228
229 return GetterUtil.getBoolean(values[1]);
230 }
231
232 protected void migrateDL() throws PortalException {
233 int count = DLFileEntryLocalServiceUtil.getFileEntriesCount();
234
235 MaintenanceUtil.appendStatus(
236 "Migrating " + count + " documents and media files");
237
238 ActionableDynamicQuery actionableDynamicQuery =
239 DLFileEntryLocalServiceUtil.getActionableDynamicQuery();
240
241 actionableDynamicQuery.setAddCriteriaMethod(
242 new ActionableDynamicQuery.AddCriteriaMethod() {
243
244 @Override
245 public void addCriteria(DynamicQuery dynamicQuery) {
246 Property classNameIdProperty = PropertyFactoryUtil.forName(
247 "classNameId");
248
249 dynamicQuery.add(classNameIdProperty.eq(0L));
250 }
251
252 });
253 actionableDynamicQuery.setPerformActionMethod(
254 new ActionableDynamicQuery.PerformActionMethod() {
255
256 @Override
257 public void performAction(Object object) {
258 DLFileEntry dlFileEntry = (DLFileEntry)object;
259
260 migrateDLFileEntry(
261 dlFileEntry.getCompanyId(),
262 dlFileEntry.getDataRepositoryId(), dlFileEntry);
263 }
264
265 });
266
267 actionableDynamicQuery.performActions();
268
269 if (isDeleteFilesFromSourceStore()) {
270 DLPreviewableProcessor.deleteFiles();
271 }
272 }
273
274 protected void migrateFile(
275 long companyId, long repositoryId, String fileName,
276 String versionNumber) {
277
278 try {
279 InputStream is = _sourceStore.getFileAsStream(
280 companyId, repositoryId, fileName, versionNumber);
281
282 if (versionNumber.equals(Store.VERSION_DEFAULT)) {
283 _targetStore.addFile(companyId, repositoryId, fileName, is);
284 }
285 else {
286 _targetStore.updateFile(
287 companyId, repositoryId, fileName, versionNumber, is);
288 }
289
290 if (isDeleteFilesFromSourceStore()) {
291 _sourceStore.deleteFile(
292 companyId, repositoryId, fileName, versionNumber);
293 }
294 }
295 catch (Exception e) {
296 _log.error("Migration failed for " + fileName, e);
297 }
298 }
299
300 protected void migrateImages() throws PortalException {
301 int count = ImageLocalServiceUtil.getImagesCount();
302
303 MaintenanceUtil.appendStatus("Migrating " + count + " images");
304
305 ActionableDynamicQuery actionableDynamicQuery =
306 ImageLocalServiceUtil.getActionableDynamicQuery();
307
308 actionableDynamicQuery.setPerformActionMethod(
309 new ActionableDynamicQuery.PerformActionMethod() {
310
311 @Override
312 public void performAction(Object object) {
313 Image image = (Image)object;
314
315 String fileName =
316 image.getImageId() + StringPool.PERIOD +
317 image.getType();
318
319 migrateFile(0, 0, fileName, Store.VERSION_DEFAULT);
320 }
321
322 });
323
324 actionableDynamicQuery.performActions();
325 }
326
327 protected void migrateMB() throws PortalException {
328 int count = MBMessageLocalServiceUtil.getMBMessagesCount();
329
330 MaintenanceUtil.appendStatus(
331 "Migrating message boards attachments in " + count + " messages");
332
333 ActionableDynamicQuery actionableDynamicQuery =
334 MBMessageLocalServiceUtil.getActionableDynamicQuery();
335
336 actionableDynamicQuery.setPerformActionMethod(
337 new ActionableDynamicQuery.PerformActionMethod() {
338
339 @Override
340 public void performAction(Object object)
341 throws PortalException {
342
343 MBMessage mbMessage = (MBMessage)object;
344
345 for (FileEntry fileEntry :
346 mbMessage.getAttachmentsFileEntries()) {
347
348 DLFileEntry dlFileEntry =
349 (DLFileEntry)fileEntry.getModel();
350
351 migrateDLFileEntry(
352 mbMessage.getCompanyId(),
353 DLFolderConstants.getDataRepositoryId(
354 dlFileEntry.getRepositoryId(),
355 dlFileEntry.getFolderId()),
356 dlFileEntry);
357 }
358 }
359
360 });
361
362 actionableDynamicQuery.performActions();
363 }
364
365 protected void migratePortlets() throws Exception {
366 migrateImages();
367 migrateDL();
368 migrateMB();
369
370 Collection<DLStoreConvertProcess> dlStoreConvertProcesses =
371 _getDLStoreConvertProcesses();
372
373 for (DLStoreConvertProcess dlStoreConvertProcess :
374 dlStoreConvertProcesses) {
375
376 dlStoreConvertProcess.migrate(this);
377 }
378 }
379
380 private Collection<DLStoreConvertProcess> _getDLStoreConvertProcesses() {
381 try {
382 Registry registry = RegistryUtil.getRegistry();
383
384 return registry.getServices(DLStoreConvertProcess.class, null);
385 }
386 catch (Exception e) {
387 throw new SystemException(e);
388 }
389 }
390
391 private static final String _FILE_SYSTEM_STORE_SUFFIX = "FileSystemStore";
392
393 private static final String[] _HOOKS = new String[] {
394 AdvancedFileSystemStore.class.getName(), CMISStore.class.getName(),
395 DBStore.class.getName(), FileSystemStore.class.getName(),
396 JCRStore.class.getName(), S3Store.class.getName()
397 };
398
399 private static final Log _log = LogFactoryUtil.getLog(
400 ConvertDocumentLibrary.class);
401
402 private Store _sourceStore;
403 private Store _targetStore;
404
405 }