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.exception.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.exception.NoSuchFileEntryException;
057    import com.liferay.portlet.documentlibrary.exception.NoSuchFolderException;
058    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
059    import com.liferay.portlet.documentlibrary.util.comparator.RepositoryModelTitleComparator;
060    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationParameterMapFactory;
061    import com.liferay.portlet.exportimport.exception.RemoteExportException;
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    
350                    if (stagedRemotely) {
351                            long oldRemoteGroupId = GetterUtil.getLong(
352                                    typeSettingsProperties.getProperty("remoteGroupId"));
353    
354                            String oldRemoteURL = StagingUtil.buildRemoteURL(
355                                    typeSettingsProperties);
356    
357                            if (!remoteURL.equals(oldRemoteURL) ||
358                                    (remoteGroupId != oldRemoteGroupId)) {
359    
360                                    disableRemoteStaging(oldRemoteURL, oldRemoteGroupId, false);
361    
362                                    stagedRemotely = false;
363                            }
364                    }
365    
366                    if (!stagedRemotely) {
367                            enableRemoteStaging(remoteURL, remoteGroupId);
368                    }
369    
370                    checkDefaultLayoutSetBranches(
371                            userId, stagingGroup, branchingPublic, branchingPrivate, true,
372                            serviceContext);
373    
374                    typeSettingsProperties.setProperty(
375                            "branchingPrivate", String.valueOf(branchingPrivate));
376                    typeSettingsProperties.setProperty(
377                            "branchingPublic", String.valueOf(branchingPublic));
378                    typeSettingsProperties.setProperty("remoteAddress", remoteAddress);
379                    typeSettingsProperties.setProperty(
380                            "remoteGroupId", String.valueOf(remoteGroupId));
381                    typeSettingsProperties.setProperty(
382                            "remotePathContext", remotePathContext);
383                    typeSettingsProperties.setProperty(
384                            "remotePort", String.valueOf(remotePort));
385                    typeSettingsProperties.setProperty(
386                            "secureConnection", String.valueOf(secureConnection));
387    
388                    if (!oldStagedRemotely) {
389                            typeSettingsProperties.setProperty(
390                                    "staged", Boolean.TRUE.toString());
391                            typeSettingsProperties.setProperty(
392                                    "stagedRemotely", Boolean.TRUE.toString());
393    
394                            setCommonStagingOptions(typeSettingsProperties, serviceContext);
395                    }
396    
397                    groupLocalService.updateGroup(
398                            stagingGroup.getGroupId(), typeSettingsProperties.toString());
399    
400                    updateStagedPortlets(remoteURL, remoteGroupId, typeSettingsProperties);
401            }
402    
403            /**
404             * @deprecated As of 7.0.0, with no direct replacement
405             */
406            @Deprecated
407            @Override
408            @SuppressWarnings("unused")
409            public MissingReferences publishStagingRequest(
410                            long userId, long stagingRequestId, boolean privateLayout,
411                            Map<String, String[]> parameterMap)
412                    throws PortalException {
413    
414                    throw new UnsupportedOperationException();
415            }
416    
417            @Override
418            public MissingReferences publishStagingRequest(
419                            long userId, long stagingRequestId,
420                            ExportImportConfiguration exportImportConfiguration)
421                    throws PortalException {
422    
423                    File file = null;
424    
425                    Locale siteDefaultLocale = LocaleThreadLocal.getSiteDefaultLocale();
426    
427                    try {
428                            ExportImportThreadLocal.setLayoutImportInProcess(true);
429                            ExportImportThreadLocal.setLayoutStagingInProcess(true);
430    
431                            Folder folder = PortletFileRepositoryUtil.getPortletFolder(
432                                    stagingRequestId);
433    
434                            FileEntry stagingRequestFileEntry = getStagingRequestFileEntry(
435                                    userId, stagingRequestId, folder);
436    
437                            file = FileUtil.createTempFile("lar");
438    
439                            FileUtil.write(file, stagingRequestFileEntry.getContentStream());
440    
441                            Map<String, Serializable> settingsMap =
442                                    exportImportConfiguration.getSettingsMap();
443    
444                            settingsMap.put("userId", userId);
445    
446                            long targetGroupId = MapUtil.getLong(settingsMap, "targetGroupId");
447    
448                            LocaleThreadLocal.setSiteDefaultLocale(
449                                    PortalUtil.getSiteDefaultLocale(targetGroupId));
450    
451                            exportImportLocalService.importLayoutsDataDeletions(
452                                    exportImportConfiguration, file);
453    
454                            MissingReferences missingReferences =
455                                    exportImportLocalService.validateImportLayoutsFile(
456                                            exportImportConfiguration, file);
457    
458                            exportImportLocalService.importLayouts(
459                                    exportImportConfiguration, file);
460    
461                            return missingReferences;
462                    }
463                    catch (IOException ioe) {
464                            throw new SystemException(ioe);
465                    }
466                    finally {
467                            ExportImportThreadLocal.setLayoutImportInProcess(false);
468                            ExportImportThreadLocal.setLayoutStagingInProcess(false);
469    
470                            LocaleThreadLocal.setSiteDefaultLocale(siteDefaultLocale);
471                    }
472            }
473    
474            @Override
475            public void updateStagingRequest(
476                            long userId, long stagingRequestId, String fileName, byte[] bytes)
477                    throws PortalException {
478    
479                    Folder folder = PortletFileRepositoryUtil.getPortletFolder(
480                            stagingRequestId);
481    
482                    PortletFileRepositoryUtil.addPortletFileEntry(
483                            folder.getGroupId(), userId, Group.class.getName(),
484                            folder.getGroupId(), _PORTLET_REPOSITORY_ID, folder.getFolderId(),
485                            new UnsyncByteArrayInputStream(bytes), fileName,
486                            ContentTypes.APPLICATION_ZIP, false);
487            }
488    
489            /**
490             * @deprecated As of 7.0.0, replaced by {@link #publishStagingRequest(long,
491             *             long, boolean, Map)}
492             */
493            @Deprecated
494            @Override
495            public MissingReferences validateStagingRequest(
496                    long userId, long stagingRequestId, boolean privateLayout,
497                    Map<String, String[]> parameterMap) {
498    
499                    return new MissingReferences();
500            }
501    
502            protected void addDefaultLayoutSetBranch(
503                            long userId, long groupId, String groupName, boolean privateLayout,
504                            ServiceContext serviceContext)
505                    throws PortalException {
506    
507                    String masterBranchDescription =
508                            LayoutSetBranchConstants.MASTER_BRANCH_DESCRIPTION_PUBLIC;
509    
510                    if (privateLayout) {
511                            masterBranchDescription =
512                                    LayoutSetBranchConstants.MASTER_BRANCH_DESCRIPTION_PRIVATE;
513                    }
514    
515                    String description = LanguageUtil.format(
516                            PortalUtil.getSiteDefaultLocale(groupId), masterBranchDescription,
517                            groupName, false);
518    
519                    try {
520                            serviceContext.setWorkflowAction(WorkflowConstants.STATUS_APPROVED);
521    
522                            LayoutSetBranch layoutSetBranch =
523                                    layoutSetBranchLocalService.addLayoutSetBranch(
524                                            userId, groupId, privateLayout,
525                                            LayoutSetBranchConstants.MASTER_BRANCH_NAME, description,
526                                            true, LayoutSetBranchConstants.ALL_BRANCHES,
527                                            serviceContext);
528    
529                            List<LayoutRevision> layoutRevisions =
530                                    layoutRevisionLocalService.getLayoutRevisions(
531                                            layoutSetBranch.getLayoutSetBranchId(), false);
532    
533                            for (LayoutRevision layoutRevision : layoutRevisions) {
534                                    layoutRevisionLocalService.updateStatus(
535                                            userId, layoutRevision.getLayoutRevisionId(),
536                                            WorkflowConstants.STATUS_APPROVED, serviceContext);
537                            }
538                    }
539                    catch (PortalException pe) {
540                            if (_log.isWarnEnabled()) {
541                                    _log.warn(
542                                            "Unable to create master branch for " +
543                                                    (privateLayout ? "private" : "public") + " layouts",
544                                            pe);
545                            }
546                    }
547            }
548    
549            protected Group addStagingGroup(
550                            long userId, Group liveGroup, ServiceContext serviceContext)
551                    throws PortalException {
552    
553                    long parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
554    
555                    if (liveGroup.getParentGroupId() !=
556                                    GroupConstants.DEFAULT_PARENT_GROUP_ID) {
557    
558                            Group parentGroup = liveGroup.getParentGroup();
559    
560                            if (parentGroup.hasStagingGroup()) {
561                                    parentGroup = parentGroup.getStagingGroup();
562                            }
563    
564                            parentGroupId = parentGroup.getGroupId();
565                    }
566    
567                    Group stagingGroup = groupLocalService.addGroup(
568                            userId, parentGroupId, liveGroup.getClassName(),
569                            liveGroup.getClassPK(), liveGroup.getGroupId(),
570                            liveGroup.getNameMap(), liveGroup.getDescriptionMap(),
571                            liveGroup.getType(), liveGroup.isManualMembership(),
572                            liveGroup.getMembershipRestriction(), liveGroup.getFriendlyURL(),
573                            false, liveGroup.isActive(), serviceContext);
574    
575                    if (LanguageUtil.isInheritLocales(liveGroup.getGroupId())) {
576                            return stagingGroup;
577                    }
578    
579                    UnicodeProperties liveTypeSettingsProperties =
580                            liveGroup.getTypeSettingsProperties();
581    
582                    UnicodeProperties stagingTypeSettingsProperties =
583                            stagingGroup.getTypeSettingsProperties();
584    
585                    stagingTypeSettingsProperties.setProperty(
586                            GroupConstants.TYPE_SETTINGS_KEY_INHERIT_LOCALES,
587                            Boolean.FALSE.toString());
588                    stagingTypeSettingsProperties.setProperty(
589                            PropsKeys.LOCALES,
590                            liveTypeSettingsProperties.getProperty(PropsKeys.LOCALES));
591                    stagingTypeSettingsProperties.setProperty(
592                            "languageId",
593                            liveTypeSettingsProperties.getProperty(
594                                    "languageId",
595                                    LocaleUtil.toLanguageId(LocaleUtil.getDefault())));
596    
597                    return groupLocalService.updateGroup(
598                            stagingGroup.getGroupId(),
599                            stagingTypeSettingsProperties.toString());
600            }
601    
602            protected void deleteLayoutSetBranches(long groupId, boolean privateLayout)
603                    throws PortalException {
604    
605                    // Find the latest layout revision for all the layouts
606    
607                    Map<Long, LayoutRevision> layoutRevisions = new HashMap<>();
608    
609                    List<LayoutSetBranch> layoutSetBranches =
610                            layoutSetBranchLocalService.getLayoutSetBranches(
611                                    groupId, privateLayout);
612    
613                    boolean publishedToLive = false;
614    
615                    for (LayoutSetBranch layoutSetBranch : layoutSetBranches) {
616                            String lastPublishDateString = layoutSetBranch.getSettingsProperty(
617                                    "last-publish-date");
618    
619                            if (Validator.isNotNull(lastPublishDateString)) {
620                                    publishedToLive = true;
621    
622                                    break;
623                            }
624                    }
625    
626                    for (LayoutSetBranch layoutSetBranch : layoutSetBranches) {
627                            String lastPublishDateString = layoutSetBranch.getSettingsProperty(
628                                    "last-publish-date");
629    
630                            if (Validator.isNull(lastPublishDateString) && publishedToLive) {
631                                    continue;
632                            }
633    
634                            Date lastPublishDate = null;
635    
636                            if (Validator.isNotNull(lastPublishDateString)) {
637                                    lastPublishDate = new Date(
638                                            GetterUtil.getLong(lastPublishDateString));
639                            }
640    
641                            List<LayoutRevision> headLayoutRevisions =
642                                    layoutRevisionLocalService.getLayoutRevisions(
643                                            layoutSetBranch.getLayoutSetBranchId(), true);
644    
645                            for (LayoutRevision headLayoutRevision : headLayoutRevisions) {
646                                    LayoutRevision layoutRevision = layoutRevisions.get(
647                                            headLayoutRevision.getPlid());
648    
649                                    if (layoutRevision == null) {
650                                            layoutRevisions.put(
651                                                    headLayoutRevision.getPlid(), headLayoutRevision);
652    
653                                            continue;
654                                    }
655    
656                                    Date statusDate = headLayoutRevision.getStatusDate();
657    
658                                    if (statusDate.after(layoutRevision.getStatusDate()) &&
659                                            ((lastPublishDate == null) ||
660                                             lastPublishDate.after(statusDate))) {
661    
662                                            layoutRevisions.put(
663                                                    headLayoutRevision.getPlid(), headLayoutRevision);
664                                    }
665                            }
666                    }
667    
668                    // Update all layouts based on their latest revision
669    
670                    for (LayoutRevision layoutRevision : layoutRevisions.values()) {
671                            updateLayoutWithLayoutRevision(layoutRevision);
672                    }
673    
674                    layoutSetBranchLocalService.deleteLayoutSetBranches(
675                            groupId, privateLayout, true);
676            }
677    
678            protected void disableRemoteStaging(
679                            String remoteURL, long remoteGroupId, boolean forceDisable)
680                    throws PortalException {
681    
682                    PermissionChecker permissionChecker =
683                            PermissionThreadLocal.getPermissionChecker();
684    
685                    User user = permissionChecker.getUser();
686    
687                    HttpPrincipal httpPrincipal = new HttpPrincipal(
688                            remoteURL, user.getLogin(), user.getPassword(),
689                            user.getPasswordEncrypted());
690    
691                    try {
692                            GroupServiceHttp.disableStaging(httpPrincipal, remoteGroupId);
693                    }
694                    catch (NoSuchGroupException nsge) {
695                            if (_log.isWarnEnabled()) {
696                                    _log.warn("Remote live group was already deleted", nsge);
697                            }
698                    }
699                    catch (PrincipalException pe) {
700                            RemoteExportException ree = new RemoteExportException(
701                                    RemoteExportException.NO_PERMISSIONS);
702    
703                            ree.setGroupId(remoteGroupId);
704    
705                            throw ree;
706                    }
707                    catch (RemoteAuthException rae) {
708                            rae.setURL(remoteURL);
709    
710                            throw rae;
711                    }
712                    catch (SystemException se) {
713                            if (!forceDisable) {
714                                    RemoteExportException ree = new RemoteExportException(
715                                            RemoteExportException.BAD_CONNECTION);
716    
717                                    ree.setURL(remoteURL);
718    
719                                    throw ree;
720                            }
721    
722                            if (_log.isWarnEnabled()) {
723                                    _log.warn("Forcibly disable remote staging");
724                            }
725                    }
726            }
727    
728            protected void enableRemoteStaging(String remoteURL, long remoteGroupId)
729                    throws PortalException {
730    
731                    PermissionChecker permissionChecker =
732                            PermissionThreadLocal.getPermissionChecker();
733    
734                    User user = permissionChecker.getUser();
735    
736                    HttpPrincipal httpPrincipal = new HttpPrincipal(
737                            remoteURL, user.getLogin(), user.getPassword(),
738                            user.getPasswordEncrypted());
739    
740                    try {
741                            GroupServiceHttp.enableStaging(httpPrincipal, remoteGroupId);
742                    }
743                    catch (NoSuchGroupException nsge) {
744                            RemoteExportException ree = new RemoteExportException(
745                                    RemoteExportException.NO_GROUP);
746    
747                            ree.setGroupId(remoteGroupId);
748    
749                            throw ree;
750                    }
751                    catch (PrincipalException pe) {
752                            RemoteExportException ree = new RemoteExportException(
753                                    RemoteExportException.NO_PERMISSIONS);
754    
755                            ree.setGroupId(remoteGroupId);
756    
757                            throw ree;
758                    }
759                    catch (RemoteAuthException rae) {
760                            rae.setURL(remoteURL);
761    
762                            throw rae;
763                    }
764                    catch (SystemException se) {
765                            RemoteExportException ree = new RemoteExportException(
766                                    RemoteExportException.BAD_CONNECTION);
767    
768                            ree.setURL(remoteURL);
769    
770                            throw ree;
771                    }
772            }
773    
774            protected FileEntry fetchStagingRequestFileEntry(
775                            long stagingRequestId, Folder folder)
776                    throws PortalException {
777    
778                    try {
779                            return PortletFileRepositoryUtil.getPortletFileEntry(
780                                    folder.getGroupId(), folder.getFolderId(),
781                                    getAssembledFileName(stagingRequestId));
782                    }
783                    catch (NoSuchFileEntryException nsfe) {
784                            return null;
785                    }
786            }
787    
788            protected String getAssembledFileName(long stagingRequestId) {
789                    return _ASSEMBLED_LAR_PREFIX + String.valueOf(stagingRequestId) +
790                            ".lar";
791            }
792    
793            protected FileEntry getStagingRequestFileEntry(
794                            long userId, long stagingRequestId, Folder folder)
795                    throws PortalException {
796    
797                    FileEntry stagingRequestFileEntry = fetchStagingRequestFileEntry(
798                            stagingRequestId, folder);
799    
800                    if (stagingRequestFileEntry != null) {
801                            return stagingRequestFileEntry;
802                    }
803    
804                    FileOutputStream fileOutputStream = null;
805    
806                    File tempFile = null;
807    
808                    try {
809                            tempFile = FileUtil.createTempFile("lar");
810    
811                            fileOutputStream = new FileOutputStream(tempFile);
812    
813                            List<FileEntry> fileEntries =
814                                    PortletFileRepositoryUtil.getPortletFileEntries(
815                                            folder.getGroupId(), folder.getFolderId(),
816                                            new RepositoryModelTitleComparator<FileEntry>(true));
817    
818                            for (FileEntry fileEntry : fileEntries) {
819                                    try {
820                                            StreamUtil.transfer(
821                                                    fileEntry.getContentStream(),
822                                                    StreamUtil.uncloseable(fileOutputStream));
823                                    }
824                                    finally {
825                                            PortletFileRepositoryUtil.deletePortletFileEntry(
826                                                    fileEntry.getFileEntryId());
827                                    }
828                            }
829    
830                            String checksum = FileUtil.getMD5Checksum(tempFile);
831    
832                            if (!checksum.equals(folder.getName())) {
833                                    throw new SystemException("Invalid checksum for LAR file");
834                            }
835    
836                            PortletFileRepositoryUtil.addPortletFileEntry(
837                                    folder.getGroupId(), userId, Group.class.getName(),
838                                    folder.getGroupId(), _PORTLET_REPOSITORY_ID,
839                                    folder.getFolderId(), tempFile,
840                                    getAssembledFileName(stagingRequestId),
841                                    ContentTypes.APPLICATION_ZIP, false);
842    
843                            stagingRequestFileEntry = fetchStagingRequestFileEntry(
844                                    stagingRequestId, folder);
845    
846                            if (stagingRequestFileEntry == null) {
847                                    throw new SystemException("Unable to assemble LAR file");
848                            }
849    
850                            return stagingRequestFileEntry;
851                    }
852                    catch (IOException ioe) {
853                            throw new SystemException("Unable to reassemble LAR file", ioe);
854                    }
855                    finally {
856                            StreamUtil.cleanUp(fileOutputStream);
857    
858                            FileUtil.delete(tempFile);
859                    }
860            }
861    
862            protected void setCommonStagingOptions(
863                    UnicodeProperties typeSettingsProperties,
864                    ServiceContext serviceContext) {
865    
866                    typeSettingsProperties.putAll(
867                            PropertiesParamUtil.getProperties(
868                                    serviceContext, StagingConstants.STAGED_PREFIX));
869            }
870    
871            protected Layout updateLayoutWithLayoutRevision(
872                    LayoutRevision layoutRevision) {
873    
874                    // Suppress the usage of the advice to get the latest layout to prevent
875                    // a StaleObjectStateException
876    
877                    Layout layout = null;
878    
879                    boolean stagingAdvicesThreadLocalEnabled =
880                            StagingAdvicesThreadLocal.isEnabled();
881    
882                    try {
883                            StagingAdvicesThreadLocal.setEnabled(false);
884    
885                            layout = layoutLocalService.fetchLayout(layoutRevision.getPlid());
886                    }
887                    finally {
888                            StagingAdvicesThreadLocal.setEnabled(
889                                    stagingAdvicesThreadLocalEnabled);
890                    }
891    
892                    updatePortletPreferences(layoutRevision, layout);
893    
894                    layout.setUserId(layoutRevision.getUserId());
895                    layout.setUserName(layoutRevision.getUserName());
896                    layout.setCreateDate(layoutRevision.getCreateDate());
897                    layout.setModifiedDate(layoutRevision.getModifiedDate());
898                    layout.setPrivateLayout(layoutRevision.getPrivateLayout());
899                    layout.setName(layoutRevision.getName());
900                    layout.setTitle(layoutRevision.getTitle());
901                    layout.setDescription(layoutRevision.getDescription());
902                    layout.setKeywords(layoutRevision.getKeywords());
903                    layout.setRobots(layoutRevision.getRobots());
904                    layout.setTypeSettings(layoutRevision.getTypeSettings());
905                    layout.setIconImageId(layoutRevision.getIconImageId());
906                    layout.setThemeId(layoutRevision.getThemeId());
907                    layout.setColorSchemeId(layoutRevision.getColorSchemeId());
908                    layout.setWapThemeId(layoutRevision.getWapThemeId());
909                    layout.setWapColorSchemeId(layoutRevision.getWapColorSchemeId());
910                    layout.setCss(layoutRevision.getCss());
911    
912                    return layoutLocalService.updateLayout(layout);
913            }
914    
915            protected void updatePortletPreferences(
916                    LayoutRevision layoutRevision, Layout layout) {
917    
918                    portletPreferencesLocalService.deletePortletPreferencesByPlid(
919                            layout.getPlid());
920    
921                    List<PortletPreferences> portletPreferencesList =
922                            portletPreferencesLocalService.getPortletPreferencesByPlid(
923                                    layoutRevision.getLayoutRevisionId());
924    
925                    for (PortletPreferences portletPreferences : portletPreferencesList) {
926                            portletPreferencesLocalService.addPortletPreferences(
927                                    layoutRevision.getCompanyId(), portletPreferences.getOwnerId(),
928                                    portletPreferences.getOwnerType(), layout.getPlid(),
929                                    portletPreferences.getPortletId(), null,
930                                    portletPreferences.getPreferences());
931                    }
932            }
933    
934            protected void updateStagedPortlets(
935                            String remoteURL, long remoteGroupId,
936                            UnicodeProperties typeSettingsProperties)
937                    throws PortalException {
938    
939                    PermissionChecker permissionChecker =
940                            PermissionThreadLocal.getPermissionChecker();
941    
942                    User user = permissionChecker.getUser();
943    
944                    HttpPrincipal httpPrincipal = new HttpPrincipal(
945                            remoteURL, user.getLogin(), user.getPassword(),
946                            user.getPasswordEncrypted());
947    
948                    Map<String, String> stagedPortletIds = new HashMap<>();
949    
950                    for (String key : typeSettingsProperties.keySet()) {
951                            if (key.startsWith(StagingConstants.STAGED_PORTLET)) {
952                                    stagedPortletIds.put(
953                                            key, typeSettingsProperties.getProperty(key));
954                            }
955                    }
956    
957                    try {
958                            GroupServiceHttp.updateStagedPortlets(
959                                    httpPrincipal, remoteGroupId, stagedPortletIds);
960                    }
961                    catch (NoSuchGroupException nsge) {
962                            RemoteExportException ree = new RemoteExportException(
963                                    RemoteExportException.NO_GROUP);
964    
965                            ree.setGroupId(remoteGroupId);
966    
967                            throw ree;
968                    }
969                    catch (PrincipalException pe) {
970                            RemoteExportException ree = new RemoteExportException(
971                                    RemoteExportException.NO_PERMISSIONS);
972    
973                            ree.setGroupId(remoteGroupId);
974    
975                            throw ree;
976                    }
977                    catch (RemoteAuthException rae) {
978                            rae.setURL(remoteURL);
979    
980                            throw rae;
981                    }
982                    catch (SystemException se) {
983                            RemoteExportException ree = new RemoteExportException(
984                                    RemoteExportException.BAD_CONNECTION);
985    
986                            ree.setURL(remoteURL);
987    
988                            throw ree;
989                    }
990            }
991    
992            private static final String _ASSEMBLED_LAR_PREFIX = "assembled_";
993    
994            private static final String _PORTLET_REPOSITORY_ID = "134";
995    
996            private static final Log _log = LogFactoryUtil.getLog(
997                    StagingLocalServiceImpl.class);
998    
999    }