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 headerElement.addAttribute("group-id", String.valueOf(groupId));
321 headerElement.addAttribute(
322 "private-layout", String.valueOf(privateLayout));
323
324 Group group = layoutSet.getGroup();
325
326 String type = "layout-set";
327
328 if (group.isLayoutPrototype()) {
329 type = "layout-prototype";
330
331 LayoutPrototype layoutPrototype =
332 LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
333 group.getClassPK());
334
335 headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
336 }
337 else if (group.isLayoutSetPrototype()) {
338 type ="layout-set-prototype";
339
340 LayoutSetPrototype layoutSetPrototype =
341 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
342 group.getClassPK());
343
344 headerElement.addAttribute(
345 "type-uuid", layoutSetPrototype.getUuid());
346 }
347
348 headerElement.addAttribute("type", type);
349
350 if (exportTheme || exportThemeSettings) {
351 headerElement.addAttribute("theme-id", layoutSet.getThemeId());
352 headerElement.addAttribute(
353 "color-scheme-id", layoutSet.getColorSchemeId());
354 }
355
356 if (exportLogo) {
357 Image image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
358
359 if ((image != null) && (image.getTextObj() != null)) {
360 String logoPath = getLayoutSetLogoPath(portletDataContext);
361
362 headerElement.addAttribute("logo-path", logoPath);
363
364 portletDataContext.addZipEntry(logoPath, image.getTextObj());
365 }
366 }
367
368 if (exportLayoutSetSettings) {
369 Element settingsElement = headerElement.addElement("settings");
370
371 settingsElement.addCDATA(layoutSet.getSettings());
372 }
373
374 Element cssElement = headerElement.addElement("css");
375
376 cssElement.addCDATA(layoutSet.getCss());
377
378 Portlet layoutConfigurationPortlet =
379 PortletLocalServiceUtil.getPortletById(
380 portletDataContext.getCompanyId(),
381 PortletKeys.LAYOUT_CONFIGURATION);
382
383 Map<String, Object[]> portletIds =
384 new LinkedHashMap<String, Object[]>();
385
386 List<Layout> layouts = null;
387
388 if ((layoutIds == null) || (layoutIds.length == 0)) {
389 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
390 }
391 else {
392 layouts = LayoutLocalServiceUtil.getLayouts(
393 groupId, privateLayout, layoutIds);
394 }
395
396 List<Portlet> portlets = getAlwaysExportablePortlets(companyId);
397
398 long plid = LayoutConstants.DEFAULT_PLID;
399
400 if (!layouts.isEmpty()) {
401 Layout firstLayout = layouts.get(0);
402
403 plid = firstLayout.getPlid();
404 }
405
406 if (group.isStagingGroup()) {
407 group = group.getLiveGroup();
408 }
409
410 for (Portlet portlet : portlets) {
411 String portletId = portlet.getRootPortletId();
412
413 if (!group.isStagedPortlet(portletId)) {
414 continue;
415 }
416
417 String key = PortletPermissionUtil.getPrimaryKey(0, portletId);
418
419 if (portletIds.get(key) == null) {
420 portletIds.put(
421 key,
422 new Object[] {
423 portletId, plid, groupId, StringPool.BLANK,
424 StringPool.BLANK
425 });
426 }
427 }
428
429 Element layoutsElement = rootElement.addElement("layouts");
430
431 String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
432
433 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
434 LayoutSetPrototype layoutSetPrototype =
435 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
436 layoutSetPrototypeUuid);
437
438 layoutsElement.addAttribute(
439 "layout-set-prototype-uuid", layoutSetPrototypeUuid);
440
441 layoutsElement.addAttribute(
442 "layout-set-prototype-name",
443 layoutSetPrototype.getName(LocaleUtil.getDefault()));
444 }
445
446 for (Layout layout : layouts) {
447 exportLayout(
448 portletDataContext, layoutConfigurationPortlet, layoutCache,
449 portlets, portletIds, exportPermissions, exportUserPermissions,
450 layout, layoutsElement);
451 }
452
453 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
454 Element rolesElement = rootElement.addElement("roles");
455
456 if (exportPermissions) {
457 _permissionExporter.exportLayoutRoles(
458 layoutCache, companyId, groupId, rolesElement);
459 }
460 }
461
462 long previousScopeGroupId = portletDataContext.getScopeGroupId();
463
464 Element portletsElement = rootElement.addElement("portlets");
465
466 for (Map.Entry<String, Object[]> portletIdsEntry :
467 portletIds.entrySet()) {
468
469 Object[] portletObjects = portletIdsEntry.getValue();
470
471 String portletId = null;
472 plid = LayoutConstants.DEFAULT_PLID;
473 long scopeGroupId = 0;
474 String scopeType = StringPool.BLANK;
475 String scopeLayoutUuid = null;
476
477 if (portletObjects.length == 4) {
478 portletId = (String)portletIdsEntry.getValue()[0];
479 plid = (Long)portletIdsEntry.getValue()[1];
480 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
481 scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
482 }
483 else {
484 portletId = (String)portletIdsEntry.getValue()[0];
485 plid = (Long)portletIdsEntry.getValue()[1];
486 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
487 scopeType = (String)portletIdsEntry.getValue()[3];
488 scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
489 }
490
491 Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
492
493 if (layout == null) {
494 if (!group.isCompany() &&
495 (plid <= LayoutConstants.DEFAULT_PLID)) {
496
497 continue;
498 }
499
500 if (_log.isWarnEnabled()) {
501 _log.warn(
502 "Assuming global scope because no layout was found");
503 }
504
505 layout = new LayoutImpl();
506
507 layout.setGroupId(groupId);
508 layout.setCompanyId(companyId);
509 }
510
511 portletDataContext.setPlid(plid);
512 portletDataContext.setOldPlid(plid);
513 portletDataContext.setScopeGroupId(scopeGroupId);
514 portletDataContext.setScopeType(scopeType);
515 portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
516
517 boolean[] exportPortletControls = getExportPortletControls(
518 companyId, portletId, portletDataContext, parameterMap);
519
520 _portletExporter.exportPortlet(
521 portletDataContext, layoutCache, portletId, layout,
522 portletsElement, defaultUserId, exportPermissions,
523 exportPortletArchivedSetups, exportPortletControls[0],
524 exportPortletControls[1], exportPortletUserPreferences,
525 exportUserPermissions);
526 }
527
528 portletDataContext.setScopeGroupId(previousScopeGroupId);
529
530 if (exportCategories || group.isCompany()) {
531 exportAssetCategories(portletDataContext);
532 }
533
534 _portletExporter.exportAssetLinks(portletDataContext);
535 _portletExporter.exportAssetTags(portletDataContext);
536 _portletExporter.exportComments(portletDataContext);
537 _portletExporter.exportExpandoTables(portletDataContext);
538 _portletExporter.exportLocks(portletDataContext);
539
540 if (exportPermissions) {
541 _permissionExporter.exportPortletDataPermissions(
542 portletDataContext);
543 }
544
545 _portletExporter.exportRatingsEntries(portletDataContext, rootElement);
546
547 if (exportTheme && !portletDataContext.isPerformDirectBinaryImport()) {
548 exportTheme(layoutSet, zipWriter);
549 }
550
551 if (_log.isInfoEnabled()) {
552 if (stopWatch != null) {
553 _log.info(
554 "Exporting layouts takes " + stopWatch.getTime() + " ms");
555 }
556 else {
557 _log.info("Exporting layouts is finished");
558 }
559 }
560
561 portletDataContext.addZipEntry(
562 "/manifest.xml", document.formattedString());
563
564 try {
565 return zipWriter.getFile();
566 }
567 finally {
568 if (updateLastPublishDate) {
569 updateLastPublishDate(layoutSet, lastPublishDate);
570 }
571 }
572 }
573
574 protected void exportAssetCategories(PortletDataContext portletDataContext)
575 throws Exception {
576
577 Document document = SAXReaderUtil.createDocument();
578
579 Element rootElement = document.addElement("categories-hierarchy");
580
581 Element assetVocabulariesElement = rootElement.addElement(
582 "vocabularies");
583
584 List<AssetVocabulary> assetVocabularies =
585 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
586 portletDataContext.getGroupId());
587
588 for (AssetVocabulary assetVocabulary : assetVocabularies) {
589 _portletExporter.exportAssetVocabulary(
590 portletDataContext, assetVocabulariesElement, assetVocabulary);
591 }
592
593 Element categoriesElement = rootElement.addElement("categories");
594
595 List<AssetCategory> assetCategories = AssetCategoryUtil.findByGroupId(
596 portletDataContext.getGroupId());
597
598 for (AssetCategory assetCategory : assetCategories) {
599 _portletExporter.exportAssetCategory(
600 portletDataContext, assetVocabulariesElement, categoriesElement,
601 assetCategory);
602 }
603
604 _portletExporter.exportAssetCategories(portletDataContext, rootElement);
605
606 portletDataContext.addZipEntry(
607 portletDataContext.getRootPath() + "/categories-hierarchy.xml",
608 document.formattedString());
609 }
610
611 protected void exportJournalArticle(
612 PortletDataContext portletDataContext, Layout layout,
613 Element layoutElement)
614 throws Exception {
615
616 UnicodeProperties typeSettingsProperties =
617 layout.getTypeSettingsProperties();
618
619 String articleId = typeSettingsProperties.getProperty(
620 "article-id", StringPool.BLANK);
621
622 long articleGroupId = layout.getGroupId();
623
624 if (Validator.isNull(articleId)) {
625 if (_log.isWarnEnabled()) {
626 _log.warn(
627 "No article id found in typeSettings of layout " +
628 layout.getPlid());
629 }
630 }
631
632 JournalArticle article = null;
633
634 try {
635 article = JournalArticleLocalServiceUtil.getLatestArticle(
636 articleGroupId, articleId, WorkflowConstants.STATUS_APPROVED);
637 }
638 catch (NoSuchArticleException nsae) {
639 if (_log.isWarnEnabled()) {
640 _log.warn(
641 "No approved article found with group id " +
642 articleGroupId + " and article id " + articleId);
643 }
644 }
645
646 if (article == null) {
647 return;
648 }
649
650 String path = JournalPortletDataHandlerImpl.getArticlePath(
651 portletDataContext, article);
652
653 Element articleElement = layoutElement.addElement("article");
654
655 articleElement.addAttribute("path", path);
656
657 Element dlFileEntryTypesElement = layoutElement.addElement(
658 "dl-file-entry-types");
659 Element dlFoldersElement = layoutElement.addElement("dl-folders");
660 Element dlFilesElement = layoutElement.addElement("dl-file-entries");
661 Element dlFileRanksElement = layoutElement.addElement("dl-file-ranks");
662 Element dlRepositoriesElement = layoutElement.addElement(
663 "dl-repositories");
664 Element dlRepositoryEntriesElement = layoutElement.addElement(
665 "dl-repository-entries");
666
667 JournalPortletDataHandlerImpl.exportArticle(
668 portletDataContext, layoutElement, layoutElement, layoutElement,
669 dlFileEntryTypesElement, dlFoldersElement, dlFilesElement,
670 dlFileRanksElement, dlRepositoriesElement,
671 dlRepositoryEntriesElement, article, null, false);
672 }
673
674 protected void exportLayout(
675 PortletDataContext portletDataContext,
676 Portlet layoutConfigurationPortlet, LayoutCache layoutCache,
677 List<Portlet> portlets, Map<String, Object[]> portletIds,
678 boolean exportPermissions, boolean exportUserPermissions,
679 Layout layout, Element layoutsElement)
680 throws Exception {
681
682 String path = portletDataContext.getLayoutPath(
683 layout.getLayoutId()) + "/layout.xml";
684
685 if (!portletDataContext.isPathNotProcessed(path)) {
686 return;
687 }
688
689 LayoutRevision layoutRevision = null;
690
691 ServiceContext serviceContext =
692 ServiceContextThreadLocal.getServiceContext();
693
694 boolean exportLAR = ParamUtil.getBoolean(serviceContext, "exportLAR");
695
696 if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout) &&
697 !layout.isTypeURL()) {
698
699 long layoutSetBranchId = ParamUtil.getLong(
700 serviceContext, "layoutSetBranchId");
701
702 if (layoutSetBranchId <= 0) {
703 return;
704 }
705
706 layoutRevision = LayoutRevisionUtil.fetchByL_H_P(
707 layoutSetBranchId, true, layout.getPlid());
708
709 if (layoutRevision == null) {
710 return;
711 }
712
713 LayoutStagingHandler layoutStagingHandler =
714 LayoutStagingUtil.getLayoutStagingHandler(layout);
715
716 layoutStagingHandler.setLayoutRevision(layoutRevision);
717 }
718
719 Element layoutElement = layoutsElement.addElement("layout");
720
721 if (layoutRevision != null) {
722 layoutElement.addAttribute(
723 "layout-revision-id",
724 String.valueOf(layoutRevision.getLayoutRevisionId()));
725 layoutElement.addAttribute(
726 "layout-branch-id",
727 String.valueOf(layoutRevision.getLayoutBranchId()));
728 layoutElement.addAttribute(
729 "layout-branch-name",
730 String.valueOf(layoutRevision.getLayoutBranch().getName()));
731 }
732
733 layoutElement.addAttribute("layout-uuid", layout.getUuid());
734 layoutElement.addAttribute(
735 "layout-id", String.valueOf(layout.getLayoutId()));
736
737 long parentLayoutId = layout.getParentLayoutId();
738
739 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
740 Layout parentLayout = LayoutLocalServiceUtil.getLayout(
741 layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
742
743 if (parentLayout != null) {
744 layoutElement.addAttribute(
745 "parent-layout-uuid", parentLayout.getUuid());
746 }
747 }
748
749 String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
750
751 if (Validator.isNotNull(layoutPrototypeUuid)) {
752 LayoutPrototype layoutPrototype =
753 LayoutPrototypeLocalServiceUtil.getLayoutPrototypeByUuid(
754 layoutPrototypeUuid);
755
756 layoutElement.addAttribute(
757 "layout-prototype-uuid", layoutPrototypeUuid);
758 layoutElement.addAttribute(
759 "layout-prototype-name",
760 layoutPrototype.getName(LocaleUtil.getDefault()));
761 }
762
763 boolean deleteLayout = MapUtil.getBoolean(
764 portletDataContext.getParameterMap(), "delete_" + layout.getPlid());
765
766 if (deleteLayout) {
767 layoutElement.addAttribute("delete", String.valueOf(true));
768
769 return;
770 }
771
772 portletDataContext.setPlid(layout.getPlid());
773
774 if (layout.isIconImage()) {
775 Image image = ImageLocalServiceUtil.getImage(
776 layout.getIconImageId());
777
778 if (image != null) {
779 String iconPath = getLayoutIconPath(
780 portletDataContext, layout, image);
781
782 layoutElement.addElement("icon-image-path").addText(iconPath);
783
784 portletDataContext.addZipEntry(iconPath, image.getTextObj());
785 }
786 }
787
788 _portletExporter.exportPortletData(
789 portletDataContext, layoutConfigurationPortlet, layout, null,
790 layoutElement);
791
792
793
794 if (exportPermissions) {
795 _permissionExporter.exportLayoutPermissions(
796 portletDataContext, layoutCache,
797 portletDataContext.getCompanyId(),
798 portletDataContext.getScopeGroupId(), layout, layoutElement,
799 exportUserPermissions);
800 }
801
802 if (layout.isTypeArticle()) {
803 exportJournalArticle(portletDataContext, layout, layoutElement);
804 }
805 else if (layout.isTypeLinkToLayout()) {
806 UnicodeProperties typeSettingsProperties =
807 layout.getTypeSettingsProperties();
808
809 long linkToLayoutId = GetterUtil.getLong(
810 typeSettingsProperties.getProperty(
811 "linkToLayoutId", StringPool.BLANK));
812
813 if (linkToLayoutId > 0) {
814 try {
815 Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
816 portletDataContext.getScopeGroupId(),
817 layout.isPrivateLayout(), linkToLayoutId);
818
819 exportLayout(
820 portletDataContext, layoutConfigurationPortlet,
821 layoutCache, portlets, portletIds, exportPermissions,
822 exportUserPermissions, linkedToLayout, layoutsElement);
823 }
824 catch (NoSuchLayoutException nsle) {
825 }
826 }
827 }
828 else if (layout.isTypePortlet()) {
829 for (Portlet portlet : portlets) {
830 if (portlet.isScopeable() && layout.hasScopeGroup()) {
831 String key = PortletPermissionUtil.getPrimaryKey(
832 layout.getPlid(), portlet.getPortletId());
833
834 portletIds.put(
835 key,
836 new Object[] {
837 portlet.getPortletId(), layout.getPlid(),
838 layout.getScopeGroup().getGroupId(),
839 StringPool.BLANK, layout.getUuid()
840 });
841 }
842 }
843
844 LayoutTypePortlet layoutTypePortlet =
845 (LayoutTypePortlet)layout.getLayoutType();
846
847 for (String portletId : layoutTypePortlet.getPortletIds()) {
848 javax.portlet.PortletPreferences jxPreferences =
849 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
850 layout, portletId);
851
852 String scopeType = GetterUtil.getString(
853 jxPreferences.getValue("lfrScopeType", null));
854 String scopeLayoutUuid = GetterUtil.getString(
855 jxPreferences.getValue("lfrScopeLayoutUuid", null));
856
857 long scopeGroupId = portletDataContext.getScopeGroupId();
858
859 if (Validator.isNotNull(scopeType)) {
860 Group scopeGroup = null;
861
862 if (scopeType.equals("company")) {
863 scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
864 layout.getCompanyId());
865 }
866 else if (scopeType.equals("layout")) {
867 Layout scopeLayout = null;
868
869 scopeLayout = LayoutLocalServiceUtil.
870 fetchLayoutByUuidAndGroupId(
871 scopeLayoutUuid,
872 portletDataContext.getGroupId());
873
874 if (scopeLayout == null) {
875 continue;
876 }
877
878 scopeGroup = scopeLayout.getScopeGroup();
879 }
880 else {
881 throw new IllegalArgumentException(
882 "Scope type " + scopeType + " is invalid");
883 }
884
885 if (scopeGroup != null) {
886 scopeGroupId = scopeGroup.getGroupId();
887 }
888 }
889
890 String key = PortletPermissionUtil.getPrimaryKey(
891 layout.getPlid(), portletId);
892
893 portletIds.put(
894 key,
895 new Object[] {
896 portletId, layout.getPlid(), scopeGroupId, scopeType,
897 scopeLayoutUuid
898 }
899 );
900 }
901 }
902
903 fixTypeSettings(layout);
904
905 layoutElement.addAttribute("path", path);
906
907 portletDataContext.addExpando(layoutElement, path, layout);
908
909 portletDataContext.addZipEntry(path, layout);
910 }
911
912 protected void exportTheme(LayoutSet layoutSet, ZipWriter zipWriter)
913 throws Exception {
914
915 Theme theme = layoutSet.getTheme();
916
917 String lookAndFeelXML = ContentUtil.get(
918 "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
919
920 lookAndFeelXML = StringUtil.replace(
921 lookAndFeelXML,
922 new String[] {
923 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
924 },
925 new String[] {
926 theme.getTemplateExtension(), theme.getVirtualPath()
927 }
928 );
929
930 String servletContextName = theme.getServletContextName();
931
932 ServletContext servletContext = ServletContextPool.get(
933 servletContextName);
934
935 if (servletContext == null) {
936 if (_log.isWarnEnabled()) {
937 _log.warn(
938 "Servlet context not found for theme " +
939 theme.getThemeId());
940 }
941
942 return;
943 }
944
945 File themeZip = new File(zipWriter.getPath() + "/theme.zip");
946
947 ZipWriter themeZipWriter = ZipWriterFactoryUtil.getZipWriter(themeZip);
948
949 themeZipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
950
951 File cssPath = null;
952 File imagesPath = null;
953 File javaScriptPath = null;
954 File templatesPath = null;
955
956 if (!theme.isLoadFromServletContext()) {
957 ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
958 servletContextName);
959
960 if (themeLoader == null) {
961 _log.error(
962 servletContextName + " does not map to a theme loader");
963 }
964 else {
965 String realPath =
966 themeLoader.getFileStorage().getPath() + StringPool.SLASH +
967 theme.getName();
968
969 cssPath = new File(realPath + "/css");
970 imagesPath = new File(realPath + "/images");
971 javaScriptPath = new File(realPath + "/javascript");
972 templatesPath = new File(realPath + "/templates");
973 }
974 }
975 else {
976 cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
977 imagesPath = new File(
978 servletContext.getRealPath(theme.getImagesPath()));
979 javaScriptPath = new File(
980 servletContext.getRealPath(theme.getJavaScriptPath()));
981 templatesPath = new File(
982 servletContext.getRealPath(theme.getTemplatesPath()));
983 }
984
985 exportThemeFiles("css", cssPath, themeZipWriter);
986 exportThemeFiles("images", imagesPath, themeZipWriter);
987 exportThemeFiles("javascript", javaScriptPath, themeZipWriter);
988 exportThemeFiles("templates", templatesPath, themeZipWriter);
989 }
990
991 protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
992 throws Exception {
993
994 if ((dir == null) || !dir.exists()) {
995 return;
996 }
997
998 File[] files = dir.listFiles();
999
1000 for (File file : files) {
1001 if (file.isDirectory()) {
1002 exportThemeFiles(
1003 path + StringPool.SLASH + file.getName(), file, zipWriter);
1004 }
1005 else {
1006 zipWriter.addEntry(
1007 path + StringPool.SLASH + file.getName(),
1008 FileUtil.getBytes(file));
1009 }
1010 }
1011 }
1012
1013 protected void fixTypeSettings(Layout layout) throws Exception {
1014 if (!layout.isTypeURL()) {
1015 return;
1016 }
1017
1018 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
1019
1020 String url = GetterUtil.getString(typeSettings.getProperty("url"));
1021
1022 String friendlyURLPrivateGroupPath =
1023 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
1024 String friendlyURLPrivateUserPath =
1025 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
1026 String friendlyURLPublicPath =
1027 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
1028
1029 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
1030 !url.startsWith(friendlyURLPrivateUserPath) &&
1031 !url.startsWith(friendlyURLPublicPath)) {
1032
1033 return;
1034 }
1035
1036 int x = url.indexOf(CharPool.SLASH, 1);
1037
1038 if (x == -1) {
1039 return;
1040 }
1041
1042 int y = url.indexOf(CharPool.SLASH, x + 1);
1043
1044 if (y == -1) {
1045 return;
1046 }
1047
1048 String friendlyURL = url.substring(x, y);
1049 String groupFriendlyURL = layout.getGroup().getFriendlyURL();
1050
1051 if (!friendlyURL.equals(groupFriendlyURL)) {
1052 return;
1053 }
1054
1055 typeSettings.setProperty(
1056 "url",
1057 url.substring(0, x) + SAME_GROUP_FRIENDLY_URL + url.substring(y));
1058 }
1059
1060 protected boolean[] getExportPortletControls(
1061 long companyId, String portletId,
1062 PortletDataContext portletDataContext,
1063 Map<String, String[]> parameterMap)
1064 throws Exception {
1065
1066 boolean exportPortletData = MapUtil.getBoolean(
1067 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
1068 boolean exportPortletDataAll = MapUtil.getBoolean(
1069 parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
1070 boolean exportPortletSetup = MapUtil.getBoolean(
1071 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
1072 boolean exportPortletSetupAll = MapUtil.getBoolean(
1073 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
1074
1075 if (_log.isDebugEnabled()) {
1076 _log.debug("Export portlet data " + exportPortletData);
1077 _log.debug("Export all portlet data " + exportPortletDataAll);
1078 _log.debug("Export portlet setup " + exportPortletSetup);
1079 }
1080
1081 boolean exportCurPortletData = exportPortletData;
1082 boolean exportCurPortletSetup = exportPortletSetup;
1083
1084
1085
1086
1087
1088 if (exportPortletDataAll) {
1089 exportCurPortletData = true;
1090 exportCurPortletSetup = true;
1091 }
1092 else {
1093 Portlet portlet = PortletLocalServiceUtil.getPortletById(
1094 companyId, portletId);
1095
1096 if (portlet != null) {
1097 String portletDataHandlerClass =
1098 portlet.getPortletDataHandlerClass();
1099
1100
1101
1102
1103
1104
1105 if (portletDataHandlerClass != null) {
1106 String rootPortletId = PortletConstants.getRootPortletId(
1107 portletId);
1108
1109
1110
1111
1112 exportCurPortletData =
1113 exportPortletData &&
1114 MapUtil.getBoolean(
1115 parameterMap,
1116 PortletDataHandlerKeys.PORTLET_DATA +
1117 StringPool.UNDERLINE + rootPortletId);
1118
1119
1120
1121
1122 exportCurPortletSetup =
1123 exportPortletSetup &&
1124 MapUtil.getBoolean(
1125 parameterMap,
1126 PortletDataHandlerKeys.PORTLET_SETUP +
1127 StringPool.UNDERLINE + rootPortletId);
1128 }
1129 }
1130 }
1131
1132 if (exportPortletSetupAll) {
1133 exportCurPortletSetup = true;
1134 }
1135
1136 return new boolean[] {exportCurPortletData, exportCurPortletSetup};
1137 }
1138
1139 protected String getLayoutIconPath(
1140 PortletDataContext portletDataContext, Layout layout, Image image) {
1141
1142 StringBundler sb = new StringBundler(5);
1143
1144 sb.append(portletDataContext.getLayoutPath(layout.getLayoutId()));
1145 sb.append("/icons/");
1146 sb.append(image.getImageId());
1147 sb.append(StringPool.PERIOD);
1148 sb.append(image.getType());
1149
1150 return sb.toString();
1151 }
1152
1153 protected String getLayoutSetLogoPath(
1154 PortletDataContext portletDataContext) {
1155
1156 return portletDataContext.getRootPath().concat("/logo/");
1157 }
1158
1159 protected String getLayoutSetPrototype(
1160 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
1161
1162 StringBundler sb = new StringBundler(3);
1163
1164 sb.append(portletDataContext.getRootPath());
1165 sb.append("/layout-set-prototype/");
1166 sb.append(layoutSetPrototypeUuid);
1167
1168 return sb.toString();
1169 }
1170
1171 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
1172
1173 private PermissionExporter _permissionExporter = new PermissionExporter();
1174 private PortletExporter _portletExporter = new PortletExporter();
1175
1176 }