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