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