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