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