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.lar.PortletDataContext;
28 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
29 import com.liferay.portal.kernel.util.FileUtil;
30 import com.liferay.portal.kernel.util.ReleaseInfo;
31 import com.liferay.portal.kernel.util.StringPool;
32 import com.liferay.portal.kernel.util.StringUtil;
33 import com.liferay.portal.kernel.util.Time;
34 import com.liferay.portal.kernel.zip.ZipWriter;
35 import com.liferay.portal.model.Group;
36 import com.liferay.portal.model.Image;
37 import com.liferay.portal.model.Layout;
38 import com.liferay.portal.model.LayoutConstants;
39 import com.liferay.portal.model.LayoutSet;
40 import com.liferay.portal.model.LayoutTypePortlet;
41 import com.liferay.portal.model.Portlet;
42 import com.liferay.portal.model.Theme;
43 import com.liferay.portal.model.impl.GroupImpl;
44 import com.liferay.portal.service.GroupLocalServiceUtil;
45 import com.liferay.portal.service.ImageLocalServiceUtil;
46 import com.liferay.portal.service.LayoutLocalServiceUtil;
47 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
48 import com.liferay.portal.service.PortletLocalServiceUtil;
49 import com.liferay.portal.service.UserLocalServiceUtil;
50 import com.liferay.portal.service.persistence.LayoutUtil;
51 import com.liferay.portal.theme.ThemeLoader;
52 import com.liferay.portal.theme.ThemeLoaderFactory;
53 import com.liferay.portal.util.ContentUtil;
54 import com.liferay.portal.util.PortletKeys;
55 import com.liferay.portal.velocity.VelocityContextPool;
56 import com.liferay.util.MapUtil;
57 import com.liferay.util.xml.XMLFormatter;
58
59 import java.io.File;
60 import java.io.IOException;
61
62 import java.util.Date;
63 import java.util.HashSet;
64 import java.util.LinkedHashMap;
65 import java.util.List;
66 import java.util.Map;
67
68 import javax.servlet.ServletContext;
69
70 import org.apache.commons.lang.time.StopWatch;
71 import org.apache.commons.logging.Log;
72 import org.apache.commons.logging.LogFactory;
73
74 import org.dom4j.Document;
75 import org.dom4j.DocumentHelper;
76 import org.dom4j.Element;
77
78
89 public class LayoutExporter {
90
91 public byte[] exportLayouts(
92 long groupId, boolean privateLayout, long[] layoutIds,
93 Map<String, String[]> parameterMap, Date startDate, Date endDate)
94 throws PortalException, SystemException {
95
96 boolean exportPermissions = MapUtil.getBoolean(
97 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
98 boolean exportUserPermissions = MapUtil.getBoolean(
99 parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
100 boolean exportPortletData = MapUtil.getBoolean(
101 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
102 boolean exportPortletSetup = MapUtil.getBoolean(
103 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
104 boolean exportPortletArchivedSetups = MapUtil.getBoolean(
105 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
106 boolean exportPortletUserPreferences = MapUtil.getBoolean(
107 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
108 boolean exportTheme = MapUtil.getBoolean(
109 parameterMap, PortletDataHandlerKeys.THEME);
110
111 if (_log.isDebugEnabled()) {
112 _log.debug("Export permissions " + exportPermissions);
113 _log.debug("Export user permissions " + exportUserPermissions);
114 _log.debug("Export portlet data " + exportPortletData);
115 _log.debug("Export portlet setup " + exportPortletSetup);
116 _log.debug(
117 "Export portlet archived setups " +
118 exportPortletArchivedSetups);
119 _log.debug(
120 "Export portlet user preferences " +
121 exportPortletUserPreferences);
122 _log.debug("Export theme " + exportTheme);
123 }
124
125 StopWatch stopWatch = null;
126
127 if (_log.isInfoEnabled()) {
128 stopWatch = new StopWatch();
129
130 stopWatch.start();
131 }
132
133 LayoutCache layoutCache = new LayoutCache();
134
135 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
136 groupId, privateLayout);
137
138 long companyId = layoutSet.getCompanyId();
139 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
140
141 ZipWriter zipWriter = new ZipWriter();
142
143 PortletDataContext context = new PortletDataContextImpl(
144 companyId, groupId, parameterMap, new HashSet(), startDate, endDate,
145 zipWriter);
146
147 Group guestGroup = GroupLocalServiceUtil.getGroup(
148 companyId, GroupImpl.GUEST);
149
150
152 Document doc = DocumentHelper.createDocument();
153
154 Element root = doc.addElement("root");
155
156 Element header = root.addElement("header");
157
158 header.addAttribute(
159 "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
160 header.addAttribute("export-date", Time.getRFC822());
161
162 if (context.hasDateRange()) {
163 header.addAttribute(
164 "start-date", String.valueOf(context.getStartDate()));
165 header.addAttribute(
166 "end-date", String.valueOf(context.getEndDate()));
167 }
168
169 header.addAttribute("type", "layout-set");
170 header.addAttribute("group-id", String.valueOf(groupId));
171 header.addAttribute("private-layout", String.valueOf(privateLayout));
172 header.addAttribute("theme-id", layoutSet.getThemeId());
173 header.addAttribute("color-scheme-id", layoutSet.getColorSchemeId());
174
175
177 Portlet layoutConfigurationPortlet =
178 PortletLocalServiceUtil.getPortletById(
179 context.getCompanyId(), PortletKeys.LAYOUT_CONFIGURATION);
180
181
183 Map<String, Long> portletIds = new LinkedHashMap<String, Long>();
184
185 List<Layout> layouts = null;
186
187 if ((layoutIds == null) || (layoutIds.length == 0)) {
188 layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
189 }
190 else {
191 layouts = LayoutLocalServiceUtil.getLayouts(
192 groupId, privateLayout, layoutIds);
193 }
194
195 Element layoutsEl = root.addElement("layouts");
196
197 for (Layout layout : layouts) {
198 context.setPlid(layout.getPlid());
199
200 Document layoutDoc = DocumentHelper.createDocument();
201
202 Element layoutEl = layoutDoc.addElement("layout");
203
204 layoutEl.addAttribute("old-plid", String.valueOf(layout.getPlid()));
205 layoutEl.addAttribute(
206 "layout-id", String.valueOf(layout.getLayoutId()));
207 layoutEl.addElement("parent-layout-id").addText(
208 String.valueOf(layout.getParentLayoutId()));
209 layoutEl.addElement("name").addCDATA(layout.getName());
210 layoutEl.addElement("title").addCDATA(layout.getTitle());
211 layoutEl.addElement("description").addText(layout.getDescription());
212 layoutEl.addElement("type").addText(layout.getType());
213 layoutEl.addElement("type-settings").addCDATA(
214 layout.getTypeSettings());
215 layoutEl.addElement("hidden").addText(
216 String.valueOf(layout.getHidden()));
217 layoutEl.addElement("friendly-url").addText(
218 layout.getFriendlyURL());
219 layoutEl.addElement("icon-image").addText(
220 String.valueOf(layout.getIconImage()));
221
222 if (layout.isIconImage()) {
223 Image image = ImageLocalServiceUtil.getImage(
224 layout.getIconImageId());
225
226 if (image != null) {
227 String iconPath = getLayoutIconPath(context, layout, image);
228
229 layoutEl.addElement("icon-image-path").addText(
230 iconPath);
231
232 context.addZipEntry(iconPath, image.getTextObj());
233 }
234 }
235
236 layoutEl.addElement("theme-id").addText(layout.getThemeId());
237 layoutEl.addElement("color-scheme-id").addText(
238 layout.getColorSchemeId());
239 layoutEl.addElement("wap-theme-id").addText(layout.getWapThemeId());
240 layoutEl.addElement("wap-color-scheme-id").addText(
241 layout.getWapColorSchemeId());
242 layoutEl.addElement("css").addCDATA(layout.getCss());
243 layoutEl.addElement("priority").addText(
244 String.valueOf(layout.getPriority()));
245
246 Element permissionsEl = layoutEl.addElement("permissions");
247
248
250 if (exportPermissions) {
251 exportLayoutPermissions(
252 layoutCache, companyId, groupId, guestGroup, layout,
253 permissionsEl, exportUserPermissions);
254 }
255
256 if (layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
257 LayoutTypePortlet layoutTypePortlet =
258 (LayoutTypePortlet)layout.getLayoutType();
259
260 for (String portletId : layoutTypePortlet.getPortletIds()) {
261 if (!portletIds.containsKey(portletId)) {
262 portletIds.put(portletId, new Long(layout.getPlid()));
263 }
264 }
265 }
266
267 String layoutPath = context.getLayoutPath(layout.getLayoutId()) +
268 "/layout.xml";
269
270 Element el = layoutsEl.addElement("layout");
271 el.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
272 el.addAttribute("path", layoutPath);
273
274 _portletExporter.exportPortletData(
275 context, layoutConfigurationPortlet, null, layoutEl);
276
277 try {
278 context.addZipEntry(
279 layoutPath, XMLFormatter.toString(layoutDoc));
280 }
281 catch (IOException ioe) {
282 }
283 }
284
285 Element rolesEl = root.addElement("roles");
286
287
289 if (exportPermissions) {
290 exportLayoutRoles(layoutCache, companyId, groupId, rolesEl);
291 }
292
293
295 Element portletsEl = root.addElement("portlets");
296
297 for (Map.Entry<String, Long> portletIdsEntry : portletIds.entrySet()) {
298 Layout layout = LayoutUtil.findByPrimaryKey(
299 portletIdsEntry.getValue());
300
301 context.setPlid(layout.getPlid());
302
303 _portletExporter.exportPortlet(
304 context, layoutCache, portletIdsEntry.getKey(), layout,
305 portletsEl, defaultUserId, exportPortletData,
306 exportPortletSetup, exportPortletArchivedSetups,
307 exportPortletUserPreferences, exportPermissions,
308 exportUserPermissions);
309 }
310
311
313 _portletExporter.exportComments(context, root);
314
315
317 _portletExporter.exportRatings(context, root);
318
319
321 _portletExporter.exportTags(context, root);
322
323
325 byte[] themeZip = null;
326
327 try {
328 if (exportTheme) {
329 themeZip = exportTheme(layoutSet);
330
331 }
332 }
333 catch (IOException ioe) {
334 throw new SystemException(ioe);
335 }
336
337
339 if (_log.isInfoEnabled()) {
340 _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
341 }
342
343
345 try {
346 context.addZipEntry(
347 "/manifest.xml", XMLFormatter.toString(doc));
348
349 if (themeZip != null) {
350 context.addZipEntry("/theme.zip", themeZip);
351 }
352
353 return zipWriter.finish();
354 }
355 catch (IOException ioe) {
356 throw new SystemException(ioe);
357 }
358 }
359
360 protected void exportLayoutPermissions(
361 LayoutCache layoutCache, long companyId, long groupId,
362 Group guestGroup, Layout layout, Element permissionsEl,
363 boolean exportUserPermissions)
364 throws PortalException, SystemException {
365
366 String resourceName = Layout.class.getName();
367 String resourcePrimKey = String.valueOf(layout.getPlid());
368
369 _portletExporter.exportGroupPermissions(
370 companyId, groupId, resourceName, resourcePrimKey, permissionsEl,
371 "community-actions");
372
373 if (groupId != guestGroup.getGroupId()) {
374 _portletExporter.exportGroupPermissions(
375 companyId, guestGroup.getGroupId(), resourceName,
376 resourcePrimKey, permissionsEl, "guest-actions");
377 }
378
379 if (exportUserPermissions) {
380 _portletExporter.exportUserPermissions(
381 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
382 permissionsEl);
383 }
384
385 _portletExporter.exportInheritedPermissions(
386 layoutCache, companyId, resourceName, resourcePrimKey,
387 permissionsEl, "organization");
388
389 _portletExporter.exportInheritedPermissions(
390 layoutCache, companyId, resourceName, resourcePrimKey,
391 permissionsEl, "location");
392
393 _portletExporter.exportInheritedPermissions(
394 layoutCache, companyId, resourceName, resourcePrimKey,
395 permissionsEl, "user-group");
396 }
397
398 protected void exportLayoutRoles(
399 LayoutCache layoutCache, long companyId, long groupId,
400 Element rolesEl)
401 throws PortalException, SystemException {
402
403 String resourceName = Layout.class.getName();
404
405 _portletExporter.exportGroupRoles(
406 layoutCache, companyId, groupId, resourceName, "community",
407 rolesEl);
408
409 _portletExporter.exportUserRoles(
410 layoutCache, companyId, groupId, resourceName, rolesEl);
411
412 _portletExporter.exportInheritedRoles(
413 layoutCache, companyId, groupId, resourceName, "organization",
414 rolesEl);
415
416 _portletExporter.exportInheritedRoles(
417 layoutCache, companyId, groupId, resourceName, "location", rolesEl);
418
419 _portletExporter.exportInheritedRoles(
420 layoutCache, companyId, groupId, resourceName, "user-group",
421 rolesEl);
422 }
423
424 protected byte[] exportTheme(LayoutSet layoutSet) throws IOException {
425 Theme theme = layoutSet.getTheme();
426
427 ZipWriter zipWriter = new ZipWriter();
428
429 String lookAndFeelXML = ContentUtil.get(
430 "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
431
432 lookAndFeelXML = StringUtil.replace(
433 lookAndFeelXML,
434 new String[] {
435 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
436 },
437 new String[] {
438 theme.getTemplateExtension(), theme.getVirtualPath()
439 }
440 );
441
442 zipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
443
444 String servletContextName = theme.getServletContextName();
445
446 ServletContext servletContext = VelocityContextPool.get(
447 servletContextName);
448
449 if (servletContext == null) {
450 if (_log.isWarnEnabled()) {
451 _log.warn(
452 "Servlet context not found for theme " +
453 theme.getThemeId());
454 }
455
456 return null;
457 }
458
459 File cssPath = null;
460 File imagesPath = null;
461 File javaScriptPath = null;
462 File templatesPath = null;
463
464 if (!theme.isLoadFromServletContext()) {
465 ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
466 servletContextName);
467
468 if (themeLoader == null) {
469 _log.error(
470 servletContextName + " does not map to a theme loader");
471 }
472 else {
473 String realPath =
474 themeLoader.getFileStorage().getPath() + "/" +
475 theme.getName();
476
477 cssPath = new File(realPath + "/css");
478 imagesPath = new File(realPath + "/images");
479 javaScriptPath = new File(realPath + "/javascript");
480 templatesPath = new File(realPath + "/templates");
481 }
482 }
483 else {
484 cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
485 imagesPath = new File(
486 servletContext.getRealPath(theme.getImagesPath()));
487 javaScriptPath = new File(
488 servletContext.getRealPath(theme.getJavaScriptPath()));
489 templatesPath = new File(
490 servletContext.getRealPath(theme.getTemplatesPath()));
491 }
492
493 exportThemeFiles("css", cssPath, zipWriter);
494 exportThemeFiles("images", imagesPath, zipWriter);
495 exportThemeFiles("javascript", javaScriptPath, zipWriter);
496 exportThemeFiles("templates", templatesPath, zipWriter);
497
498 return zipWriter.finish();
499 }
500
501 protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
502 throws IOException {
503
504 if ((dir == null) || (!dir.exists())) {
505 return;
506 }
507
508 File[] files = dir.listFiles();
509
510 for (int i = 0; i < files.length; i++) {
511 File file = files[i];
512
513 if (file.isDirectory()) {
514 exportThemeFiles(path + "/" + file.getName(), file, zipWriter);
515 }
516 else {
517 zipWriter.addEntry(
518 path + "/" + file.getName(), FileUtil.getBytes(file));
519 }
520 }
521 }
522
523 protected String getLayoutIconPath(
524 PortletDataContext context, Layout layout, Image image) {
525
526 StringBuilder sb = new StringBuilder();
527
528 sb.append(context.getLayoutPath(layout.getLayoutId()));
529 sb.append("/icons/");
530 sb.append(image.getImageId());
531 sb.append(StringPool.PERIOD);
532 sb.append(image.getType());
533
534 return sb.toString();
535 }
536
537 private static Log _log = LogFactory.getLog(LayoutExporter.class);
538
539 private PortletExporter _portletExporter = new PortletExporter();
540
541 }