001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.lar;
016    
017    import com.liferay.portal.LayoutImportException;
018    import com.liferay.portal.NoSuchPortletPreferencesException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.lar.ImportExportThreadLocal;
021    import com.liferay.portal.kernel.lar.PortletDataContext;
022    import com.liferay.portal.kernel.lar.PortletDataHandler;
023    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.util.CharPool;
027    import com.liferay.portal.kernel.util.FileUtil;
028    import com.liferay.portal.kernel.util.GetterUtil;
029    import com.liferay.portal.kernel.util.MapUtil;
030    import com.liferay.portal.kernel.util.ReleaseInfo;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.kernel.util.Time;
035    import com.liferay.portal.kernel.util.UnicodeProperties;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.kernel.xml.Document;
038    import com.liferay.portal.kernel.xml.Element;
039    import com.liferay.portal.kernel.xml.Node;
040    import com.liferay.portal.kernel.xml.SAXReaderUtil;
041    import com.liferay.portal.kernel.zip.ZipWriter;
042    import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
043    import com.liferay.portal.model.Group;
044    import com.liferay.portal.model.Layout;
045    import com.liferay.portal.model.LayoutTypePortlet;
046    import com.liferay.portal.model.Lock;
047    import com.liferay.portal.model.Portlet;
048    import com.liferay.portal.model.PortletConstants;
049    import com.liferay.portal.model.PortletItem;
050    import com.liferay.portal.model.PortletPreferences;
051    import com.liferay.portal.service.GroupLocalServiceUtil;
052    import com.liferay.portal.service.LayoutLocalServiceUtil;
053    import com.liferay.portal.service.PortletItemLocalServiceUtil;
054    import com.liferay.portal.service.PortletLocalServiceUtil;
055    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
056    import com.liferay.portal.service.UserLocalServiceUtil;
057    import com.liferay.portal.util.PortalUtil;
058    import com.liferay.portal.util.PortletKeys;
059    import com.liferay.portlet.PortletPreferencesFactoryUtil;
060    import com.liferay.portlet.asset.model.AssetCategory;
061    import com.liferay.portlet.asset.model.AssetCategoryConstants;
062    import com.liferay.portlet.asset.model.AssetCategoryProperty;
063    import com.liferay.portlet.asset.model.AssetVocabulary;
064    import com.liferay.portlet.asset.service.AssetCategoryPropertyLocalServiceUtil;
065    import com.liferay.portlet.asset.service.AssetCategoryServiceUtil;
066    import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
067    import com.liferay.portlet.asset.service.persistence.AssetVocabularyUtil;
068    import com.liferay.portlet.expando.model.ExpandoColumn;
069    import com.liferay.portlet.messageboards.model.MBMessage;
070    import com.liferay.portlet.ratings.model.RatingsEntry;
071    import com.liferay.util.xml.DocUtil;
072    
073    import java.io.File;
074    import java.io.IOException;
075    
076    import java.util.Date;
077    import java.util.HashSet;
078    import java.util.List;
079    import java.util.Map;
080    
081    import org.apache.commons.lang.time.StopWatch;
082    
083    /**
084     * @author Brian Wing Shun Chan
085     * @author Joel Kozikowski
086     * @author Charles May
087     * @author Raymond Augé
088     * @author Jorge Ferrer
089     * @author Bruno Farache
090     * @author Zsigmond Rab
091     * @author Douglas Wong
092     */
093    public class PortletExporter {
094    
095            public byte[] exportPortletInfo(
096                            long plid, long groupId, String portletId,
097                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
098                    throws Exception {
099    
100                    File file = exportPortletInfoAsFile(
101                            plid, groupId, portletId, parameterMap, startDate, endDate);
102    
103                    try {
104                            return FileUtil.getBytes(file);
105                    }
106                    catch (IOException ioe) {
107                            throw new SystemException(ioe);
108                    }
109                    finally {
110                            file.delete();
111                    }
112            }
113    
114            public File exportPortletInfoAsFile(
115                            long plid, long groupId, String portletId,
116                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
117                    throws Exception {
118    
119                    try {
120                            ImportExportThreadLocal.setPortletExportInProcess(true);
121    
122                            return doExportPortletInfoAsFile(
123                                    plid, groupId, portletId, parameterMap, startDate, endDate);
124                    }
125                    finally {
126                            ImportExportThreadLocal.setPortletExportInProcess(false);
127                    }
128            }
129    
130            protected File doExportPortletInfoAsFile(
131                            long plid, long groupId, String portletId,
132                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
133                    throws Exception {
134    
135                    boolean exportCategories = MapUtil.getBoolean(
136                            parameterMap, PortletDataHandlerKeys.CATEGORIES);
137                    boolean exportPermissions = MapUtil.getBoolean(
138                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
139                    boolean exportPortletArchivedSetups = MapUtil.getBoolean(
140                            parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
141    
142                    boolean exportPortletData = false;
143    
144                    if (parameterMap.containsKey(
145                                    PortletDataHandlerKeys.PORTLET_DATA + "_" +
146                                            PortletConstants.getRootPortletId(portletId))) {
147    
148                            exportPortletData = MapUtil.getBoolean(
149                                    parameterMap,
150                                    PortletDataHandlerKeys.PORTLET_DATA + "_" +
151                                            PortletConstants.getRootPortletId(portletId));
152                    }
153                    else {
154                            exportPortletData = MapUtil.getBoolean(
155                                    parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
156                    }
157    
158                    boolean exportPortletDataAll = MapUtil.getBoolean(
159                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
160                    boolean exportPortletSetup = MapUtil.getBoolean(
161                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
162                    boolean exportPortletUserPreferences = MapUtil.getBoolean(
163                            parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
164                    boolean exportUserPermissions = MapUtil.getBoolean(
165                            parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
166    
167                    if (_log.isDebugEnabled()) {
168                            _log.debug("Export categories " + exportCategories);
169                            _log.debug("Export permissions " + exportPermissions);
170                            _log.debug(
171                                    "Export portlet archived setups " +
172                                            exportPortletArchivedSetups);
173                            _log.debug("Export portlet data " + exportPortletData);
174                            _log.debug("Export all portlet data " + exportPortletDataAll);
175                            _log.debug("Export portlet setup " + exportPortletSetup);
176                            _log.debug(
177                                    "Export portlet user preferences " +
178                                            exportPortletUserPreferences);
179                            _log.debug("Export user permissions " + exportUserPermissions);
180                    }
181    
182                    if (exportPortletDataAll) {
183                            exportPortletData = true;
184                    }
185    
186                    StopWatch stopWatch = null;
187    
188                    if (_log.isInfoEnabled()) {
189                            stopWatch = new StopWatch();
190    
191                            stopWatch.start();
192                    }
193    
194                    LayoutCache layoutCache = new LayoutCache();
195    
196                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
197    
198                    if (!layout.isTypeControlPanel() && !layout.isTypePanel() &&
199                            !layout.isTypePortlet()) {
200    
201                            throw new LayoutImportException(
202                                    "Layout type " + layout.getType() + " is not valid");
203                    }
204    
205                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
206                            layout.getCompanyId());
207    
208                    ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
209    
210                    long scopeGroupId = groupId;
211    
212                    javax.portlet.PortletPreferences jxPreferences =
213                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
214                                    layout, portletId);
215    
216                    String scopeType = GetterUtil.getString(
217                            jxPreferences.getValue("lfrScopeType", null));
218                    String scopeLayoutUuid = GetterUtil.getString(
219                            jxPreferences.getValue("lfrScopeLayoutUuid", null));
220    
221                    if (Validator.isNotNull(scopeType)) {
222                            Group scopeGroup = null;
223    
224                            if (scopeType.equals("company")) {
225                                    scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
226                                            layout.getCompanyId());
227                            }
228                            else if (Validator.isNotNull(scopeLayoutUuid)) {
229                                    scopeGroup = layout.getScopeGroup();
230                            }
231    
232                            if (scopeGroup != null) {
233                                    scopeGroupId = scopeGroup.getGroupId();
234                            }
235                    }
236    
237                    PortletDataContext portletDataContext = new PortletDataContextImpl(
238                            layout.getCompanyId(), scopeGroupId, parameterMap,
239                            new HashSet<String>(), startDate, endDate, zipWriter);
240    
241                    portletDataContext.setPortetDataContextListener(
242                            new PortletDataContextListenerImpl(portletDataContext));
243    
244                    portletDataContext.setPlid(plid);
245                    portletDataContext.setOldPlid(plid);
246                    portletDataContext.setScopeType(scopeType);
247                    portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
248    
249                    Document document = SAXReaderUtil.createDocument();
250    
251                    Element rootElement = document.addElement("root");
252    
253                    Element headerElement = rootElement.addElement("header");
254    
255                    headerElement.addAttribute(
256                            "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
257                    headerElement.addAttribute("export-date", Time.getRFC822());
258    
259                    if (portletDataContext.hasDateRange()) {
260                            headerElement.addAttribute(
261                                    "start-date",
262                                    String.valueOf(portletDataContext.getStartDate()));
263                            headerElement.addAttribute(
264                                    "end-date", String.valueOf(portletDataContext.getEndDate()));
265                    }
266    
267                    headerElement.addAttribute("type", "portlet");
268                    headerElement.addAttribute("group-id", String.valueOf(scopeGroupId));
269                    headerElement.addAttribute(
270                            "private-layout", String.valueOf(layout.isPrivateLayout()));
271                    headerElement.addAttribute(
272                            "root-portlet-id", PortletConstants.getRootPortletId(portletId));
273    
274                    exportPortlet(
275                            portletDataContext, layoutCache, portletId, layout, rootElement,
276                            defaultUserId, exportPermissions, exportPortletArchivedSetups,
277                            exportPortletData, exportPortletSetup, exportPortletUserPreferences,
278                            exportUserPermissions);
279    
280                    if (exportCategories) {
281                            exportAssetCategories(portletDataContext);
282                    }
283    
284                    exportAssetLinks(portletDataContext);
285                    exportAssetTags(portletDataContext);
286                    exportComments(portletDataContext);
287                    exportExpandoTables(portletDataContext);
288                    exportLocks(portletDataContext);
289    
290                    if (exportPermissions) {
291                            _permissionExporter.exportPortletDataPermissions(
292                                    portletDataContext);
293                    }
294    
295                    exportRatingsEntries(portletDataContext, rootElement);
296    
297                    if (_log.isInfoEnabled()) {
298                            _log.info("Exporting portlet took " + stopWatch.getTime() + " ms");
299                    }
300    
301                    try {
302                            portletDataContext.addZipEntry(
303                                    "/manifest.xml", document.formattedString());
304                    }
305                    catch (IOException ioe) {
306                            throw new SystemException(ioe);
307                    }
308    
309                    return zipWriter.getFile();
310            }
311    
312            protected void exportAssetCategories(PortletDataContext portletDataContext)
313                    throws Exception {
314    
315                    Document document = SAXReaderUtil.createDocument();
316    
317                    Element rootElement = document.addElement("categories-hierarchy");
318    
319                    exportAssetCategories(portletDataContext, rootElement);
320    
321                    portletDataContext.addZipEntry(
322                            portletDataContext.getRootPath() + "/categories-hierarchy.xml",
323                            document.formattedString());
324            }
325    
326            protected void exportAssetCategories(
327                            PortletDataContext portletDataContext, Element rootElement)
328                    throws Exception {
329    
330                    Element assetVocabulariesElement = rootElement.element(
331                            "vocabularies");
332    
333                    if (assetVocabulariesElement == null) {
334                            assetVocabulariesElement = rootElement.addElement(
335                                    "vocabularies");
336                    }
337    
338                    Element assetsElement = rootElement.addElement("assets");
339    
340                    Element assetCategoriesElement = rootElement.addElement("categories");
341    
342                    Map<String, String[]> assetCategoryUuidsMap =
343                            portletDataContext.getAssetCategoryUuidsMap();
344    
345                    for (Map.Entry<String, String[]> entry :
346                                    assetCategoryUuidsMap.entrySet()) {
347    
348                            String[] assetCategoryEntryParts = StringUtil.split(
349                                    entry.getKey(), CharPool.POUND);
350    
351                            String className = assetCategoryEntryParts[0];
352                            long classPK = GetterUtil.getLong(assetCategoryEntryParts[1]);
353    
354                            Element assetElement = assetsElement.addElement("asset");
355    
356                            assetElement.addAttribute("class-name", className);
357                            assetElement.addAttribute("class-pk", String.valueOf(classPK));
358                            assetElement.addAttribute(
359                                    "category-uuids", StringUtil.merge(entry.getValue()));
360    
361                            List<AssetCategory> assetCategories =
362                                    AssetCategoryServiceUtil.getCategories(className, classPK);
363    
364                            for (AssetCategory assestCategory : assetCategories) {
365                                    exportAssetCategory(
366                                            portletDataContext, assetVocabulariesElement,
367                                            assetCategoriesElement, assestCategory);
368                            }
369                    }
370            }
371    
372            protected void exportAssetCategory(
373                            PortletDataContext portletDataContext,
374                            Element assetVocabulariesElement, Element assetCategoriesElement,
375                            AssetCategory assetCategory)
376                    throws Exception {
377    
378                    exportAssetVocabulary(
379                            portletDataContext, assetVocabulariesElement,
380                            assetCategory.getVocabularyId());
381    
382                    if (assetCategory.getParentCategoryId() !=
383                                    AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
384    
385                            exportAssetCategory(
386                                    portletDataContext, assetVocabulariesElement,
387                                    assetCategoriesElement, assetCategory.getParentCategoryId());
388                    }
389    
390                    String path = getAssetCategoryPath(
391                            portletDataContext, assetCategory.getCategoryId());
392    
393                    if (!portletDataContext.isPathNotProcessed(path)) {
394                            return;
395                    }
396    
397                    Element assetCategoryElement = assetCategoriesElement.addElement(
398                            "category");
399    
400                    assetCategoryElement.addAttribute("path", path);
401    
402                    assetCategory.setUserUuid(assetCategory.getUserUuid());
403    
404                    portletDataContext.addZipEntry(path, assetCategory);
405    
406                    List<AssetCategoryProperty> assetCategoryProperties =
407                            AssetCategoryPropertyLocalServiceUtil.getCategoryProperties(
408                                    assetCategory.getCategoryId());
409    
410                    for (AssetCategoryProperty assetCategoryProperty :
411                                    assetCategoryProperties) {
412    
413                            Element propertyElement = assetCategoryElement.addElement(
414                                    "property");
415    
416                            propertyElement.addAttribute(
417                                    "userUuid", assetCategoryProperty.getUserUuid());
418                            propertyElement.addAttribute(
419                                    "key", assetCategoryProperty.getKey());
420                            propertyElement.addAttribute(
421                                    "value", assetCategoryProperty.getValue());
422                    }
423    
424                    portletDataContext.addPermissions(
425                            AssetCategory.class, assetCategory.getCategoryId());
426            }
427    
428            protected void exportAssetCategory(
429                            PortletDataContext portletDataContext,
430                            Element assetVocabulariesElement, Element assetCategoriesElement,
431                            long assetCategoryId)
432                    throws Exception {
433    
434                    AssetCategory assetCategory = AssetCategoryUtil.fetchByPrimaryKey(
435                            assetCategoryId);
436    
437                    if (assetCategory != null) {
438                            exportAssetCategory(
439                                    portletDataContext, assetVocabulariesElement,
440                                    assetCategoriesElement, assetCategory);
441                    }
442            }
443    
444            protected void exportAssetLinks(PortletDataContext portletDataContext)
445                    throws Exception {
446    
447                    Document document = SAXReaderUtil.createDocument();
448    
449                    Element rootElement = document.addElement("links");
450    
451                    Map<String, String[]> assetLinkUuidsMap =
452                            portletDataContext.getAssetLinkUuidsMap();
453    
454                    for (Map.Entry<String, String[]> entry : assetLinkUuidsMap.entrySet()) {
455                            String[] assetLinkNameParts = StringUtil.split(
456                                    entry.getKey(), CharPool.POUND);
457                            String[] targetAssetEntryUuids = entry.getValue();
458    
459                            String sourceAssetEntryUuid = assetLinkNameParts[0];
460                            String assetLinkType = assetLinkNameParts[1];
461    
462                            Element assetElement = rootElement.addElement("asset-link");
463    
464                            assetElement.addAttribute("source-uuid", sourceAssetEntryUuid);
465                            assetElement.addAttribute(
466                                    "target-uuids", StringUtil.merge(targetAssetEntryUuids));
467                            assetElement.addAttribute("type", assetLinkType);
468                    }
469    
470                    portletDataContext.addZipEntry(
471                            portletDataContext.getRootPath() + "/links.xml",
472                            document.formattedString());
473            }
474    
475            protected void exportAssetTags(PortletDataContext portletDataContext)
476                    throws Exception {
477    
478                    Document document = SAXReaderUtil.createDocument();
479    
480                    Element rootElement = document.addElement("tags");
481    
482                    Map<String, String[]> assetTagNamesMap =
483                            portletDataContext.getAssetTagNamesMap();
484    
485                    for (Map.Entry<String, String[]> entry : assetTagNamesMap.entrySet()) {
486                            String[] assetTagNameParts = StringUtil.split(
487                                    entry.getKey(), CharPool.POUND);
488    
489                            String className = assetTagNameParts[0];
490                            String classPK = assetTagNameParts[1];
491    
492                            Element assetElement = rootElement.addElement("asset");
493    
494                            assetElement.addAttribute("class-name", className);
495                            assetElement.addAttribute("class-pk", classPK);
496                            assetElement.addAttribute(
497                                    "tags", StringUtil.merge(entry.getValue()));
498                    }
499    
500                    portletDataContext.addZipEntry(
501                            portletDataContext.getRootPath() + "/tags.xml",
502                            document.formattedString());
503            }
504    
505            protected void exportAssetVocabulary(
506                            PortletDataContext portletDataContext,
507                            Element assetVocabulariesElement, AssetVocabulary assetVocabulary)
508                    throws Exception {
509    
510                    String path = getAssetVocabulariesPath(
511                            portletDataContext, assetVocabulary.getVocabularyId());
512    
513                    if (!portletDataContext.isPathNotProcessed(path)) {
514                            return;
515                    }
516    
517                    Element assetVocabularyElement = assetVocabulariesElement.addElement(
518                            "vocabulary");
519    
520                    assetVocabularyElement.addAttribute("path", path);
521    
522                    assetVocabulary.setUserUuid(assetVocabulary.getUserUuid());
523    
524                    portletDataContext.addZipEntry(path, assetVocabulary);
525    
526                    portletDataContext.addPermissions(
527                            AssetVocabulary.class, assetVocabulary.getVocabularyId());
528            }
529    
530            protected void exportAssetVocabulary(
531                            PortletDataContext portletDataContext,
532                            Element assetVocabulariesElement, long assetVocabularyId)
533                    throws Exception {
534    
535                    AssetVocabulary assetVocabulary = AssetVocabularyUtil.findByPrimaryKey(
536                            assetVocabularyId);
537    
538                    exportAssetVocabulary(
539                            portletDataContext, assetVocabulariesElement, assetVocabulary);
540            }
541    
542            protected void exportComments(PortletDataContext portletDataContext)
543                    throws Exception {
544    
545                    Document document = SAXReaderUtil.createDocument();
546    
547                    Element rootElement = document.addElement("comments");
548    
549                    Map<String, List<MBMessage>> commentsMap =
550                            portletDataContext.getComments();
551    
552                    for (Map.Entry<String, List<MBMessage>> entry :
553                                    commentsMap.entrySet()) {
554    
555                            String[] commentParts = StringUtil.split(
556                                    entry.getKey(), CharPool.POUND);
557    
558                            String className = commentParts[0];
559                            String classPK = commentParts[1];
560    
561                            String commentsPath = getCommentsPath(
562                                    portletDataContext, className, classPK);
563    
564                            Element assetElement = rootElement.addElement("asset");
565    
566                            assetElement.addAttribute("path", commentsPath);
567                            assetElement.addAttribute("class-name", className);
568                            assetElement.addAttribute("class-pk", classPK);
569    
570                            List<MBMessage> mbMessages = entry.getValue();
571    
572                            for (MBMessage mbMessage : mbMessages) {
573                                    String commentPath = getCommentPath(
574                                            portletDataContext, className, classPK, mbMessage);
575    
576                                    if (portletDataContext.isPathNotProcessed(commentPath)) {
577                                            portletDataContext.addZipEntry(commentPath, mbMessage);
578                                    }
579                            }
580                    }
581    
582                    portletDataContext.addZipEntry(
583                            portletDataContext.getRootPath() + "/comments.xml",
584                            document.formattedString());
585            }
586    
587            protected void exportExpandoTables(PortletDataContext portletDataContext)
588                    throws Exception {
589    
590                    Document document = SAXReaderUtil.createDocument();
591    
592                    Element rootElement = document.addElement("expando-tables");
593    
594                    Map<String, List<ExpandoColumn>> expandoColumnsMap =
595                            portletDataContext.getExpandoColumns();
596    
597                    for (Map.Entry<String, List<ExpandoColumn>> entry :
598                                    expandoColumnsMap.entrySet()) {
599    
600                            String className = entry.getKey();
601    
602                            Element expandoTableElement = rootElement.addElement(
603                                    "expando-table");
604    
605                            expandoTableElement.addAttribute("class-name", className);
606    
607                            List<ExpandoColumn> expandoColumns = entry.getValue();
608    
609                            for (ExpandoColumn expandoColumn: expandoColumns) {
610                                    Element expandoColumnElement =
611                                            expandoTableElement.addElement("expando-column");
612    
613                                    expandoColumnElement.addAttribute(
614                                            "column-id", String.valueOf(expandoColumn.getColumnId()));
615                                    expandoColumnElement.addAttribute(
616                                            "name", expandoColumn.getName());
617                                    expandoColumnElement.addAttribute(
618                                            "type", String.valueOf(expandoColumn.getType()));
619    
620                                    DocUtil.add(
621                                            expandoColumnElement, "default-data",
622                                            expandoColumn.getDefaultData());
623    
624                                    Element typeSettingsElement = expandoColumnElement.addElement(
625                                            "type-settings");
626    
627                                    UnicodeProperties typeSettingsProperties =
628                                            expandoColumn.getTypeSettingsProperties();
629    
630                                    typeSettingsElement.addCDATA(typeSettingsProperties.toString());
631                            }
632                    }
633    
634                    portletDataContext.addZipEntry(
635                            portletDataContext.getRootPath() + "/expando-tables.xml",
636                            document.formattedString());
637            }
638    
639            protected void exportLocks(PortletDataContext portletDataContext)
640                    throws Exception {
641    
642                    Document document = SAXReaderUtil.createDocument();
643    
644                    Element rootElement = document.addElement("locks");
645    
646                    Map<String, Lock> locksMap = portletDataContext.getLocks();
647    
648                    for (Map.Entry<String, Lock> entry : locksMap.entrySet()) {
649                            Lock lock = entry.getValue();
650    
651                            String entryKey = entry.getKey();
652    
653                            int pos = entryKey.indexOf(CharPool.POUND);
654    
655                            String className = entryKey.substring(0, pos);
656                            String key = entryKey.substring(pos + 1);
657    
658                            String path = getLockPath(
659                                    portletDataContext, className, key, lock);
660    
661                            Element assetElement = rootElement.addElement("asset");
662    
663                            assetElement.addAttribute("path", path);
664                            assetElement.addAttribute("class-name", className);
665                            assetElement.addAttribute("key", key);
666    
667                            if (portletDataContext.isPathNotProcessed(path)) {
668                                    portletDataContext.addZipEntry(path, lock);
669                            }
670                    }
671    
672                    portletDataContext.addZipEntry(
673                            portletDataContext.getRootPath() + "/locks.xml",
674                            document.formattedString());
675            }
676    
677            protected void exportPortlet(
678                            PortletDataContext portletDataContext, LayoutCache layoutCache,
679                            String portletId, Layout layout, Element parentElement,
680                            long defaultUserId, boolean exportPermissions,
681                            boolean exportPortletArchivedSetups, boolean exportPortletData,
682                            boolean exportPortletSetup, boolean exportPortletUserPreferences,
683                            boolean exportUserPermissions)
684                    throws Exception {
685    
686                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
687                            portletDataContext.getCompanyId(), portletId);
688    
689                    if (portlet == null) {
690                            if (_log.isDebugEnabled()) {
691                                    _log.debug(
692                                            "Do not export portlet " + portletId +
693                                                    " because the portlet does not exist");
694                            }
695    
696                            return;
697                    }
698    
699                    if ((!portlet.isInstanceable()) &&
700                            (!portlet.isPreferencesUniquePerLayout()) &&
701                            (portletDataContext.hasNotUniquePerLayout(portletId))) {
702    
703                            return;
704                    }
705    
706                    Document document = SAXReaderUtil.createDocument();
707    
708                    Element portletElement = document.addElement("portlet");
709    
710                    portletElement.addAttribute("portlet-id", portletId);
711                    portletElement.addAttribute(
712                            "root-portlet-id", PortletConstants.getRootPortletId(portletId));
713                    portletElement.addAttribute(
714                            "old-plid", String.valueOf(layout.getPlid()));
715                    portletElement.addAttribute(
716                            "scope-layout-type", portletDataContext.getScopeType());
717                    portletElement.addAttribute(
718                            "scope-layout-uuid", portletDataContext.getScopeLayoutUuid());
719    
720                    // Data
721    
722                    javax.portlet.PortletPreferences jxPreferences =
723                            PortletPreferencesFactoryUtil.getPortletSetup(
724                                    layout, portletId, StringPool.BLANK);
725    
726                    if (exportPortletData) {
727                            if (!portlet.isPreferencesUniquePerLayout()) {
728                                    StringBundler sb = new StringBundler(5);
729    
730                                    sb.append(portletId);
731                                    sb.append(StringPool.AT);
732                                    sb.append(portletDataContext.getScopeType());
733                                    sb.append(StringPool.AT);
734                                    sb.append(portletDataContext.getScopeLayoutUuid());
735    
736                                    String dataKey = sb.toString();
737    
738                                    if (!portletDataContext.hasNotUniquePerLayout(dataKey)) {
739                                            portletDataContext.putNotUniquePerLayout(dataKey);
740    
741                                            exportPortletData(
742                                                    portletDataContext, portlet, layout, jxPreferences,
743                                                    portletElement);
744                                    }
745                            }
746                            else {
747                                    exportPortletData(
748                                            portletDataContext, portlet, layout, jxPreferences,
749                                            portletElement);
750                            }
751                    }
752    
753                    // Portlet preferences
754    
755                    if (exportPortletSetup) {
756                            exportPortletPreferences(
757                                    portletDataContext, PortletKeys.PREFS_OWNER_ID_DEFAULT,
758                                    PortletKeys.PREFS_OWNER_TYPE_LAYOUT, false, layout, portletId,
759                                    portletElement);
760    
761                            exportPortletPreferences(
762                                    portletDataContext, portletDataContext.getScopeGroupId(),
763                                    PortletKeys.PREFS_OWNER_TYPE_GROUP, false, layout, portletId,
764                                    portletElement);
765    
766                            exportPortletPreferences(
767                                    portletDataContext, portletDataContext.getCompanyId(),
768                                    PortletKeys.PREFS_OWNER_TYPE_COMPANY, false, layout, portletId,
769                                    portletElement);
770                    }
771    
772                    // Portlet preferences
773    
774                    if (exportPortletUserPreferences) {
775                            exportPortletPreferences(
776                                    portletDataContext, defaultUserId,
777                                    PortletKeys.PREFS_OWNER_TYPE_USER, true, layout, portletId,
778                                    portletElement);
779    
780                            try {
781                                    PortletPreferences groupPortletPreferences =
782                                            PortletPreferencesLocalServiceUtil.getPortletPreferences(
783                                                    portletDataContext.getScopeGroupId(),
784                                                    PortletKeys.PREFS_OWNER_TYPE_GROUP,
785                                                    PortletKeys.PREFS_PLID_SHARED, portletId);
786    
787                                    exportPortletPreference(
788                                            portletDataContext, portletDataContext.getScopeGroupId(),
789                                            PortletKeys.PREFS_OWNER_TYPE_GROUP, false,
790                                            groupPortletPreferences, portletId,
791                                            PortletKeys.PREFS_PLID_SHARED, portletElement);
792                            }
793                            catch (NoSuchPortletPreferencesException nsppe) {
794                            }
795                    }
796    
797                    // Archived setups
798    
799                    if (exportPortletArchivedSetups) {
800                            String rootPortletId = PortletConstants.getRootPortletId(portletId);
801    
802                            List<PortletItem> portletItems =
803                                    PortletItemLocalServiceUtil.getPortletItems(
804                                            portletDataContext.getGroupId(), rootPortletId,
805                                            PortletPreferences.class.getName());
806    
807                            for (PortletItem portletItem : portletItems) {
808                                    exportPortletPreferences(
809                                            portletDataContext, portletItem.getPortletItemId(),
810                                            PortletKeys.PREFS_OWNER_TYPE_ARCHIVED, false, null,
811                                            portletItem.getPortletId(), portletElement);
812                            }
813                    }
814    
815                    // Permissions
816    
817                    if (exportPermissions) {
818                            _permissionExporter.exportPortletPermissions(
819                                    portletDataContext, layoutCache, portletId, layout,
820                                    portletElement);
821                    }
822    
823                    // Zip
824    
825                    StringBundler sb = new StringBundler(4);
826    
827                    sb.append(portletDataContext.getPortletPath(portletId));
828                    sb.append(StringPool.SLASH);
829                    sb.append(layout.getPlid());
830                    sb.append("/portlet.xml");
831    
832                    String path = sb.toString();
833    
834                    Element element = parentElement.addElement("portlet");
835    
836                    element.addAttribute("portlet-id", portletId);
837                    element.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
838                    element.addAttribute("path", path);
839    
840                    if (portletDataContext.isPathNotProcessed(path)) {
841                            try {
842                                    portletDataContext.addZipEntry(
843                                            path, document.formattedString());
844                            }
845                            catch (IOException ioe) {
846                                    if (_log.isWarnEnabled()) {
847                                            _log.warn(ioe.getMessage());
848                                    }
849                            }
850    
851                            portletDataContext.addPrimaryKey(String.class, path);
852                    }
853            }
854    
855            protected void exportPortletData(
856                            PortletDataContext portletDataContext, Portlet portlet,
857                            Layout layout, javax.portlet.PortletPreferences jxPreferences,
858                            Element parentElement)
859                    throws Exception {
860    
861                    PortletDataHandler portletDataHandler =
862                            portlet.getPortletDataHandlerInstance();
863    
864                    if (portletDataHandler == null) {
865                            return;
866                    }
867    
868                    String portletId = portlet.getPortletId();
869    
870                    Group liveGroup = layout.getGroup();
871    
872                    if (liveGroup.isStagingGroup()) {
873                            liveGroup = liveGroup.getLiveGroup();
874                    }
875    
876                    boolean staged = liveGroup.isStagedPortlet(portlet.getRootPortletId());
877    
878                    if (!staged) {
879                            if (_log.isDebugEnabled()) {
880                                    _log.debug(
881                                            "Not exporting data for " + portletId +
882                                                    " because it is configured not to be staged");
883                            }
884    
885                            return;
886                    }
887    
888                    if (_log.isDebugEnabled()) {
889                            _log.debug("Exporting data for " + portletId);
890                    }
891    
892                    StringBundler sb = new StringBundler(4);
893    
894                    sb.append(portletDataContext.getPortletPath(portletId));
895                    sb.append(StringPool.SLASH);
896    
897                    if (portlet.isPreferencesUniquePerLayout()) {
898                            sb.append(layout.getPlid());
899                    }
900                    else {
901                            sb.append(portletDataContext.getScopeGroupId());
902                    }
903    
904                    sb.append("/portlet-data.xml");
905    
906                    String path = sb.toString();
907    
908                    if (!portletDataContext.isPathNotProcessed(path)) {
909                            return;
910                    }
911    
912                    long lastPublishDate = GetterUtil.getLong(
913                            jxPreferences.getValue("last-publish-date", StringPool.BLANK));
914    
915                    Date startDate = portletDataContext.getStartDate();
916    
917                    if ((lastPublishDate > 0) && (startDate != null) &&
918                            (lastPublishDate < startDate.getTime())) {
919    
920                            portletDataContext.setStartDate(new Date(lastPublishDate));
921                    }
922    
923                    String data = null;
924    
925                    long groupId = portletDataContext.getGroupId();
926    
927                    portletDataContext.setGroupId(portletDataContext.getScopeGroupId());
928    
929                    try {
930                            data = portletDataHandler.exportData(
931                                    portletDataContext, portletId, jxPreferences);
932                    }
933                    catch (Exception e) {
934                            throw new SystemException(e);
935                    }
936                    finally {
937                            portletDataContext.setGroupId(groupId);
938                            portletDataContext.setStartDate(startDate);
939                    }
940    
941                    if (Validator.isNull(data)) {
942                            if (_log.isDebugEnabled()) {
943                                    _log.debug(
944                                            "Not exporting data for " + portletId +
945                                                    " because null data was returned");
946                            }
947    
948                            return;
949                    }
950    
951                    Element portletDataElement = parentElement.addElement("portlet-data");
952    
953                    portletDataElement.addAttribute("path", path);
954    
955                    portletDataContext.addZipEntry(path, data);
956    
957                    Date endDate = portletDataContext.getEndDate();
958    
959                    if (endDate != null) {
960                            try {
961                                    jxPreferences.setValue(
962                                            "last-publish-date", String.valueOf(endDate.getTime()));
963    
964                                    jxPreferences.store();
965                            }
966                            catch (Exception e) {
967                                    _log.error(e, e);
968                            }
969                    }
970            }
971    
972            protected void exportPortletPreference(
973                            PortletDataContext portletDataContext, long ownerId, int ownerType,
974                            boolean defaultUser, PortletPreferences portletPreferences,
975                            String portletId, long plid, Element parentElement)
976                    throws Exception {
977    
978                    String preferencesXML = portletPreferences.getPreferences();
979    
980                    if (Validator.isNull(preferencesXML)) {
981                            preferencesXML = PortletConstants.DEFAULT_PREFERENCES;
982                    }
983    
984                    Document document = SAXReaderUtil.read(preferencesXML);
985    
986                    Element rootElement = document.getRootElement();
987    
988                    rootElement.addAttribute("owner-id", String.valueOf(ownerId));
989                    rootElement.addAttribute("owner-type", String.valueOf(ownerType));
990                    rootElement.addAttribute("default-user", String.valueOf(defaultUser));
991                    rootElement.addAttribute("plid", String.valueOf(plid));
992                    rootElement.addAttribute("portlet-id", portletId);
993    
994                    if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
995                            PortletItem portletItem =
996                                    PortletItemLocalServiceUtil.getPortletItem(ownerId);
997    
998                            rootElement.addAttribute(
999                                    "archive-user-uuid", portletItem.getUserUuid());
1000                            rootElement.addAttribute("archive-name", portletItem.getName());
1001                    }
1002    
1003                    List<Node> nodes = document.selectNodes(
1004                            "/portlet-preferences/preference[name/text() = " +
1005                                    "'last-publish-date']");
1006    
1007                    for (Node node : nodes) {
1008                            document.remove(node);
1009                    }
1010    
1011                    String path = getPortletPreferencesPath(
1012                            portletDataContext, portletId, ownerId, ownerType, plid);
1013    
1014                    Element portletPreferencesElement = parentElement.addElement(
1015                            "portlet-preferences");
1016    
1017                    portletPreferencesElement.addAttribute("path", path);
1018    
1019                    if (portletDataContext.isPathNotProcessed(path)) {
1020                            portletDataContext.addZipEntry(
1021                                    path, document.formattedString(StringPool.TAB, false, false));
1022                    }
1023            }
1024    
1025            protected void exportPortletPreferences(
1026                            PortletDataContext portletDataContext, long ownerId, int ownerType,
1027                            boolean defaultUser, Layout layout, String portletId,
1028                            Element parentElement)
1029                    throws Exception {
1030    
1031                    PortletPreferences portletPreferences = null;
1032    
1033                    long plid = PortletKeys.PREFS_OWNER_ID_DEFAULT;
1034    
1035                    if (layout != null) {
1036                            plid = layout.getPlid();
1037                    }
1038    
1039                    if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) ||
1040                            (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
1041                            (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED)) {
1042    
1043                            plid = PortletKeys.PREFS_OWNER_ID_DEFAULT;
1044                    }
1045    
1046                    try {
1047                            portletPreferences =
1048                                    PortletPreferencesLocalServiceUtil.getPortletPreferences(
1049                                            ownerId, ownerType, plid, portletId);
1050                    }
1051                    catch (NoSuchPortletPreferencesException nsppe) {
1052                            return;
1053                    }
1054    
1055                    LayoutTypePortlet layoutTypePortlet = null;
1056    
1057                    if (layout != null) {
1058                            layoutTypePortlet = (LayoutTypePortlet)layout.getLayoutType();
1059                    }
1060    
1061                    if ((layoutTypePortlet == null) ||
1062                            (layoutTypePortlet.hasPortletId(portletId))) {
1063    
1064                            exportPortletPreference(
1065                                    portletDataContext, ownerId, ownerType, defaultUser,
1066                                    portletPreferences, portletId, plid, parentElement);
1067                    }
1068            }
1069    
1070            protected void exportRatingsEntries(
1071                            PortletDataContext portletDataContext, Element parentElement)
1072                    throws Exception {
1073    
1074                    Document document = SAXReaderUtil.createDocument();
1075    
1076                    Element rootElement = document.addElement("ratings");
1077    
1078                    Map<String, List<RatingsEntry>> ratingsEntriesMap =
1079                            portletDataContext.getRatingsEntries();
1080    
1081                    for (Map.Entry<String, List<RatingsEntry>> entry :
1082                                    ratingsEntriesMap.entrySet()) {
1083    
1084                            String[] ratingsEntryParts = StringUtil.split(
1085                                    entry.getKey(), CharPool.POUND);
1086    
1087                            String className = ratingsEntryParts[0];
1088                            String classPK = ratingsEntryParts[1];
1089    
1090                            String ratingsEntriesPath = getRatingsEntriesPath(
1091                                    portletDataContext, className, classPK);
1092    
1093                            Element assetElement = rootElement.addElement("asset");
1094    
1095                            assetElement.addAttribute("path", ratingsEntriesPath);
1096                            assetElement.addAttribute("class-name", className);
1097                            assetElement.addAttribute("class-pk", classPK);
1098    
1099                            List<RatingsEntry> ratingsEntries = entry.getValue();
1100    
1101                            for (RatingsEntry ratingsEntry : ratingsEntries) {
1102                                    String ratingsEntryPath = getRatingsEntryPath(
1103                                            portletDataContext, className, classPK, ratingsEntry);
1104    
1105                                    portletDataContext.addZipEntry(ratingsEntryPath, ratingsEntry);
1106                            }
1107                    }
1108    
1109                    portletDataContext.addZipEntry(
1110                            portletDataContext.getRootPath() + "/ratings.xml",
1111                            document.formattedString());
1112            }
1113    
1114            protected String getAssetCategoryPath(
1115                    PortletDataContext portletDataContext, long assetCategoryId) {
1116    
1117                    StringBundler sb = new StringBundler(6);
1118    
1119                    sb.append(portletDataContext.getRootPath());
1120                    sb.append("/categories/");
1121                    sb.append(assetCategoryId);
1122                    sb.append(".xml");
1123    
1124                    return sb.toString();
1125            }
1126    
1127            protected String getAssetVocabulariesPath(
1128                    PortletDataContext portletDataContext, long assetVocabularyId) {
1129    
1130                    StringBundler sb = new StringBundler(8);
1131    
1132                    sb.append(portletDataContext.getRootPath());
1133                    sb.append("/vocabularies/");
1134                    sb.append(assetVocabularyId);
1135                    sb.append(".xml");
1136    
1137                    return sb.toString();
1138            }
1139    
1140            protected String getCommentPath(
1141                    PortletDataContext portletDataContext, String className, String classPK,
1142                    MBMessage mbMessage) {
1143    
1144                    StringBundler sb = new StringBundler(8);
1145    
1146                    sb.append(portletDataContext.getRootPath());
1147                    sb.append("/comments/");
1148                    sb.append(PortalUtil.getClassNameId(className));
1149                    sb.append(CharPool.FORWARD_SLASH);
1150                    sb.append(classPK);
1151                    sb.append(CharPool.FORWARD_SLASH);
1152                    sb.append(mbMessage.getMessageId());
1153                    sb.append(".xml");
1154    
1155                    return sb.toString();
1156            }
1157    
1158            protected String getCommentsPath(
1159                    PortletDataContext portletDataContext, String className,
1160                    String classPK) {
1161    
1162                    StringBundler sb = new StringBundler(6);
1163    
1164                    sb.append(portletDataContext.getRootPath());
1165                    sb.append("/comments/");
1166                    sb.append(PortalUtil.getClassNameId(className));
1167                    sb.append(CharPool.FORWARD_SLASH);
1168                    sb.append(classPK);
1169                    sb.append(CharPool.FORWARD_SLASH);
1170    
1171                    return sb.toString();
1172            }
1173    
1174            protected String getLockPath(
1175                    PortletDataContext portletDataContext, String className, String key,
1176                    Lock lock) {
1177    
1178                    StringBundler sb = new StringBundler(8);
1179    
1180                    sb.append(portletDataContext.getRootPath());
1181                    sb.append("/locks/");
1182                    sb.append(PortalUtil.getClassNameId(className));
1183                    sb.append(CharPool.FORWARD_SLASH);
1184                    sb.append(key);
1185                    sb.append(CharPool.FORWARD_SLASH);
1186                    sb.append(lock.getLockId());
1187                    sb.append(".xml");
1188    
1189                    return sb.toString();
1190            }
1191    
1192            protected String getPortletDataPath(
1193                    PortletDataContext portletDataContext, String portletId) {
1194    
1195                    return portletDataContext.getPortletPath(portletId) +
1196                            "/portlet-data.xml";
1197            }
1198    
1199            protected String getPortletPreferencesPath(
1200                    PortletDataContext portletDataContext, String portletId, long ownerId,
1201                    int ownerType, long plid) {
1202    
1203                    StringBundler sb = new StringBundler(8);
1204    
1205                    sb.append(portletDataContext.getPortletPath(portletId));
1206                    sb.append("/preferences/");
1207    
1208                    if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
1209                            sb.append("company/");
1210                    }
1211                    else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
1212                            sb.append("group/");
1213                    }
1214                    else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT) {
1215                            sb.append("layout/");
1216                    }
1217                    else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) {
1218                            sb.append("user/");
1219                    }
1220                    else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
1221                            sb.append("archived/");
1222                    }
1223    
1224                    sb.append(ownerId);
1225                    sb.append(CharPool.FORWARD_SLASH);
1226                    sb.append(plid);
1227                    sb.append(CharPool.FORWARD_SLASH);
1228                    sb.append("portlet-preferences.xml");
1229    
1230                    return sb.toString();
1231            }
1232    
1233            protected String getRatingsEntriesPath(
1234                    PortletDataContext portletDataContext, String className,
1235                    String classPK) {
1236    
1237                    StringBundler sb = new StringBundler(6);
1238    
1239                    sb.append(portletDataContext.getRootPath());
1240                    sb.append("/ratings/");
1241                    sb.append(PortalUtil.getClassNameId(className));
1242                    sb.append(CharPool.FORWARD_SLASH);
1243                    sb.append(classPK);
1244                    sb.append(CharPool.FORWARD_SLASH);
1245    
1246                    return sb.toString();
1247            }
1248    
1249            protected String getRatingsEntryPath(
1250                    PortletDataContext portletDataContext, String className, String classPK,
1251                    RatingsEntry ratingsEntry) {
1252    
1253                    StringBundler sb = new StringBundler(8);
1254    
1255                    sb.append(portletDataContext.getRootPath());
1256                    sb.append("/ratings/");
1257                    sb.append(PortalUtil.getClassNameId(className));
1258                    sb.append(CharPool.FORWARD_SLASH);
1259                    sb.append(classPK);
1260                    sb.append(CharPool.FORWARD_SLASH);
1261                    sb.append(ratingsEntry.getEntryId());
1262                    sb.append(".xml");
1263    
1264                    return sb.toString();
1265            }
1266    
1267            private static Log _log = LogFactoryUtil.getLog(PortletExporter.class);
1268    
1269            private PermissionExporter _permissionExporter = new PermissionExporter();
1270    
1271    }