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