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