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