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