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