1
14
15 package com.liferay.portal.lar;
16
17 import com.liferay.counter.service.CounterLocalServiceUtil;
18 import com.liferay.portal.LARFileException;
19 import com.liferay.portal.LARTypeException;
20 import com.liferay.portal.LayoutImportException;
21 import com.liferay.portal.NoSuchLayoutException;
22 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
23 import com.liferay.portal.kernel.cluster.ClusterRequest;
24 import com.liferay.portal.kernel.log.Log;
25 import com.liferay.portal.kernel.log.LogFactoryUtil;
26 import com.liferay.portal.kernel.util.ArrayUtil;
27 import com.liferay.portal.kernel.util.CharPool;
28 import com.liferay.portal.kernel.util.FileUtil;
29 import com.liferay.portal.kernel.util.GetterUtil;
30 import com.liferay.portal.kernel.util.LocaleUtil;
31 import com.liferay.portal.kernel.util.MapUtil;
32 import com.liferay.portal.kernel.util.MethodHandler;
33 import com.liferay.portal.kernel.util.MethodKey;
34 import com.liferay.portal.kernel.util.ReleaseInfo;
35 import com.liferay.portal.kernel.util.StringPool;
36 import com.liferay.portal.kernel.util.StringUtil;
37 import com.liferay.portal.kernel.util.Time;
38 import com.liferay.portal.kernel.util.UnicodeProperties;
39 import com.liferay.portal.kernel.util.Validator;
40 import com.liferay.portal.kernel.xml.Document;
41 import com.liferay.portal.kernel.xml.Element;
42 import com.liferay.portal.kernel.xml.Node;
43 import com.liferay.portal.kernel.xml.SAXReaderUtil;
44 import com.liferay.portal.kernel.zip.ZipReader;
45 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
46 import com.liferay.portal.model.Layout;
47 import com.liferay.portal.model.LayoutConstants;
48 import com.liferay.portal.model.LayoutSet;
49 import com.liferay.portal.model.LayoutTemplate;
50 import com.liferay.portal.model.LayoutTypePortlet;
51 import com.liferay.portal.model.LayoutTypePortletConstants;
52 import com.liferay.portal.model.Portlet;
53 import com.liferay.portal.model.PortletConstants;
54 import com.liferay.portal.model.User;
55 import com.liferay.portal.model.impl.ColorSchemeImpl;
56 import com.liferay.portal.service.ImageLocalServiceUtil;
57 import com.liferay.portal.service.LayoutLocalServiceUtil;
58 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
59 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
60 import com.liferay.portal.service.PortletLocalServiceUtil;
61 import com.liferay.portal.service.ServiceContext;
62 import com.liferay.portal.service.persistence.LayoutUtil;
63 import com.liferay.portal.service.persistence.UserUtil;
64 import com.liferay.portal.theme.ThemeLoader;
65 import com.liferay.portal.theme.ThemeLoaderFactory;
66 import com.liferay.portal.util.PortalUtil;
67 import com.liferay.portal.util.PortletKeys;
68 import com.liferay.portal.util.PropsValues;
69 import com.liferay.portlet.journal.model.JournalArticle;
70 import com.liferay.portlet.tags.DuplicateEntryException;
71 import com.liferay.portlet.tags.DuplicateVocabularyException;
72 import com.liferay.portlet.tags.model.TagsEntryConstants;
73 import com.liferay.portlet.tags.service.TagsEntryLocalServiceUtil;
74 import com.liferay.portlet.tags.service.TagsVocabularyLocalServiceUtil;
75
76 import java.io.File;
77 import java.io.IOException;
78 import java.io.InputStream;
79
80 import java.util.ArrayList;
81 import java.util.Date;
82 import java.util.HashSet;
83 import java.util.List;
84 import java.util.Locale;
85 import java.util.Map;
86 import java.util.Set;
87
88 import org.apache.commons.lang.time.StopWatch;
89
90
104 public class LayoutImporter {
105
106 public void importLayouts(
107 long userId, long groupId, boolean privateLayout,
108 Map<String, String[]> parameterMap, File file)
109 throws Exception {
110
111 boolean deleteMissingLayouts = MapUtil.getBoolean(
112 parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
113 Boolean.TRUE.booleanValue());
114 boolean deletePortletData = MapUtil.getBoolean(
115 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
116 boolean importCategories = MapUtil.getBoolean(
117 parameterMap, PortletDataHandlerKeys.CATEGORIES);
118 boolean importPermissions = MapUtil.getBoolean(
119 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
120 boolean importUserPermissions = MapUtil.getBoolean(
121 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
122 boolean importPortletData = MapUtil.getBoolean(
123 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
124 boolean importPortletSetup = MapUtil.getBoolean(
125 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
126 boolean importPortletArchivedSetups = MapUtil.getBoolean(
127 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
128 boolean importPortletUserPreferences = MapUtil.getBoolean(
129 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
130 boolean importTheme = MapUtil.getBoolean(
131 parameterMap, PortletDataHandlerKeys.THEME);
132 String layoutsImportMode = MapUtil.getString(
133 parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
134 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_FRIENDLY_URL);
135 String portletsMergeMode = MapUtil.getString(
136 parameterMap, PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
137 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
138 String userIdStrategy = MapUtil.getString(
139 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
140
141 if (_log.isDebugEnabled()) {
142 _log.debug("Delete portlet data " + deletePortletData);
143 _log.debug("Import categories " + importCategories);
144 _log.debug("Import permissions " + importPermissions);
145 _log.debug("Import user permissions " + importUserPermissions);
146 _log.debug("Import portlet data " + importPortletData);
147 _log.debug("Import portlet setup " + importPortletSetup);
148 _log.debug(
149 "Import portlet archived setups " +
150 importPortletArchivedSetups);
151 _log.debug(
152 "Import portlet user preferences " +
153 importPortletUserPreferences);
154 _log.debug("Import theme " + importTheme);
155 }
156
157 StopWatch stopWatch = null;
158
159 if (_log.isInfoEnabled()) {
160 stopWatch = new StopWatch();
161
162 stopWatch.start();
163 }
164
165 LayoutCache layoutCache = new LayoutCache();
166
167 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
168 groupId, privateLayout);
169
170 long companyId = layoutSet.getCompanyId();
171
172 User user = UserUtil.findByPrimaryKey(userId);
173
174 UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
175 user, userIdStrategy);
176
177 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
178
179 PortletDataContext context = new PortletDataContextImpl(
180 companyId, groupId, parameterMap, new HashSet<String>(), strategy,
181 zipReader);
182
183 context.setPrivateLayout(privateLayout);
184
185
187 Element rootElement = null;
188 InputStream themeZip = null;
189
190
192 String xml = context.getZipEntryAsString("/manifest.xml");
193
194 if (xml == null) {
195 throw new LARFileException("manifest.xml not found in the LAR");
196 }
197
198 try {
199 Document document = SAXReaderUtil.read(xml);
200
201 rootElement = document.getRootElement();
202 }
203 catch (Exception e) {
204 throw new LARFileException(e);
205 }
206
207
209 Element headerElement = rootElement.element("header");
210
211 int buildNumber = ReleaseInfo.getBuildNumber();
212
213 int importBuildNumber = GetterUtil.getInteger(
214 headerElement.attributeValue("build-number"));
215
216 if (buildNumber != importBuildNumber) {
217 throw new LayoutImportException(
218 "LAR build number " + importBuildNumber + " does not match " +
219 "portal build number " + buildNumber);
220 }
221
222
224 String larType = headerElement.attributeValue("type");
225
226 if (!larType.equals("layout-set")) {
227 throw new LARTypeException(
228 "Invalid type of LAR file (" + larType + ")");
229 }
230
231
233 long sourceGroupId = GetterUtil.getLong(
234 headerElement.attributeValue("group-id"));
235
236 context.setSourceGroupId(sourceGroupId);
237
238
240 if (importTheme) {
241 themeZip = context.getZipEntryAsInputStream("theme.zip");
242 }
243
244
246 String themeId = headerElement.attributeValue("theme-id");
247 String colorSchemeId = headerElement.attributeValue("color-scheme-id");
248 String css = GetterUtil.getString(headerElement.elementText("css"));
249
250 boolean useThemeZip = false;
251
252 if (themeZip != null) {
253 String importThemeId = importTheme(layoutSet, themeZip);
254
255 if (importThemeId != null) {
256 themeId = importThemeId;
257 colorSchemeId =
258 ColorSchemeImpl.getDefaultRegularColorSchemeId();
259
260 useThemeZip = true;
261 }
262
263 if (_log.isDebugEnabled()) {
264 _log.debug(
265 "Importing theme takes " + stopWatch.getTime() + " ms");
266 }
267 }
268
269 boolean wapTheme = false;
270
271 LayoutSetLocalServiceUtil.updateLookAndFeel(
272 groupId, privateLayout, themeId, colorSchemeId, css, wapTheme);
273
274
277 if (importCategories) {
278 importCategories(context);
279 }
280
281 _portletImporter.readCategories(context, rootElement);
282 _portletImporter.readComments(context, rootElement);
283 _portletImporter.readLocks(context, rootElement);
284
285 if (importPermissions) {
286 _permissionImporter.readPortletDataPermissions(context);
287 }
288
289 _portletImporter.readRatings(context, rootElement);
290 _portletImporter.readTags(context, rootElement);
291
292
294 List<Layout> previousLayouts = LayoutUtil.findByG_P(
295 groupId, privateLayout);
296
297 List<Layout> newLayouts = new ArrayList<Layout>();
298
299 Set<Long> newLayoutIds = new HashSet<Long>();
300
301 Map<Long, Layout> newLayoutsMap =
302 (Map<Long, Layout>)context.getNewPrimaryKeysMap(Layout.class);
303
304 Element layoutsElement = rootElement.element("layouts");
305
306 List<Element> layoutElements = layoutsElement.elements("layout");
307
308 if (_log.isDebugEnabled()) {
309 if (layoutElements.size() > 0) {
310 _log.debug("Importing layouts");
311 }
312 }
313
314 for (Element layoutElement : layoutElements) {
315 importLayout(
316 context, user, layoutCache, previousLayouts, newLayouts,
317 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
318 colorSchemeId, layoutsImportMode, privateLayout,
319 importPermissions, importUserPermissions, useThemeZip,
320 rootElement, layoutElement);
321 }
322
323 Element portletsElement = rootElement.element("portlets");
324
325 List<Element> portletElements = portletsElement.elements("portlet");
326
327
329 if (deletePortletData) {
330 if (_log.isDebugEnabled()) {
331 if (portletElements.size() > 0) {
332 _log.debug("Deleting portlet data");
333 }
334 }
335
336 for (Element portletElement : portletElements) {
337 String portletId = portletElement.attributeValue("portlet-id");
338 long layoutId = GetterUtil.getLong(
339 portletElement.attributeValue("layout-id"));
340 long plid = newLayoutsMap.get(layoutId).getPlid();
341
342 context.setPlid(plid);
343
344 _portletImporter.deletePortletData(context, portletId, plid);
345 }
346 }
347
348
350 if (_log.isDebugEnabled()) {
351 if (portletElements.size() > 0) {
352 _log.debug("Importing portlets");
353 }
354 }
355
356 for (Element portletElement : portletElements) {
357 String portletPath = portletElement.attributeValue("path");
358 String portletId = portletElement.attributeValue("portlet-id");
359 long layoutId = GetterUtil.getLong(
360 portletElement.attributeValue("layout-id"));
361 long plid = newLayoutsMap.get(layoutId).getPlid();
362 long oldPlid = GetterUtil.getLong(
363 portletElement.attributeValue("old-plid"));
364
365 Portlet portlet = PortletLocalServiceUtil.getPortletById(
366 context.getCompanyId(), portletId);
367
368 if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
369 continue;
370 }
371
372 Layout layout = null;
373
374 try {
375 layout = LayoutUtil.findByPrimaryKey(plid);
376 }
377 catch (NoSuchLayoutException nsle) {
378 continue;
379 }
380
381 context.setPlid(plid);
382 context.setOldPlid(oldPlid);
383
384 Document portletDocument = SAXReaderUtil.read(
385 context.getZipEntryAsString(portletPath));
386
387 portletElement = portletDocument.getRootElement();
388
389
394
396 _portletImporter.importPortletPreferences(
397 context, layoutSet.getCompanyId(), layout.getGroupId(),
398 layout, null, portletElement, importPortletSetup,
399 importPortletArchivedSetups, importPortletUserPreferences,
400 false);
401
402
404 long scopeLayoutId = GetterUtil.getLong(
405 portletElement.attributeValue("scope-layout-id"));
406
407 context.setScopeLayoutId(scopeLayoutId);
408
409
411 Element portletDataElement = portletElement.element("portlet-data");
412
413 if (importPortletData && portletDataElement != null) {
414 _portletImporter.importPortletData(
415 context, portletId, plid, portletDataElement);
416 }
417
418
420 if (importPermissions) {
421 _permissionImporter.importPortletPermissions(
422 layoutCache, companyId, groupId, userId, layout,
423 portletElement, portletId, importUserPermissions);
424 }
425
426
428 _portletImporter.importPortletPreferences(
429 context, layoutSet.getCompanyId(), groupId, null, null,
430 portletElement, importPortletSetup, importPortletArchivedSetups,
431 importPortletUserPreferences, false);
432 }
433
434
436 if (deleteMissingLayouts) {
437 deleteMissingLayouts(
438 groupId, privateLayout, newLayoutIds, previousLayouts);
439 }
440
441
443 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
444
445 if (_log.isInfoEnabled()) {
446 _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
447 }
448
449
451 for (Layout layout : newLayouts) {
452 UnicodeProperties typeSettingsProperties =
453 layout.getTypeSettingsProperties();
454
455 String articleId = typeSettingsProperties.getProperty("article-id");
456
457 if (Validator.isNotNull(articleId)) {
458 Map<String, String> articleIds =
459 (Map<String, String>)context.getNewPrimaryKeysMap(
460 JournalArticle.class);
461
462 typeSettingsProperties.setProperty(
463 "article-id",
464 MapUtil.getString(articleIds, articleId, articleId));
465
466 LayoutUtil.update(layout, false);
467 }
468 }
469
470 zipReader.close();
471 }
472
473 protected String[] appendPortletIds(
474 String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
475
476 for (String portletId : newPortletIds) {
477 if (ArrayUtil.contains(portletIds, portletId)) {
478 continue;
479 }
480
481 if (portletsMergeMode.equals(
482 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
483
484 portletIds = ArrayUtil.append(portletIds, portletId);
485 }
486 else {
487 portletIds = ArrayUtil.append(
488 new String[] {portletId}, portletIds);
489 }
490 }
491
492 return portletIds;
493 }
494
495 protected void deleteMissingLayouts(
496 long groupId, boolean privateLayout, Set<Long> newLayoutIds,
497 List<Layout> previousLayouts)
498 throws Exception {
499
500
502 if (_log.isDebugEnabled()) {
503 if (newLayoutIds.size() > 0) {
504 _log.debug("Delete missing layouts");
505 }
506 }
507
508 for (Layout layout : previousLayouts) {
509 if (!newLayoutIds.contains(layout.getLayoutId())) {
510 try {
511 LayoutLocalServiceUtil.deleteLayout(layout, false);
512 }
513 catch (NoSuchLayoutException nsle) {
514 }
515 }
516 }
517
518
520 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
521 }
522
523 protected void fixTypeSettings(Layout layout) {
524 if (!layout.isTypeURL()) {
525 return;
526 }
527
528 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
529
530 String url = GetterUtil.getString(typeSettings.getProperty("url"));
531
532 String friendlyURLPrivateGroupPath =
533 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
534 String friendlyURLPrivateUserPath =
535 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
536 String friendlyURLPublicPath =
537 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
538
539 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
540 !url.startsWith(friendlyURLPrivateUserPath) &&
541 !url.startsWith(friendlyURLPublicPath)) {
542
543 return;
544 }
545
546 int x = url.indexOf(CharPool.SLASH, 1);
547
548 if (x == -1) {
549 return;
550 }
551
552 int y = url.indexOf(CharPool.SLASH, x + 1);
553
554 if (y == -1) {
555 return;
556 }
557
558 String friendlyURL = url.substring(x, y);
559
560 if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
561 return;
562 }
563
564 typeSettings.setProperty(
565 "url",
566 url.substring(0, x) + layout.getGroup().getFriendlyURL() +
567 url.substring(y));
568 }
569
570 protected void importCategories(PortletDataContext context)
571 throws Exception {
572
573 String xml = context.getZipEntryAsString(
574 context.getSourceRootPath() + "/categories-hierarchy.xml");
575
576 if (Validator.isNull(xml)) {
577 return;
578 }
579
580 Document doc = SAXReaderUtil.read(xml);
581
582 Element root = doc.getRootElement();
583
584 List<Element> vocabularies = root.elements("vocabulary");
585
586 for (Element vocabularyEl : vocabularies) {
587 String vocabularyName = GetterUtil.getString(
588 vocabularyEl.attributeValue("name"));
589 String userUuid = GetterUtil.getString(
590 vocabularyEl.attributeValue("userUuid"));
591
592 ServiceContext serviceContext = new ServiceContext();
593
594 serviceContext.setAddCommunityPermissions(true);
595 serviceContext.setAddGuestPermissions(true);
596 serviceContext.setScopeGroupId(context.getGroupId());
597
598 try {
599 TagsVocabularyLocalServiceUtil.addVocabulary(
600 context.getUserId(userUuid), vocabularyName,
601 TagsEntryConstants.FOLKSONOMY_CATEGORY, serviceContext);
602 }
603 catch (DuplicateVocabularyException dve) {
604 }
605
606 List<Element> categories = vocabularyEl.elements("category");
607
608 for (Element category : categories) {
609 String categoryName = GetterUtil.getString(
610 category.attributeValue("name"));
611 String parentEntryName = GetterUtil.getString(
612 category.attributeValue("parentEntryName"));
613 String[] properties = null;
614
615 try {
616 TagsEntryLocalServiceUtil.addEntry(
617 context.getUserId(userUuid), parentEntryName,
618 categoryName, vocabularyName, properties,
619 serviceContext);
620 }
621 catch (DuplicateEntryException dee) {
622 }
623 }
624 }
625 }
626
627 protected void importLayout(
628 PortletDataContext context, User user, LayoutCache layoutCache,
629 List<Layout> previousLayouts, List<Layout> newLayouts,
630 Map<Long, Layout> newLayoutsMap, Set<Long> newLayoutIds,
631 String portletsMergeMode, String themeId, String colorSchemeId,
632 String layoutsImportMode, boolean privateLayout,
633 boolean importPermissions, boolean importUserPermissions,
634 boolean useThemeZip, Element rootElement, Element layoutElement)
635 throws Exception {
636
637 long groupId = context.getGroupId();
638 long sourceGroupId = context.getSourceGroupId();
639
640 long layoutId = GetterUtil.getInteger(
641 layoutElement.attributeValue("layout-id"));
642
643 long oldLayoutId = layoutId;
644
645 boolean deleteLayout = GetterUtil.getBoolean(
646 layoutElement.attributeValue("delete"));
647
648 if (deleteLayout) {
649 try {
650 String layoutFriendlyURL = GetterUtil.getString(
651 layoutElement.attributeValue("layout-friendly-url"));
652
653 Layout layout = null;
654
655 if (Validator.isNotNull(layoutFriendlyURL)) {
656 layout = LayoutLocalServiceUtil.getFriendlyURLLayout(
657 groupId, privateLayout, layoutFriendlyURL);
658 }
659
660 if (layout != null) {
661 newLayoutsMap.put(oldLayoutId, layout);
662
663 LayoutLocalServiceUtil.deleteLayout(layout);
664 }
665 }
666 catch (NoSuchLayoutException nsle) {
667 _log.warn(
668 "Error deleting layout for {" + sourceGroupId + ", " +
669 privateLayout + ", " + oldLayoutId + "}");
670 }
671
672 return;
673 }
674
675 String path = layoutElement.attributeValue("path");
676
677 if (!context.isPathNotProcessed(path)) {
678 return;
679 }
680
681 Layout layout = (Layout)context.getZipEntryAsObject(path);
682
683 Layout existingLayout = null;
684 Layout importedLayout = null;
685
686 String friendlyURL = layout.getFriendlyURL();
687
688 if (layoutsImportMode.equals(
689 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
690
691 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
692 groupId, privateLayout);
693 friendlyURL = StringPool.SLASH + layoutId;
694 }
695 else if (layoutsImportMode.equals(
696 PortletDataHandlerKeys.
697 LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
698
699 Locale locale = LocaleUtil.getDefault();
700
701 String localizedName = layout.getName(locale);
702
703 for (Layout curLayout : previousLayouts) {
704 if (curLayout.getName(locale).equals(localizedName)) {
705 existingLayout = curLayout;
706
707 break;
708 }
709 }
710
711 if (existingLayout == null) {
712 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
713 groupId, privateLayout);
714 }
715 }
716 else if (layoutsImportMode.equals(
717 PortletDataHandlerKeys.
718 LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_ID)) {
719
720 existingLayout = LayoutUtil.fetchByG_P_L(
721 groupId, privateLayout, oldLayoutId);
722
723 layoutId = layout.getLayoutId();
724 }
725 else {
726 existingLayout = LayoutUtil.fetchByG_P_F(
727 groupId, privateLayout, friendlyURL);
728
729 if (existingLayout == null) {
730 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
731 groupId, privateLayout);
732 }
733 }
734
735 if (_log.isDebugEnabled()) {
736 if (layout == null) {
737 _log.debug(
738 "Layout with {groupId=" + groupId + ",privateLayout=" +
739 privateLayout + ",layoutId=" + layoutId +
740 "} does not exist");
741 }
742 else {
743 _log.debug(
744 "Layout with {groupId=" + groupId + ",privateLayout=" +
745 privateLayout + ",layoutId=" + layoutId +
746 "} exists");
747 }
748 }
749
750 if (existingLayout == null) {
751 long plid = CounterLocalServiceUtil.increment();
752
753 importedLayout = LayoutUtil.create(plid);
754
755 importedLayout.setGroupId(groupId);
756 importedLayout.setPrivateLayout(privateLayout);
757 importedLayout.setLayoutId(layoutId);
758
759 if (layout.isIconImage()) {
760 long iconImageId = CounterLocalServiceUtil.increment();
761
762 importedLayout.setIconImageId(iconImageId);
763 }
764 }
765 else {
766 importedLayout = existingLayout;
767 }
768
769 newLayoutsMap.put(oldLayoutId, importedLayout);
770
771 long parentLayoutId = layout.getParentLayoutId();
772
773 Node parentLayoutNode = rootElement.selectSingleNode(
774 "./layouts/layout[@layout-id='" + parentLayoutId + "']");
775
776 String parentLayoutFriendlyURL = GetterUtil.getString(
777 layoutElement.attributeValue("parent-layout-friendly-url"));
778
779 if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
780 (parentLayoutNode != null)) {
781
782 importLayout(
783 context, user, layoutCache, previousLayouts, newLayouts,
784 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
785 colorSchemeId, layoutsImportMode, privateLayout,
786 importPermissions, importUserPermissions, useThemeZip,
787 rootElement, (Element)parentLayoutNode);
788
789 Layout parentLayout = newLayoutsMap.get(parentLayoutId);
790
791 parentLayoutId = parentLayout.getLayoutId();
792 }
793 else if (Validator.isNotNull(parentLayoutFriendlyURL)) {
794 Layout parentLayout = LayoutLocalServiceUtil.getFriendlyURLLayout(
795 groupId, privateLayout, parentLayoutFriendlyURL);
796
797 parentLayoutId = parentLayout.getLayoutId();
798 }
799
800 if (_log.isDebugEnabled()) {
801 _log.debug(
802 "Importing layout with layout id " + layoutId +
803 " and parent layout id " + parentLayoutId);
804 }
805
806 importedLayout.setCompanyId(user.getCompanyId());
807 importedLayout.setParentLayoutId(parentLayoutId);
808 importedLayout.setName(layout.getName());
809 importedLayout.setTitle(layout.getTitle());
810 importedLayout.setDescription(layout.getDescription());
811 importedLayout.setType(layout.getType());
812
813 if (layout.isTypePortlet() &&
814 Validator.isNotNull(layout.getTypeSettings()) &&
815 !portletsMergeMode.equals(
816 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
817
818 mergePortlets(
819 importedLayout, layout.getTypeSettings(), portletsMergeMode);
820 }
821 else if (layout.isTypeLinkToLayout()) {
822 UnicodeProperties typeSettingsProperties =
823 layout.getTypeSettingsProperties();
824
825 long linkToLayoutId = GetterUtil.getLong(
826 typeSettingsProperties.getProperty(
827 "linkToLayoutId", StringPool.BLANK));
828
829 if (linkToLayoutId > 0) {
830 Node linkedLayoutNode = rootElement.selectSingleNode(
831 "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
832
833 importLayout(
834 context, user, layoutCache, previousLayouts, newLayouts,
835 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
836 colorSchemeId, layoutsImportMode, privateLayout,
837 importPermissions, importUserPermissions, useThemeZip,
838 rootElement, (Element)linkedLayoutNode);
839
840 Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
841
842 typeSettingsProperties.setProperty(
843 "linkToLayoutId",
844 String.valueOf(linkedLayout.getLayoutId()));
845 }
846
847 importedLayout.setTypeSettings(layout.getTypeSettings());
848 }
849 else {
850 importedLayout.setTypeSettings(layout.getTypeSettings());
851 }
852
853 importedLayout.setHidden(layout.isHidden());
854 importedLayout.setFriendlyURL(friendlyURL);
855
856 if (useThemeZip) {
857 importedLayout.setThemeId(StringPool.BLANK);
858 importedLayout.setColorSchemeId(StringPool.BLANK);
859 }
860 else {
861 importedLayout.setThemeId(layout.getThemeId());
862 importedLayout.setColorSchemeId(layout.getColorSchemeId());
863 }
864
865 importedLayout.setWapThemeId(layout.getWapThemeId());
866 importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
867 importedLayout.setCss(layout.getCss());
868 importedLayout.setPriority(layout.getPriority());
869
870 fixTypeSettings(importedLayout);
871
872 if (layout.isIconImage()) {
873 String iconImagePath = layoutElement.elementText("icon-image-path");
874
875 byte[] iconBytes = context.getZipEntryAsByteArray(iconImagePath);
876
877 if ((iconBytes != null) && (iconBytes.length > 0)) {
878 importedLayout.setIconImage(true);
879
880 ImageLocalServiceUtil.updateImage(
881 importedLayout.getIconImageId(), iconBytes);
882 }
883 }
884 else {
885 ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
886 }
887
888 LayoutUtil.update(importedLayout, false);
889
890 context.setPlid(importedLayout.getPlid());
891 context.setOldPlid(layout.getPlid());
892
893 newLayoutIds.add(importedLayout.getLayoutId());
894
895 newLayouts.add(importedLayout);
896
897
899 if (importPermissions) {
900 _permissionImporter.importLayoutPermissions(
901 layoutCache, context.getCompanyId(), groupId, user.getUserId(),
902 importedLayout, layoutElement, rootElement,
903 importUserPermissions);
904 }
905
906 _portletImporter.importPortletData(
907 context, PortletKeys.LAYOUT_CONFIGURATION, null, layoutElement);
908 }
909
910 protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
911 throws Exception {
912
913 ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
914
915 if (themeLoader == null) {
916 _log.error("No theme loaders are deployed");
917
918 return null;
919 }
920
921 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
922
923 String lookAndFeelXML = zipReader.getEntryAsString(
924 "liferay-look-and-feel.xml");
925
926 String themeId = String.valueOf(layoutSet.getGroupId());
927
928 if (layoutSet.isPrivateLayout()) {
929 themeId += "-private";
930 }
931 else {
932 themeId += "-public";
933 }
934
935 if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
936 Date now = new Date();
937
938 themeId += "-" + Time.getShortTimestamp(now);
939 }
940
941 String themeName = themeId;
942
943 lookAndFeelXML = StringUtil.replace(
944 lookAndFeelXML,
945 new String[] {
946 "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
947 },
948 new String[] {
949 String.valueOf(layoutSet.getGroupId()), themeId, themeName
950 }
951 );
952
953 FileUtil.deltree(
954 themeLoader.getFileStorage() + StringPool.SLASH + themeId);
955
956 List<String> zipEntries = zipReader.getEntries();
957
958 for (String zipEntry : zipEntries) {
959 String key = zipEntry;
960
961 if (key.contains(StringPool.SLASH)) {
962 key = key.substring(key.lastIndexOf(CharPool.SLASH));
963 }
964
965 if (key.equals("liferay-look-and-feel.xml")) {
966 FileUtil.write(
967 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
968 StringPool.SLASH + key,
969 lookAndFeelXML.getBytes());
970 }
971 else {
972 InputStream is = zipReader.getEntryAsInputStream(zipEntry);
973
974 FileUtil.write(
975 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
976 StringPool.SLASH + key,
977 is);
978 }
979 }
980
981 themeLoader.loadThemes();
982
983 ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
984 _loadThemesMethodHandler, true);
985
986 clusterRequest.setFireAndForget(true);
987
988 ClusterExecutorUtil.execute(clusterRequest);
989
990 themeId +=
991 PortletConstants.WAR_SEPARATOR +
992 themeLoader.getServletContextName();
993
994 return PortalUtil.getJsSafePortletId(themeId);
995 }
996
997 protected void mergePortlets(
998 Layout layout, String newTypeSettings, String portletsMergeMode) {
999
1000 try {
1001 UnicodeProperties previousTypeSettingsProperties =
1002 layout.getTypeSettingsProperties();
1003
1004 LayoutTypePortlet previousLayoutType =
1005 (LayoutTypePortlet)layout.getLayoutType();
1006
1007 LayoutTemplate previousLayoutTemplate =
1008 previousLayoutType.getLayoutTemplate();
1009
1010 List<String> previousColumns = previousLayoutTemplate.getColumns();
1011
1012 UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1013 true);
1014
1015 newTypeSettingsProperties.load(newTypeSettings);
1016
1017 String layoutTemplateId = newTypeSettingsProperties.getProperty(
1018 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1019
1020 previousTypeSettingsProperties.setProperty(
1021 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1022 layoutTemplateId);
1023
1024 LayoutTemplate newLayoutTemplate =
1025 LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1026 layoutTemplateId, false, null);
1027
1028 String[] newPortletIds = new String[0];
1029
1030 for (String columnId : newLayoutTemplate.getColumns()) {
1031 String columnValue = newTypeSettingsProperties.getProperty(
1032 columnId);
1033
1034 String[] portletIds = StringUtil.split(columnValue);
1035
1036 if (!previousColumns.contains(columnId)) {
1037 newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1038 }
1039 else {
1040 String[] previousPortletIds = StringUtil.split(
1041 previousTypeSettingsProperties.getProperty(columnId));
1042
1043 portletIds = appendPortletIds(
1044 previousPortletIds, portletIds, portletsMergeMode);
1045
1046 previousTypeSettingsProperties.setProperty(
1047 columnId, StringUtil.merge(portletIds));
1048 }
1049 }
1050
1051
1053 String columnId = previousColumns.get(0);
1054
1055 String[] portletIds = StringUtil.split(
1056 previousTypeSettingsProperties.getProperty(columnId));
1057
1058 appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1059
1060 previousTypeSettingsProperties.setProperty(
1061 columnId, StringUtil.merge(portletIds));
1062
1063 layout.setTypeSettings(previousTypeSettingsProperties.toString());
1064 }
1065 catch (IOException ioe) {
1066 layout.setTypeSettings(newTypeSettings);
1067 }
1068 }
1069
1070 private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1071
1072 private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1073 new MethodKey(ThemeLoaderFactory.class.getName(), "loadThemes"));
1074
1075 private PermissionImporter _permissionImporter = new PermissionImporter();
1076 private PortletImporter _portletImporter = new PortletImporter();
1077
1078}