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.service.impl;
016    
017    import com.liferay.portal.NoSuchGroupException;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
021    import com.liferay.portal.kernel.language.LanguageUtil;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.repository.model.FileEntry;
025    import com.liferay.portal.kernel.repository.model.Folder;
026    import com.liferay.portal.kernel.util.ContentTypes;
027    import com.liferay.portal.kernel.util.FileUtil;
028    import com.liferay.portal.kernel.util.GetterUtil;
029    import com.liferay.portal.kernel.util.LocaleUtil;
030    import com.liferay.portal.kernel.util.PropertiesParamUtil;
031    import com.liferay.portal.kernel.util.PropsKeys;
032    import com.liferay.portal.kernel.util.StreamUtil;
033    import com.liferay.portal.kernel.util.UnicodeProperties;
034    import com.liferay.portal.kernel.util.Validator;
035    import com.liferay.portal.kernel.workflow.WorkflowConstants;
036    import com.liferay.portal.model.Group;
037    import com.liferay.portal.model.GroupConstants;
038    import com.liferay.portal.model.Layout;
039    import com.liferay.portal.model.LayoutRevision;
040    import com.liferay.portal.model.LayoutSetBranch;
041    import com.liferay.portal.model.LayoutSetBranchConstants;
042    import com.liferay.portal.model.PortletPreferences;
043    import com.liferay.portal.model.Repository;
044    import com.liferay.portal.model.User;
045    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
046    import com.liferay.portal.security.auth.HttpPrincipal;
047    import com.liferay.portal.security.auth.PrincipalException;
048    import com.liferay.portal.security.auth.RemoteAuthException;
049    import com.liferay.portal.security.permission.PermissionChecker;
050    import com.liferay.portal.security.permission.PermissionThreadLocal;
051    import com.liferay.portal.service.ServiceContext;
052    import com.liferay.portal.service.http.GroupServiceHttp;
053    import com.liferay.portal.util.PortalUtil;
054    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
055    import com.liferay.portlet.documentlibrary.NoSuchFolderException;
056    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
057    import com.liferay.portlet.documentlibrary.util.comparator.RepositoryModelTitleComparator;
058    import com.liferay.portlet.exportimport.RemoteExportException;
059    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationParameterMapFactory;
060    import com.liferay.portlet.exportimport.lar.ExportImportDateUtil;
061    import com.liferay.portlet.exportimport.lar.ExportImportThreadLocal;
062    import com.liferay.portlet.exportimport.lar.MissingReferences;
063    import com.liferay.portlet.exportimport.model.ExportImportConfiguration;
064    import com.liferay.portlet.exportimport.service.base.StagingLocalServiceBaseImpl;
065    import com.liferay.portlet.exportimport.staging.StagingAdvicesThreadLocal;
066    import com.liferay.portlet.exportimport.staging.StagingConstants;
067    import com.liferay.portlet.exportimport.staging.StagingUtil;
068    
069    import java.io.File;
070    import java.io.FileOutputStream;
071    import java.io.IOException;
072    import java.io.Serializable;
073    
074    import java.util.Date;
075    import java.util.HashMap;
076    import java.util.HashSet;
077    import java.util.List;
078    import java.util.Map;
079    import java.util.Set;
080    
081    import javax.portlet.PortletRequest;
082    
083    /**
084     * @author Michael C. Han
085     * @author Mate Thurzo
086     * @author Vilmos Papp
087     */
088    public class StagingLocalServiceImpl extends StagingLocalServiceBaseImpl {
089    
090            @Override
091            public void checkDefaultLayoutSetBranches(
092                            long userId, Group liveGroup, boolean branchingPublic,
093                            boolean branchingPrivate, boolean remote,
094                            ServiceContext serviceContext)
095                    throws PortalException {
096    
097                    long targetGroupId = 0;
098    
099                    if (remote) {
100                            targetGroupId = liveGroup.getGroupId();
101                    }
102                    else {
103                            Group stagingGroup = liveGroup.getStagingGroup();
104    
105                            if (stagingGroup == null) {
106                                    return;
107                            }
108    
109                            targetGroupId = stagingGroup.getGroupId();
110                    }
111    
112                    LayoutSetBranch layoutSetBranch =
113                            layoutSetBranchLocalService.fetchLayoutSetBranch(
114                                    targetGroupId, false,
115                                    LayoutSetBranchConstants.MASTER_BRANCH_NAME);
116    
117                    if (branchingPublic && (layoutSetBranch == null)) {
118                            addDefaultLayoutSetBranch(
119                                    userId, targetGroupId, liveGroup.getDescriptiveName(), false,
120                                    serviceContext);
121                    }
122                    else if (!branchingPublic && (layoutSetBranch != null)) {
123                            deleteLayoutSetBranches(targetGroupId, false);
124                    }
125                    else if (layoutSetBranch != null) {
126                            ExportImportDateUtil.clearLastPublishDate(targetGroupId, false);
127                    }
128    
129                    layoutSetBranch = layoutSetBranchLocalService.fetchLayoutSetBranch(
130                            targetGroupId, true, LayoutSetBranchConstants.MASTER_BRANCH_NAME);
131    
132                    if (branchingPrivate && (layoutSetBranch == null)) {
133                            addDefaultLayoutSetBranch(
134                                    userId, targetGroupId, liveGroup.getDescriptiveName(), true,
135                                    serviceContext);
136                    }
137                    else if (!branchingPrivate && (layoutSetBranch != null)) {
138                            deleteLayoutSetBranches(targetGroupId, true);
139                    }
140                    else if (layoutSetBranch != null) {
141                            ExportImportDateUtil.clearLastPublishDate(targetGroupId, true);
142                    }
143            }
144    
145            @Override
146            public void cleanUpStagingRequest(long stagingRequestId)
147                    throws PortalException {
148    
149                    try {
150                            PortletFileRepositoryUtil.deletePortletFolder(stagingRequestId);
151                    }
152                    catch (NoSuchFolderException nsfe) {
153                            if (_log.isDebugEnabled()) {
154                                    _log.debug(
155                                            "Unable to clean up staging request " + stagingRequestId,
156                                            nsfe);
157                            }
158                    }
159            }
160    
161            @Override
162            public long createStagingRequest(long userId, long groupId, String checksum)
163                    throws PortalException {
164    
165                    ServiceContext serviceContext = new ServiceContext();
166    
167                    Repository repository = PortletFileRepositoryUtil.addPortletRepository(
168                            groupId, _PORTLET_REPOSITORY_ID, serviceContext);
169    
170                    Folder folder = PortletFileRepositoryUtil.addPortletFolder(
171                            userId, repository.getRepositoryId(),
172                            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, checksum,
173                            serviceContext);
174    
175                    return folder.getFolderId();
176            }
177    
178            @Override
179            public void disableStaging(Group liveGroup, ServiceContext serviceContext)
180                    throws PortalException {
181    
182                    disableStaging((PortletRequest)null, liveGroup, serviceContext);
183            }
184    
185            @Override
186            public void disableStaging(
187                            PortletRequest portletRequest, Group liveGroup,
188                            ServiceContext serviceContext)
189                    throws PortalException {
190    
191                    UnicodeProperties typeSettingsProperties =
192                            liveGroup.getTypeSettingsProperties();
193    
194                    boolean stagedRemotely = GetterUtil.getBoolean(
195                            typeSettingsProperties.getProperty("stagedRemotely"));
196    
197                    if (stagedRemotely) {
198                            String remoteURL = StagingUtil.buildRemoteURL(
199                                    typeSettingsProperties);
200    
201                            long remoteGroupId = GetterUtil.getLong(
202                                    typeSettingsProperties.getProperty("remoteGroupId"));
203                            boolean forceDisable = GetterUtil.getBoolean(
204                                    serviceContext.getAttribute("forceDisable"));
205    
206                            disableRemoteStaging(remoteURL, remoteGroupId, forceDisable);
207                    }
208    
209                    typeSettingsProperties.remove("branchingPrivate");
210                    typeSettingsProperties.remove("branchingPublic");
211                    typeSettingsProperties.remove("remoteAddress");
212                    typeSettingsProperties.remove("remoteGroupId");
213                    typeSettingsProperties.remove("remotePathContext");
214                    typeSettingsProperties.remove("remotePort");
215                    typeSettingsProperties.remove("secureConnection");
216                    typeSettingsProperties.remove("staged");
217                    typeSettingsProperties.remove("stagedRemotely");
218    
219                    Set<String> keys = new HashSet<>();
220    
221                    for (String key : typeSettingsProperties.keySet()) {
222                            if (key.startsWith(StagingConstants.STAGED_PORTLET)) {
223                                    keys.add(key);
224                            }
225                    }
226    
227                    for (String key : keys) {
228                            typeSettingsProperties.remove(key);
229                    }
230    
231                    StagingUtil.deleteLastImportSettings(liveGroup, true);
232                    StagingUtil.deleteLastImportSettings(liveGroup, false);
233    
234                    checkDefaultLayoutSetBranches(
235                            serviceContext.getUserId(), liveGroup, false, false, stagedRemotely,
236                            serviceContext);
237    
238                    if (liveGroup.hasStagingGroup()) {
239                            Group stagingGroup = liveGroup.getStagingGroup();
240    
241                            groupLocalService.deleteGroup(stagingGroup.getGroupId());
242    
243                            liveGroup.clearStagingGroup();
244                    }
245    
246                    groupLocalService.updateGroup(
247                            liveGroup.getGroupId(), typeSettingsProperties.toString());
248            }
249    
250            @Override
251            public void enableLocalStaging(
252                            long userId, Group liveGroup, boolean branchingPublic,
253                            boolean branchingPrivate, ServiceContext serviceContext)
254                    throws PortalException {
255    
256                    if (liveGroup.isStagedRemotely()) {
257                            disableStaging(liveGroup, serviceContext);
258                    }
259    
260                    boolean hasStagingGroup = liveGroup.hasStagingGroup();
261    
262                    if (!hasStagingGroup) {
263                            serviceContext.setAttribute("staging", String.valueOf(true));
264    
265                            addStagingGroup(userId, liveGroup, serviceContext);
266                    }
267    
268                    checkDefaultLayoutSetBranches(
269                            userId, liveGroup, branchingPublic, branchingPrivate, false,
270                            serviceContext);
271    
272                    UnicodeProperties typeSettingsProperties =
273                            liveGroup.getTypeSettingsProperties();
274    
275                    typeSettingsProperties.setProperty(
276                            "branchingPrivate", String.valueOf(branchingPrivate));
277                    typeSettingsProperties.setProperty(
278                            "branchingPublic", String.valueOf(branchingPublic));
279                    typeSettingsProperties.setProperty("staged", Boolean.TRUE.toString());
280                    typeSettingsProperties.setProperty(
281                            "stagedRemotely", String.valueOf(false));
282    
283                    setCommonStagingOptions(
284                            liveGroup, typeSettingsProperties, serviceContext);
285    
286                    groupLocalService.updateGroup(
287                            liveGroup.getGroupId(), typeSettingsProperties.toString());
288    
289                    if (!hasStagingGroup) {
290                            Group stagingGroup = liveGroup.getStagingGroup();
291    
292                            Map<String, String[]> parameterMap =
293                                    ExportImportConfigurationParameterMapFactory.
294                                            buildParameterMap();
295    
296                            if (liveGroup.hasPrivateLayouts()) {
297                                    StagingUtil.publishLayouts(
298                                            userId, liveGroup.getGroupId(), stagingGroup.getGroupId(),
299                                            true, parameterMap);
300                            }
301    
302                            if (liveGroup.hasPublicLayouts() ||
303                                    !liveGroup.hasPrivateLayouts()) {
304    
305                                    StagingUtil.publishLayouts(
306                                            userId, liveGroup.getGroupId(), stagingGroup.getGroupId(),
307                                            false, parameterMap);
308                            }
309                    }
310            }
311    
312            @Override
313            public void enableRemoteStaging(
314                            long userId, Group stagingGroup, boolean branchingPublic,
315                            boolean branchingPrivate, String remoteAddress, int remotePort,
316                            String remotePathContext, boolean secureConnection,
317                            long remoteGroupId, ServiceContext serviceContext)
318                    throws PortalException {
319    
320                    StagingUtil.validateRemote(
321                            stagingGroup.getGroupId(), remoteAddress, remotePort,
322                            remotePathContext, secureConnection, remoteGroupId);
323    
324                    if (stagingGroup.hasStagingGroup()) {
325                            disableStaging(stagingGroup, serviceContext);
326                    }
327    
328                    String remoteURL = StagingUtil.buildRemoteURL(
329                            remoteAddress, remotePort, remotePathContext, secureConnection,
330                            GroupConstants.DEFAULT_LIVE_GROUP_ID, false);
331    
332                    UnicodeProperties typeSettingsProperties =
333                            stagingGroup.getTypeSettingsProperties();
334    
335                    boolean stagedRemotely = GetterUtil.getBoolean(
336                            typeSettingsProperties.getProperty("stagedRemotely"));
337    
338                    if (stagedRemotely) {
339                            long oldRemoteGroupId = GetterUtil.getLong(
340                                    typeSettingsProperties.getProperty("remoteGroupId"));
341    
342                            String oldRemoteURL = StagingUtil.buildRemoteURL(
343                                    typeSettingsProperties);
344    
345                            if (!remoteURL.equals(oldRemoteURL) ||
346                                    (remoteGroupId != oldRemoteGroupId)) {
347    
348                                    disableRemoteStaging(oldRemoteURL, oldRemoteGroupId, false);
349    
350                                    stagedRemotely = false;
351                            }
352                    }
353    
354                    if (!stagedRemotely) {
355                            enableRemoteStaging(remoteURL, remoteGroupId);
356                    }
357    
358                    checkDefaultLayoutSetBranches(
359                            userId, stagingGroup, branchingPublic, branchingPrivate, true,
360                            serviceContext);
361    
362                    typeSettingsProperties.setProperty(
363                            "branchingPrivate", String.valueOf(branchingPrivate));
364                    typeSettingsProperties.setProperty(
365                            "branchingPublic", String.valueOf(branchingPublic));
366                    typeSettingsProperties.setProperty("remoteAddress", remoteAddress);
367                    typeSettingsProperties.setProperty(
368                            "remoteGroupId", String.valueOf(remoteGroupId));
369                    typeSettingsProperties.setProperty(
370                            "remotePathContext", remotePathContext);
371                    typeSettingsProperties.setProperty(
372                            "remotePort", String.valueOf(remotePort));
373                    typeSettingsProperties.setProperty(
374                            "secureConnection", String.valueOf(secureConnection));
375                    typeSettingsProperties.setProperty("staged", Boolean.TRUE.toString());
376                    typeSettingsProperties.setProperty(
377                            "stagedRemotely", Boolean.TRUE.toString());
378    
379                    setCommonStagingOptions(
380                            stagingGroup, typeSettingsProperties, serviceContext);
381    
382                    groupLocalService.updateGroup(
383                            stagingGroup.getGroupId(), typeSettingsProperties.toString());
384    
385                    updateStagedPortlets(remoteURL, remoteGroupId, typeSettingsProperties);
386            }
387    
388            /**
389             * @deprecated As of 7.0.0, with no direct replacement
390             */
391            @Deprecated
392            @Override
393            @SuppressWarnings("unused")
394            public MissingReferences publishStagingRequest(
395                            long userId, long stagingRequestId, boolean privateLayout,
396                            Map<String, String[]> parameterMap)
397                    throws PortalException {
398    
399                    throw new UnsupportedOperationException();
400            }
401    
402            @Override
403            public MissingReferences publishStagingRequest(
404                            long userId, long stagingRequestId,
405                            ExportImportConfiguration exportImportConfiguration)
406                    throws PortalException {
407    
408                    File file = null;
409    
410                    try {
411                            ExportImportThreadLocal.setLayoutImportInProcess(true);
412                            ExportImportThreadLocal.setLayoutStagingInProcess(true);
413    
414                            Folder folder = PortletFileRepositoryUtil.getPortletFolder(
415                                    stagingRequestId);
416    
417                            FileEntry stagingRequestFileEntry = getStagingRequestFileEntry(
418                                    userId, stagingRequestId, folder);
419    
420                            file = FileUtil.createTempFile("lar");
421    
422                            FileUtil.write(file, stagingRequestFileEntry.getContentStream());
423    
424                            Map<String, Serializable> settingsMap =
425                                    exportImportConfiguration.getSettingsMap();
426    
427                            settingsMap.put("userId", userId);
428    
429                            exportImportLocalService.importLayoutsDataDeletions(
430                                    exportImportConfiguration, file);
431    
432                            MissingReferences missingReferences =
433                                    exportImportLocalService.validateImportLayoutsFile(
434                                            exportImportConfiguration, file);
435    
436                            exportImportLocalService.importLayouts(
437                                    exportImportConfiguration, file);
438    
439                            return missingReferences;
440                    }
441                    catch (IOException ioe) {
442                            throw new SystemException(ioe);
443                    }
444                    finally {
445                            ExportImportThreadLocal.setLayoutImportInProcess(false);
446                            ExportImportThreadLocal.setLayoutStagingInProcess(false);
447                    }
448            }
449    
450            @Override
451            public void updateStagingRequest(
452                            long userId, long stagingRequestId, String fileName, byte[] bytes)
453                    throws PortalException {
454    
455                    Folder folder = PortletFileRepositoryUtil.getPortletFolder(
456                            stagingRequestId);
457    
458                    PortletFileRepositoryUtil.addPortletFileEntry(
459                            folder.getGroupId(), userId, Group.class.getName(),
460                            folder.getGroupId(), _PORTLET_REPOSITORY_ID, folder.getFolderId(),
461                            new UnsyncByteArrayInputStream(bytes), fileName,
462                            ContentTypes.APPLICATION_ZIP, false);
463            }
464    
465            /**
466             * @deprecated As of 7.0.0, replaced by {@link #publishStagingRequest(long,
467             *             long, boolean, Map)}
468             */
469            @Deprecated
470            @Override
471            public MissingReferences validateStagingRequest(
472                    long userId, long stagingRequestId, boolean privateLayout,
473                    Map<String, String[]> parameterMap) {
474    
475                    return new MissingReferences();
476            }
477    
478            protected void addDefaultLayoutSetBranch(
479                            long userId, long groupId, String groupName, boolean privateLayout,
480                            ServiceContext serviceContext)
481                    throws PortalException {
482    
483                    String masterBranchDescription =
484                            LayoutSetBranchConstants.MASTER_BRANCH_DESCRIPTION_PUBLIC;
485    
486                    if (privateLayout) {
487                            masterBranchDescription =
488                                    LayoutSetBranchConstants.MASTER_BRANCH_DESCRIPTION_PRIVATE;
489                    }
490    
491                    String description = LanguageUtil.format(
492                            PortalUtil.getSiteDefaultLocale(groupId), masterBranchDescription,
493                            groupName, false);
494    
495                    try {
496                            serviceContext.setWorkflowAction(WorkflowConstants.STATUS_APPROVED);
497    
498                            LayoutSetBranch layoutSetBranch =
499                                    layoutSetBranchLocalService.addLayoutSetBranch(
500                                            userId, groupId, privateLayout,
501                                            LayoutSetBranchConstants.MASTER_BRANCH_NAME, description,
502                                            true, LayoutSetBranchConstants.ALL_BRANCHES,
503                                            serviceContext);
504    
505                            List<LayoutRevision> layoutRevisions =
506                                    layoutRevisionLocalService.getLayoutRevisions(
507                                            layoutSetBranch.getLayoutSetBranchId(), false);
508    
509                            for (LayoutRevision layoutRevision : layoutRevisions) {
510                                    layoutRevisionLocalService.updateStatus(
511                                            userId, layoutRevision.getLayoutRevisionId(),
512                                            WorkflowConstants.STATUS_APPROVED, serviceContext);
513                            }
514                    }
515                    catch (PortalException pe) {
516                            if (_log.isWarnEnabled()) {
517                                    _log.warn(
518                                            "Unable to create master branch for " +
519                                                    (privateLayout ? "private" : "public") + " layouts",
520                                            pe);
521                            }
522                    }
523            }
524    
525            protected Group addStagingGroup(
526                            long userId, Group liveGroup, ServiceContext serviceContext)
527                    throws PortalException {
528    
529                    long parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
530    
531                    if (liveGroup.getParentGroupId() !=
532                                    GroupConstants.DEFAULT_PARENT_GROUP_ID) {
533    
534                            Group parentGroup = liveGroup.getParentGroup();
535    
536                            if (parentGroup.hasStagingGroup()) {
537                                    parentGroup = parentGroup.getStagingGroup();
538                            }
539    
540                            parentGroupId = parentGroup.getGroupId();
541                    }
542    
543                    Group stagingGroup = groupLocalService.addGroup(
544                            userId, parentGroupId, liveGroup.getClassName(),
545                            liveGroup.getClassPK(), liveGroup.getGroupId(),
546                            liveGroup.getNameMap(), liveGroup.getDescriptionMap(),
547                            liveGroup.getType(), liveGroup.isManualMembership(),
548                            liveGroup.getMembershipRestriction(), liveGroup.getFriendlyURL(),
549                            false, liveGroup.isActive(), serviceContext);
550    
551                    if (LanguageUtil.isInheritLocales(liveGroup.getGroupId())) {
552                            return stagingGroup;
553                    }
554    
555                    UnicodeProperties liveTypeSettingsProperties =
556                            liveGroup.getTypeSettingsProperties();
557    
558                    UnicodeProperties stagingTypeSettingsProperties =
559                            stagingGroup.getTypeSettingsProperties();
560    
561                    stagingTypeSettingsProperties.setProperty(
562                            GroupConstants.TYPE_SETTINGS_KEY_INHERIT_LOCALES,
563                            Boolean.FALSE.toString());
564                    stagingTypeSettingsProperties.setProperty(
565                            PropsKeys.LOCALES,
566                            liveTypeSettingsProperties.getProperty(PropsKeys.LOCALES));
567                    stagingTypeSettingsProperties.setProperty(
568                            "languageId",
569                            liveTypeSettingsProperties.getProperty(
570                                    "languageId",
571                                    LocaleUtil.toLanguageId(LocaleUtil.getDefault())));
572    
573                    return groupLocalService.updateGroup(
574                            stagingGroup.getGroupId(),
575                            stagingTypeSettingsProperties.toString());
576            }
577    
578            protected void deleteLayoutSetBranches(long groupId, boolean privateLayout)
579                    throws PortalException {
580    
581                    // Find the latest layout revision for all the layouts
582    
583                    Map<Long, LayoutRevision> layoutRevisions = new HashMap<>();
584    
585                    List<LayoutSetBranch> layoutSetBranches =
586                            layoutSetBranchLocalService.getLayoutSetBranches(
587                                    groupId, privateLayout);
588    
589                    boolean publishedToLive = false;
590    
591                    for (LayoutSetBranch layoutSetBranch : layoutSetBranches) {
592                            String lastPublishDateString = layoutSetBranch.getSettingsProperty(
593                                    "last-publish-date");
594    
595                            if (Validator.isNotNull(lastPublishDateString)) {
596                                    publishedToLive = true;
597    
598                                    break;
599                            }
600                    }
601    
602                    for (LayoutSetBranch layoutSetBranch : layoutSetBranches) {
603                            String lastPublishDateString = layoutSetBranch.getSettingsProperty(
604                                    "last-publish-date");
605    
606                            if (Validator.isNull(lastPublishDateString) && publishedToLive) {
607                                    continue;
608                            }
609    
610                            Date lastPublishDate = null;
611    
612                            if (Validator.isNotNull(lastPublishDateString)) {
613                                    lastPublishDate = new Date(
614                                            GetterUtil.getLong(lastPublishDateString));
615                            }
616    
617                            List<LayoutRevision> headLayoutRevisions =
618                                    layoutRevisionLocalService.getLayoutRevisions(
619                                            layoutSetBranch.getLayoutSetBranchId(), true);
620    
621                            for (LayoutRevision headLayoutRevision : headLayoutRevisions) {
622                                    LayoutRevision layoutRevision = layoutRevisions.get(
623                                            headLayoutRevision.getPlid());
624    
625                                    if (layoutRevision == null) {
626                                            layoutRevisions.put(
627                                                    headLayoutRevision.getPlid(), headLayoutRevision);
628    
629                                            continue;
630                                    }
631    
632                                    Date statusDate = headLayoutRevision.getStatusDate();
633    
634                                    if (statusDate.after(layoutRevision.getStatusDate()) &&
635                                            ((lastPublishDate == null) ||
636                                             lastPublishDate.after(statusDate))) {
637    
638                                            layoutRevisions.put(
639                                                    headLayoutRevision.getPlid(), headLayoutRevision);
640                                    }
641                            }
642                    }
643    
644                    // Update all layouts based on their latest revision
645    
646                    for (LayoutRevision layoutRevision : layoutRevisions.values()) {
647                            updateLayoutWithLayoutRevision(layoutRevision);
648                    }
649    
650                    layoutSetBranchLocalService.deleteLayoutSetBranches(
651                            groupId, privateLayout, true);
652            }
653    
654            protected void disableRemoteStaging(
655                            String remoteURL, long remoteGroupId, boolean forceDisable)
656                    throws PortalException {
657    
658                    PermissionChecker permissionChecker =
659                            PermissionThreadLocal.getPermissionChecker();
660    
661                    User user = permissionChecker.getUser();
662    
663                    HttpPrincipal httpPrincipal = new HttpPrincipal(
664                            remoteURL, user.getLogin(), user.getPassword(),
665                            user.getPasswordEncrypted());
666    
667                    try {
668                            GroupServiceHttp.disableStaging(httpPrincipal, remoteGroupId);
669                    }
670                    catch (NoSuchGroupException nsge) {
671                            if (_log.isWarnEnabled()) {
672                                    _log.warn("Remote live group was already deleted", nsge);
673                            }
674                    }
675                    catch (PrincipalException pe) {
676                            RemoteExportException ree = new RemoteExportException(
677                                    RemoteExportException.NO_PERMISSIONS);
678    
679                            ree.setGroupId(remoteGroupId);
680    
681                            throw ree;
682                    }
683                    catch (RemoteAuthException rae) {
684                            rae.setURL(remoteURL);
685    
686                            throw rae;
687                    }
688                    catch (SystemException se) {
689                            if (!forceDisable) {
690                                    RemoteExportException ree = new RemoteExportException(
691                                            RemoteExportException.BAD_CONNECTION);
692    
693                                    ree.setURL(remoteURL);
694    
695                                    throw ree;
696                            }
697    
698                            if (_log.isWarnEnabled()) {
699                                    _log.warn("Forcibly disable remote staging");
700                            }
701                    }
702            }
703    
704            protected void enableRemoteStaging(String remoteURL, long remoteGroupId)
705                    throws PortalException {
706    
707                    PermissionChecker permissionChecker =
708                            PermissionThreadLocal.getPermissionChecker();
709    
710                    User user = permissionChecker.getUser();
711    
712                    HttpPrincipal httpPrincipal = new HttpPrincipal(
713                            remoteURL, user.getLogin(), user.getPassword(),
714                            user.getPasswordEncrypted());
715    
716                    try {
717                            GroupServiceHttp.enableStaging(httpPrincipal, remoteGroupId);
718                    }
719                    catch (NoSuchGroupException nsge) {
720                            RemoteExportException ree = new RemoteExportException(
721                                    RemoteExportException.NO_GROUP);
722    
723                            ree.setGroupId(remoteGroupId);
724    
725                            throw ree;
726                    }
727                    catch (PrincipalException pe) {
728                            RemoteExportException ree = new RemoteExportException(
729                                    RemoteExportException.NO_PERMISSIONS);
730    
731                            ree.setGroupId(remoteGroupId);
732    
733                            throw ree;
734                    }
735                    catch (RemoteAuthException rae) {
736                            rae.setURL(remoteURL);
737    
738                            throw rae;
739                    }
740                    catch (SystemException se) {
741                            RemoteExportException ree = new RemoteExportException(
742                                    RemoteExportException.BAD_CONNECTION);
743    
744                            ree.setURL(remoteURL);
745    
746                            throw ree;
747                    }
748            }
749    
750            protected FileEntry fetchStagingRequestFileEntry(
751                            long stagingRequestId, Folder folder)
752                    throws PortalException {
753    
754                    try {
755                            return PortletFileRepositoryUtil.getPortletFileEntry(
756                                    folder.getGroupId(), folder.getFolderId(),
757                                    getAssembledFileName(stagingRequestId));
758                    }
759                    catch (NoSuchFileEntryException nsfe) {
760                            return null;
761                    }
762            }
763    
764            protected String getAssembledFileName(long stagingRequestId) {
765                    return _ASSEMBLED_LAR_PREFIX + String.valueOf(stagingRequestId) +
766                            ".lar";
767            }
768    
769            protected FileEntry getStagingRequestFileEntry(
770                            long userId, long stagingRequestId, Folder folder)
771                    throws PortalException {
772    
773                    FileEntry stagingRequestFileEntry = fetchStagingRequestFileEntry(
774                            stagingRequestId, folder);
775    
776                    if (stagingRequestFileEntry != null) {
777                            return stagingRequestFileEntry;
778                    }
779    
780                    FileOutputStream fileOutputStream = null;
781    
782                    File tempFile = null;
783    
784                    try {
785                            tempFile = FileUtil.createTempFile("lar");
786    
787                            fileOutputStream = new FileOutputStream(tempFile);
788    
789                            List<FileEntry> fileEntries =
790                                    PortletFileRepositoryUtil.getPortletFileEntries(
791                                            folder.getGroupId(), folder.getFolderId(),
792                                            new RepositoryModelTitleComparator<FileEntry>(true));
793    
794                            for (FileEntry fileEntry : fileEntries) {
795                                    try {
796                                            StreamUtil.transfer(
797                                                    fileEntry.getContentStream(),
798                                                    StreamUtil.uncloseable(fileOutputStream));
799                                    }
800                                    finally {
801                                            PortletFileRepositoryUtil.deletePortletFileEntry(
802                                                    fileEntry.getFileEntryId());
803                                    }
804                            }
805    
806                            String checksum = FileUtil.getMD5Checksum(tempFile);
807    
808                            if (!checksum.equals(folder.getName())) {
809                                    throw new SystemException("Invalid checksum for LAR file");
810                            }
811    
812                            PortletFileRepositoryUtil.addPortletFileEntry(
813                                    folder.getGroupId(), userId, Group.class.getName(),
814                                    folder.getGroupId(), _PORTLET_REPOSITORY_ID,
815                                    folder.getFolderId(), tempFile,
816                                    getAssembledFileName(stagingRequestId),
817                                    ContentTypes.APPLICATION_ZIP, false);
818    
819                            stagingRequestFileEntry = fetchStagingRequestFileEntry(
820                                    stagingRequestId, folder);
821    
822                            if (stagingRequestFileEntry == null) {
823                                    throw new SystemException("Unable to assemble LAR file");
824                            }
825    
826                            return stagingRequestFileEntry;
827                    }
828                    catch (IOException ioe) {
829                            throw new SystemException("Unable to reassemble LAR file", ioe);
830                    }
831                    finally {
832                            StreamUtil.cleanUp(fileOutputStream);
833    
834                            FileUtil.delete(tempFile);
835                    }
836            }
837    
838            protected void setCommonStagingOptions(
839                    Group liveGroup, UnicodeProperties typeSettingsProperties,
840                    ServiceContext serviceContext) {
841    
842                    if (liveGroup.hasRemoteStagingGroup()) {
843                            return;
844                    }
845    
846                    typeSettingsProperties.putAll(
847                            PropertiesParamUtil.getProperties(
848                                    serviceContext, StagingConstants.STAGED_PREFIX));
849            }
850    
851            protected Layout updateLayoutWithLayoutRevision(
852                    LayoutRevision layoutRevision) {
853    
854                    // Suppress the usage of the advice to get the latest layout to prevent
855                    // a StaleObjectStateException
856    
857                    Layout layout = null;
858    
859                    boolean stagingAdvicesThreadLocalEnabled =
860                            StagingAdvicesThreadLocal.isEnabled();
861    
862                    try {
863                            StagingAdvicesThreadLocal.setEnabled(false);
864    
865                            layout = layoutLocalService.fetchLayout(layoutRevision.getPlid());
866                    }
867                    finally {
868                            StagingAdvicesThreadLocal.setEnabled(
869                                    stagingAdvicesThreadLocalEnabled);
870                    }
871    
872                    updatePortletPreferences(layoutRevision, layout);
873    
874                    layout.setUserId(layoutRevision.getUserId());
875                    layout.setUserName(layoutRevision.getUserName());
876                    layout.setCreateDate(layoutRevision.getCreateDate());
877                    layout.setModifiedDate(layoutRevision.getModifiedDate());
878                    layout.setPrivateLayout(layoutRevision.getPrivateLayout());
879                    layout.setName(layoutRevision.getName());
880                    layout.setTitle(layoutRevision.getTitle());
881                    layout.setDescription(layoutRevision.getDescription());
882                    layout.setKeywords(layoutRevision.getKeywords());
883                    layout.setRobots(layoutRevision.getRobots());
884                    layout.setTypeSettings(layoutRevision.getTypeSettings());
885                    layout.setIconImageId(layoutRevision.getIconImageId());
886                    layout.setThemeId(layoutRevision.getThemeId());
887                    layout.setColorSchemeId(layoutRevision.getColorSchemeId());
888                    layout.setWapThemeId(layoutRevision.getWapThemeId());
889                    layout.setWapColorSchemeId(layoutRevision.getWapColorSchemeId());
890                    layout.setCss(layoutRevision.getCss());
891    
892                    return layoutLocalService.updateLayout(layout);
893            }
894    
895            protected void updatePortletPreferences(
896                    LayoutRevision layoutRevision, Layout layout) {
897    
898                    portletPreferencesLocalService.deletePortletPreferencesByPlid(
899                            layout.getPlid());
900    
901                    List<PortletPreferences> portletPreferencesList =
902                            portletPreferencesLocalService.getPortletPreferencesByPlid(
903                                    layoutRevision.getLayoutRevisionId());
904    
905                    for (PortletPreferences portletPreferences : portletPreferencesList) {
906                            portletPreferencesLocalService.addPortletPreferences(
907                                    layoutRevision.getCompanyId(), portletPreferences.getOwnerId(),
908                                    portletPreferences.getOwnerType(), layout.getPlid(),
909                                    portletPreferences.getPortletId(), null,
910                                    portletPreferences.getPreferences());
911                    }
912            }
913    
914            protected void updateStagedPortlets(
915                            String remoteURL, long remoteGroupId,
916                            UnicodeProperties typeSettingsProperties)
917                    throws PortalException {
918    
919                    PermissionChecker permissionChecker =
920                            PermissionThreadLocal.getPermissionChecker();
921    
922                    User user = permissionChecker.getUser();
923    
924                    HttpPrincipal httpPrincipal = new HttpPrincipal(
925                            remoteURL, user.getLogin(), user.getPassword(),
926                            user.getPasswordEncrypted());
927    
928                    Map<String, String> stagedPortletIds = new HashMap<>();
929    
930                    for (String key : typeSettingsProperties.keySet()) {
931                            if (key.startsWith(StagingConstants.STAGED_PORTLET)) {
932                                    stagedPortletIds.put(
933                                            key, typeSettingsProperties.getProperty(key));
934                            }
935                    }
936    
937                    try {
938                            GroupServiceHttp.updateStagedPortlets(
939                                    httpPrincipal, remoteGroupId, stagedPortletIds);
940                    }
941                    catch (NoSuchGroupException nsge) {
942                            RemoteExportException ree = new RemoteExportException(
943                                    RemoteExportException.NO_GROUP);
944    
945                            ree.setGroupId(remoteGroupId);
946    
947                            throw ree;
948                    }
949                    catch (PrincipalException pe) {
950                            RemoteExportException ree = new RemoteExportException(
951                                    RemoteExportException.NO_PERMISSIONS);
952    
953                            ree.setGroupId(remoteGroupId);
954    
955                            throw ree;
956                    }
957                    catch (RemoteAuthException rae) {
958                            rae.setURL(remoteURL);
959    
960                            throw rae;
961                    }
962                    catch (SystemException se) {
963                            RemoteExportException ree = new RemoteExportException(
964                                    RemoteExportException.BAD_CONNECTION);
965    
966                            ree.setURL(remoteURL);
967    
968                            throw ree;
969                    }
970            }
971    
972            private static final String _ASSEMBLED_LAR_PREFIX = "assembled_";
973    
974            private static final String _PORTLET_REPOSITORY_ID = "134";
975    
976            private static final Log _log = LogFactoryUtil.getLog(
977                    StagingLocalServiceImpl.class);
978    
979    }