@Test
  public void testTypeLinkToLayout() throws Exception {
    initExport();

    Map<String, List<StagedModel>> dependentStagedModelsMap = new HashMap<>();

    Layout linkedLayout = LayoutTestUtil.addLayout(stagingGroup);

    List<LayoutFriendlyURL> linkedLayoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(linkedLayout.getPlid());

    addDependentStagedModel(dependentStagedModelsMap, Layout.class, linkedLayout);

    addDependentLayoutFriendlyURLs(dependentStagedModelsMap, linkedLayout);

    Layout layout =
        LayoutTestUtil.addTypeLinkToLayoutLayout(
            stagingGroup.getGroupId(), linkedLayout.getLayoutId());

    List<LayoutFriendlyURL> layoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(layout.getPlid());

    addDependentLayoutFriendlyURLs(dependentStagedModelsMap, layout);

    StagedModelDataHandlerUtil.exportStagedModel(portletDataContext, layout);

    validateExport(portletDataContext, layout, dependentStagedModelsMap);

    initImport();

    Layout exportedLayout = (Layout) readExportedStagedModel(layout);

    StagedModelDataHandlerUtil.importStagedModel(portletDataContext, exportedLayout);

    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
        linkedLayout.getUuid(), liveGroup.getGroupId(), false);

    LayoutFriendlyURL linkedLayoutFriendlyURL = linkedLayoutFriendlyURLs.get(0);

    LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLByUuidAndGroupId(
        linkedLayoutFriendlyURL.getUuid(), liveGroup.getGroupId());

    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
        layout.getUuid(), liveGroup.getGroupId(), false);

    LayoutFriendlyURL layoutFriendlyURL = layoutFriendlyURLs.get(0);

    LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLByUuidAndGroupId(
        layoutFriendlyURL.getUuid(), liveGroup.getGroupId());
  }
  protected void validatePrototypedLayouts(Class<?> clazz, long groupId) throws Exception {

    List<Layout> layouts = getLayouts(clazz);

    for (Layout layout : layouts) {
      Layout importedLayout =
          LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
              layout.getUuid(), groupId, layout.getPrivateLayout());

      Assert.assertNotNull(importedLayout);
      Assert.assertEquals(
          layout.getTypeSettingsProperty(
              LayoutSetPrototypeStagedModelDataHandlerTest.class.getName()),
          importedLayout.getTypeSettingsProperty(
              LayoutSetPrototypeStagedModelDataHandlerTest.class.getName()));
    }

    List<LayoutFriendlyURL> layoutFriendlyURLs = getLayoutFriendlyURLs(clazz);

    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
      LayoutFriendlyURL importedLayoutFriendlyURL =
          LayoutFriendlyURLLocalServiceUtil.fetchLayoutFriendlyURLByUuidAndGroupId(
              layoutFriendlyURL.getUuid(), groupId);

      Assert.assertNotNull(importedLayoutFriendlyURL);
      Assert.assertEquals(
          layoutFriendlyURL.getFriendlyURL(), importedLayoutFriendlyURL.getFriendlyURL());
    }
  }
  protected LayoutPrototype addLayoutPrototype(
      Map<String, List<StagedModel>> dependentStagedModelsMap) throws Exception {

    _layoutPrototype = LayoutTestUtil.addLayoutPrototype(RandomTestUtil.randomString());

    addDependentStagedModel(dependentStagedModelsMap, LayoutPrototype.class, _layoutPrototype);

    List<Layout> layouts =
        LayoutLocalServiceUtil.getLayouts(
            _layoutPrototype.getGroupId(), true, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);

    Assert.assertEquals(1, layouts.size());

    Layout layout = layouts.get(0);

    addDependentStagedModel(dependentStagedModelsMap, Layout.class, layout);

    addLayout(LayoutPrototype.class, layout);

    List<LayoutFriendlyURL> layoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(layout.getPlid());

    Assert.assertEquals(1, layoutFriendlyURLs.size());

    addDependentStagedModel(
        dependentStagedModelsMap, LayoutFriendlyURL.class, layoutFriendlyURLs.get(0));

    addLayoutFriendlyURLs(LayoutPrototype.class, layout.getPlid());

    return _layoutPrototype;
  }
  @Override
  public void deleteStagedModel(String uuid, long groupId, String className, String extraData) {

    LayoutFriendlyURL layoutFriendlyURL = fetchStagedModelByUuidAndGroupId(uuid, groupId);

    LayoutFriendlyURLLocalServiceUtil.deleteLayoutFriendlyURL(layoutFriendlyURL);
  }
  protected LayoutFriendlyURL getUniqueLayoutFriendlyURL(
      PortletDataContext portletDataContext,
      LayoutFriendlyURL layoutFriendlyURL,
      LayoutFriendlyURL existingLayoutFriendlyURL)
      throws Exception {

    String friendlyURL = layoutFriendlyURL.getFriendlyURL();

    for (int i = 1; ; i++) {
      LayoutFriendlyURL duplicateLayoutFriendlyURL =
          LayoutFriendlyURLLocalServiceUtil.fetchLayoutFriendlyURL(
              portletDataContext.getScopeGroupId(),
              layoutFriendlyURL.isPrivateLayout(),
              layoutFriendlyURL.getFriendlyURL(),
              layoutFriendlyURL.getLanguageId());

      if ((duplicateLayoutFriendlyURL == null)
          || ((existingLayoutFriendlyURL != null)
              && (existingLayoutFriendlyURL.getLayoutFriendlyURLId()
                  == duplicateLayoutFriendlyURL.getLayoutFriendlyURLId()))) {

        break;
      }

      layoutFriendlyURL.setFriendlyURL(friendlyURL + i);
    }

    return layoutFriendlyURL;
  }
  public LayoutFriendlyURLActionableDynamicQuery() {
    setBaseLocalService(LayoutFriendlyURLLocalServiceUtil.getService());
    setClass(LayoutFriendlyURL.class);

    setClassLoader(PortalClassLoaderUtil.getClassLoader());

    setPrimaryKeyPropertyName("layoutFriendlyURLId");
  }
  protected void initActionableDynamicQuery(ActionableDynamicQuery actionableDynamicQuery) {
    actionableDynamicQuery.setBaseLocalService(
        com.liferay.portal.service.LayoutFriendlyURLLocalServiceUtil.getService());
    actionableDynamicQuery.setClassLoader(getClassLoader());
    actionableDynamicQuery.setModelClass(LayoutFriendlyURL.class);

    actionableDynamicQuery.setPrimaryKeyPropertyName("layoutFriendlyURLId");
  }
  protected void addDependentLayoutFriendlyURLs(
      Map<String, List<StagedModel>> dependentStagedModelsMap, Layout layout) throws Exception {

    List<LayoutFriendlyURL> layoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(layout.getPlid());

    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
      addDependentStagedModel(dependentStagedModelsMap, LayoutFriendlyURL.class, layoutFriendlyURL);
    }
  }
  @Override
  public ActionableDynamicQuery getActionableDynamicQuery() {
    ActionableDynamicQuery actionableDynamicQuery = new DefaultActionableDynamicQuery();

    actionableDynamicQuery.setBaseLocalService(
        com.liferay.portal.service.LayoutFriendlyURLLocalServiceUtil.getService());
    actionableDynamicQuery.setClassLoader(getClassLoader());
    actionableDynamicQuery.setModelClass(LayoutFriendlyURL.class);

    actionableDynamicQuery.setPrimaryKeyPropertyName("layoutFriendlyURLId");

    return actionableDynamicQuery;
  }
  @Override
  protected void validateImport(
      Map<String, List<StagedModel>> dependentStagedModelsMap, Group group) throws Exception {

    List<StagedModel> dependentStagedModels =
        dependentStagedModelsMap.get(Layout.class.getSimpleName());

    Assert.assertEquals(1, dependentStagedModels.size());

    Layout parentLayout = (Layout) dependentStagedModels.get(0);

    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
        parentLayout.getUuid(), group.getGroupId(), false);

    List<LayoutFriendlyURL> parentLayoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(parentLayout.getPlid());

    LayoutFriendlyURL parentLayoutFriendlyURL = parentLayoutFriendlyURLs.get(0);

    LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLByUuidAndGroupId(
        parentLayoutFriendlyURL.getUuid(), group.getGroupId());
  }
  @Override
  public Map<Locale, String> getFriendlyURLMap() throws SystemException {
    Map<Locale, String> friendlyURLMap = new HashMap<Locale, String>();

    List<LayoutFriendlyURL> layoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(getPlid());

    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
      friendlyURLMap.put(
          LocaleUtil.fromLanguageId(layoutFriendlyURL.getLanguageId()),
          layoutFriendlyURL.getFriendlyURL());
    }

    return friendlyURLMap;
  }
  protected LayoutFriendlyURL fetchExistingLayoutFriendlyURL(
      PortletDataContext portletDataContext, LayoutFriendlyURL layoutFriendlyURL, long plid) {

    LayoutFriendlyURL existingLayoutFriendlyURL =
        fetchStagedModelByUuidAndGroupId(
            layoutFriendlyURL.getUuid(), portletDataContext.getScopeGroupId());

    if (existingLayoutFriendlyURL == null) {
      existingLayoutFriendlyURL =
          LayoutFriendlyURLLocalServiceUtil.fetchLayoutFriendlyURL(
              plid, layoutFriendlyURL.getLanguageId(), false);
    }

    return existingLayoutFriendlyURL;
  }
  @Override
  public String getFriendlyURL(Locale locale) {
    Layout layout = this;

    String friendlyURL = layout.getFriendlyURL();

    try {
      LayoutFriendlyURL layoutFriendlyURL =
          LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURL(
              layout.getPlid(), LocaleUtil.toLanguageId(locale));

      friendlyURL = layoutFriendlyURL.getFriendlyURL();
    } catch (Exception e) {
    }

    return friendlyURL;
  }
  @Override
  public LayoutFriendlyURL fetchStagedModelByUuidAndCompanyId(String uuid, long companyId) {

    List<LayoutFriendlyURL> friendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLsByUuidAndCompanyId(
            uuid,
            companyId,
            QueryUtil.ALL_POS,
            QueryUtil.ALL_POS,
            new StagedModelModifiedDateComparator<LayoutFriendlyURL>());

    if (ListUtil.isEmpty(friendlyURLs)) {
      return null;
    }

    return friendlyURLs.get(0);
  }
  protected void addLayoutFriendlyURLs(Class<?> clazz, long plid) throws Exception {

    List<LayoutFriendlyURL> layoutFriendlyURLs = _layoutFriendlyURLs.get(clazz.getSimpleName());

    if (layoutFriendlyURLs == null) {
      layoutFriendlyURLs = new ArrayList<>();

      _layoutFriendlyURLs.put(clazz.getSimpleName(), layoutFriendlyURLs);
    }

    List<LayoutFriendlyURL> layoutLayoutFriendlyURLs =
        LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(plid);

    Assert.assertEquals(1, layoutLayoutFriendlyURLs.size());

    layoutFriendlyURLs.add(layoutLayoutFriendlyURLs.get(0));
  }
  @Override
  protected void doImportStagedModel(
      PortletDataContext portletDataContext, LayoutFriendlyURL layoutFriendlyURL) throws Exception {

    long userId = portletDataContext.getUserId(layoutFriendlyURL.getUserUuid());

    Map<Long, Long> plids = (Map<Long, Long>) portletDataContext.getNewPrimaryKeysMap(Layout.class);

    long plid = MapUtil.getLong(plids, layoutFriendlyURL.getPlid(), layoutFriendlyURL.getPlid());

    ServiceContext serviceContext = portletDataContext.createServiceContext(layoutFriendlyURL);

    LayoutFriendlyURL importedLayoutFriendlyURL = null;

    if (portletDataContext.isDataStrategyMirror()) {
      LayoutFriendlyURL existingLayoutFriendlyURL =
          fetchExistingLayoutFriendlyURL(portletDataContext, layoutFriendlyURL, plid);

      layoutFriendlyURL =
          getUniqueLayoutFriendlyURL(
              portletDataContext, layoutFriendlyURL, existingLayoutFriendlyURL);

      if (existingLayoutFriendlyURL == null) {
        serviceContext.setUuid(layoutFriendlyURL.getUuid());

        importedLayoutFriendlyURL =
            LayoutFriendlyURLLocalServiceUtil.addLayoutFriendlyURL(
                userId,
                portletDataContext.getCompanyId(),
                portletDataContext.getScopeGroupId(),
                plid,
                portletDataContext.isPrivateLayout(),
                layoutFriendlyURL.getFriendlyURL(),
                layoutFriendlyURL.getLanguageId(),
                serviceContext);
      } else {
        importedLayoutFriendlyURL =
            LayoutFriendlyURLLocalServiceUtil.updateLayoutFriendlyURL(
                userId,
                portletDataContext.getCompanyId(),
                portletDataContext.getScopeGroupId(),
                plid,
                portletDataContext.isPrivateLayout(),
                layoutFriendlyURL.getFriendlyURL(),
                layoutFriendlyURL.getLanguageId(),
                serviceContext);
      }
    } else {
      layoutFriendlyURL = getUniqueLayoutFriendlyURL(portletDataContext, layoutFriendlyURL, null);

      importedLayoutFriendlyURL =
          LayoutFriendlyURLLocalServiceUtil.addLayoutFriendlyURL(
              userId,
              portletDataContext.getCompanyId(),
              portletDataContext.getScopeGroupId(),
              plid,
              portletDataContext.isPrivateLayout(),
              layoutFriendlyURL.getFriendlyURL(),
              layoutFriendlyURL.getLanguageId(),
              serviceContext);
    }

    portletDataContext.importClassedModel(layoutFriendlyURL, importedLayoutFriendlyURL);
  }
  @Override
  public LayoutFriendlyURL fetchStagedModelByUuidAndGroupId(String uuid, long groupId) {

    return LayoutFriendlyURLLocalServiceUtil.fetchLayoutFriendlyURLByUuidAndGroupId(uuid, groupId);
  }