001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.portal.NoSuchLayoutException;
018 import com.liferay.portal.kernel.lar.ImportExportThreadLocal;
019 import com.liferay.portal.kernel.lar.PortletDataContext;
020 import com.liferay.portal.kernel.lar.PortletDataHandler;
021 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
022 import com.liferay.portal.kernel.log.Log;
023 import com.liferay.portal.kernel.log.LogFactoryUtil;
024 import com.liferay.portal.kernel.servlet.ServletContextPool;
025 import com.liferay.portal.kernel.staging.LayoutStagingUtil;
026 import com.liferay.portal.kernel.util.CharPool;
027 import com.liferay.portal.kernel.util.FileUtil;
028 import com.liferay.portal.kernel.util.GetterUtil;
029 import com.liferay.portal.kernel.util.MapUtil;
030 import com.liferay.portal.kernel.util.ReleaseInfo;
031 import com.liferay.portal.kernel.util.StringBundler;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.StringUtil;
034 import com.liferay.portal.kernel.util.Time;
035 import com.liferay.portal.kernel.util.UnicodeProperties;
036 import com.liferay.portal.kernel.util.Validator;
037 import com.liferay.portal.kernel.workflow.WorkflowConstants;
038 import com.liferay.portal.kernel.xml.Document;
039 import com.liferay.portal.kernel.xml.Element;
040 import com.liferay.portal.kernel.xml.SAXReaderUtil;
041 import com.liferay.portal.kernel.zip.ZipWriter;
042 import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
043 import com.liferay.portal.model.Group;
044 import com.liferay.portal.model.Image;
045 import com.liferay.portal.model.Layout;
046 import com.liferay.portal.model.LayoutConstants;
047 import com.liferay.portal.model.LayoutRevision;
048 import com.liferay.portal.model.LayoutSet;
049 import com.liferay.portal.model.LayoutSetPrototype;
050 import com.liferay.portal.model.LayoutStagingHandler;
051 import com.liferay.portal.model.LayoutTypePortlet;
052 import com.liferay.portal.model.Portlet;
053 import com.liferay.portal.model.PortletConstants;
054 import com.liferay.portal.model.Theme;
055 import com.liferay.portal.service.GroupLocalServiceUtil;
056 import com.liferay.portal.service.ImageLocalServiceUtil;
057 import com.liferay.portal.service.LayoutLocalServiceUtil;
058 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
059 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
060 import com.liferay.portal.service.PortletLocalServiceUtil;
061 import com.liferay.portal.service.ServiceContext;
062 import com.liferay.portal.service.ServiceContextThreadLocal;
063 import com.liferay.portal.service.UserLocalServiceUtil;
064 import com.liferay.portal.service.permission.PortletPermissionUtil;
065 import com.liferay.portal.service.persistence.LayoutRevisionUtil;
066 import com.liferay.portal.theme.ThemeLoader;
067 import com.liferay.portal.theme.ThemeLoaderFactory;
068 import com.liferay.portal.util.PortletKeys;
069 import com.liferay.portal.util.PropsValues;
070 import com.liferay.portlet.PortletPreferencesFactoryUtil;
071 import com.liferay.portlet.asset.model.AssetCategory;
072 import com.liferay.portlet.asset.model.AssetVocabulary;
073 import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
074 import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
075 import com.liferay.portlet.journal.NoSuchArticleException;
076 import com.liferay.portlet.journal.lar.JournalPortletDataHandlerImpl;
077 import com.liferay.portlet.journal.model.JournalArticle;
078 import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
079 import com.liferay.portlet.sites.util.SitesUtil;
080 import com.liferay.util.ContentUtil;
081
082 import de.schlichtherle.io.FileInputStream;
083
084 import java.io.File;
085
086 import java.util.Date;
087 import java.util.HashSet;
088 import java.util.Iterator;
089 import java.util.LinkedHashMap;
090 import java.util.List;
091 import java.util.Map;
092
093 import javax.servlet.ServletContext;
094
095 import org.apache.commons.lang.time.StopWatch;
096
097
108 public class LayoutExporter {
109
110 public static final String SAME_GROUP_FRIENDLY_URL =
111 "/[$SAME_GROUP_FRIENDLY_URL$]";
112
113 public static List<Portlet> getAlwaysExportablePortlets(long companyId)
114 throws Exception {
115
116 List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
117
118 Iterator<Portlet> itr = portlets.iterator();
119
120 while (itr.hasNext()) {
121 Portlet portlet = itr.next();
122
123 if (!portlet.isActive()) {
124 itr.remove();
125
126 continue;
127 }
128
129 PortletDataHandler portletDataHandler =
130 portlet.getPortletDataHandlerInstance();
131
132 if ((portletDataHandler == null) ||
133 (!portletDataHandler.isAlwaysExportable())) {
134
135 itr.remove();
136 }
137 }
138
139 return portlets;
140 }
141
142 public static void updateLastPublishDate(
143 LayoutSet layoutSet, long lastPublishDate)
144 throws Exception {
145
146 UnicodeProperties settingsProperties =
147 layoutSet.getSettingsProperties();
148
149 if (lastPublishDate <= 0) {
150 settingsProperties.remove("last-publish-date");
151 }
152 else {
153 settingsProperties.setProperty(
154 "last-publish-date", String.valueOf(lastPublishDate));
155 }
156
157 LayoutSetLocalServiceUtil.updateSettings(
158 layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
159 settingsProperties.toString());
160 }
161
162 public byte[] exportLayouts(
163 long groupId, boolean privateLayout, long[] layoutIds,
164 Map<String, String[]> parameterMap, Date startDate, Date endDate)
165 throws Exception {
166
167 File file = exportLayoutsAsFile(
168 groupId, privateLayout, layoutIds, parameterMap, startDate,
169 endDate);
170
171 try {
172 return FileUtil.getBytes(file);
173 }
174 finally {
175 file.delete();
176 }
177 }
178
179 public File exportLayoutsAsFile(
180 long groupId, boolean privateLayout, long[] layoutIds,
181 Map<String, String[]> parameterMap, Date startDate, Date endDate)
182 throws Exception {
183
184 try {
185 ImportExportThreadLocal.setLayoutExportInProcess(true);
186
187 return doExportLayoutsAsFile(
188 groupId, privateLayout, layoutIds, parameterMap, startDate,
189 endDate);
190 }
191 finally {
192 ImportExportThreadLocal.setLayoutExportInProcess(false);
193 }
194 }
195
196 protected File doExportLayoutsAsFile(
197 long groupId, boolean privateLayout, long[] layoutIds,
198 Map<String, String[]> parameterMap, Date startDate, Date endDate)
199 throws Exception {
200
201 boolean exportCategories = MapUtil.getBoolean(
202 parameterMap, PortletDataHandlerKeys.CATEGORIES);
203 boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
204 parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
205 boolean exportPermissions = MapUtil.getBoolean(
206 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
207 boolean exportUserPermissions = MapUtil.getBoolean(
208 parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
209 boolean exportPortletArchivedSetups = MapUtil.getBoolean(
210 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
211 boolean exportPortletUserPreferences = MapUtil.getBoolean(
212 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
213 boolean exportTheme = MapUtil.getBoolean(
214 parameterMap, PortletDataHandlerKeys.THEME);
215 boolean exportThemeSettings = MapUtil.getBoolean(
216 parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
217 boolean layoutSetPrototypeInherited = MapUtil.getBoolean(
218 parameterMap,
219 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED);
220 boolean publishToRemote = MapUtil.getBoolean(
221 parameterMap, PortletDataHandlerKeys.PUBLISH_TO_REMOTE);
222 boolean updateLastPublishDate = MapUtil.getBoolean(
223 parameterMap, PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);
224
225 if (_log.isDebugEnabled()) {
226 _log.debug("Export categories " + exportCategories);
227 _log.debug("Export permissions " + exportPermissions);
228 _log.debug("Export user permissions " + exportUserPermissions);
229 _log.debug(
230 "Export portlet archived setups " +
231 exportPortletArchivedSetups);
232 _log.debug(
233 "Export portlet user preferences " +
234 exportPortletUserPreferences);
235 _log.debug("Export theme " + exportTheme);
236 }
237
238 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
239 groupId, privateLayout);
240
241 long companyId = layoutSet.getCompanyId();
242 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
243
244 ServiceContext serviceContext =
245 ServiceContextThreadLocal.getServiceContext();
246
247 if (serviceContext == null) {
248 serviceContext = new ServiceContext();
249
250 serviceContext.setCompanyId(companyId);
251 serviceContext.setSignedIn(false);
252 serviceContext.setUserId(defaultUserId);
253
254 ServiceContextThreadLocal.pushServiceContext(serviceContext);
255 }
256
257 serviceContext.setAttribute("exporting", Boolean.TRUE);
258
259 long layoutSetBranchId = MapUtil.getLong(
260 parameterMap, "layoutSetBranchId");
261
262 serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
263
264 long lastPublishDate = System.currentTimeMillis();
265
266 if (endDate != null) {
267 lastPublishDate = endDate.getTime();
268 }
269
270 if (exportIgnoreLastPublishDate) {
271 endDate = null;
272 startDate = null;
273 }
274
275 StopWatch stopWatch = null;
276
277 if (_log.isInfoEnabled()) {
278 stopWatch = new StopWatch();
279
280 stopWatch.start();
281 }
282
283 LayoutCache layoutCache = new LayoutCache();
284
285 ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
286
287 PortletDataContext portletDataContext = new PortletDataContextImpl(
288 companyId, groupId, parameterMap, new HashSet<String>(), startDate,
289 endDate, zipWriter);
290
291 portletDataContext.setPortetDataContextListener(
292 new PortletDataContextListenerImpl(portletDataContext));
293
294 Document document = SAXReaderUtil.createDocument();
295
296 Element rootElement = document.addElement("root");
297
298 Element headerElement = rootElement.addElement("header");
299
300 headerElement.addAttribute(
301 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
302 headerElement.addAttribute("export-date", Time.getRFC822());
303
304 if (portletDataContext.hasDateRange()) {
305 headerElement.addAttribute(
306 "start-date",
307 String.valueOf(portletDataContext.getStartDate()));
308 headerElement.addAttribute(
309 "end-date", String.valueOf(portletDataContext.getEndDate()));
310 }
311
312 headerElement.addAttribute("type", "layout-set");
313 headerElement.addAttribute("group-id", String.valueOf(groupId));
314 headerElement.addAttribute(
315 "private-layout", String.valueOf(privateLayout));
316
317 Group group = layoutSet.getGroup();
318
319 if (layoutSetPrototypeInherited && group.isLayoutSetPrototype()) {
320 LayoutSetPrototype layoutSetPrototype =
321 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
322 group.getClassPK());
323
324 String layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
325
326 headerElement.addAttribute(
327 "layout-set-prototype-uuid", layoutSetPrototypeUuid);
328
329 if (publishToRemote) {
330 String path = getLayoutSetPrototype(
331 portletDataContext, layoutSetPrototypeUuid);
332
333 File layoutSetPrototypeFile =
334 SitesUtil.exportLayoutSetPrototype(
335 layoutSetPrototype, serviceContext);
336
337 try {
338 portletDataContext.addZipEntry(
339 path.concat(".lar"),
340 new FileInputStream(layoutSetPrototypeFile));
341 portletDataContext.addZipEntry(
342 path.concat(".xml"), layoutSetPrototype);
343 }
344 finally {
345 layoutSetPrototypeFile.delete();
346 }
347 }
348 }
349
350 if (exportTheme || exportThemeSettings) {
351 headerElement.addAttribute("theme-id", layoutSet.getThemeId());
352 headerElement.addAttribute(
353 "color-scheme-id", layoutSet.getColorSchemeId());
354 }
355
356 Element cssElement = headerElement.addElement("css");
357
358 cssElement.addCDATA(layoutSet.getCss());
359
360 Portlet layoutConfigurationPortlet =
361 PortletLocalServiceUtil.getPortletById(
362 portletDataContext.getCompanyId(),
363 PortletKeys.LAYOUT_CONFIGURATION);
364
365 Map<String, Object[]> portletIds =
366 new LinkedHashMap<String, Object[]>();
367
368 List<Layout> layouts = null;
369
370 if ((layoutIds == null) || (layoutIds.length == 0)) {
371 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
372 }
373 else {
374 layouts = LayoutLocalServiceUtil.getLayouts(
375 groupId, privateLayout, layoutIds);
376 }
377
378 List<Portlet> portlets = getAlwaysExportablePortlets(companyId);
379
380 if (!layouts.isEmpty()) {
381 Layout firstLayout = layouts.get(0);
382
383 if (group.isStagingGroup()) {
384 group = group.getLiveGroup();
385 }
386
387 for (Portlet portlet : portlets) {
388 String portletId = portlet.getRootPortletId();
389
390 if (!group.isStagedPortlet(portletId)) {
391 continue;
392 }
393
394 String key = PortletPermissionUtil.getPrimaryKey(0, portletId);
395
396 if (portletIds.get(key) == null) {
397 portletIds.put(
398 key,
399 new Object[] {
400 portletId, firstLayout.getPlid(), groupId,
401 StringPool.BLANK, StringPool.BLANK
402 });
403 }
404 }
405 }
406
407 Element layoutsElement = rootElement.addElement("layouts");
408
409 for (Layout layout : layouts) {
410 exportLayout(
411 portletDataContext, layoutConfigurationPortlet, layoutCache,
412 portlets, portletIds, exportPermissions, exportUserPermissions,
413 layout, layoutsElement);
414 }
415
416 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
417 Element rolesElement = rootElement.addElement("roles");
418
419 if (exportPermissions) {
420 _permissionExporter.exportLayoutRoles(
421 layoutCache, companyId, groupId, rolesElement);
422 }
423 }
424
425 long previousScopeGroupId = portletDataContext.getScopeGroupId();
426
427 Element portletsElement = rootElement.addElement("portlets");
428
429 for (Map.Entry<String, Object[]> portletIdsEntry :
430 portletIds.entrySet()) {
431
432 Object[] portletObjects = portletIdsEntry.getValue();
433
434 String portletId = null;
435 long plid = 0;
436 long scopeGroupId = 0;
437 String scopeType = StringPool.BLANK;
438 String scopeLayoutUuid = null;
439
440 if (portletObjects.length == 4) {
441 portletId = (String)portletIdsEntry.getValue()[0];
442 plid = (Long)portletIdsEntry.getValue()[1];
443 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
444 scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
445 }
446 else {
447 portletId = (String)portletIdsEntry.getValue()[0];
448 plid = (Long)portletIdsEntry.getValue()[1];
449 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
450 scopeType = (String)portletIdsEntry.getValue()[3];
451 scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
452 }
453
454 Layout layout = LayoutLocalServiceUtil.getLayout(plid);
455
456 portletDataContext.setPlid(layout.getPlid());
457 portletDataContext.setOldPlid(layout.getPlid());
458 portletDataContext.setScopeGroupId(scopeGroupId);
459 portletDataContext.setScopeType(scopeType);
460 portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
461
462 boolean[] exportPortletControls = getExportPortletControls(
463 companyId, portletId, portletDataContext, parameterMap);
464
465 _portletExporter.exportPortlet(
466 portletDataContext, layoutCache, portletId, layout,
467 portletsElement, defaultUserId, exportPermissions,
468 exportPortletArchivedSetups, exportPortletControls[0],
469 exportPortletControls[1], exportPortletUserPreferences,
470 exportUserPermissions);
471 }
472
473 portletDataContext.setScopeGroupId(previousScopeGroupId);
474
475 if (exportCategories) {
476 exportAssetCategories(portletDataContext);
477 }
478
479 _portletExporter.exportAssetLinks(portletDataContext);
480 _portletExporter.exportAssetTags(portletDataContext);
481 _portletExporter.exportComments(portletDataContext);
482 _portletExporter.exportExpandoTables(portletDataContext);
483 _portletExporter.exportLocks(portletDataContext);
484
485 if (exportPermissions) {
486 _permissionExporter.exportPortletDataPermissions(
487 portletDataContext);
488 }
489
490 _portletExporter.exportRatingsEntries(portletDataContext, rootElement);
491
492 if (exportTheme && !portletDataContext.isPerformDirectBinaryImport()) {
493 exportTheme(layoutSet, zipWriter);
494 }
495
496 if (_log.isInfoEnabled()) {
497 if (stopWatch != null) {
498 _log.info(
499 "Exporting layouts takes " + stopWatch.getTime() + " ms");
500 }
501 else {
502 _log.info("Exporting layouts is finished");
503 }
504 }
505
506 portletDataContext.addZipEntry(
507 "/manifest.xml", document.formattedString());
508
509 try {
510 return zipWriter.getFile();
511 }
512 finally {
513 if (updateLastPublishDate) {
514 updateLastPublishDate(layoutSet, lastPublishDate);
515 }
516 }
517 }
518
519 protected void exportAssetCategories(PortletDataContext portletDataContext)
520 throws Exception {
521
522 Document document = SAXReaderUtil.createDocument();
523
524 Element rootElement = document.addElement("categories-hierarchy");
525
526 Element assetVocabulariesElement = rootElement.addElement(
527 "vocabularies");
528
529 List<AssetVocabulary> assetVocabularies =
530 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
531 portletDataContext.getGroupId());
532
533 for (AssetVocabulary assetVocabulary : assetVocabularies) {
534 _portletExporter.exportAssetVocabulary(
535 portletDataContext, assetVocabulariesElement, assetVocabulary);
536 }
537
538 Element categoriesElement = rootElement.addElement("categories");
539
540 List<AssetCategory> assetCategories =
541 AssetCategoryUtil.findByGroupId(portletDataContext.getGroupId());
542
543 for (AssetCategory assetCategory : assetCategories) {
544 _portletExporter.exportAssetCategory(
545 portletDataContext, assetVocabulariesElement, categoriesElement,
546 assetCategory);
547 }
548
549 _portletExporter.exportAssetCategories(portletDataContext, rootElement);
550
551 portletDataContext.addZipEntry(
552 portletDataContext.getRootPath() + "/categories-hierarchy.xml",
553 document.formattedString());
554 }
555
556 protected void exportJournalArticle(
557 PortletDataContext portletDataContext, Layout layout,
558 Element layoutElement)
559 throws Exception {
560
561 UnicodeProperties typeSettingsProperties =
562 layout.getTypeSettingsProperties();
563
564 String articleId = typeSettingsProperties.getProperty(
565 "article-id", StringPool.BLANK);
566
567 long articleGroupId = layout.getGroupId();
568
569 if (Validator.isNull(articleId)) {
570 if (_log.isWarnEnabled()) {
571 _log.warn(
572 "No article id found in typeSettings of layout " +
573 layout.getPlid());
574 }
575 }
576
577 JournalArticle article = null;
578
579 try {
580 article = JournalArticleLocalServiceUtil.getLatestArticle(
581 articleGroupId, articleId,
582 WorkflowConstants.STATUS_APPROVED);
583 }
584 catch (NoSuchArticleException nsae) {
585 if (_log.isWarnEnabled()) {
586 _log.warn(
587 "No approved article found with group id " +
588 articleGroupId + " and article id " + articleId);
589 }
590 }
591
592 if (article == null) {
593 return;
594 }
595
596 String path = JournalPortletDataHandlerImpl.getArticlePath(
597 portletDataContext, article);
598
599 Element articleElement = layoutElement.addElement("article");
600
601 articleElement.addAttribute("path", path);
602
603 Element dlFileEntryTypesElement = layoutElement.addElement(
604 "dl-file-entry-types");
605 Element dlFoldersElement = layoutElement.addElement("dl-folders");
606 Element dlFilesElement = layoutElement.addElement("dl-file-entries");
607 Element dlFileRanksElement = layoutElement.addElement("dl-file-ranks");
608 Element igFoldersElement = layoutElement.addElement("ig-folders");
609 Element igImagesElement = layoutElement.addElement("ig-images");
610
611 JournalPortletDataHandlerImpl.exportArticle(
612 portletDataContext, layoutElement, layoutElement, layoutElement,
613 dlFileEntryTypesElement, dlFoldersElement, dlFilesElement,
614 dlFileRanksElement, igFoldersElement, igImagesElement, article,
615 false);
616 }
617
618 protected void exportLayout(
619 PortletDataContext portletDataContext,
620 Portlet layoutConfigurationPortlet, LayoutCache layoutCache,
621 List<Portlet> portlets, Map<String, Object[]> portletIds,
622 boolean exportPermissions, boolean exportUserPermissions,
623 Layout layout, Element layoutsElement)
624 throws Exception {
625
626 String path = portletDataContext.getLayoutPath(
627 layout.getLayoutId()) + "/layout.xml";
628
629 if (!portletDataContext.isPathNotProcessed(path)) {
630 return;
631 }
632
633 LayoutRevision layoutRevision = null;
634
635 if (LayoutStagingUtil.isBranchingLayout(layout)) {
636 layoutRevision = LayoutStagingUtil.getLayoutRevision(layout);
637
638 layoutRevision = LayoutRevisionUtil.fetchByL_H_P(
639 layoutRevision.getLayoutSetBranchId(), true, layout.getPlid());
640
641 if (layoutRevision != null) {
642 if (!layoutRevision.isHead()) {
643 return;
644 }
645 else {
646 LayoutStagingHandler layoutStagingHandler =
647 LayoutStagingUtil.getLayoutStagingHandler(layout);
648
649 layoutStagingHandler.setLayoutRevision(layoutRevision);
650 }
651 }
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
996 if (_log.isDebugEnabled()) {
997 _log.debug("Export portlet data " + exportPortletData);
998 _log.debug("Export all portlet data " + exportPortletDataAll);
999 _log.debug("Export portlet setup " + exportPortletSetup);
1000 }
1001
1002 boolean exportCurPortletData = exportPortletData;
1003 boolean exportCurPortletSetup = exportPortletSetup;
1004
1005
1006
1007
1008
1009 if (exportPortletDataAll) {
1010 exportCurPortletData = true;
1011 exportCurPortletSetup = true;
1012 }
1013 else {
1014 Portlet portlet = PortletLocalServiceUtil.getPortletById(
1015 companyId, portletId);
1016
1017 if (portlet != null) {
1018 String portletDataHandlerClass =
1019 portlet.getPortletDataHandlerClass();
1020
1021
1022
1023
1024
1025
1026 if (portletDataHandlerClass != null) {
1027 String rootPortletId = PortletConstants.getRootPortletId(
1028 portletId);
1029
1030
1031
1032
1033 exportCurPortletData =
1034 exportPortletData &&
1035 MapUtil.getBoolean(
1036 parameterMap,
1037 PortletDataHandlerKeys.PORTLET_DATA +
1038 StringPool.UNDERLINE + rootPortletId);
1039
1040
1041
1042
1043 exportCurPortletSetup =
1044 exportPortletData &&
1045 MapUtil.getBoolean(
1046 parameterMap,
1047 PortletDataHandlerKeys.PORTLET_SETUP +
1048 StringPool.UNDERLINE + rootPortletId);
1049 }
1050 }
1051 }
1052
1053 return new boolean[] {exportCurPortletData, exportCurPortletSetup};
1054 }
1055
1056 protected String getLayoutIconPath(
1057 PortletDataContext portletDataContext, Layout layout, Image image) {
1058
1059 StringBundler sb = new StringBundler(5);
1060
1061 sb.append(portletDataContext.getLayoutPath(layout.getLayoutId()));
1062 sb.append("/icons/");
1063 sb.append(image.getImageId());
1064 sb.append(StringPool.PERIOD);
1065 sb.append(image.getType());
1066
1067 return sb.toString();
1068 }
1069
1070 protected String getLayoutSetPrototype(
1071 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
1072
1073 StringBundler sb = new StringBundler(3);
1074
1075 sb.append(portletDataContext.getRootPath());
1076 sb.append("/layout-set-prototype/");
1077 sb.append(layoutSetPrototypeUuid);
1078
1079 return sb.toString();
1080 }
1081
1082 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
1083
1084 private PermissionExporter _permissionExporter = new PermissionExporter();
1085 private PortletExporter _portletExporter = new PortletExporter();
1086
1087 }