001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
018 import com.liferay.portal.kernel.language.LanguageUtil;
019 import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
020 import com.liferay.portal.kernel.lar.ExportImportPathUtil;
021 import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
022 import com.liferay.portal.kernel.lar.ManifestSummary;
023 import com.liferay.portal.kernel.lar.PortletDataContext;
024 import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
025 import com.liferay.portal.kernel.lar.PortletDataHandler;
026 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
027 import com.liferay.portal.kernel.lar.PortletDataHandlerStatusMessageSenderUtil;
028 import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
029 import com.liferay.portal.kernel.lar.StagedModelType;
030 import com.liferay.portal.kernel.lar.xstream.XStreamAliasRegistryUtil;
031 import com.liferay.portal.kernel.log.Log;
032 import com.liferay.portal.kernel.log.LogFactoryUtil;
033 import com.liferay.portal.kernel.settings.Settings;
034 import com.liferay.portal.kernel.settings.SettingsFactoryUtil;
035 import com.liferay.portal.kernel.staging.LayoutStagingUtil;
036 import com.liferay.portal.kernel.util.ArrayUtil;
037 import com.liferay.portal.kernel.util.Constants;
038 import com.liferay.portal.kernel.util.FileUtil;
039 import com.liferay.portal.kernel.util.LocaleUtil;
040 import com.liferay.portal.kernel.util.MapUtil;
041 import com.liferay.portal.kernel.util.ReleaseInfo;
042 import com.liferay.portal.kernel.util.StringPool;
043 import com.liferay.portal.kernel.util.StringUtil;
044 import com.liferay.portal.kernel.util.Time;
045 import com.liferay.portal.kernel.util.Validator;
046 import com.liferay.portal.kernel.xml.Document;
047 import com.liferay.portal.kernel.xml.Element;
048 import com.liferay.portal.kernel.xml.SAXReaderUtil;
049 import com.liferay.portal.kernel.zip.ZipWriter;
050 import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
051 import com.liferay.portal.model.Group;
052 import com.liferay.portal.model.Image;
053 import com.liferay.portal.model.Layout;
054 import com.liferay.portal.model.LayoutConstants;
055 import com.liferay.portal.model.LayoutPrototype;
056 import com.liferay.portal.model.LayoutRevision;
057 import com.liferay.portal.model.LayoutSet;
058 import com.liferay.portal.model.LayoutSetBranch;
059 import com.liferay.portal.model.LayoutSetPrototype;
060 import com.liferay.portal.model.LayoutStagingHandler;
061 import com.liferay.portal.model.LayoutTypePortlet;
062 import com.liferay.portal.model.Portlet;
063 import com.liferay.portal.model.impl.LayoutImpl;
064 import com.liferay.portal.service.GroupLocalServiceUtil;
065 import com.liferay.portal.service.ImageLocalServiceUtil;
066 import com.liferay.portal.service.LayoutLocalServiceUtil;
067 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
068 import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
069 import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
070 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
071 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
072 import com.liferay.portal.service.PortletLocalServiceUtil;
073 import com.liferay.portal.service.ServiceContext;
074 import com.liferay.portal.service.ServiceContextThreadLocal;
075 import com.liferay.portal.service.UserLocalServiceUtil;
076 import com.liferay.portal.service.permission.PortletPermissionUtil;
077
078 import java.io.File;
079
080 import java.util.Collections;
081 import java.util.Date;
082 import java.util.Iterator;
083 import java.util.LinkedHashMap;
084 import java.util.List;
085 import java.util.Map;
086
087 import org.apache.commons.lang.time.StopWatch;
088
089
101 public class LayoutExporter {
102
103 public static List<Portlet> getDataSiteLevelPortlets(long companyId)
104 throws Exception {
105
106 return getDataSiteLevelPortlets(companyId, false);
107 }
108
109 public static List<Portlet> getDataSiteLevelPortlets(
110 long companyId, boolean excludeDataAlwaysStaged)
111 throws Exception {
112
113 List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
114
115 Iterator<Portlet> itr = portlets.iterator();
116
117 while (itr.hasNext()) {
118 Portlet portlet = itr.next();
119
120 if (!portlet.isActive()) {
121 itr.remove();
122
123 continue;
124 }
125
126 PortletDataHandler portletDataHandler =
127 portlet.getPortletDataHandlerInstance();
128
129 if ((portletDataHandler == null) ||
130 !portletDataHandler.isDataSiteLevel() ||
131 (excludeDataAlwaysStaged &&
132 portletDataHandler.isDataAlwaysStaged())) {
133
134 itr.remove();
135 }
136 }
137
138 return portlets;
139 }
140
141 public static LayoutExporter getInstance() {
142 return _instance;
143 }
144
145
148 @Deprecated
149 public static List<Portlet> getPortletDataHandlerPortlets(
150 long groupId, List<Layout> layouts)
151 throws Exception {
152
153 return Collections.emptyList();
154 }
155
156
159 @Deprecated
160 public byte[] exportLayouts(
161 long groupId, boolean privateLayout, long[] layoutIds,
162 Map<String, String[]> parameterMap, Date startDate, Date endDate)
163 throws Exception {
164
165 File file = exportLayoutsAsFile(
166 groupId, privateLayout, layoutIds, parameterMap, startDate,
167 endDate);
168
169 try {
170 return FileUtil.getBytes(file);
171 }
172 finally {
173 file.delete();
174 }
175 }
176
177 public File exportLayoutsAsFile(
178 long groupId, boolean privateLayout, long[] layoutIds,
179 Map<String, String[]> parameterMap, Date startDate, Date endDate)
180 throws Exception {
181
182 try {
183 ExportImportThreadLocal.setLayoutExportInProcess(true);
184
185 return doExportLayoutsAsFile(
186 groupId, privateLayout, layoutIds, parameterMap, startDate,
187 endDate);
188 }
189 finally {
190 ExportImportThreadLocal.setLayoutExportInProcess(false);
191 }
192 }
193
194 protected File doExportLayoutsAsFile(
195 long groupId, boolean privateLayout, long[] layoutIds,
196 Map<String, String[]> parameterMap, Date startDate, Date endDate)
197 throws Exception {
198
199 boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
200 parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
201 boolean exportPermissions = MapUtil.getBoolean(
202 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
203 boolean exportLogo = MapUtil.getBoolean(
204 parameterMap, PortletDataHandlerKeys.LOGO);
205 boolean exportLayoutSetSettings = MapUtil.getBoolean(
206 parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
207
208 if (_log.isDebugEnabled()) {
209 _log.debug("Export permissions " + exportPermissions);
210 }
211
212 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
213 groupId, privateLayout);
214
215 long companyId = layoutSet.getCompanyId();
216 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
217
218 ServiceContext serviceContext =
219 ServiceContextThreadLocal.getServiceContext();
220
221 if (serviceContext == null) {
222 serviceContext = new ServiceContext();
223
224 serviceContext.setCompanyId(companyId);
225 serviceContext.setSignedIn(false);
226 serviceContext.setUserId(defaultUserId);
227
228 ServiceContextThreadLocal.pushServiceContext(serviceContext);
229 }
230
231 serviceContext.setAttribute("exporting", Boolean.TRUE);
232
233 long layoutSetBranchId = MapUtil.getLong(
234 parameterMap, "layoutSetBranchId");
235
236 serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
237
238 if (exportIgnoreLastPublishDate) {
239 endDate = null;
240 startDate = null;
241 }
242
243 StopWatch stopWatch = new StopWatch();
244
245 stopWatch.start();
246
247 ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
248
249 PortletDataContext portletDataContext =
250 PortletDataContextFactoryUtil.createExportPortletDataContext(
251 companyId, groupId, parameterMap, startDate, endDate,
252 zipWriter);
253
254 portletDataContext.setPortetDataContextListener(
255 new PortletDataContextListenerImpl(portletDataContext));
256
257 Document document = SAXReaderUtil.createDocument();
258
259 Element rootElement = document.addElement("root");
260
261 portletDataContext.setExportDataRootElement(rootElement);
262
263 Element headerElement = rootElement.addElement("header");
264
265 headerElement.addAttribute(
266 "available-locales",
267 StringUtil.merge(
268 LanguageUtil.getAvailableLocales(
269 portletDataContext.getScopeGroupId())));
270 headerElement.addAttribute(
271 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
272 headerElement.addAttribute("export-date", Time.getRFC822());
273
274 if (portletDataContext.hasDateRange()) {
275 headerElement.addAttribute(
276 "start-date",
277 String.valueOf(portletDataContext.getStartDate()));
278 headerElement.addAttribute(
279 "end-date", String.valueOf(portletDataContext.getEndDate()));
280 }
281
282 headerElement.addAttribute(
283 "company-id", String.valueOf(portletDataContext.getCompanyId()));
284 headerElement.addAttribute(
285 "company-group-id",
286 String.valueOf(portletDataContext.getCompanyGroupId()));
287 headerElement.addAttribute("group-id", String.valueOf(groupId));
288 headerElement.addAttribute(
289 "user-personal-site-group-id",
290 String.valueOf(portletDataContext.getUserPersonalSiteGroupId()));
291 headerElement.addAttribute(
292 "private-layout", String.valueOf(privateLayout));
293
294 Group group = layoutSet.getGroup();
295
296 String type = "layout-set";
297
298 if (group.isLayoutPrototype()) {
299 type = "layout-prototype";
300
301 LayoutPrototype layoutPrototype =
302 LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
303 group.getClassPK());
304
305 headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
306 }
307 else if (group.isLayoutSetPrototype()) {
308 type ="layout-set-prototype";
309
310 LayoutSetPrototype layoutSetPrototype =
311 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
312 group.getClassPK());
313
314 headerElement.addAttribute(
315 "type-uuid", layoutSetPrototype.getUuid());
316 }
317
318 headerElement.addAttribute("type", type);
319
320 LayoutSetBranch layoutSetBranch =
321 LayoutSetBranchLocalServiceUtil.fetchLayoutSetBranch(
322 layoutSetBranchId);
323
324 if (exportLogo) {
325 Image image = null;
326
327 if (layoutSetBranch != null) {
328 image = ImageLocalServiceUtil.getImage(
329 layoutSetBranch.getLogoId());
330 }
331 else {
332 image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
333 }
334
335 if ((image != null) && (image.getTextObj() != null)) {
336 String logoPath = ExportImportPathUtil.getRootPath(
337 portletDataContext);
338
339 logoPath += "/logo";
340
341 headerElement.addAttribute("logo-path", logoPath);
342
343 portletDataContext.addZipEntry(logoPath, image.getTextObj());
344 }
345 }
346
347 Element missingReferencesElement = rootElement.addElement(
348 "missing-references");
349
350 portletDataContext.setMissingReferencesElement(
351 missingReferencesElement);
352
353 if (layoutSetBranch != null) {
354 _themeExporter.exportTheme(portletDataContext, layoutSetBranch);
355 }
356 else {
357 _themeExporter.exportTheme(portletDataContext, layoutSet);
358 }
359
360 if (exportLayoutSetSettings) {
361 Element settingsElement = headerElement.addElement("settings");
362
363 if (layoutSetBranch != null) {
364 settingsElement.addCDATA(layoutSetBranch.getSettings());
365 }
366 else {
367 settingsElement.addCDATA(layoutSet.getSettings());
368 }
369 }
370
371 Map<String, Object[]> portletIds =
372 new LinkedHashMap<String, Object[]>();
373
374 List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
375 groupId, privateLayout);
376
377 if (group.isStagingGroup()) {
378 group = group.getLiveGroup();
379 }
380
381
382
383 for (Portlet portlet : getDataSiteLevelPortlets(companyId)) {
384 String portletId = portlet.getRootPortletId();
385
386 if (!group.isStagedPortlet(portletId)) {
387 continue;
388 }
389
390
391
392 if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
393 PortletDataHandler portletDataHandler =
394 portlet.getPortletDataHandlerInstance();
395
396 portletDataHandler.prepareManifestSummary(portletDataContext);
397 }
398
399
400
401 portletIds.put(
402 PortletPermissionUtil.getPrimaryKey(0, portletId),
403 new Object[] {
404 portletId, LayoutConstants.DEFAULT_PLID, groupId,
405 StringPool.BLANK, StringPool.BLANK
406 });
407
408 if (!portlet.isScopeable()) {
409 continue;
410 }
411
412
413
414 for (Layout layout : layouts) {
415 if ((!ArrayUtil.contains(layoutIds, layout.getLayoutId()) &&
416 ArrayUtil.isNotEmpty(layoutIds)) ||
417 !layout.isTypePortlet() || !layout.hasScopeGroup()) {
418
419 continue;
420 }
421
422 Group scopeGroup = layout.getScopeGroup();
423
424 portletIds.put(
425 PortletPermissionUtil.getPrimaryKey(
426 layout.getPlid(), portlet.getPortletId()),
427 new Object[] {
428 portlet.getPortletId(), layout.getPlid(),
429 scopeGroup.getGroupId(), StringPool.BLANK,
430 layout.getUuid()
431 });
432 }
433 }
434
435 portletDataContext.addDeletionSystemEventStagedModelTypes(
436 new StagedModelType(Layout.class));
437
438 Element layoutsElement = portletDataContext.getExportDataGroupElement(
439 Layout.class);
440
441 String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
442
443 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
444 LayoutSetPrototype layoutSetPrototype =
445 LayoutSetPrototypeLocalServiceUtil.
446 getLayoutSetPrototypeByUuidAndCompanyId(
447 layoutSetPrototypeUuid, companyId);
448
449 layoutsElement.addAttribute(
450 "layout-set-prototype-uuid", layoutSetPrototypeUuid);
451
452 layoutsElement.addAttribute(
453 "layout-set-prototype-name",
454 layoutSetPrototype.getName(LocaleUtil.getDefault()));
455 }
456
457 for (Layout layout : layouts) {
458 exportLayout(portletDataContext, layoutIds, portletIds, layout);
459 }
460
461 if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
462 ManifestSummary manifestSummary =
463 portletDataContext.getManifestSummary();
464
465 PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
466 "layout", ArrayUtil.toStringArray(portletIds.keySet()),
467 manifestSummary);
468
469 manifestSummary.resetCounters();
470 }
471
472 Element portletsElement = rootElement.addElement("portlets");
473
474 Element servicesElement = rootElement.addElement("services");
475
476 long previousScopeGroupId = portletDataContext.getScopeGroupId();
477
478 for (Map.Entry<String, Object[]> portletIdsEntry :
479 portletIds.entrySet()) {
480
481 Object[] portletObjects = portletIdsEntry.getValue();
482
483 String portletId = null;
484 long plid = LayoutConstants.DEFAULT_PLID;
485 long scopeGroupId = 0;
486 String scopeType = StringPool.BLANK;
487 String scopeLayoutUuid = null;
488
489 if (portletObjects.length == 4) {
490 portletId = (String)portletIdsEntry.getValue()[0];
491 plid = (Long)portletIdsEntry.getValue()[1];
492 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
493 scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
494 }
495 else {
496 portletId = (String)portletIdsEntry.getValue()[0];
497 plid = (Long)portletIdsEntry.getValue()[1];
498 scopeGroupId = (Long)portletIdsEntry.getValue()[2];
499 scopeType = (String)portletIdsEntry.getValue()[3];
500 scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
501 }
502
503 Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
504
505 if (layout == null) {
506 layout = new LayoutImpl();
507
508 layout.setCompanyId(companyId);
509 layout.setGroupId(groupId);
510 }
511
512 portletDataContext.setPlid(plid);
513 portletDataContext.setOldPlid(plid);
514 portletDataContext.setScopeGroupId(scopeGroupId);
515 portletDataContext.setScopeType(scopeType);
516 portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
517
518 Map<String, Boolean> exportPortletControlsMap =
519 ExportImportHelperUtil.getExportPortletControlsMap(
520 companyId, portletId, parameterMap, type);
521
522 _portletExporter.exportPortlet(
523 portletDataContext, portletId, layout, portletsElement,
524 exportPermissions,
525 exportPortletControlsMap.get(
526 PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS),
527 exportPortletControlsMap.get(
528 PortletDataHandlerKeys.PORTLET_DATA),
529 exportPortletControlsMap.get(
530 PortletDataHandlerKeys.PORTLET_SETUP),
531 exportPortletControlsMap.get(
532 PortletDataHandlerKeys.PORTLET_USER_PREFERENCES));
533 _portletExporter.exportService(
534 portletDataContext, portletId, servicesElement,
535 exportPortletControlsMap.get(
536 PortletDataHandlerKeys.PORTLET_SETUP));
537 }
538
539 portletDataContext.setScopeGroupId(previousScopeGroupId);
540
541 _portletExporter.exportAssetLinks(portletDataContext);
542 _portletExporter.exportAssetTags(portletDataContext);
543 _portletExporter.exportExpandoTables(portletDataContext);
544 _portletExporter.exportLocks(portletDataContext);
545
546 _deletionSystemEventExporter.exportDeletionSystemEvents(
547 portletDataContext);
548
549 if (exportPermissions) {
550 _permissionExporter.exportPortletDataPermissions(
551 portletDataContext);
552 }
553
554 ExportImportHelperUtil.writeManifestSummary(
555 document, portletDataContext.getManifestSummary());
556
557 if (_log.isInfoEnabled()) {
558 _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
559 }
560
561 portletDataContext.addZipEntry(
562 "/manifest.xml", document.formattedString());
563
564 return zipWriter.getFile();
565 }
566
567 protected void exportLayout(
568 PortletDataContext portletDataContext, long[] layoutIds,
569 Map<String, Object[]> portletIds, Layout layout)
570 throws Exception {
571
572 if (!ArrayUtil.contains(layoutIds, layout.getLayoutId()) &&
573 ArrayUtil.isNotEmpty(layoutIds)) {
574
575 Element layoutElement = portletDataContext.getExportDataElement(
576 layout);
577
578 layoutElement.addAttribute(Constants.ACTION, Constants.SKIP);
579
580 return;
581 }
582
583 boolean exportLAR = MapUtil.getBoolean(
584 portletDataContext.getParameterMap(), "exportLAR");
585
586 if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout)) {
587 long layoutSetBranchId = MapUtil.getLong(
588 portletDataContext.getParameterMap(), "layoutSetBranchId");
589
590 if (layoutSetBranchId <= 0) {
591 return;
592 }
593
594 LayoutRevision layoutRevision =
595 LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
596 layoutSetBranchId, true, layout.getPlid());
597
598 if (layoutRevision == null) {
599 return;
600 }
601
602 LayoutStagingHandler layoutStagingHandler =
603 LayoutStagingUtil.getLayoutStagingHandler(layout);
604
605 layoutStagingHandler.setLayoutRevision(layoutRevision);
606 }
607
608 StagedModelDataHandlerUtil.exportStagedModel(
609 portletDataContext, layout);
610
611 if (!layout.isSupportsEmbeddedPortlets()) {
612
613
614
615 return;
616 }
617
618 LayoutTypePortlet layoutTypePortlet =
619 (LayoutTypePortlet)layout.getLayoutType();
620
621
622
623
624
625 for (Portlet portlet : layoutTypePortlet.getAllPortlets(false)) {
626 String portletId = portlet.getPortletId();
627
628 Settings portletInstanceSettings =
629 SettingsFactoryUtil.getPortletInstanceSettings(
630 layout, portletId);
631
632 String scopeType = portletInstanceSettings.getValue(
633 "lfrScopeType", null);
634 String scopeLayoutUuid = portletInstanceSettings.getValue(
635 "lfrScopeLayoutUuid", null);
636
637 long scopeGroupId = portletDataContext.getScopeGroupId();
638
639 if (Validator.isNotNull(scopeType)) {
640 Group scopeGroup = null;
641
642 if (scopeType.equals("company")) {
643 scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
644 layout.getCompanyId());
645 }
646 else if (scopeType.equals("layout")) {
647 Layout scopeLayout = null;
648
649 scopeLayout =
650 LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
651 scopeLayoutUuid, portletDataContext.getGroupId(),
652 portletDataContext.isPrivateLayout());
653
654 if (scopeLayout == null) {
655 continue;
656 }
657
658 scopeGroup = scopeLayout.getScopeGroup();
659 }
660 else {
661 throw new IllegalArgumentException(
662 "Scope type " + scopeType + " is invalid");
663 }
664
665 if (scopeGroup != null) {
666 scopeGroupId = scopeGroup.getGroupId();
667 }
668 }
669
670 String key = PortletPermissionUtil.getPrimaryKey(
671 layout.getPlid(), portletId);
672
673 portletIds.put(
674 key,
675 new Object[] {
676 portletId, layout.getPlid(), scopeGroupId, scopeType,
677 scopeLayoutUuid
678 }
679 );
680 }
681 }
682
683 private LayoutExporter() {
684 XStreamAliasRegistryUtil.register(LayoutImpl.class, "Layout");
685 }
686
687 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
688
689 private static LayoutExporter _instance = new LayoutExporter();
690
691 private DeletionSystemEventExporter _deletionSystemEventExporter =
692 DeletionSystemEventExporter.getInstance();
693 private PermissionExporter _permissionExporter =
694 PermissionExporter.getInstance();
695 private PortletExporter _portletExporter = PortletExporter.getInstance();
696 private ThemeExporter _themeExporter = ThemeExporter.getInstance();
697
698 }