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