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