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