001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.portal.NoSuchLayoutException;
018 import com.liferay.portal.kernel.language.LanguageUtil;
019 import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
020 import com.liferay.portal.kernel.lar.PortletDataContext;
021 import com.liferay.portal.kernel.lar.PortletDataHandler;
022 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.servlet.ServletContextPool;
026 import com.liferay.portal.kernel.staging.LayoutStagingUtil;
027 import com.liferay.portal.kernel.util.CharPool;
028 import com.liferay.portal.kernel.util.FileUtil;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.LocaleUtil;
031 import com.liferay.portal.kernel.util.MapUtil;
032 import com.liferay.portal.kernel.util.ParamUtil;
033 import com.liferay.portal.kernel.util.ReleaseInfo;
034 import com.liferay.portal.kernel.util.StringBundler;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.StringUtil;
037 import com.liferay.portal.kernel.util.Time;
038 import com.liferay.portal.kernel.util.UnicodeProperties;
039 import com.liferay.portal.kernel.util.Validator;
040 import com.liferay.portal.kernel.workflow.WorkflowConstants;
041 import com.liferay.portal.kernel.xml.Document;
042 import com.liferay.portal.kernel.xml.Element;
043 import com.liferay.portal.kernel.xml.SAXReaderUtil;
044 import com.liferay.portal.kernel.zip.ZipWriter;
045 import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
046 import com.liferay.portal.model.Group;
047 import com.liferay.portal.model.Image;
048 import com.liferay.portal.model.Layout;
049 import com.liferay.portal.model.LayoutConstants;
050 import com.liferay.portal.model.LayoutPrototype;
051 import com.liferay.portal.model.LayoutRevision;
052 import com.liferay.portal.model.LayoutSet;
053 import com.liferay.portal.model.LayoutSetPrototype;
054 import com.liferay.portal.model.LayoutStagingHandler;
055 import com.liferay.portal.model.LayoutTypePortlet;
056 import com.liferay.portal.model.Portlet;
057 import com.liferay.portal.model.PortletConstants;
058 import com.liferay.portal.model.Theme;
059 import com.liferay.portal.model.impl.LayoutImpl;
060 import com.liferay.portal.service.GroupLocalServiceUtil;
061 import com.liferay.portal.service.ImageLocalServiceUtil;
062 import com.liferay.portal.service.LayoutLocalServiceUtil;
063 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
064 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
065 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
066 import com.liferay.portal.service.PortletLocalServiceUtil;
067 import com.liferay.portal.service.ServiceContext;
068 import com.liferay.portal.service.ServiceContextThreadLocal;
069 import com.liferay.portal.service.UserLocalServiceUtil;
070 import com.liferay.portal.service.permission.PortletPermissionUtil;
071 import com.liferay.portal.service.persistence.LayoutRevisionUtil;
072 import com.liferay.portal.theme.ThemeLoader;
073 import com.liferay.portal.theme.ThemeLoaderFactory;
074 import com.liferay.portal.util.PortletKeys;
075 import com.liferay.portal.util.PropsValues;
076 import com.liferay.portlet.PortletPreferencesFactoryUtil;
077 import com.liferay.portlet.asset.model.AssetCategory;
078 import com.liferay.portlet.asset.model.AssetVocabulary;
079 import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
080 import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
081 import com.liferay.portlet.journal.NoSuchArticleException;
082 import com.liferay.portlet.journal.lar.JournalPortletDataHandler;
083 import com.liferay.portlet.journal.model.JournalArticle;
084 import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
085 import com.liferay.util.ContentUtil;
086
087 import java.io.File;
088
089 import java.util.Date;
090 import java.util.HashSet;
091 import java.util.Iterator;
092 import java.util.LinkedHashMap;
093 import java.util.List;
094 import java.util.Map;
095
096 import javax.servlet.ServletContext;
097
098 import org.apache.commons.lang.time.StopWatch;
099
100
112 public class LayoutExporter {
113
114 public static final String SAME_GROUP_FRIENDLY_URL =
115 "/[$SAME_GROUP_FRIENDLY_URL$]";
116
117 public static List<Portlet> getAlwaysExportablePortlets(long companyId)
118 throws Exception {
119
120 List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
121
122 Iterator<Portlet> itr = portlets.iterator();
123
124 while (itr.hasNext()) {
125 Portlet portlet = itr.next();
126
127 if (!portlet.isActive()) {
128 itr.remove();
129
130 continue;
131 }
132
133 PortletDataHandler portletDataHandler =
134 portlet.getPortletDataHandlerInstance();
135
136 if ((portletDataHandler == null) ||
137 !portletDataHandler.isAlwaysExportable()) {
138
139 itr.remove();
140 }
141 }
142
143 return portlets;
144 }
145
146 public static void updateLastPublishDate(
147 LayoutSet layoutSet, long lastPublishDate)
148 throws Exception {
149
150 UnicodeProperties settingsProperties =
151 layoutSet.getSettingsProperties();
152
153 if (lastPublishDate <= 0) {
154 settingsProperties.remove("last-publish-date");
155 }
156 else {
157 settingsProperties.setProperty(
158 "last-publish-date", String.valueOf(lastPublishDate));
159 }
160
161 LayoutSetLocalServiceUtil.updateSettings(
162 layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
163 settingsProperties.toString());
164 }
165
166 public byte[] exportLayouts(
167 long groupId, boolean privateLayout, long[] layoutIds,
168 Map<String, String[]> parameterMap, Date startDate, Date endDate)
169 throws Exception {
170
171 File file = exportLayoutsAsFile(
172 groupId, privateLayout, layoutIds, parameterMap, startDate,
173 endDate);
174
175 try {
176 return FileUtil.getBytes(file);
177 }
178 finally {
179 file.delete();
180 }
181 }
182
183 public File exportLayoutsAsFile(
184 long groupId, boolean privateLayout, long[] layoutIds,
185 Map<String, String[]> parameterMap, Date startDate, Date endDate)
186 throws Exception {
187
188 try {
189 ExportImportThreadLocal.setLayoutExportInProcess(true);
190
191 return doExportLayoutsAsFile(
192 groupId, privateLayout, layoutIds, parameterMap, startDate,
193 endDate);
194 }
195 finally {
196 ExportImportThreadLocal.setLayoutExportInProcess(false);
197 }
198 }
199
200 protected File doExportLayoutsAsFile(
201 long groupId, boolean privateLayout, long[] layoutIds,
202 Map<String, String[]> parameterMap, Date startDate, Date endDate)
203 throws Exception {
204
205 boolean exportCategories = MapUtil.getBoolean(
206 parameterMap, PortletDataHandlerKeys.CATEGORIES);
207 boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
208 parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
209 boolean exportPermissions = MapUtil.getBoolean(
210 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
211 boolean exportPortletArchivedSetups = MapUtil.getBoolean(
212 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
213 boolean exportPortletUserPreferences = MapUtil.getBoolean(
214 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
215 boolean exportTheme = MapUtil.getBoolean(
216 parameterMap, PortletDataHandlerKeys.THEME);
217 boolean exportThemeSettings = MapUtil.getBoolean(
218 parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
219 boolean exportLogo = MapUtil.getBoolean(
220 parameterMap, PortletDataHandlerKeys.LOGO);
221 boolean exportLayoutSetSettings = MapUtil.getBoolean(
222 parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
223
224
225 boolean updateLastPublishDate = MapUtil.getBoolean(
226 parameterMap, PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);
227
228 if (_log.isDebugEnabled()) {
229 _log.debug("Export categories " + exportCategories);
230 _log.debug("Export permissions " + exportPermissions);
231 _log.debug(
232 "Export portlet archived setups " +
233 exportPortletArchivedSetups);
234 _log.debug(
235 "Export portlet user preferences " +
236 exportPortletUserPreferences);
237 _log.debug("Export theme " + exportTheme);
238 }
239
240 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
241 groupId, privateLayout);
242
243 long companyId = layoutSet.getCompanyId();
244 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
245
246 ServiceContext serviceContext =
247 ServiceContextThreadLocal.getServiceContext();
248
249 if (serviceContext == null) {
250 serviceContext = new ServiceContext();
251
252 serviceContext.setCompanyId(companyId);
253 serviceContext.setSignedIn(false);
254 serviceContext.setUserId(defaultUserId);
255
256 ServiceContextThreadLocal.pushServiceContext(serviceContext);
257 }
258
259 serviceContext.setAttribute("exporting", Boolean.TRUE);
260
261 long layoutSetBranchId = MapUtil.getLong(
262 parameterMap, "layoutSetBranchId");
263
264 serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
265
266 long lastPublishDate = System.currentTimeMillis();
267
268 if (endDate != null) {
269 lastPublishDate = endDate.getTime();
270 }
271
272 if (exportIgnoreLastPublishDate) {
273 endDate = null;
274 startDate = null;
275 }
276
277 StopWatch stopWatch = null;
278
279 if (_log.isInfoEnabled()) {
280 stopWatch = new StopWatch();
281
282 stopWatch.start();
283 }
284
285 LayoutCache layoutCache = new LayoutCache();
286
287 ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
288
289 PortletDataContext portletDataContext = new PortletDataContextImpl(
290 companyId, groupId, parameterMap, new HashSet<String>(), startDate,
291 endDate, zipWriter);
292
293 portletDataContext.setPortetDataContextListener(
294 new PortletDataContextListenerImpl(portletDataContext));
295
296 Document document = SAXReaderUtil.createDocument();
297
298 Element rootElement = document.addElement("root");
299
300 Element headerElement = rootElement.addElement("header");
301
302 headerElement.addAttribute(
303 "available-locales",
304 StringUtil.merge(LanguageUtil.getAvailableLocales()));
305 headerElement.addAttribute(
306 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
307 headerElement.addAttribute("export-date", Time.getRFC822());
308
309 if (portletDataContext.hasDateRange()) {
310 headerElement.addAttribute(
311 "start-date",
312 String.valueOf(portletDataContext.getStartDate()));
313 headerElement.addAttribute(
314 "end-date", String.valueOf(portletDataContext.getEndDate()));
315 }
316
317 headerElement.addAttribute("group-id", String.valueOf(groupId));
318 headerElement.addAttribute(
319 "private-layout", String.valueOf(privateLayout));
320
321 Group group = layoutSet.getGroup();
322
323 String type = "layout-set";
324
325 if (group.isLayoutPrototype()) {
326 type = "layout-prototype";
327
328 LayoutPrototype layoutPrototype =
329 LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
330 group.getClassPK());
331
332 headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
333 }
334 else if (group.isLayoutSetPrototype()) {
335 type ="layout-set-prototype";
336
337 LayoutSetPrototype layoutSetPrototype =
338 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
339 group.getClassPK());
340
341 headerElement.addAttribute(
342 "type-uuid", layoutSetPrototype.getUuid());
343 }
344
345 headerElement.addAttribute("type", type);
346
347 if (exportTheme || exportThemeSettings) {
348 headerElement.addAttribute("theme-id", layoutSet.getThemeId());
349 headerElement.addAttribute(
350 "color-scheme-id", layoutSet.getColorSchemeId());
351 }
352
353 if (exportLogo) {
354 Image image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
355
356 if ((image != null) && (image.getTextObj() != null)) {
357 String logoPath = getLayoutSetLogoPath(portletDataContext);
358
359 headerElement.addAttribute("logo-path", logoPath);
360
361 portletDataContext.addZipEntry(logoPath, image.getTextObj());
362 }
363 }
364
365 if (exportLayoutSetSettings) {
366 Element settingsElement = headerElement.addElement("settings");
367
368 settingsElement.addCDATA(layoutSet.getSettings());
369 }
370
371 Element cssElement = headerElement.addElement("css");
372
373 cssElement.addCDATA(layoutSet.getCss());
374
375 Portlet layoutConfigurationPortlet =
376 PortletLocalServiceUtil.getPortletById(
377 portletDataContext.getCompanyId(),
378 PortletKeys.LAYOUT_CONFIGURATION);
379
380 Map<String, Object[]> portletIds =
381 new LinkedHashMap<String, Object[]>();
382
383 List<Layout> layouts = null;
384
385 if ((layoutIds == null) || (layoutIds.length == 0)) {
386 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
387 }
388 else {
389 layouts = LayoutLocalServiceUtil.getLayouts(
390 groupId, privateLayout, layoutIds);
391 }
392
393 List<Portlet> portlets = getAlwaysExportablePortlets(companyId);
394
395 long plid = LayoutConstants.DEFAULT_PLID;
396
397 if (!layouts.isEmpty()) {
398 Layout firstLayout = layouts.get(0);
399
400 plid = firstLayout.getPlid();
401 }
402
403 if (group.isStagingGroup()) {
404 group = group.getLiveGroup();
405 }
406
407 for (Portlet portlet : portlets) {
408 String portletId = portlet.getRootPortletId();
409
410 if (!group.isStagedPortlet(portletId)) {
411 continue;
412 }
413
414 String key = PortletPermissionUtil.getPrimaryKey(0, portletId);
415
416 if (portletIds.get(key) == null) {
417 portletIds.put(
418 key,
419 new Object[] {
420 portletId, plid, groupId, StringPool.BLANK,
421 StringPool.BLANK
422 });
423 }
424 }
425
426 Element layoutsElement = rootElement.addElement("layouts");
427
428 String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
429
430 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
431 LayoutSetPrototype layoutSetPrototype =
432 LayoutSetPrototypeLocalServiceUtil.
433 getLayoutSetPrototypeByUuidAndCompanyId(
434 layoutSetPrototypeUuid, companyId);
435
436 layoutsElement.addAttribute(
437 "layout-set-prototype-uuid", layoutSetPrototypeUuid);
438
439 layoutsElement.addAttribute(
440 "layout-set-prototype-name",
441 layoutSetPrototype.getName(LocaleUtil.getDefault()));
442 }
443
444 for (Layout layout : layouts) {
445 exportLayout(
446 portletDataContext, layoutConfigurationPortlet, layoutCache,
447 portlets, portletIds, exportPermissions, layout,
448 layoutsElement);
449 }
450
451 long previousScopeGroupId = portletDataContext.getScopeGroupId();
452
453 Element portletsElement = rootElement.addElement("portlets");
454
455 for (Map.Entry<String, Object[]> portletIdsEntry :
456 portletIds.entrySet()) {
457
458 Object[] portletObjects = portletIdsEntry.getValue();
459
460 String portletId = null;
461 plid = LayoutConstants.DEFAULT_PLID;
462 long scopeGroupId = 0;
463 String scopeType = StringPool.BLANK;
464 String scopeLayoutUuid = null;
465
466 if (portletObjects.length == 4) {
467 portletId = (String)portletIdsEntry.getValue()[0];
468 plid = (Long)portletIdsEntry.getValue()[1];
469 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
470 scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
471 }
472 else {
473 portletId = (String)portletIdsEntry.getValue()[0];
474 plid = (Long)portletIdsEntry.getValue()[1];
475 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
476 scopeType = (String)portletIdsEntry.getValue()[3];
477 scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
478 }
479
480 Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
481
482 if (layout == null) {
483 if (!group.isCompany() &&
484 (plid <= LayoutConstants.DEFAULT_PLID)) {
485
486 continue;
487 }
488
489 if (_log.isWarnEnabled()) {
490 _log.warn(
491 "Assuming global scope because no layout was found");
492 }
493
494 layout = new LayoutImpl();
495
496 layout.setGroupId(groupId);
497 layout.setCompanyId(companyId);
498 }
499
500 portletDataContext.setPlid(plid);
501 portletDataContext.setOldPlid(plid);
502 portletDataContext.setScopeGroupId(scopeGroupId);
503 portletDataContext.setScopeType(scopeType);
504 portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
505
506 boolean[] exportPortletControls = getExportPortletControls(
507 companyId, portletId, portletDataContext, parameterMap, type);
508
509 _portletExporter.exportPortlet(
510 portletDataContext, layoutCache, portletId, layout,
511 portletsElement, defaultUserId, exportPermissions,
512 exportPortletArchivedSetups, exportPortletControls[0],
513 exportPortletControls[1], exportPortletUserPreferences);
514 }
515
516 portletDataContext.setScopeGroupId(previousScopeGroupId);
517
518 if (exportCategories || group.isCompany()) {
519 exportAssetCategories(portletDataContext);
520 }
521
522 _portletExporter.exportAssetLinks(portletDataContext);
523 _portletExporter.exportAssetTags(portletDataContext);
524 _portletExporter.exportComments(portletDataContext);
525 _portletExporter.exportExpandoTables(portletDataContext);
526 _portletExporter.exportLocks(portletDataContext);
527
528 if (exportPermissions) {
529 _permissionExporter.exportPortletDataPermissions(
530 portletDataContext);
531 }
532
533 _portletExporter.exportRatingsEntries(portletDataContext, rootElement);
534
535 if (exportTheme && !portletDataContext.isPerformDirectBinaryImport()) {
536 exportTheme(layoutSet, zipWriter);
537 }
538
539 if (_log.isInfoEnabled()) {
540 if (stopWatch != null) {
541 _log.info(
542 "Exporting layouts takes " + stopWatch.getTime() + " ms");
543 }
544 else {
545 _log.info("Exporting layouts is finished");
546 }
547 }
548
549 portletDataContext.addZipEntry(
550 "/manifest.xml", document.formattedString());
551
552 try {
553 return zipWriter.getFile();
554 }
555 finally {
556 if (updateLastPublishDate) {
557 updateLastPublishDate(layoutSet, lastPublishDate);
558 }
559 }
560 }
561
562 protected void exportAssetCategories(PortletDataContext portletDataContext)
563 throws Exception {
564
565 Document document = SAXReaderUtil.createDocument();
566
567 Element rootElement = document.addElement("categories-hierarchy");
568
569 Element assetVocabulariesElement = rootElement.addElement(
570 "vocabularies");
571
572 List<AssetVocabulary> assetVocabularies =
573 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
574 portletDataContext.getGroupId());
575
576 for (AssetVocabulary assetVocabulary : assetVocabularies) {
577 _portletExporter.exportAssetVocabulary(
578 portletDataContext, assetVocabulariesElement, assetVocabulary);
579 }
580
581 Element categoriesElement = rootElement.addElement("categories");
582
583 List<AssetCategory> assetCategories = AssetCategoryUtil.findByGroupId(
584 portletDataContext.getGroupId());
585
586 for (AssetCategory assetCategory : assetCategories) {
587 _portletExporter.exportAssetCategory(
588 portletDataContext, assetVocabulariesElement, categoriesElement,
589 assetCategory);
590 }
591
592 _portletExporter.exportAssetCategories(portletDataContext, rootElement);
593
594 portletDataContext.addZipEntry(
595 portletDataContext.getRootPath() + "/categories-hierarchy.xml",
596 document.formattedString());
597 }
598
599 protected void exportJournalArticle(
600 PortletDataContext portletDataContext, Layout layout,
601 Element layoutElement)
602 throws Exception {
603
604 UnicodeProperties typeSettingsProperties =
605 layout.getTypeSettingsProperties();
606
607 String articleId = typeSettingsProperties.getProperty(
608 "article-id", StringPool.BLANK);
609
610 long articleGroupId = layout.getGroupId();
611
612 if (Validator.isNull(articleId)) {
613 if (_log.isWarnEnabled()) {
614 _log.warn(
615 "No article id found in typeSettings of layout " +
616 layout.getPlid());
617 }
618 }
619
620 JournalArticle article = null;
621
622 try {
623 article = JournalArticleLocalServiceUtil.getLatestArticle(
624 articleGroupId, articleId, WorkflowConstants.STATUS_APPROVED);
625 }
626 catch (NoSuchArticleException nsae) {
627 if (_log.isWarnEnabled()) {
628 _log.warn(
629 "No approved article found with group id " +
630 articleGroupId + " and article id " + articleId);
631 }
632 }
633
634 if (article == null) {
635 return;
636 }
637
638 String path = JournalPortletDataHandler.getArticlePath(
639 portletDataContext, article);
640
641 Element articleElement = layoutElement.addElement("article");
642
643 articleElement.addAttribute("path", path);
644
645 Element dlFileEntryTypesElement = layoutElement.addElement(
646 "dl-file-entry-types");
647 Element dlFoldersElement = layoutElement.addElement("dl-folders");
648 Element dlFilesElement = layoutElement.addElement("dl-file-entries");
649 Element dlFileRanksElement = layoutElement.addElement("dl-file-ranks");
650 Element dlRepositoriesElement = layoutElement.addElement(
651 "dl-repositories");
652 Element dlRepositoryEntriesElement = layoutElement.addElement(
653 "dl-repository-entries");
654
655 JournalPortletDataHandler.exportArticle(
656 portletDataContext, layoutElement, layoutElement, layoutElement,
657 dlFileEntryTypesElement, dlFoldersElement, dlFilesElement,
658 dlFileRanksElement, dlRepositoriesElement,
659 dlRepositoryEntriesElement, article, false);
660 }
661
662 protected void exportLayout(
663 PortletDataContext portletDataContext,
664 Portlet layoutConfigurationPortlet, LayoutCache layoutCache,
665 List<Portlet> portlets, Map<String, Object[]> portletIds,
666 boolean exportPermissions, Layout layout, Element layoutsElement)
667 throws Exception {
668
669 String path = portletDataContext.getLayoutPath(
670 layout.getLayoutId()) + "/layout.xml";
671
672 if (!portletDataContext.isPathNotProcessed(path)) {
673 return;
674 }
675
676 LayoutRevision layoutRevision = null;
677
678 ServiceContext serviceContext =
679 ServiceContextThreadLocal.getServiceContext();
680
681 boolean exportLAR = ParamUtil.getBoolean(serviceContext, "exportLAR");
682
683 if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout) &&
684 !layout.isTypeURL()) {
685
686 long layoutSetBranchId = ParamUtil.getLong(
687 serviceContext, "layoutSetBranchId");
688
689 if (layoutSetBranchId <= 0) {
690 return;
691 }
692
693 layoutRevision = LayoutRevisionUtil.fetchByL_H_P(
694 layoutSetBranchId, true, layout.getPlid());
695
696 if (layoutRevision == null) {
697 return;
698 }
699
700 LayoutStagingHandler layoutStagingHandler =
701 LayoutStagingUtil.getLayoutStagingHandler(layout);
702
703 layoutStagingHandler.setLayoutRevision(layoutRevision);
704 }
705
706 Element layoutElement = layoutsElement.addElement("layout");
707
708 if (layoutRevision != null) {
709 layoutElement.addAttribute(
710 "layout-revision-id",
711 String.valueOf(layoutRevision.getLayoutRevisionId()));
712 layoutElement.addAttribute(
713 "layout-branch-id",
714 String.valueOf(layoutRevision.getLayoutBranchId()));
715 layoutElement.addAttribute(
716 "layout-branch-name",
717 String.valueOf(layoutRevision.getLayoutBranch().getName()));
718 }
719
720 layoutElement.addAttribute("layout-uuid", layout.getUuid());
721 layoutElement.addAttribute(
722 "layout-id", String.valueOf(layout.getLayoutId()));
723
724 long parentLayoutId = layout.getParentLayoutId();
725
726 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
727 Layout parentLayout = LayoutLocalServiceUtil.getLayout(
728 layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
729
730 if (parentLayout != null) {
731 layoutElement.addAttribute(
732 "parent-layout-uuid", parentLayout.getUuid());
733 }
734 }
735
736 String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
737
738 if (Validator.isNotNull(layoutPrototypeUuid)) {
739 LayoutPrototype layoutPrototype =
740 LayoutPrototypeLocalServiceUtil.
741 getLayoutPrototypeByUuidAndCompanyId(
742 layoutPrototypeUuid, portletDataContext.getCompanyId());
743
744 layoutElement.addAttribute(
745 "layout-prototype-uuid", layoutPrototypeUuid);
746 layoutElement.addAttribute(
747 "layout-prototype-name",
748 layoutPrototype.getName(LocaleUtil.getDefault()));
749 }
750
751 boolean deleteLayout = MapUtil.getBoolean(
752 portletDataContext.getParameterMap(), "delete_" + layout.getPlid());
753
754 if (deleteLayout) {
755 layoutElement.addAttribute("delete", String.valueOf(true));
756
757 return;
758 }
759
760 portletDataContext.setPlid(layout.getPlid());
761
762 if (layout.isIconImage()) {
763 Image image = ImageLocalServiceUtil.getImage(
764 layout.getIconImageId());
765
766 if (image != null) {
767 String iconPath = getLayoutIconPath(
768 portletDataContext, layout, image);
769
770 layoutElement.addElement("icon-image-path").addText(iconPath);
771
772 portletDataContext.addZipEntry(iconPath, image.getTextObj());
773 }
774 }
775
776 _portletExporter.exportPortletData(
777 portletDataContext, layoutConfigurationPortlet, layout, null,
778 layoutElement);
779
780
781
782 if (exportPermissions) {
783 _permissionExporter.exportLayoutPermissions(
784 portletDataContext, layoutCache,
785 portletDataContext.getCompanyId(),
786 portletDataContext.getScopeGroupId(), layout, layoutElement);
787 }
788
789 if (layout.isTypeArticle()) {
790 exportJournalArticle(portletDataContext, layout, layoutElement);
791 }
792
793 if (layout.isTypeLinkToLayout()) {
794 UnicodeProperties typeSettingsProperties =
795 layout.getTypeSettingsProperties();
796
797 long linkToLayoutId = GetterUtil.getLong(
798 typeSettingsProperties.getProperty(
799 "linkToLayoutId", StringPool.BLANK));
800
801 if (linkToLayoutId > 0) {
802 try {
803 Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
804 portletDataContext.getScopeGroupId(),
805 layout.isPrivateLayout(), linkToLayoutId);
806
807 exportLayout(
808 portletDataContext, layoutConfigurationPortlet,
809 layoutCache, portlets, portletIds, exportPermissions,
810 linkedToLayout, layoutsElement);
811 }
812 catch (NoSuchLayoutException nsle) {
813 }
814 }
815 }
816 else if (layout.isSupportsEmbeddedPortlets()) {
817
818
819
820 if (layout.isTypePortlet()) {
821 for (Portlet portlet : portlets) {
822 if (portlet.isScopeable() && layout.hasScopeGroup()) {
823 String key = PortletPermissionUtil.getPrimaryKey(
824 layout.getPlid(), portlet.getPortletId());
825
826 portletIds.put(
827 key,
828 new Object[] {
829 portlet.getPortletId(), layout.getPlid(),
830 layout.getScopeGroup().getGroupId(),
831 StringPool.BLANK, layout.getUuid()
832 });
833 }
834 }
835 }
836
837 LayoutTypePortlet layoutTypePortlet =
838 (LayoutTypePortlet)layout.getLayoutType();
839
840
841
842
843
844 for (Portlet portlet : layoutTypePortlet.getAllPortlets()) {
845 String portletId = portlet.getPortletId();
846
847 javax.portlet.PortletPreferences jxPreferences =
848 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
849 layout, portletId);
850
851 String scopeType = GetterUtil.getString(
852 jxPreferences.getValue("lfrScopeType", null));
853 String scopeLayoutUuid = GetterUtil.getString(
854 jxPreferences.getValue("lfrScopeLayoutUuid", null));
855
856 long scopeGroupId = portletDataContext.getScopeGroupId();
857
858 if (Validator.isNotNull(scopeType)) {
859 Group scopeGroup = null;
860
861 if (scopeType.equals("company")) {
862 scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
863 layout.getCompanyId());
864 }
865 else if (scopeType.equals("layout")) {
866 Layout scopeLayout = null;
867
868 scopeLayout = LayoutLocalServiceUtil.
869 fetchLayoutByUuidAndGroupId(
870 scopeLayoutUuid,
871 portletDataContext.getGroupId(),
872 portletDataContext.isPrivateLayout());
873
874 if (scopeLayout == null) {
875 continue;
876 }
877
878 scopeGroup = scopeLayout.getScopeGroup();
879 }
880 else {
881 throw new IllegalArgumentException(
882 "Scope type " + scopeType + " is invalid");
883 }
884
885 if (scopeGroup != null) {
886 scopeGroupId = scopeGroup.getGroupId();
887 }
888 }
889
890 String key = PortletPermissionUtil.getPrimaryKey(
891 layout.getPlid(), portletId);
892
893 portletIds.put(
894 key,
895 new Object[] {
896 portletId, layout.getPlid(), scopeGroupId, scopeType,
897 scopeLayoutUuid
898 }
899 );
900 }
901 }
902
903 fixTypeSettings(layout);
904
905 layoutElement.addAttribute("path", path);
906
907 portletDataContext.addExpando(layoutElement, path, layout);
908
909 portletDataContext.addZipEntry(path, layout);
910 }
911
912 protected void exportTheme(LayoutSet layoutSet, ZipWriter zipWriter)
913 throws Exception {
914
915 Theme theme = layoutSet.getTheme();
916
917 String lookAndFeelXML = ContentUtil.get(
918 "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
919
920 lookAndFeelXML = StringUtil.replace(
921 lookAndFeelXML,
922 new String[] {
923 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
924 },
925 new String[] {
926 theme.getTemplateExtension(), theme.getVirtualPath()
927 }
928 );
929
930 String servletContextName = theme.getServletContextName();
931
932 ServletContext servletContext = ServletContextPool.get(
933 servletContextName);
934
935 if (servletContext == null) {
936 if (_log.isWarnEnabled()) {
937 _log.warn(
938 "Servlet context not found for theme " +
939 theme.getThemeId());
940 }
941
942 return;
943 }
944
945 File themeZip = new File(zipWriter.getPath() + "/theme.zip");
946
947 ZipWriter themeZipWriter = ZipWriterFactoryUtil.getZipWriter(themeZip);
948
949 themeZipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
950
951 File cssPath = null;
952 File imagesPath = null;
953 File javaScriptPath = null;
954 File templatesPath = null;
955
956 if (!theme.isLoadFromServletContext()) {
957 ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
958 servletContextName);
959
960 if (themeLoader == null) {
961 _log.error(
962 servletContextName + " does not map to a theme loader");
963 }
964 else {
965 String realPath =
966 themeLoader.getFileStorage().getPath() + StringPool.SLASH +
967 theme.getName();
968
969 cssPath = new File(realPath + "/css");
970 imagesPath = new File(realPath + "/images");
971 javaScriptPath = new File(realPath + "/javascript");
972 templatesPath = new File(realPath + "/templates");
973 }
974 }
975 else {
976 cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
977 imagesPath = new File(
978 servletContext.getRealPath(theme.getImagesPath()));
979 javaScriptPath = new File(
980 servletContext.getRealPath(theme.getJavaScriptPath()));
981 templatesPath = new File(
982 servletContext.getRealPath(theme.getTemplatesPath()));
983 }
984
985 exportThemeFiles("css", cssPath, themeZipWriter);
986 exportThemeFiles("images", imagesPath, themeZipWriter);
987 exportThemeFiles("javascript", javaScriptPath, themeZipWriter);
988 exportThemeFiles("templates", templatesPath, themeZipWriter);
989 }
990
991 protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
992 throws Exception {
993
994 if ((dir == null) || !dir.exists()) {
995 return;
996 }
997
998 File[] files = dir.listFiles();
999
1000 for (File file : files) {
1001 if (file.isDirectory()) {
1002 exportThemeFiles(
1003 path + StringPool.SLASH + file.getName(), file, zipWriter);
1004 }
1005 else {
1006 zipWriter.addEntry(
1007 path + StringPool.SLASH + file.getName(),
1008 FileUtil.getBytes(file));
1009 }
1010 }
1011 }
1012
1013 protected void fixTypeSettings(Layout layout) throws Exception {
1014 if (!layout.isTypeURL()) {
1015 return;
1016 }
1017
1018 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
1019
1020 String url = GetterUtil.getString(typeSettings.getProperty("url"));
1021
1022 String friendlyURLPrivateGroupPath =
1023 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
1024 String friendlyURLPrivateUserPath =
1025 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
1026 String friendlyURLPublicPath =
1027 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
1028
1029 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
1030 !url.startsWith(friendlyURLPrivateUserPath) &&
1031 !url.startsWith(friendlyURLPublicPath)) {
1032
1033 return;
1034 }
1035
1036 int x = url.indexOf(CharPool.SLASH, 1);
1037
1038 if (x == -1) {
1039 return;
1040 }
1041
1042 int y = url.indexOf(CharPool.SLASH, x + 1);
1043
1044 if (y == -1) {
1045 return;
1046 }
1047
1048 String friendlyURL = url.substring(x, y);
1049 String groupFriendlyURL = layout.getGroup().getFriendlyURL();
1050
1051 if (!friendlyURL.equals(groupFriendlyURL)) {
1052 return;
1053 }
1054
1055 typeSettings.setProperty(
1056 "url",
1057 url.substring(0, x) + SAME_GROUP_FRIENDLY_URL + url.substring(y));
1058 }
1059
1060 protected boolean[] getExportPortletControls(
1061 long companyId, String portletId,
1062 PortletDataContext portletDataContext,
1063 Map<String, String[]> parameterMap, String type)
1064 throws Exception {
1065
1066 boolean exportPortletData = MapUtil.getBoolean(
1067 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
1068 boolean exportPortletDataAll = MapUtil.getBoolean(
1069 parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
1070 boolean exportPortletSetup = MapUtil.getBoolean(
1071 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
1072 boolean exportPortletSetupAll = MapUtil.getBoolean(
1073 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
1074
1075 if (_log.isDebugEnabled()) {
1076 _log.debug("Export portlet data " + exportPortletData);
1077 _log.debug("Export all portlet data " + exportPortletDataAll);
1078 _log.debug("Export portlet setup " + exportPortletSetup);
1079 }
1080
1081 boolean exportCurPortletData = exportPortletData;
1082 boolean exportCurPortletSetup = exportPortletSetup;
1083
1084
1085
1086
1087
1088 if (exportPortletDataAll) {
1089 exportCurPortletData = true;
1090 exportCurPortletSetup = true;
1091 }
1092 else {
1093 Portlet portlet = PortletLocalServiceUtil.getPortletById(
1094 companyId, portletId);
1095
1096 if (portlet != null) {
1097 String portletDataHandlerClass =
1098 portlet.getPortletDataHandlerClass();
1099
1100
1101
1102
1103
1104
1105 if (portletDataHandlerClass != null) {
1106 String rootPortletId = PortletConstants.getRootPortletId(
1107 portletId);
1108
1109
1110
1111
1112 exportCurPortletData =
1113 exportPortletData &&
1114 MapUtil.getBoolean(
1115 parameterMap,
1116 PortletDataHandlerKeys.PORTLET_DATA +
1117 StringPool.UNDERLINE + rootPortletId);
1118
1119
1120
1121
1122 exportCurPortletSetup =
1123 exportPortletSetup &&
1124 MapUtil.getBoolean(
1125 parameterMap,
1126 PortletDataHandlerKeys.PORTLET_SETUP +
1127 StringPool.UNDERLINE + rootPortletId);
1128 }
1129 }
1130 }
1131
1132 if (exportPortletSetupAll ||
1133 (exportPortletSetup && type.equals("layout-prototype"))) {
1134
1135 exportCurPortletSetup = true;
1136 }
1137
1138 return new boolean[] {exportCurPortletData, exportCurPortletSetup};
1139 }
1140
1141 protected String getLayoutIconPath(
1142 PortletDataContext portletDataContext, Layout layout, Image image) {
1143
1144 StringBundler sb = new StringBundler(5);
1145
1146 sb.append(portletDataContext.getLayoutPath(layout.getLayoutId()));
1147 sb.append("/icons/");
1148 sb.append(image.getImageId());
1149 sb.append(StringPool.PERIOD);
1150 sb.append(image.getType());
1151
1152 return sb.toString();
1153 }
1154
1155 protected String getLayoutSetLogoPath(
1156 PortletDataContext portletDataContext) {
1157
1158 return portletDataContext.getRootPath().concat("/logo/");
1159 }
1160
1161 protected String getLayoutSetPrototype(
1162 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
1163
1164 StringBundler sb = new StringBundler(3);
1165
1166 sb.append(portletDataContext.getRootPath());
1167 sb.append("/layout-set-prototype/");
1168 sb.append(layoutSetPrototypeUuid);
1169
1170 return sb.toString();
1171 }
1172
1173 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
1174
1175 private PermissionExporter _permissionExporter = new PermissionExporter();
1176 private PortletExporter _portletExporter = new PortletExporter();
1177
1178 }