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.ImportExportThreadLocal;
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.JournalPortletDataHandlerImpl;
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 ImportExportThreadLocal.setLayoutExportInProcess(true);
190
191 return doExportLayoutsAsFile(
192 groupId, privateLayout, layoutIds, parameterMap, startDate,
193 endDate);
194 }
195 finally {
196 ImportExportThreadLocal.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 exportUserPermissions = MapUtil.getBoolean(
212 parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
213 boolean exportPortletArchivedSetups = MapUtil.getBoolean(
214 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
215 boolean exportPortletUserPreferences = MapUtil.getBoolean(
216 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
217 boolean exportTheme = MapUtil.getBoolean(
218 parameterMap, PortletDataHandlerKeys.THEME);
219 boolean exportThemeSettings = MapUtil.getBoolean(
220 parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
221 boolean exportLogo = MapUtil.getBoolean(
222 parameterMap, PortletDataHandlerKeys.LOGO);
223 boolean exportLayoutSetSettings = MapUtil.getBoolean(
224 parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
225
226
227 boolean updateLastPublishDate = MapUtil.getBoolean(
228 parameterMap, PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);
229
230 if (_log.isDebugEnabled()) {
231 _log.debug("Export categories " + exportCategories);
232 _log.debug("Export permissions " + exportPermissions);
233 _log.debug("Export user permissions " + exportUserPermissions);
234 _log.debug(
235 "Export portlet archived setups " +
236 exportPortletArchivedSetups);
237 _log.debug(
238 "Export portlet user preferences " +
239 exportPortletUserPreferences);
240 _log.debug("Export theme " + exportTheme);
241 }
242
243 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
244 groupId, privateLayout);
245
246 long companyId = layoutSet.getCompanyId();
247 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
248
249 ServiceContext serviceContext =
250 ServiceContextThreadLocal.getServiceContext();
251
252 if (serviceContext == null) {
253 serviceContext = new ServiceContext();
254
255 serviceContext.setCompanyId(companyId);
256 serviceContext.setSignedIn(false);
257 serviceContext.setUserId(defaultUserId);
258
259 ServiceContextThreadLocal.pushServiceContext(serviceContext);
260 }
261
262 serviceContext.setAttribute("exporting", Boolean.TRUE);
263
264 long layoutSetBranchId = MapUtil.getLong(
265 parameterMap, "layoutSetBranchId");
266
267 serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
268
269 long lastPublishDate = System.currentTimeMillis();
270
271 if (endDate != null) {
272 lastPublishDate = endDate.getTime();
273 }
274
275 if (exportIgnoreLastPublishDate) {
276 endDate = null;
277 startDate = null;
278 }
279
280 StopWatch stopWatch = null;
281
282 if (_log.isInfoEnabled()) {
283 stopWatch = new StopWatch();
284
285 stopWatch.start();
286 }
287
288 LayoutCache layoutCache = new LayoutCache();
289
290 ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
291
292 PortletDataContext portletDataContext = new PortletDataContextImpl(
293 companyId, groupId, parameterMap, new HashSet<String>(), startDate,
294 endDate, zipWriter);
295
296 portletDataContext.setPortetDataContextListener(
297 new PortletDataContextListenerImpl(portletDataContext));
298
299 Document document = SAXReaderUtil.createDocument();
300
301 Element rootElement = document.addElement("root");
302
303 Element headerElement = rootElement.addElement("header");
304
305 headerElement.addAttribute(
306 "available-locales",
307 StringUtil.merge(LanguageUtil.getAvailableLocales()));
308 headerElement.addAttribute(
309 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
310 headerElement.addAttribute("export-date", Time.getRFC822());
311
312 if (portletDataContext.hasDateRange()) {
313 headerElement.addAttribute(
314 "start-date",
315 String.valueOf(portletDataContext.getStartDate()));
316 headerElement.addAttribute(
317 "end-date", String.valueOf(portletDataContext.getEndDate()));
318 }
319
320 Group companyGroup = GroupLocalServiceUtil.getCompanyGroup(companyId);
321
322 headerElement.addAttribute(
323 "company-group-id", String.valueOf(companyGroup.getGroupId()));
324
325 headerElement.addAttribute("group-id", String.valueOf(groupId));
326 headerElement.addAttribute(
327 "private-layout", String.valueOf(privateLayout));
328
329 Group group = layoutSet.getGroup();
330
331 String type = "layout-set";
332
333 if (group.isLayoutPrototype()) {
334 type = "layout-prototype";
335
336 LayoutPrototype layoutPrototype =
337 LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
338 group.getClassPK());
339
340 headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
341 }
342 else if (group.isLayoutSetPrototype()) {
343 type ="layout-set-prototype";
344
345 LayoutSetPrototype layoutSetPrototype =
346 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
347 group.getClassPK());
348
349 headerElement.addAttribute(
350 "type-uuid", layoutSetPrototype.getUuid());
351 }
352
353 headerElement.addAttribute("type", type);
354
355 if (exportTheme || exportThemeSettings) {
356 headerElement.addAttribute("theme-id", layoutSet.getThemeId());
357 headerElement.addAttribute(
358 "color-scheme-id", layoutSet.getColorSchemeId());
359 }
360
361 if (exportLogo) {
362 Image image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
363
364 if ((image != null) && (image.getTextObj() != null)) {
365 String logoPath = getLayoutSetLogoPath(portletDataContext);
366
367 headerElement.addAttribute("logo-path", logoPath);
368
369 portletDataContext.addZipEntry(logoPath, image.getTextObj());
370 }
371 }
372
373 if (exportLayoutSetSettings) {
374 Element settingsElement = headerElement.addElement("settings");
375
376 settingsElement.addCDATA(layoutSet.getSettings());
377 }
378
379 Element cssElement = headerElement.addElement("css");
380
381 cssElement.addCDATA(layoutSet.getCss());
382
383 Portlet layoutConfigurationPortlet =
384 PortletLocalServiceUtil.getPortletById(
385 portletDataContext.getCompanyId(),
386 PortletKeys.LAYOUT_CONFIGURATION);
387
388 Map<String, Object[]> portletIds =
389 new LinkedHashMap<String, Object[]>();
390
391 List<Layout> layouts = null;
392
393 if ((layoutIds == null) || (layoutIds.length == 0)) {
394 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
395 }
396 else {
397 layouts = LayoutLocalServiceUtil.getLayouts(
398 groupId, privateLayout, layoutIds);
399 }
400
401 List<Portlet> portlets = getAlwaysExportablePortlets(companyId);
402
403 long plid = LayoutConstants.DEFAULT_PLID;
404
405 if (!layouts.isEmpty()) {
406 Layout firstLayout = layouts.get(0);
407
408 plid = firstLayout.getPlid();
409 }
410
411 if (group.isStagingGroup()) {
412 group = group.getLiveGroup();
413 }
414
415 for (Portlet portlet : portlets) {
416 String portletId = portlet.getRootPortletId();
417
418 if (!group.isStagedPortlet(portletId)) {
419 continue;
420 }
421
422 String key = PortletPermissionUtil.getPrimaryKey(0, portletId);
423
424 if (portletIds.get(key) == null) {
425 portletIds.put(
426 key,
427 new Object[] {
428 portletId, plid, groupId, StringPool.BLANK,
429 StringPool.BLANK
430 });
431 }
432 }
433
434 Element layoutsElement = rootElement.addElement("layouts");
435
436 String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
437
438 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
439 LayoutSetPrototype layoutSetPrototype =
440 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
441 layoutSetPrototypeUuid);
442
443 layoutsElement.addAttribute(
444 "layout-set-prototype-uuid", layoutSetPrototypeUuid);
445
446 layoutsElement.addAttribute(
447 "layout-set-prototype-name",
448 layoutSetPrototype.getName(LocaleUtil.getDefault()));
449 }
450
451 for (Layout layout : layouts) {
452 exportLayout(
453 portletDataContext, layoutConfigurationPortlet, layoutCache,
454 portlets, portletIds, exportPermissions, exportUserPermissions,
455 layout, layoutsElement);
456 }
457
458 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
459 Element rolesElement = rootElement.addElement("roles");
460
461 if (exportPermissions) {
462 _permissionExporter.exportLayoutRoles(
463 layoutCache, companyId, groupId, rolesElement);
464 }
465 }
466
467 long previousScopeGroupId = portletDataContext.getScopeGroupId();
468
469 Element portletsElement = rootElement.addElement("portlets");
470
471 for (Map.Entry<String, Object[]> portletIdsEntry :
472 portletIds.entrySet()) {
473
474 Object[] portletObjects = portletIdsEntry.getValue();
475
476 String portletId = null;
477 plid = LayoutConstants.DEFAULT_PLID;
478 long scopeGroupId = 0;
479 String scopeType = StringPool.BLANK;
480 String scopeLayoutUuid = null;
481
482 if (portletObjects.length == 4) {
483 portletId = (String)portletIdsEntry.getValue()[0];
484 plid = (Long)portletIdsEntry.getValue()[1];
485 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
486 scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
487 }
488 else {
489 portletId = (String)portletIdsEntry.getValue()[0];
490 plid = (Long)portletIdsEntry.getValue()[1];
491 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
492 scopeType = (String)portletIdsEntry.getValue()[3];
493 scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
494 }
495
496 Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
497
498 if (layout == null) {
499 if (!group.isCompany() &&
500 (plid <= LayoutConstants.DEFAULT_PLID)) {
501
502 continue;
503 }
504
505 if (_log.isWarnEnabled()) {
506 _log.warn(
507 "Assuming global scope because no layout was found");
508 }
509
510 layout = new LayoutImpl();
511
512 layout.setGroupId(groupId);
513 layout.setCompanyId(companyId);
514 }
515
516 portletDataContext.setPlid(plid);
517 portletDataContext.setOldPlid(plid);
518 portletDataContext.setScopeGroupId(scopeGroupId);
519 portletDataContext.setScopeType(scopeType);
520 portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
521
522 boolean[] exportPortletControls = getExportPortletControls(
523 companyId, portletId, portletDataContext, parameterMap, type);
524
525 _portletExporter.exportPortlet(
526 portletDataContext, layoutCache, portletId, layout,
527 portletsElement, defaultUserId, exportPermissions,
528 exportPortletArchivedSetups, exportPortletControls[0],
529 exportPortletControls[1], exportPortletUserPreferences,
530 exportUserPermissions);
531 }
532
533 portletDataContext.setScopeGroupId(previousScopeGroupId);
534
535 if (exportCategories || group.isCompany()) {
536 exportAssetCategories(portletDataContext);
537 }
538
539 _portletExporter.exportAssetLinks(portletDataContext);
540 _portletExporter.exportAssetTags(portletDataContext);
541 _portletExporter.exportComments(portletDataContext);
542 _portletExporter.exportExpandoTables(portletDataContext);
543 _portletExporter.exportLocks(portletDataContext);
544
545 if (exportPermissions) {
546 _permissionExporter.exportPortletDataPermissions(
547 portletDataContext);
548 }
549
550 _portletExporter.exportRatingsEntries(portletDataContext, rootElement);
551
552 if (exportTheme && !portletDataContext.isPerformDirectBinaryImport()) {
553 exportTheme(layoutSet, zipWriter);
554 }
555
556 if (_log.isInfoEnabled()) {
557 if (stopWatch != null) {
558 _log.info(
559 "Exporting layouts takes " + stopWatch.getTime() + " ms");
560 }
561 else {
562 _log.info("Exporting layouts is finished");
563 }
564 }
565
566 portletDataContext.addZipEntry(
567 "/manifest.xml", document.formattedString());
568
569 try {
570 return zipWriter.getFile();
571 }
572 finally {
573 if (updateLastPublishDate) {
574 updateLastPublishDate(layoutSet, lastPublishDate);
575 }
576 }
577 }
578
579 protected void exportAssetCategories(PortletDataContext portletDataContext)
580 throws Exception {
581
582 Document document = SAXReaderUtil.createDocument();
583
584 Element rootElement = document.addElement("categories-hierarchy");
585
586 Element assetVocabulariesElement = rootElement.addElement(
587 "vocabularies");
588
589 List<AssetVocabulary> assetVocabularies =
590 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
591 portletDataContext.getGroupId());
592
593 for (AssetVocabulary assetVocabulary : assetVocabularies) {
594 _portletExporter.exportAssetVocabulary(
595 portletDataContext, assetVocabulariesElement, assetVocabulary);
596 }
597
598 Element categoriesElement = rootElement.addElement("categories");
599
600 List<AssetCategory> assetCategories = AssetCategoryUtil.findByGroupId(
601 portletDataContext.getGroupId());
602
603 for (AssetCategory assetCategory : assetCategories) {
604 _portletExporter.exportAssetCategory(
605 portletDataContext, assetVocabulariesElement, categoriesElement,
606 assetCategory);
607 }
608
609 _portletExporter.exportAssetCategories(portletDataContext, rootElement);
610
611 portletDataContext.addZipEntry(
612 portletDataContext.getRootPath() + "/categories-hierarchy.xml",
613 document.formattedString());
614 }
615
616 protected void exportJournalArticle(
617 PortletDataContext portletDataContext, Layout layout,
618 Element layoutElement)
619 throws Exception {
620
621 UnicodeProperties typeSettingsProperties =
622 layout.getTypeSettingsProperties();
623
624 String articleId = typeSettingsProperties.getProperty(
625 "article-id", StringPool.BLANK);
626
627 long articleGroupId = layout.getGroupId();
628
629 if (Validator.isNull(articleId)) {
630 if (_log.isWarnEnabled()) {
631 _log.warn(
632 "No article id found in typeSettings of layout " +
633 layout.getPlid());
634 }
635 }
636
637 JournalArticle article = null;
638
639 try {
640 article = JournalArticleLocalServiceUtil.getLatestArticle(
641 articleGroupId, articleId, WorkflowConstants.STATUS_APPROVED);
642 }
643 catch (NoSuchArticleException nsae) {
644 if (_log.isWarnEnabled()) {
645 _log.warn(
646 "No approved article found with group id " +
647 articleGroupId + " and article id " + articleId);
648 }
649 }
650
651 if (article == null) {
652 return;
653 }
654
655 String path = JournalPortletDataHandlerImpl.getArticlePath(
656 portletDataContext, article);
657
658 Element articleElement = layoutElement.addElement("article");
659
660 articleElement.addAttribute("path", path);
661
662 Element dlFileEntryTypesElement = layoutElement.addElement(
663 "dl-file-entry-types");
664 Element dlFoldersElement = layoutElement.addElement("dl-folders");
665 Element dlFilesElement = layoutElement.addElement("dl-file-entries");
666 Element dlFileRanksElement = layoutElement.addElement("dl-file-ranks");
667 Element dlRepositoriesElement = layoutElement.addElement(
668 "dl-repositories");
669 Element dlRepositoryEntriesElement = layoutElement.addElement(
670 "dl-repository-entries");
671
672 JournalPortletDataHandlerImpl.exportArticle(
673 portletDataContext, layoutElement, layoutElement, layoutElement,
674 dlFileEntryTypesElement, dlFoldersElement, dlFilesElement,
675 dlFileRanksElement, dlRepositoriesElement,
676 dlRepositoryEntriesElement, article, false);
677 }
678
679 protected void exportLayout(
680 PortletDataContext portletDataContext,
681 Portlet layoutConfigurationPortlet, LayoutCache layoutCache,
682 List<Portlet> portlets, Map<String, Object[]> portletIds,
683 boolean exportPermissions, boolean exportUserPermissions,
684 Layout layout, Element layoutsElement)
685 throws Exception {
686
687 String path = portletDataContext.getLayoutPath(
688 layout.getLayoutId()) + "/layout.xml";
689
690 if (!portletDataContext.isPathNotProcessed(path)) {
691 return;
692 }
693
694 LayoutRevision layoutRevision = null;
695
696 ServiceContext serviceContext =
697 ServiceContextThreadLocal.getServiceContext();
698
699 boolean exportLAR = ParamUtil.getBoolean(serviceContext, "exportLAR");
700
701 if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout) &&
702 !layout.isTypeURL()) {
703
704 long layoutSetBranchId = ParamUtil.getLong(
705 serviceContext, "layoutSetBranchId");
706
707 if (layoutSetBranchId <= 0) {
708 return;
709 }
710
711 layoutRevision = LayoutRevisionUtil.fetchByL_H_P(
712 layoutSetBranchId, true, layout.getPlid());
713
714 if (layoutRevision == null) {
715 return;
716 }
717
718 LayoutStagingHandler layoutStagingHandler =
719 LayoutStagingUtil.getLayoutStagingHandler(layout);
720
721 layoutStagingHandler.setLayoutRevision(layoutRevision);
722 }
723
724 Element layoutElement = layoutsElement.addElement("layout");
725
726 if (layoutRevision != null) {
727 layoutElement.addAttribute(
728 "layout-revision-id",
729 String.valueOf(layoutRevision.getLayoutRevisionId()));
730 layoutElement.addAttribute(
731 "layout-branch-id",
732 String.valueOf(layoutRevision.getLayoutBranchId()));
733 layoutElement.addAttribute(
734 "layout-branch-name",
735 String.valueOf(layoutRevision.getLayoutBranch().getName()));
736 }
737
738 layoutElement.addAttribute("layout-uuid", layout.getUuid());
739 layoutElement.addAttribute(
740 "layout-id", String.valueOf(layout.getLayoutId()));
741
742 long parentLayoutId = layout.getParentLayoutId();
743
744 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
745 Layout parentLayout = LayoutLocalServiceUtil.getLayout(
746 layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
747
748 if (parentLayout != null) {
749 layoutElement.addAttribute(
750 "parent-layout-uuid", parentLayout.getUuid());
751 }
752 }
753
754 String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
755
756 if (Validator.isNotNull(layoutPrototypeUuid)) {
757 LayoutPrototype layoutPrototype =
758 LayoutPrototypeLocalServiceUtil.getLayoutPrototypeByUuid(
759 layoutPrototypeUuid);
760
761 layoutElement.addAttribute(
762 "layout-prototype-uuid", layoutPrototypeUuid);
763 layoutElement.addAttribute(
764 "layout-prototype-name",
765 layoutPrototype.getName(LocaleUtil.getDefault()));
766 }
767
768 boolean deleteLayout = MapUtil.getBoolean(
769 portletDataContext.getParameterMap(), "delete_" + layout.getPlid());
770
771 if (deleteLayout) {
772 layoutElement.addAttribute("delete", String.valueOf(true));
773
774 return;
775 }
776
777 portletDataContext.setPlid(layout.getPlid());
778
779 if (layout.isIconImage()) {
780 Image image = ImageLocalServiceUtil.getImage(
781 layout.getIconImageId());
782
783 if (image != null) {
784 String iconPath = getLayoutIconPath(
785 portletDataContext, layout, image);
786
787 layoutElement.addElement("icon-image-path").addText(iconPath);
788
789 portletDataContext.addZipEntry(iconPath, image.getTextObj());
790 }
791 }
792
793 _portletExporter.exportPortletData(
794 portletDataContext, layoutConfigurationPortlet, layout, null,
795 layoutElement);
796
797
798
799 if (exportPermissions) {
800 _permissionExporter.exportLayoutPermissions(
801 portletDataContext, layoutCache,
802 portletDataContext.getCompanyId(),
803 portletDataContext.getScopeGroupId(), layout, layoutElement,
804 exportUserPermissions);
805 }
806
807 if (layout.isTypeArticle()) {
808 exportJournalArticle(portletDataContext, layout, layoutElement);
809 }
810 else if (layout.isTypeLinkToLayout()) {
811 UnicodeProperties typeSettingsProperties =
812 layout.getTypeSettingsProperties();
813
814 long linkToLayoutId = GetterUtil.getLong(
815 typeSettingsProperties.getProperty(
816 "linkToLayoutId", StringPool.BLANK));
817
818 if (linkToLayoutId > 0) {
819 try {
820 Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
821 portletDataContext.getScopeGroupId(),
822 layout.isPrivateLayout(), linkToLayoutId);
823
824 exportLayout(
825 portletDataContext, layoutConfigurationPortlet,
826 layoutCache, portlets, portletIds, exportPermissions,
827 exportUserPermissions, linkedToLayout, layoutsElement);
828 }
829 catch (NoSuchLayoutException nsle) {
830 }
831 }
832 }
833 else if (layout.isTypePortlet()) {
834 for (Portlet portlet : portlets) {
835 if (portlet.isScopeable() && layout.hasScopeGroup()) {
836 String key = PortletPermissionUtil.getPrimaryKey(
837 layout.getPlid(), portlet.getPortletId());
838
839 portletIds.put(
840 key,
841 new Object[] {
842 portlet.getPortletId(), layout.getPlid(),
843 layout.getScopeGroup().getGroupId(),
844 StringPool.BLANK, layout.getUuid()
845 });
846 }
847 }
848
849 LayoutTypePortlet layoutTypePortlet =
850 (LayoutTypePortlet)layout.getLayoutType();
851
852 for (String portletId : layoutTypePortlet.getPortletIds()) {
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 =
875 LayoutLocalServiceUtil.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(portletDataContext.getLayoutPath(layout.getLayoutId()));
1153 sb.append("/icons/");
1154 sb.append(image.getImageId());
1155 sb.append(StringPool.PERIOD);
1156 sb.append(image.getType());
1157
1158 return sb.toString();
1159 }
1160
1161 protected String getLayoutSetLogoPath(
1162 PortletDataContext portletDataContext) {
1163
1164 return portletDataContext.getRootPath().concat("/logo/");
1165 }
1166
1167 protected String getLayoutSetPrototype(
1168 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
1169
1170 StringBundler sb = new StringBundler(3);
1171
1172 sb.append(portletDataContext.getRootPath());
1173 sb.append("/layout-set-prototype/");
1174 sb.append(layoutSetPrototypeUuid);
1175
1176 return sb.toString();
1177 }
1178
1179 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
1180
1181 private PermissionExporter _permissionExporter = new PermissionExporter();
1182 private PortletExporter _portletExporter = new PortletExporter();
1183
1184 }