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