protected void exportAssetLinks(PortletDataContext portletDataContext) throws Exception {

    Document document = SAXReaderUtil.createDocument();

    Element rootElement = document.addElement("links");

    Element exportDataRootElement = portletDataContext.getExportDataRootElement();

    try {
      portletDataContext.setExportDataRootElement(rootElement);

      ActionableDynamicQuery linkActionableDynamicQuery =
          _assetLinkLocalService.getExportActionbleDynamicQuery(portletDataContext);

      linkActionableDynamicQuery.performActions();

      for (long linkId : portletDataContext.getAssetLinkIds()) {
        AssetLink assetLink = _assetLinkLocalService.getAssetLink(linkId);

        StagedAssetLink stagedAssetLink =
            ModelAdapterUtil.adapt(assetLink, AssetLink.class, StagedAssetLink.class);

        portletDataContext.addClassedModel(
            portletDataContext.getExportDataElement(stagedAssetLink),
            ExportImportPathUtil.getModelPath(stagedAssetLink),
            stagedAssetLink);
      }
    } finally {
      portletDataContext.setExportDataRootElement(exportDataRootElement);
    }

    portletDataContext.addZipEntry(
        ExportImportPathUtil.getRootPath(portletDataContext) + "/links.xml",
        document.formattedString());
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, WikiPage page)
      throws Exception {

    Element pageElement = portletDataContext.getExportDataElement(page);

    StagedModelDataHandlerUtil.exportReferenceStagedModel(
        portletDataContext, page, page.getNode(), PortletDataContext.REFERENCE_TYPE_PARENT);

    String content =
        _wikiPageExportImportContentProcessor.replaceExportContentReferences(
            portletDataContext,
            page,
            page.getContent(),
            portletDataContext.getBooleanParameter("wiki", "referenced-content"),
            true);

    page.setContent(content);

    if (page.isHead()) {
      for (FileEntry fileEntry : page.getAttachmentsFileEntries()) {
        StagedModelDataHandlerUtil.exportReferenceStagedModel(
            portletDataContext, page, fileEntry, PortletDataContext.REFERENCE_TYPE_WEAK);
      }
    }

    WikiPageResource pageResource =
        _wikiPageResourceLocalService.getPageResource(page.getResourcePrimKey());

    pageElement.addAttribute("page-resource-uuid", pageResource.getUuid());

    portletDataContext.addClassedModel(pageElement, ExportImportPathUtil.getModelPath(page), page);
  }
  protected void readExpandoTables(PortletDataContext portletDataContext) throws Exception {

    String xml =
        portletDataContext.getZipEntryAsString(
            ExportImportPathUtil.getSourceRootPath(portletDataContext) + "/expando-tables.xml");

    if (xml == null) {
      return;
    }

    Document document = SAXReaderUtil.read(xml);

    Element rootElement = document.getRootElement();

    List<Element> expandoTableElements = rootElement.elements("expando-table");

    for (Element expandoTableElement : expandoTableElements) {
      String className = expandoTableElement.attributeValue("class-name");

      ExpandoTable expandoTable = null;

      try {
        expandoTable =
            _expandoTableLocalService.getDefaultTable(portletDataContext.getCompanyId(), className);
      } catch (NoSuchTableException nste) {
        expandoTable =
            _expandoTableLocalService.addDefaultTable(portletDataContext.getCompanyId(), className);
      }

      List<Element> expandoColumnElements = expandoTableElement.elements("expando-column");

      for (Element expandoColumnElement : expandoColumnElements) {
        long columnId = GetterUtil.getLong(expandoColumnElement.attributeValue("column-id"));
        String name = expandoColumnElement.attributeValue("name");
        int type = GetterUtil.getInteger(expandoColumnElement.attributeValue("type"));
        String defaultData = expandoColumnElement.elementText("default-data");
        String typeSettings = expandoColumnElement.elementText("type-settings");

        Serializable defaultDataObject =
            ExpandoConverterUtil.getAttributeFromString(type, defaultData);

        ExpandoColumn expandoColumn =
            _expandoColumnLocalService.getColumn(expandoTable.getTableId(), name);

        if (expandoColumn != null) {
          _expandoColumnLocalService.updateColumn(
              expandoColumn.getColumnId(), name, type, defaultDataObject);
        } else {
          expandoColumn =
              _expandoColumnLocalService.addColumn(
                  expandoTable.getTableId(), name, type, defaultDataObject);
        }

        _expandoColumnLocalService.updateTypeSettings(expandoColumn.getColumnId(), typeSettings);

        portletDataContext.importPermissions(
            ExpandoColumn.class, columnId, expandoColumn.getColumnId());
      }
    }
  }
  @Override
  protected void doExportStagedModel(
      PortletDataContext portletDataContext, MDRRuleGroupInstance ruleGroupInstance)
      throws Exception {

    MDRRuleGroup ruleGroup =
        _mdrRuleGroupLocalService.getRuleGroup(ruleGroupInstance.getRuleGroupId());

    StagedModelDataHandlerUtil.exportReferenceStagedModel(
        portletDataContext, ruleGroupInstance, ruleGroup, PortletDataContext.REFERENCE_TYPE_PARENT);

    Element ruleGroupInstanceElement = portletDataContext.getExportDataElement(ruleGroupInstance);

    String className = ruleGroupInstance.getClassName();

    if (className.equals(Layout.class.getName())) {
      Layout layout = _layoutLocalService.getLayout(ruleGroupInstance.getClassPK());

      ruleGroupInstanceElement.addAttribute("layout-uuid", layout.getUuid());
    }

    portletDataContext.addClassedModel(
        ruleGroupInstanceElement,
        ExportImportPathUtil.getModelPath(ruleGroupInstance),
        ruleGroupInstance);
  }
  protected void exportLocks(PortletDataContext portletDataContext) throws Exception {

    Document document = SAXReaderUtil.createDocument();

    Element rootElement = document.addElement("locks");

    Map<String, Lock> locksMap = portletDataContext.getLocks();

    for (Map.Entry<String, Lock> entry : locksMap.entrySet()) {
      Lock lock = entry.getValue();

      String entryKey = entry.getKey();

      int pos = entryKey.indexOf(CharPool.POUND);

      String className = entryKey.substring(0, pos);
      String key = entryKey.substring(pos + 1);

      String path = getLockPath(portletDataContext, className, key, lock);

      Element assetElement = rootElement.addElement("asset");

      assetElement.addAttribute("path", path);
      assetElement.addAttribute("class-name", className);
      assetElement.addAttribute("key", key);

      portletDataContext.addZipEntry(path, lock);
    }

    portletDataContext.addZipEntry(
        ExportImportPathUtil.getRootPath(portletDataContext) + "/locks.xml",
        document.formattedString());
  }
  protected void readLocks(PortletDataContext portletDataContext) throws Exception {

    String xml =
        portletDataContext.getZipEntryAsString(
            ExportImportPathUtil.getSourceRootPath(portletDataContext) + "/locks.xml");

    if (xml == null) {
      return;
    }

    Document document = SAXReaderUtil.read(xml);

    Element rootElement = document.getRootElement();

    List<Element> assetElements = rootElement.elements("asset");

    for (Element assetElement : assetElements) {
      String path = assetElement.attributeValue("path");
      String className = assetElement.attributeValue("class-name");
      String key = assetElement.attributeValue("key");

      Lock lock = (Lock) portletDataContext.getZipEntryAsObject(path);

      if (lock != null) {
        portletDataContext.addLocks(className, key, lock);
      }
    }
  }
  protected void importAssetLinks(PortletDataContext portletDataContext) throws Exception {

    String xml =
        portletDataContext.getZipEntryAsString(
            ExportImportPathUtil.getSourceRootPath(portletDataContext) + "/links.xml");

    if (xml == null) {
      return;
    }

    Element importDataRootElement = portletDataContext.getImportDataRootElement();

    try {
      Document document = SAXReaderUtil.read(xml);

      Element rootElement = document.getRootElement();

      portletDataContext.setImportDataRootElement(rootElement);

      Element linksElement = portletDataContext.getImportDataGroupElement(StagedAssetLink.class);

      List<Element> linkElements = linksElement.elements();

      for (Element linkElement : linkElements) {
        StagedModelDataHandlerUtil.importStagedModel(portletDataContext, linkElement);
      }
    } finally {
      portletDataContext.setImportDataRootElement(importDataRootElement);
    }
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, Gadget gadget)
      throws Exception {

    Element gadgetElement = portletDataContext.getExportDataElement(gadget);

    portletDataContext.addClassedModel(
        gadgetElement, ExportImportPathUtil.getModelPath(gadget), gadget);
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, KBTemplate kbTemplate)
      throws Exception {

    Element kbTemplateElement = portletDataContext.getExportDataElement(kbTemplate);

    portletDataContext.addClassedModel(
        kbTemplateElement, ExportImportPathUtil.getModelPath(kbTemplate), kbTemplate);
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, UserGroup userGroup)
      throws Exception {

    Element userGroupElement = portletDataContext.getExportDataElement(userGroup);

    portletDataContext.addClassedModel(
        userGroupElement, ExportImportPathUtil.getModelPath(userGroup), userGroup);
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, Calendar calendar)
      throws Exception {

    StagedModelDataHandlerUtil.exportReferenceStagedModel(
        portletDataContext,
        calendar,
        calendar.getCalendarResource(),
        PortletDataContext.REFERENCE_TYPE_STRONG);

    Element calendarElement = portletDataContext.getExportDataElement(calendar);

    portletDataContext.addClassedModel(
        calendarElement, ExportImportPathUtil.getModelPath(calendar), calendar);
  }
  @Override
  protected void doExportStagedModel(
      PortletDataContext portletDataContext, LayoutSetPrototype layoutSetPrototype)
      throws Exception {

    Element layoutSetPrototypeElement = portletDataContext.getExportDataElement(layoutSetPrototype);

    portletDataContext.addClassedModel(
        layoutSetPrototypeElement,
        ExportImportPathUtil.getModelPath(layoutSetPrototype),
        layoutSetPrototype);

    exportLayouts(layoutSetPrototype, portletDataContext);

    exportLayoutPrototypes(portletDataContext, layoutSetPrototype, layoutSetPrototypeElement);
  }
  protected String getLockPath(
      PortletDataContext portletDataContext, String className, String key, Lock lock) {

    StringBundler sb = new StringBundler(8);

    sb.append(ExportImportPathUtil.getRootPath(portletDataContext));
    sb.append("/locks/");
    sb.append(PortalUtil.getClassNameId(className));
    sb.append(CharPool.FORWARD_SLASH);
    sb.append(key);
    sb.append(CharPool.FORWARD_SLASH);
    sb.append(lock.getLockId());
    sb.append(".xml");

    return sb.toString();
  }
  protected void importLayouts(
      PortletDataContext portletDataContext,
      LayoutSetPrototype layoutSetPrototype,
      LayoutSetPrototype importedLayoutSetPrototype,
      ServiceContext serviceContext)
      throws PortalException {

    InputStream inputStream = null;

    try {
      String layoutSetPrototypeLARPath =
          ExportImportPathUtil.getModelPath(
              layoutSetPrototype, getLayoutSetPrototypeLARFileName(layoutSetPrototype));

      inputStream = portletDataContext.getZipEntryAsInputStream(layoutSetPrototypeLARPath);

      SitesUtil.importLayoutSetPrototype(importedLayoutSetPrototype, inputStream, serviceContext);
    } finally {
      StreamUtil.cleanUp(inputStream);
    }
  }
  protected void exportLayouts(
      LayoutSetPrototype layoutSetPrototype, PortletDataContext portletDataContext)
      throws Exception {

    File file = null;
    InputStream inputStream = null;

    try {
      file = SitesUtil.exportLayoutSetPrototype(layoutSetPrototype, new ServiceContext());

      inputStream = new FileInputStream(file);

      String layoutSetPrototypeLARPath =
          ExportImportPathUtil.getModelPath(
              layoutSetPrototype, getLayoutSetPrototypeLARFileName(layoutSetPrototype));

      portletDataContext.addZipEntry(layoutSetPrototypeLARPath, inputStream);

      List<Layout> layoutSetPrototypeLayouts =
          _layoutLocalService.getLayouts(layoutSetPrototype.getGroupId(), true);

      Element layoutSetPrototypeElement =
          portletDataContext.getExportDataElement(layoutSetPrototype);

      for (Layout layoutSetPrototypeLayout : layoutSetPrototypeLayouts) {
        portletDataContext.addReferenceElement(
            layoutSetPrototype,
            layoutSetPrototypeElement,
            layoutSetPrototypeLayout,
            PortletDataContext.REFERENCE_TYPE_EMBEDDED,
            false);
      }
    } finally {
      StreamUtil.cleanUp(inputStream);

      if (file != null) {
        file.delete();
      }
    }
  }
  protected void exportExpandoTables(PortletDataContext portletDataContext) throws Exception {

    Document document = SAXReaderUtil.createDocument();

    Element rootElement = document.addElement("expando-tables");

    Map<String, List<ExpandoColumn>> expandoColumnsMap = portletDataContext.getExpandoColumns();

    for (Map.Entry<String, List<ExpandoColumn>> entry : expandoColumnsMap.entrySet()) {

      String className = entry.getKey();

      Element expandoTableElement = rootElement.addElement("expando-table");

      expandoTableElement.addAttribute("class-name", className);

      List<ExpandoColumn> expandoColumns = entry.getValue();

      for (ExpandoColumn expandoColumn : expandoColumns) {
        Element expandoColumnElement = expandoTableElement.addElement("expando-column");

        expandoColumnElement.addAttribute("column-id", String.valueOf(expandoColumn.getColumnId()));
        expandoColumnElement.addAttribute("name", expandoColumn.getName());
        expandoColumnElement.addAttribute("type", String.valueOf(expandoColumn.getType()));

        DocUtil.add(expandoColumnElement, "default-data", expandoColumn.getDefaultData());

        Element typeSettingsElement = expandoColumnElement.addElement("type-settings");

        UnicodeProperties typeSettingsProperties = expandoColumn.getTypeSettingsProperties();

        typeSettingsElement.addCDATA(typeSettingsProperties.toString());
      }
    }

    portletDataContext.addZipEntry(
        ExportImportPathUtil.getRootPath(portletDataContext) + "/expando-tables.xml",
        document.formattedString());
  }
  @Override
  protected void doExportStagedModel(PortletDataContext portletDataContext, MDRAction action)
      throws Exception {

    MDRRuleGroupInstance ruleGroupInstance =
        _mdrRuleGroupInstanceLocalService.getRuleGroupInstance(action.getRuleGroupInstanceId());

    StagedModelDataHandlerUtil.exportReferenceStagedModel(
        portletDataContext, action, ruleGroupInstance, PortletDataContext.REFERENCE_TYPE_PARENT);

    Element actionElement = portletDataContext.getExportDataElement(action);

    String type = action.getType();

    if (type.equals(SiteRedirectActionHandler.class.getName())) {
      UnicodeProperties typeSettingsProperties = action.getTypeSettingsProperties();

      long plid = GetterUtil.getLong(typeSettingsProperties.getProperty("plid"));

      try {
        Layout layout = _layoutLocalService.getLayout(plid);

        actionElement.addAttribute("layout-uuid", layout.getUuid());
      } catch (Exception e) {
        if (_log.isWarnEnabled()) {
          _log.warn(
              "Unable to set the layout uuid of layout "
                  + plid
                  + ". Site redirect may not match after import.",
              e);
        }
      }
    }

    portletDataContext.addClassedModel(
        actionElement, ExportImportPathUtil.getModelPath(action), action);
  }
  protected File doExport(PortletDataContext portletDataContext, long[] layoutIds)
      throws Exception {

    Map<String, String[]> parameterMap = portletDataContext.getParameterMap();

    boolean ignoreLastPublishDate =
        MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
    boolean layoutSetPrototypeSettings =
        MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_SETTINGS);
    boolean layoutSetSettings =
        MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
    boolean logo = MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.LOGO);
    boolean permissions = MapUtil.getBoolean(parameterMap, PortletDataHandlerKeys.PERMISSIONS);

    if (_log.isDebugEnabled()) {
      _log.debug("Export permissions " + permissions);
    }

    LayoutSet layoutSet =
        _layoutSetLocalService.getLayoutSet(
            portletDataContext.getGroupId(), portletDataContext.isPrivateLayout());

    long companyId = layoutSet.getCompanyId();
    long defaultUserId = _userLocalService.getDefaultUserId(companyId);

    ServiceContext serviceContext = ServiceContextThreadLocal.popServiceContext();

    if (serviceContext == null) {
      serviceContext = new ServiceContext();
    }

    serviceContext.setCompanyId(companyId);
    serviceContext.setSignedIn(false);
    serviceContext.setUserId(defaultUserId);

    serviceContext.setAttribute("exporting", Boolean.TRUE);

    long layoutSetBranchId = MapUtil.getLong(parameterMap, "layoutSetBranchId");

    serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);

    ServiceContextThreadLocal.pushServiceContext(serviceContext);

    if (ignoreLastPublishDate) {
      portletDataContext.setEndDate(null);
      portletDataContext.setStartDate(null);
    }

    StopWatch stopWatch = new StopWatch();

    stopWatch.start();

    Document document = SAXReaderUtil.createDocument();

    Element rootElement = document.addElement("root");

    portletDataContext.setExportDataRootElement(rootElement);

    Element headerElement = rootElement.addElement("header");

    headerElement.addAttribute(
        "available-locales",
        StringUtil.merge(LanguageUtil.getAvailableLocales(portletDataContext.getScopeGroupId())));
    headerElement.addAttribute("build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
    headerElement.addAttribute("export-date", Time.getRFC822());

    if (portletDataContext.hasDateRange()) {
      headerElement.addAttribute("start-date", String.valueOf(portletDataContext.getStartDate()));
      headerElement.addAttribute("end-date", String.valueOf(portletDataContext.getEndDate()));
    }

    headerElement.addAttribute("company-id", String.valueOf(portletDataContext.getCompanyId()));
    headerElement.addAttribute(
        "company-group-id", String.valueOf(portletDataContext.getCompanyGroupId()));
    headerElement.addAttribute("group-id", String.valueOf(portletDataContext.getGroupId()));
    headerElement.addAttribute(
        "user-personal-site-group-id",
        String.valueOf(portletDataContext.getUserPersonalSiteGroupId()));
    headerElement.addAttribute(
        "private-layout", String.valueOf(portletDataContext.isPrivateLayout()));

    Group group = layoutSet.getGroup();

    String type = "layout-set";

    if (group.isLayoutPrototype()) {
      type = "layout-prototype";

      LayoutPrototype layoutPrototype =
          _layoutPrototypeLocalService.getLayoutPrototype(group.getClassPK());

      headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());

      layoutIds =
          ExportImportHelperUtil.getAllLayoutIds(
              portletDataContext.getGroupId(), portletDataContext.isPrivateLayout());
    } else if (group.isLayoutSetPrototype()) {
      type = "layout-set-prototype";

      LayoutSetPrototype layoutSetPrototype =
          _layoutSetPrototypeLocalService.getLayoutSetPrototype(group.getClassPK());

      headerElement.addAttribute("type-uuid", layoutSetPrototype.getUuid());
    }

    headerElement.addAttribute("type", type);

    LayoutSetBranch layoutSetBranch =
        _layoutSetBranchLocalService.fetchLayoutSetBranch(layoutSetBranchId);

    if (logo) {
      Image image = null;

      if (layoutSetBranch != null) {
        image = _imageLocalService.getImage(layoutSetBranch.getLogoId());
      } else {
        image = _imageLocalService.getImage(layoutSet.getLogoId());
      }

      if ((image != null) && (image.getTextObj() != null)) {
        String logoPath = ExportImportPathUtil.getRootPath(portletDataContext);

        logoPath += "/logo";

        headerElement.addAttribute("logo-path", logoPath);

        portletDataContext.addZipEntry(logoPath, image.getTextObj());
      }
    }

    String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();

    if (layoutSetPrototypeSettings && Validator.isNotNull(layoutSetPrototypeUuid)) {

      LayoutSetPrototype layoutSetPrototype =
          _layoutSetPrototypeLocalService.getLayoutSetPrototypeByUuidAndCompanyId(
              layoutSetPrototypeUuid, companyId);

      headerElement.addAttribute("layout-set-prototype-uuid", layoutSetPrototypeUuid);
      headerElement.addAttribute(
          "layout-set-prototype-name", layoutSetPrototype.getName(LocaleUtil.getDefault()));
    }

    Element missingReferencesElement = rootElement.addElement("missing-references");

    portletDataContext.setMissingReferencesElement(missingReferencesElement);

    if (layoutSetBranch != null) {
      _themeExporter.exportTheme(portletDataContext, layoutSetBranch);
    } else {
      _themeExporter.exportTheme(portletDataContext, layoutSet);
    }

    if (layoutSetSettings) {
      Element settingsElement = headerElement.addElement("settings");

      if (layoutSetBranch != null) {
        settingsElement.addCDATA(layoutSetBranch.getSettings());
      } else {
        settingsElement.addCDATA(layoutSet.getSettings());
      }
    }

    Map<String, Object[]> portletIds = new LinkedHashMap<>();

    List<Layout> layouts =
        _layoutLocalService.getLayouts(
            portletDataContext.getGroupId(), portletDataContext.isPrivateLayout());

    if (group.isStagingGroup()) {
      group = group.getLiveGroup();
    }

    // Collect data portlets

    for (Portlet portlet : ExportImportHelperUtil.getDataSiteLevelPortlets(companyId)) {

      String portletId = portlet.getRootPortletId();

      if (ExportImportThreadLocal.isStagingInProcess() && !group.isStagedPortlet(portletId)) {

        continue;
      }

      // Calculate the amount of exported data

      if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
        PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

        portletDataHandler.prepareManifestSummary(portletDataContext);
      }

      // Add portlet ID to exportable portlets list

      portletIds.put(
          PortletPermissionUtil.getPrimaryKey(0, portletId),
          new Object[] {
            portletId,
            LayoutConstants.DEFAULT_PLID,
            portletDataContext.getGroupId(),
            StringPool.BLANK,
            StringPool.BLANK
          });

      if (!portlet.isScopeable()) {
        continue;
      }

      // Scoped data

      for (Layout layout : layouts) {
        if (!ArrayUtil.contains(layoutIds, layout.getLayoutId())
            || !layout.isTypePortlet()
            || !layout.hasScopeGroup()) {

          continue;
        }

        Group scopeGroup = layout.getScopeGroup();

        portletIds.put(
            PortletPermissionUtil.getPrimaryKey(layout.getPlid(), portlet.getPortletId()),
            new Object[] {
              portlet.getPortletId(),
              layout.getPlid(),
              scopeGroup.getGroupId(),
              StringPool.BLANK,
              layout.getUuid()
            });
      }
    }

    // Collect layout portlets

    for (Layout layout : layouts) {
      getLayoutPortlets(portletDataContext, layoutIds, portletIds, layout);
    }

    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
      ManifestSummary manifestSummary = portletDataContext.getManifestSummary();

      PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
          "layout", ArrayUtil.toStringArray(portletIds.keySet()), manifestSummary);

      manifestSummary.resetCounters();
    }

    // Export actual data

    portletDataContext.addDeletionSystemEventStagedModelTypes(new StagedModelType(Layout.class));

    // Force to always have a layout group element

    portletDataContext.getExportDataGroupElement(Layout.class);

    for (Layout layout : layouts) {
      exportLayout(portletDataContext, layoutIds, layout);
    }

    Element portletsElement = rootElement.addElement("portlets");

    Element servicesElement = rootElement.addElement("services");

    long previousScopeGroupId = portletDataContext.getScopeGroupId();

    for (Map.Entry<String, Object[]> portletIdsEntry : portletIds.entrySet()) {

      Object[] portletObjects = portletIdsEntry.getValue();

      String portletId = null;
      long plid = LayoutConstants.DEFAULT_PLID;
      long scopeGroupId = 0;
      String scopeType = StringPool.BLANK;
      String scopeLayoutUuid = null;

      if (portletObjects.length == 4) {
        portletId = (String) portletIdsEntry.getValue()[0];
        plid = (Long) portletIdsEntry.getValue()[1];
        scopeGroupId = (Long) portletIdsEntry.getValue()[2];
        scopeLayoutUuid = (String) portletIdsEntry.getValue()[3];
      } else {
        portletId = (String) portletIdsEntry.getValue()[0];
        plid = (Long) portletIdsEntry.getValue()[1];
        scopeGroupId = (Long) portletIdsEntry.getValue()[2];
        scopeType = (String) portletIdsEntry.getValue()[3];
        scopeLayoutUuid = (String) portletIdsEntry.getValue()[4];
      }

      Layout layout = _layoutLocalService.fetchLayout(plid);

      if (layout == null) {
        layout = new LayoutImpl();

        layout.setCompanyId(companyId);
        layout.setGroupId(portletDataContext.getGroupId());
      }

      portletDataContext.setPlid(plid);
      portletDataContext.setOldPlid(plid);
      portletDataContext.setPortletId(portletId);
      portletDataContext.setScopeGroupId(scopeGroupId);
      portletDataContext.setScopeType(scopeType);
      portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);

      Map<String, Boolean> exportPortletControlsMap =
          ExportImportHelperUtil.getExportPortletControlsMap(
              companyId, portletId, parameterMap, type);

      try {
        _exportImportLifecycleManager.fireExportImportLifecycleEvent(
            EVENT_PORTLET_EXPORT_STARTED,
            getProcessFlag(),
            PortletDataContextFactoryUtil.clonePortletDataContext(portletDataContext));

        _portletExportController.exportPortlet(
            portletDataContext,
            layout,
            portletsElement,
            permissions,
            exportPortletControlsMap.get(PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS),
            exportPortletControlsMap.get(PortletDataHandlerKeys.PORTLET_DATA),
            exportPortletControlsMap.get(PortletDataHandlerKeys.PORTLET_SETUP),
            exportPortletControlsMap.get(PortletDataHandlerKeys.PORTLET_USER_PREFERENCES));
        _portletExportController.exportService(
            portletDataContext,
            servicesElement,
            exportPortletControlsMap.get(PortletDataHandlerKeys.PORTLET_SETUP));

        _exportImportLifecycleManager.fireExportImportLifecycleEvent(
            EVENT_PORTLET_EXPORT_SUCCEEDED,
            getProcessFlag(),
            PortletDataContextFactoryUtil.clonePortletDataContext(portletDataContext));
      } catch (Throwable t) {
        _exportImportLifecycleManager.fireExportImportLifecycleEvent(
            EVENT_PORTLET_EXPORT_FAILED,
            getProcessFlag(),
            PortletDataContextFactoryUtil.clonePortletDataContext(portletDataContext),
            t);

        throw t;
      }
    }

    portletDataContext.setScopeGroupId(previousScopeGroupId);

    _portletExportController.exportAssetLinks(portletDataContext);
    _portletExportController.exportExpandoTables(portletDataContext);
    _portletExportController.exportLocks(portletDataContext);

    _deletionSystemEventExporter.exportDeletionSystemEvents(portletDataContext);

    if (permissions) {
      _permissionExporter.exportPortletDataPermissions(portletDataContext);
    }

    ExportImportHelperUtil.writeManifestSummary(document, portletDataContext.getManifestSummary());

    if (_log.isInfoEnabled()) {
      _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
    }

    boolean updateLastPublishDate =
        MapUtil.getBoolean(
            portletDataContext.getParameterMap(), PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);

    if (ExportImportThreadLocal.isStagingInProcess() && updateLastPublishDate) {

      ExportImportProcessCallbackRegistryUtil.registerCallback(
          new UpdateLayoutSetLastPublishDateCallable(
              portletDataContext.getDateRange(),
              portletDataContext.getGroupId(),
              portletDataContext.isPrivateLayout()));
    }

    portletDataContext.addZipEntry("/manifest.xml", document.formattedString());

    ZipWriter zipWriter = portletDataContext.getZipWriter();

    return zipWriter.getFile();
  }
  protected void exportServicePortletPreference(
      PortletDataContext portletDataContext,
      long ownerId,
      int ownerType,
      PortletPreferences portletPreferences,
      String serviceName,
      Element parentElement)
      throws Exception {

    String path =
        ExportImportPathUtil.getServicePortletPreferencesPath(
            portletDataContext, serviceName, ownerId, ownerType);

    if (portletDataContext.isPathProcessed(path)) {
      return;
    }

    String preferencesXML = portletPreferences.getPreferences();

    if (Validator.isNull(preferencesXML)) {
      preferencesXML = PortletConstants.DEFAULT_PREFERENCES;
    }

    javax.portlet.PortletPreferences jxPortletPreferences =
        PortletPreferencesFactoryUtil.fromDefaultXML(preferencesXML);

    Element serviceElement = parentElement.addElement("service");

    serviceElement.addAttribute("service-name", serviceName);

    Document document =
        SAXReaderUtil.read(PortletPreferencesFactoryUtil.toXML(jxPortletPreferences));

    Element rootElement = document.getRootElement();

    rootElement.addAttribute("owner-id", String.valueOf(ownerId));
    rootElement.addAttribute("owner-type", String.valueOf(ownerType));
    rootElement.addAttribute("default-user", String.valueOf(false));
    rootElement.addAttribute("service-name", serviceName);

    if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
      PortletItem portletItem = _portletItemLocalService.getPortletItem(ownerId);

      rootElement.addAttribute("archive-user-uuid", portletItem.getUserUuid());
      rootElement.addAttribute("archive-name", portletItem.getName());
    } else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) {
      User user = _userLocalService.fetchUserById(ownerId);

      if (user == null) {
        return;
      }

      rootElement.addAttribute("user-uuid", user.getUserUuid());
    }

    List<Node> nodes =
        document.selectNodes(
            "/portlet-preferences/preference[name/text() = " + "'last-publish-date']");

    for (Node node : nodes) {
      document.remove(node);
    }

    serviceElement.addAttribute("path", path);

    portletDataContext.addZipEntry(path, document.formattedString());
  }
  public void exportPortletData(
      PortletDataContext portletDataContext,
      Portlet portlet,
      Layout layout,
      javax.portlet.PortletPreferences jxPortletPreferences,
      Element parentElement)
      throws Exception {

    if (portlet == null) {
      return;
    }

    PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

    if ((portletDataHandler == null) || portletDataHandler.isDataPortletInstanceLevel()) {

      return;
    }

    Group group = layout.getGroup();

    if (group.isStagingGroup()) {
      group = group.getLiveGroup();
    }

    String portletId = portlet.getPortletId();

    if (ExportImportThreadLocal.isStagingInProcess() && !group.isStagedPortlet(portletId)) {

      if (_log.isDebugEnabled()) {
        _log.debug(
            "Not exporting data for " + portletId + " because it is configured not to be staged");
      }

      return;
    }

    if (_log.isDebugEnabled()) {
      _log.debug("Exporting data for " + portletId);
    }

    StringBundler sb = new StringBundler(4);

    sb.append(ExportImportPathUtil.getPortletPath(portletDataContext, portletId));
    sb.append(StringPool.SLASH);

    if (portlet.isPreferencesUniquePerLayout()) {
      sb.append(layout.getPlid());
    } else {
      sb.append(portletDataContext.getScopeGroupId());
    }

    sb.append("/portlet-data.xml");

    String path = sb.toString();

    if (portletDataContext.hasPrimaryKey(String.class, path)) {
      return;
    }

    Date originalStartDate = portletDataContext.getStartDate();

    Date portletLastPublishDate =
        ExportImportDateUtil.getLastPublishDate(portletDataContext, jxPortletPreferences);

    portletDataContext.setStartDate(portletLastPublishDate);

    long groupId = portletDataContext.getGroupId();

    portletDataContext.setGroupId(portletDataContext.getScopeGroupId());

    portletDataContext.clearScopedPrimaryKeys();

    String data = null;

    try {
      data = portletDataHandler.exportData(portletDataContext, portletId, jxPortletPreferences);
    } catch (PortletDataException pde) {
      throw pde;
    } catch (Exception e) {
      throw new SystemException(e);
    } finally {
      portletDataContext.setGroupId(groupId);
      portletDataContext.setStartDate(originalStartDate);
    }

    if (Validator.isNull(data)) {
      if (_log.isDebugEnabled()) {
        _log.debug("Not exporting data for " + portletId + " because null data was returned");
      }

      return;
    }

    Element portletDataElement = parentElement.addElement("portlet-data");

    portletDataElement.addAttribute("path", path);

    portletDataContext.addZipEntry(path, data);

    boolean updateLastPublishDate =
        MapUtil.getBoolean(
            portletDataContext.getParameterMap(), PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);

    if (ExportImportThreadLocal.isStagingInProcess() && updateLastPublishDate) {

      DateRange adjustedDateRange =
          new DateRange(portletLastPublishDate, portletDataContext.getEndDate());

      ExportImportProcessCallbackRegistryUtil.registerCallback(
          new UpdatePortletLastPublishDateCallable(
              adjustedDateRange,
              portletDataContext.getEndDate(),
              portletDataContext.getGroupId(),
              layout.getPlid(),
              portletId));
    }
  }
  protected void exportPortlet(
      PortletDataContext portletDataContext,
      Layout layout,
      Element parentElement,
      boolean exportPermissions,
      boolean exportPortletArchivedSetups,
      boolean exportPortletData,
      boolean exportPortletSetup,
      boolean exportPortletUserPreferences)
      throws Exception {

    long plid = PortletKeys.PREFS_OWNER_ID_DEFAULT;
    long layoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;

    if (layout != null) {
      plid = layout.getPlid();
      layoutId = layout.getLayoutId();
    }

    Portlet portlet =
        _portletLocalService.getPortletById(
            portletDataContext.getCompanyId(), portletDataContext.getPortletId());

    if ((portlet == null) || portlet.isUndeployedPortlet()) {
      if (_log.isDebugEnabled()) {
        _log.debug(
            "Do not export portlet "
                + portletDataContext.getPortletId()
                + " because the portlet is not deployed");
      }

      return;
    }

    if (!portlet.isInstanceable()
        && !portlet.isPreferencesUniquePerLayout()
        && portletDataContext.hasNotUniquePerLayout(portletDataContext.getPortletId())) {

      return;
    }

    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
      PortletDataContext clonedPortletDataContext =
          PortletDataContextFactoryUtil.clonePortletDataContext(portletDataContext);

      ManifestSummary manifestSummary = clonedPortletDataContext.getManifestSummary();

      manifestSummary.resetCounters();

      PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

      portletDataHandler.prepareManifestSummary(clonedPortletDataContext);

      PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
          "portlet", portletDataContext.getPortletId(), manifestSummary);
    }

    Document document = SAXReaderUtil.createDocument();

    Element portletElement = document.addElement("portlet");

    portletElement.addAttribute("portlet-id", portletDataContext.getPortletId());
    portletElement.addAttribute("root-portlet-id", portletDataContext.getRootPortletId());
    portletElement.addAttribute("old-plid", String.valueOf(plid));
    portletElement.addAttribute(
        "scope-group-id", String.valueOf(portletDataContext.getScopeGroupId()));
    portletElement.addAttribute("scope-layout-type", portletDataContext.getScopeType());
    portletElement.addAttribute("scope-layout-uuid", portletDataContext.getScopeLayoutUuid());
    portletElement.addAttribute("private-layout", String.valueOf(layout.isPrivateLayout()));

    // Data

    if (exportPortletData) {
      javax.portlet.PortletPreferences jxPortletPreferences = null;

      if (ExportImportThreadLocal.isInitialLayoutStagingInProcess()) {
        Group liveGroup = layout.getGroup();

        Group stagingGroup = liveGroup.getStagingGroup();

        layout.setGroupId(stagingGroup.getGroupId());

        jxPortletPreferences =
            PortletPreferencesFactoryUtil.getStrictPortletSetup(
                layout, portletDataContext.getPortletId());

        layout.setGroupId(liveGroup.getGroupId());
      } else {
        jxPortletPreferences =
            PortletPreferencesFactoryUtil.getStrictPortletSetup(
                layout, portletDataContext.getPortletId());
      }

      if (!portlet.isPreferencesUniquePerLayout()) {
        StringBundler sb = new StringBundler(5);

        sb.append(portletDataContext.getPortletId());
        sb.append(StringPool.AT);
        sb.append(portletDataContext.getScopeType());
        sb.append(StringPool.AT);
        sb.append(portletDataContext.getScopeLayoutUuid());

        String dataKey = sb.toString();

        if (!portletDataContext.hasNotUniquePerLayout(dataKey)) {
          portletDataContext.putNotUniquePerLayout(dataKey);

          exportPortletData(
              portletDataContext, portlet, layout, jxPortletPreferences, portletElement);
        }
      } else {
        exportPortletData(
            portletDataContext, portlet, layout, jxPortletPreferences, portletElement);
      }
    }

    // Portlet preferences

    if (exportPortletSetup) {

      // Company

      exportPortletPreferences(
          portletDataContext,
          portletDataContext.getCompanyId(),
          PortletKeys.PREFS_OWNER_TYPE_COMPANY,
          false,
          layout,
          plid,
          portlet.getRootPortletId(),
          portletElement);

      // Group

      exportPortletPreferences(
          portletDataContext,
          portletDataContext.getScopeGroupId(),
          PortletKeys.PREFS_OWNER_TYPE_GROUP,
          false,
          layout,
          PortletKeys.PREFS_PLID_SHARED,
          portlet.getRootPortletId(),
          portletElement);

      // Layout

      exportPortletPreferences(
          portletDataContext,
          PortletKeys.PREFS_OWNER_ID_DEFAULT,
          PortletKeys.PREFS_OWNER_TYPE_LAYOUT,
          false,
          layout,
          plid,
          portletDataContext.getPortletId(),
          portletElement);
    }

    // Portlet user preferences

    if (exportPortletUserPreferences) {
      List<PortletPreferences> portletPreferencesList =
          _portletPreferencesLocalService.getPortletPreferences(
              PortletKeys.PREFS_OWNER_TYPE_USER, plid, portletDataContext.getPortletId());

      for (PortletPreferences portletPreferences : portletPreferencesList) {

        boolean defaultUser = false;

        if (portletPreferences.getOwnerId() == PortletKeys.PREFS_OWNER_ID_DEFAULT) {

          defaultUser = true;
        }

        exportPortletPreferences(
            portletDataContext,
            portletPreferences.getOwnerId(),
            PortletKeys.PREFS_OWNER_TYPE_USER,
            defaultUser,
            layout,
            plid,
            portletDataContext.getPortletId(),
            portletElement);
      }

      try {
        PortletPreferences groupPortletPreferences =
            _portletPreferencesLocalService.getPortletPreferences(
                portletDataContext.getScopeGroupId(),
                PortletKeys.PREFS_OWNER_TYPE_GROUP,
                PortletKeys.PREFS_PLID_SHARED,
                portlet.getRootPortletId());

        exportPortletPreference(
            portletDataContext,
            portletDataContext.getScopeGroupId(),
            PortletKeys.PREFS_OWNER_TYPE_GROUP,
            false,
            groupPortletPreferences,
            portlet.getRootPortletId(),
            PortletKeys.PREFS_PLID_SHARED,
            portletElement);
      } catch (NoSuchPortletPreferencesException nsppe) {
      }
    }

    // Archived setups

    if (exportPortletArchivedSetups) {
      List<PortletItem> portletItems =
          _portletItemLocalService.getPortletItems(
              portletDataContext.getGroupId(),
              portletDataContext.getRootPortletId(),
              PortletPreferences.class.getName());

      for (PortletItem portletItem : portletItems) {
        exportPortletPreferences(
            portletDataContext,
            portletItem.getPortletItemId(),
            PortletKeys.PREFS_OWNER_TYPE_ARCHIVED,
            false,
            null,
            plid,
            portletItem.getPortletId(),
            portletElement);
      }
    }

    // Permissions

    if (exportPermissions) {
      _permissionExporter.exportPortletPermissions(
          portletDataContext, portletDataContext.getPortletId(), layout, portletElement);
    }

    // Zip

    StringBundler pathSB = new StringBundler(4);

    pathSB.append(ExportImportPathUtil.getPortletPath(portletDataContext));
    pathSB.append(StringPool.SLASH);
    pathSB.append(plid);
    pathSB.append("/portlet.xml");

    String path = pathSB.toString();

    Element element = parentElement.addElement("portlet");

    element.addAttribute("portlet-id", portletDataContext.getPortletId());
    element.addAttribute("layout-id", String.valueOf(layoutId));
    element.addAttribute("path", path);
    element.addAttribute("portlet-data", String.valueOf(exportPortletData));

    PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

    element.addAttribute("schema-version", portletDataHandler.getSchemaVersion());

    StringBundler configurationOptionsSB = new StringBundler(6);

    if (exportPortletSetup) {
      configurationOptionsSB.append("setup");
      configurationOptionsSB.append(StringPool.COMMA);
    }

    if (exportPortletArchivedSetups) {
      configurationOptionsSB.append("archived-setups");
      configurationOptionsSB.append(StringPool.COMMA);
    }

    if (exportPortletUserPreferences) {
      configurationOptionsSB.append("user-preferences");
      configurationOptionsSB.append(StringPool.COMMA);
    }

    if (configurationOptionsSB.index() > 0) {
      configurationOptionsSB.setIndex(configurationOptionsSB.index() - 1);
    }

    element.addAttribute("portlet-configuration", configurationOptionsSB.toString());

    try {
      portletDataContext.addZipEntry(path, document.formattedString());
    } catch (IOException ioe) {
      if (_log.isWarnEnabled()) {
        _log.warn(ioe.getMessage());
      }
    }
  }
  protected void exportPortletPreference(
      PortletDataContext portletDataContext,
      long ownerId,
      int ownerType,
      boolean defaultUser,
      PortletPreferences portletPreferences,
      String portletId,
      long plid,
      Element parentElement)
      throws Exception {

    String preferencesXML = portletPreferences.getPreferences();

    if (Validator.isNull(preferencesXML)) {
      preferencesXML = PortletConstants.DEFAULT_PREFERENCES;
    }

    javax.portlet.PortletPreferences jxPortletPreferences =
        PortletPreferencesFactoryUtil.fromDefaultXML(preferencesXML);

    Portlet portlet =
        _portletLocalService.getPortletById(portletDataContext.getCompanyId(), portletId);

    Element portletPreferencesElement = parentElement.addElement("portlet-preferences");

    if ((portlet != null) && (portlet.getPortletDataHandlerInstance() != null)) {

      Element exportDataRootElement = portletDataContext.getExportDataRootElement();

      try {
        portletDataContext.clearScopedPrimaryKeys();

        Element preferenceDataElement = portletPreferencesElement.addElement("preference-data");

        portletDataContext.setExportDataRootElement(preferenceDataElement);

        ExportImportPortletPreferencesProcessor exportImportPortletPreferencesProcessor =
            ExportImportPortletPreferencesProcessorRegistryUtil
                .getExportImportPortletPreferencesProcessor(portlet.getRootPortletId());

        if (exportImportPortletPreferencesProcessor != null) {
          List<Capability> exportCapabilities =
              exportImportPortletPreferencesProcessor.getExportCapabilities();

          if (ListUtil.isNotEmpty(exportCapabilities)) {
            for (Capability exportCapability : exportCapabilities) {
              exportCapability.process(portletDataContext, jxPortletPreferences);
            }
          }

          exportImportPortletPreferencesProcessor.processExportPortletPreferences(
              portletDataContext, jxPortletPreferences);
        } else {
          PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

          jxPortletPreferences =
              portletDataHandler.processExportPortletPreferences(
                  portletDataContext, portletId, jxPortletPreferences);
        }
      } finally {
        portletDataContext.setExportDataRootElement(exportDataRootElement);
      }
    }

    Document document =
        SAXReaderUtil.read(PortletPreferencesFactoryUtil.toXML(jxPortletPreferences));

    Element rootElement = document.getRootElement();

    rootElement.addAttribute("owner-id", String.valueOf(ownerId));
    rootElement.addAttribute("owner-type", String.valueOf(ownerType));
    rootElement.addAttribute("default-user", String.valueOf(defaultUser));
    rootElement.addAttribute("plid", String.valueOf(plid));
    rootElement.addAttribute("portlet-id", portletId);

    if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
      PortletItem portletItem = _portletItemLocalService.getPortletItem(ownerId);

      rootElement.addAttribute("archive-user-uuid", portletItem.getUserUuid());
      rootElement.addAttribute("archive-name", portletItem.getName());
    } else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) {
      User user = _userLocalService.fetchUserById(ownerId);

      if (user == null) {
        return;
      }

      rootElement.addAttribute("user-uuid", user.getUserUuid());
    }

    List<Node> nodes =
        document.selectNodes(
            "/portlet-preferences/preference[name/text() = " + "'last-publish-date']");

    for (Node node : nodes) {
      document.remove(node);
    }

    String path =
        ExportImportPathUtil.getPortletPreferencesPath(
            portletDataContext, portletId, ownerId, ownerType, plid);

    portletPreferencesElement.addAttribute("path", path);

    portletDataContext.addZipEntry(path, document.formattedString(StringPool.TAB, false, false));
  }