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