1
22
23 package com.liferay.portal.lar;
24
25 import com.liferay.portal.PortalException;
26 import com.liferay.portal.SystemException;
27 import com.liferay.portal.kernel.io.FileCacheOutputStream;
28 import com.liferay.portal.kernel.log.Log;
29 import com.liferay.portal.kernel.log.LogFactoryUtil;
30 import com.liferay.portal.kernel.util.FileUtil;
31 import com.liferay.portal.kernel.util.MapUtil;
32 import com.liferay.portal.kernel.util.ReleaseInfo;
33 import com.liferay.portal.kernel.util.StringPool;
34 import com.liferay.portal.kernel.util.StringUtil;
35 import com.liferay.portal.kernel.util.Time;
36 import com.liferay.portal.kernel.xml.Document;
37 import com.liferay.portal.kernel.xml.Element;
38 import com.liferay.portal.kernel.xml.SAXReaderUtil;
39 import com.liferay.portal.kernel.zip.ZipWriter;
40 import com.liferay.portal.model.Group;
41 import com.liferay.portal.model.GroupConstants;
42 import com.liferay.portal.model.Image;
43 import com.liferay.portal.model.Layout;
44 import com.liferay.portal.model.LayoutConstants;
45 import com.liferay.portal.model.LayoutSet;
46 import com.liferay.portal.model.LayoutTypePortlet;
47 import com.liferay.portal.model.Portlet;
48 import com.liferay.portal.model.PortletConstants;
49 import com.liferay.portal.model.Resource;
50 import com.liferay.portal.model.ResourceConstants;
51 import com.liferay.portal.model.Theme;
52 import com.liferay.portal.service.GroupLocalServiceUtil;
53 import com.liferay.portal.service.ImageLocalServiceUtil;
54 import com.liferay.portal.service.LayoutLocalServiceUtil;
55 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
56 import com.liferay.portal.service.PortletLocalServiceUtil;
57 import com.liferay.portal.service.UserLocalServiceUtil;
58 import com.liferay.portal.service.permission.PortletPermissionUtil;
59 import com.liferay.portal.service.persistence.LayoutUtil;
60 import com.liferay.portal.theme.ThemeLoader;
61 import com.liferay.portal.theme.ThemeLoaderFactory;
62 import com.liferay.portal.util.ContentUtil;
63 import com.liferay.portal.util.PortletKeys;
64 import com.liferay.portal.util.PropsValues;
65 import com.liferay.portal.velocity.VelocityContextPool;
66
67 import java.io.File;
68 import java.io.IOException;
69
70 import java.util.Date;
71 import java.util.HashSet;
72 import java.util.LinkedHashMap;
73 import java.util.List;
74 import java.util.Map;
75
76 import javax.servlet.ServletContext;
77
78 import org.apache.commons.lang.time.StopWatch;
79
80
90 public class LayoutExporter {
91
92 public byte[] exportLayouts(
93 long groupId, boolean privateLayout, long[] layoutIds,
94 Map<String, String[]> parameterMap, Date startDate, Date endDate)
95 throws PortalException, SystemException {
96
97 FileCacheOutputStream fcos = exportLayoutsAsStream(
98 groupId, privateLayout, layoutIds, parameterMap, startDate,
99 endDate);
100
101 try {
102 return fcos.getBytes();
103 }
104 catch (IOException ioe) {
105 throw new SystemException(ioe);
106 }
107 finally {
108 fcos.cleanUp();
109 }
110 }
111
112 public FileCacheOutputStream exportLayoutsAsStream(
113 long groupId, boolean privateLayout, long[] layoutIds,
114 Map<String, String[]> parameterMap, Date startDate, Date endDate)
115 throws PortalException, SystemException {
116
117 boolean exportPermissions = MapUtil.getBoolean(
118 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
119 boolean exportUserPermissions = MapUtil.getBoolean(
120 parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
121 boolean exportPortletArchivedSetups = MapUtil.getBoolean(
122 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
123 boolean exportPortletUserPreferences = MapUtil.getBoolean(
124 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
125 boolean exportTheme = MapUtil.getBoolean(
126 parameterMap, PortletDataHandlerKeys.THEME);
127
128 if (_log.isDebugEnabled()) {
129 _log.debug("Export permissions " + exportPermissions);
130 _log.debug("Export user permissions " + exportUserPermissions);
131 _log.debug(
132 "Export portlet archived setups " +
133 exportPortletArchivedSetups);
134 _log.debug(
135 "Export portlet user preferences " +
136 exportPortletUserPreferences);
137 _log.debug("Export theme " + exportTheme);
138 }
139
140 StopWatch stopWatch = null;
141
142 if (_log.isInfoEnabled()) {
143 stopWatch = new StopWatch();
144
145 stopWatch.start();
146 }
147
148 LayoutCache layoutCache = new LayoutCache();
149
150 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
151 groupId, privateLayout);
152
153 long companyId = layoutSet.getCompanyId();
154 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
155
156 ZipWriter zipWriter = null;
157
158 try {
159 zipWriter = new ZipWriter();
160 }
161 catch (IOException ioe) {
162 throw new SystemException(ioe);
163 }
164
165 PortletDataContext context = new PortletDataContextImpl(
166 companyId, groupId, parameterMap, new HashSet<String>(), startDate,
167 endDate, zipWriter);
168
169 Group guestGroup = GroupLocalServiceUtil.getGroup(
170 companyId, GroupConstants.GUEST);
171
172
174 Document doc = SAXReaderUtil.createDocument();
175
176 Element root = doc.addElement("root");
177
178 Element header = root.addElement("header");
179
180 header.addAttribute(
181 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
182 header.addAttribute("export-date", Time.getRFC822());
183
184 if (context.hasDateRange()) {
185 header.addAttribute(
186 "start-date", String.valueOf(context.getStartDate()));
187 header.addAttribute(
188 "end-date", String.valueOf(context.getEndDate()));
189 }
190
191 header.addAttribute("type", "layout-set");
192 header.addAttribute("group-id", String.valueOf(groupId));
193 header.addAttribute("private-layout", String.valueOf(privateLayout));
194 header.addAttribute("theme-id", layoutSet.getThemeId());
195 header.addAttribute("color-scheme-id", layoutSet.getColorSchemeId());
196
197
199 Portlet layoutConfigurationPortlet =
200 PortletLocalServiceUtil.getPortletById(
201 context.getCompanyId(), PortletKeys.LAYOUT_CONFIGURATION);
202
203
205 Map<String, Object[]> portletIds =
206 new LinkedHashMap<String, Object[]>();
207
208 List<Layout> layouts = null;
209
210 if ((layoutIds == null) || (layoutIds.length == 0)) {
211 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
212 }
213 else {
214 layouts = LayoutLocalServiceUtil.getLayouts(
215 groupId, privateLayout, layoutIds);
216 }
217
218 Element layoutsEl = root.addElement("layouts");
219
220 for (Layout layout : layouts) {
221 context.setPlid(layout.getPlid());
222
223 Document layoutDoc = SAXReaderUtil.createDocument();
224
225 Element layoutEl = layoutDoc.addElement("layout");
226
227 layoutEl.addAttribute("old-plid", String.valueOf(layout.getPlid()));
228 layoutEl.addAttribute(
229 "layout-id", String.valueOf(layout.getLayoutId()));
230 layoutEl.addElement("parent-layout-id").addText(
231 String.valueOf(layout.getParentLayoutId()));
232 layoutEl.addElement("name").addCDATA(layout.getName());
233 layoutEl.addElement("title").addCDATA(layout.getTitle());
234 layoutEl.addElement("description").addText(layout.getDescription());
235 layoutEl.addElement("type").addText(layout.getType());
236 layoutEl.addElement("type-settings").addCDATA(
237 layout.getTypeSettings());
238 layoutEl.addElement("hidden").addText(
239 String.valueOf(layout.getHidden()));
240 layoutEl.addElement("friendly-url").addText(
241 layout.getFriendlyURL());
242 layoutEl.addElement("icon-image").addText(
243 String.valueOf(layout.getIconImage()));
244
245 if (layout.isIconImage()) {
246 Image image = ImageLocalServiceUtil.getImage(
247 layout.getIconImageId());
248
249 if (image != null) {
250 String iconPath = getLayoutIconPath(context, layout, image);
251
252 layoutEl.addElement("icon-image-path").addText(
253 iconPath);
254
255 context.addZipEntry(iconPath, image.getTextObj());
256 }
257 }
258
259 layoutEl.addElement("theme-id").addText(layout.getThemeId());
260 layoutEl.addElement("color-scheme-id").addText(
261 layout.getColorSchemeId());
262 layoutEl.addElement("wap-theme-id").addText(layout.getWapThemeId());
263 layoutEl.addElement("wap-color-scheme-id").addText(
264 layout.getWapColorSchemeId());
265 layoutEl.addElement("css").addCDATA(layout.getCss());
266 layoutEl.addElement("priority").addText(
267 String.valueOf(layout.getPriority()));
268
269
271 if (exportPermissions) {
272 Element permissionsEl = layoutEl.addElement("permissions");
273
274 String resourceName = Layout.class.getName();
275 String resourcePrimKey = String.valueOf(layout.getPlid());
276
277 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
278 exportLayoutPermissions_5(
279 layoutCache, companyId, groupId, resourceName,
280 resourcePrimKey, permissionsEl);
281 }
282 else if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
283 exportLayoutPermissions_6(
284 layoutCache, companyId, groupId, resourceName,
285 resourcePrimKey, permissionsEl);
286 }
287 else {
288 exportLayoutPermissions_4(
289 layoutCache, companyId, groupId, guestGroup,
290 resourceName, resourcePrimKey, permissionsEl,
291 exportUserPermissions);
292 }
293 }
294
295 if (layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
296 LayoutTypePortlet layoutTypePortlet =
297 (LayoutTypePortlet)layout.getLayoutType();
298
299 for (String portletId : layoutTypePortlet.getPortletIds()) {
300 String key = PortletPermissionUtil.getPrimaryKey(
301 layout.getPlid(), portletId);
302
303 portletIds.put(
304 key, new Object[] {portletId, layout.getPlid()});
305 }
306 }
307
308 String layoutPath = context.getLayoutPath(layout.getLayoutId()) +
309 "/layout.xml";
310
311 Element el = layoutsEl.addElement("layout");
312
313 el.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
314 el.addAttribute("path", layoutPath);
315
316 _portletExporter.exportPortletData(
317 context, layoutConfigurationPortlet, layout, null, layoutEl);
318
319 try {
320 context.addZipEntry(layoutPath, layoutDoc.formattedString());
321 }
322 catch (IOException ioe) {
323 }
324 }
325
326 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
327 Element rolesEl = root.addElement("roles");
328
329
331 if (exportPermissions) {
332 exportLayoutRoles(layoutCache, companyId, groupId, rolesEl);
333 }
334 }
335
336
338 Element portletsEl = root.addElement("portlets");
339
340 for (Map.Entry<String, Object[]> portletIdsEntry :
341 portletIds.entrySet()) {
342
343 String portletId = (String)portletIdsEntry.getValue()[0];
344 long plid = (Long)portletIdsEntry.getValue()[1];
345
346 Layout layout = LayoutUtil.findByPrimaryKey(plid);
347
348 context.setPlid(layout.getPlid());
349 context.setOldPlid(layout.getPlid());
350
351 boolean[] exportPortletControls = getExportPortletControls(
352 context.getCompanyId(), portletId, context, parameterMap);
353
354 _portletExporter.exportPortlet(
355 context, layoutCache, portletId, layout, portletsEl,
356 defaultUserId, exportPermissions, exportPortletArchivedSetups,
357 exportPortletControls[0], exportPortletControls[1],
358 exportPortletUserPreferences, exportUserPermissions);
359 }
360
361
363 _portletExporter.exportComments(context, root);
364
365
367 _portletExporter.exportRatings(context, root);
368
369
371 _portletExporter.exportTags(context, root);
372
373
375 FileCacheOutputStream fcos = null;
376
377 try {
378 if (exportTheme) {
379 fcos = exportTheme(layoutSet);
380 }
381
382
384 if (_log.isInfoEnabled()) {
385 _log.info(
386 "Exporting layouts takes " + stopWatch.getTime() + " ms");
387 }
388
389
391 context.addZipEntry("/manifest.xml", doc.formattedString());
392
393 if (fcos != null) {
394 context.addZipEntry("/theme.zip", fcos.getFileInputStream());
395 }
396
397 return zipWriter.finishWithStream();
398 }
399 catch (IOException ioe) {
400 throw new SystemException(ioe);
401 }
402 finally {
403 if (fcos != null) {
404 fcos.cleanUp();
405 }
406 }
407 }
408
409 protected void exportLayoutPermissions_4(
410 LayoutCache layoutCache, long companyId, long groupId,
411 Group guestGroup, String resourceName, String resourcePrimKey,
412 Element permissionsEl, boolean exportUserPermissions)
413 throws SystemException {
414
415 _portletExporter.exportGroupPermissions(
416 companyId, groupId, resourceName, resourcePrimKey, permissionsEl,
417 "community-actions");
418
419 if (groupId != guestGroup.getGroupId()) {
420 _portletExporter.exportGroupPermissions(
421 companyId, guestGroup.getGroupId(), resourceName,
422 resourcePrimKey, permissionsEl, "guest-actions");
423 }
424
425 if (exportUserPermissions) {
426 _portletExporter.exportUserPermissions(
427 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
428 permissionsEl);
429 }
430
431 _portletExporter.exportInheritedPermissions(
432 layoutCache, companyId, resourceName, resourcePrimKey,
433 permissionsEl, "organization");
434
435 _portletExporter.exportInheritedPermissions(
436 layoutCache, companyId, resourceName, resourcePrimKey,
437 permissionsEl, "location");
438
439 _portletExporter.exportInheritedPermissions(
440 layoutCache, companyId, resourceName, resourcePrimKey,
441 permissionsEl, "user-group");
442 }
443
444 protected void exportLayoutPermissions_5(
445 LayoutCache layoutCache, long companyId, long groupId,
446 String resourceName, String resourcePrimKey, Element permissionsEl)
447 throws PortalException, SystemException {
448
449 boolean portletActions = false;
450
451 Resource resource = layoutCache.getResource(
452 companyId, groupId, resourceName,
453 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
454 portletActions);
455
456 _portletExporter.exportPermissions_5(
457 layoutCache, groupId, resourceName, resource.getResourceId(),
458 permissionsEl);
459 }
460
461 protected void exportLayoutPermissions_6(
462 LayoutCache layoutCache, long companyId, long groupId,
463 String resourceName, String resourcePrimKey, Element permissionsEl)
464 throws PortalException, SystemException {
465
466 boolean portletActions = false;
467
468 _portletExporter.exportPermissions_6(
469 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
470 permissionsEl, portletActions);
471 }
472
473 protected void exportLayoutRoles(
474 LayoutCache layoutCache, long companyId, long groupId,
475 Element rolesEl)
476 throws SystemException {
477
478 String resourceName = Layout.class.getName();
479
480 _portletExporter.exportGroupRoles(
481 layoutCache, companyId, groupId, resourceName, "community",
482 rolesEl);
483
484 _portletExporter.exportUserRoles(
485 layoutCache, companyId, groupId, resourceName, rolesEl);
486
487 _portletExporter.exportInheritedRoles(
488 layoutCache, companyId, groupId, resourceName, "organization",
489 rolesEl);
490
491 _portletExporter.exportInheritedRoles(
492 layoutCache, companyId, groupId, resourceName, "location", rolesEl);
493
494 _portletExporter.exportInheritedRoles(
495 layoutCache, companyId, groupId, resourceName, "user-group",
496 rolesEl);
497 }
498
499 protected FileCacheOutputStream exportTheme(LayoutSet layoutSet)
500 throws IOException {
501
502 Theme theme = layoutSet.getTheme();
503
504 ZipWriter zipWriter = new ZipWriter();
505
506 String lookAndFeelXML = ContentUtil.get(
507 "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
508
509 lookAndFeelXML = StringUtil.replace(
510 lookAndFeelXML,
511 new String[] {
512 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
513 },
514 new String[] {
515 theme.getTemplateExtension(), theme.getVirtualPath()
516 }
517 );
518
519 zipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
520
521 String servletContextName = theme.getServletContextName();
522
523 ServletContext servletContext = VelocityContextPool.get(
524 servletContextName);
525
526 if (servletContext == null) {
527 if (_log.isWarnEnabled()) {
528 _log.warn(
529 "Servlet context not found for theme " +
530 theme.getThemeId());
531 }
532
533 return null;
534 }
535
536 File cssPath = null;
537 File imagesPath = null;
538 File javaScriptPath = null;
539 File templatesPath = null;
540
541 if (!theme.isLoadFromServletContext()) {
542 ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
543 servletContextName);
544
545 if (themeLoader == null) {
546 _log.error(
547 servletContextName + " does not map to a theme loader");
548 }
549 else {
550 String realPath =
551 themeLoader.getFileStorage().getPath() + "/" +
552 theme.getName();
553
554 cssPath = new File(realPath + "/css");
555 imagesPath = new File(realPath + "/images");
556 javaScriptPath = new File(realPath + "/javascript");
557 templatesPath = new File(realPath + "/templates");
558 }
559 }
560 else {
561 cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
562 imagesPath = new File(
563 servletContext.getRealPath(theme.getImagesPath()));
564 javaScriptPath = new File(
565 servletContext.getRealPath(theme.getJavaScriptPath()));
566 templatesPath = new File(
567 servletContext.getRealPath(theme.getTemplatesPath()));
568 }
569
570 exportThemeFiles("css", cssPath, zipWriter);
571 exportThemeFiles("images", imagesPath, zipWriter);
572 exportThemeFiles("javascript", javaScriptPath, zipWriter);
573 exportThemeFiles("templates", templatesPath, zipWriter);
574
575 return zipWriter.finishWithStream();
576 }
577
578 protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
579 throws IOException {
580
581 if ((dir == null) || (!dir.exists())) {
582 return;
583 }
584
585 File[] files = dir.listFiles();
586
587 for (int i = 0; i < files.length; i++) {
588 File file = files[i];
589
590 if (file.isDirectory()) {
591 exportThemeFiles(path + "/" + file.getName(), file, zipWriter);
592 }
593 else {
594 zipWriter.addEntry(
595 path + "/" + file.getName(), FileUtil.getBytes(file));
596 }
597 }
598 }
599
600 protected boolean[] getExportPortletControls(
601 long companyId, String portletId, PortletDataContext context,
602 Map<String, String[]> parameterMap)
603 throws SystemException {
604
605 boolean exportPortletData = MapUtil.getBoolean(
606 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
607 boolean exportPortletDataAll = MapUtil.getBoolean(
608 parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
609 boolean exportPortletSetup = MapUtil.getBoolean(
610 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
611
612 if (_log.isDebugEnabled()) {
613 _log.debug("Export portlet data " + exportPortletData);
614 _log.debug("Export all portlet data " + exportPortletDataAll);
615 _log.debug("Export portlet setup " + exportPortletSetup);
616 }
617
618 boolean exportCurPortletData = exportPortletData;
619 boolean exportCurPortletSetup = exportPortletSetup;
620
621 if (exportPortletDataAll) {
622 exportCurPortletData = true;
623 exportCurPortletSetup = true;
624 }
625 else {
626 Portlet portlet = PortletLocalServiceUtil.getPortletById(
627 companyId, portletId);
628
629 if (portlet != null) {
630 String portletDataHandlerClass =
631 portlet.getPortletDataHandlerClass();
632
633 if (portletDataHandlerClass != null) {
634 String rootPortletId = PortletConstants.getRootPortletId(
635 portletId);
636
637 exportCurPortletData =
638 exportPortletData &&
639 MapUtil.getBoolean(
640 parameterMap,
641 PortletDataHandlerKeys.PORTLET_DATA +
642 StringPool.UNDERLINE + rootPortletId);
643
644 exportCurPortletSetup =
645 exportPortletData &&
646 MapUtil.getBoolean(
647 parameterMap,
648 PortletDataHandlerKeys.PORTLET_SETUP +
649 StringPool.UNDERLINE + rootPortletId);
650 }
651 }
652 }
653
654 return new boolean[] {exportCurPortletData, exportCurPortletSetup};
655 }
656
657 protected String getLayoutIconPath(
658 PortletDataContext context, Layout layout, Image image) {
659
660 StringBuilder sb = new StringBuilder();
661
662 sb.append(context.getLayoutPath(layout.getLayoutId()));
663 sb.append("/icons/");
664 sb.append(image.getImageId());
665 sb.append(StringPool.PERIOD);
666 sb.append(image.getType());
667
668 return sb.toString();
669 }
670
671 private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
672
673 private PortletExporter _portletExporter = new PortletExporter();
674
675 }