001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.LARFileException;
019 import com.liferay.portal.LARTypeException;
020 import com.liferay.portal.LayoutImportException;
021 import com.liferay.portal.NoSuchLayoutException;
022 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
023 import com.liferay.portal.kernel.cluster.ClusterRequest;
024 import com.liferay.portal.kernel.lar.PortletDataContext;
025 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
026 import com.liferay.portal.kernel.lar.UserIdStrategy;
027 import com.liferay.portal.kernel.log.Log;
028 import com.liferay.portal.kernel.log.LogFactoryUtil;
029 import com.liferay.portal.kernel.util.ArrayUtil;
030 import com.liferay.portal.kernel.util.CharPool;
031 import com.liferay.portal.kernel.util.FileUtil;
032 import com.liferay.portal.kernel.util.GetterUtil;
033 import com.liferay.portal.kernel.util.LocaleUtil;
034 import com.liferay.portal.kernel.util.MapUtil;
035 import com.liferay.portal.kernel.util.MethodHandler;
036 import com.liferay.portal.kernel.util.MethodKey;
037 import com.liferay.portal.kernel.util.ReleaseInfo;
038 import com.liferay.portal.kernel.util.StringPool;
039 import com.liferay.portal.kernel.util.StringUtil;
040 import com.liferay.portal.kernel.util.Time;
041 import com.liferay.portal.kernel.util.UnicodeProperties;
042 import com.liferay.portal.kernel.util.Validator;
043 import com.liferay.portal.kernel.xml.Document;
044 import com.liferay.portal.kernel.xml.Element;
045 import com.liferay.portal.kernel.xml.Node;
046 import com.liferay.portal.kernel.xml.SAXReaderUtil;
047 import com.liferay.portal.kernel.zip.ZipReader;
048 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
049 import com.liferay.portal.model.Layout;
050 import com.liferay.portal.model.LayoutConstants;
051 import com.liferay.portal.model.LayoutSet;
052 import com.liferay.portal.model.LayoutTemplate;
053 import com.liferay.portal.model.LayoutTypePortlet;
054 import com.liferay.portal.model.LayoutTypePortletConstants;
055 import com.liferay.portal.model.Portlet;
056 import com.liferay.portal.model.PortletConstants;
057 import com.liferay.portal.model.User;
058 import com.liferay.portal.model.impl.ColorSchemeImpl;
059 import com.liferay.portal.service.ImageLocalServiceUtil;
060 import com.liferay.portal.service.LayoutLocalServiceUtil;
061 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
062 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
063 import com.liferay.portal.service.PortletLocalServiceUtil;
064 import com.liferay.portal.service.ServiceContext;
065 import com.liferay.portal.service.persistence.LayoutUtil;
066 import com.liferay.portal.service.persistence.UserUtil;
067 import com.liferay.portal.theme.ThemeLoader;
068 import com.liferay.portal.theme.ThemeLoaderFactory;
069 import com.liferay.portal.util.PortalUtil;
070 import com.liferay.portal.util.PortletKeys;
071 import com.liferay.portal.util.PropsValues;
072 import com.liferay.portlet.asset.DuplicateVocabularyException;
073 import com.liferay.portlet.asset.model.AssetVocabulary;
074 import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
075 import com.liferay.portlet.asset.service.persistence.AssetVocabularyUtil;
076 import com.liferay.portlet.journal.model.JournalArticle;
077
078 import java.io.File;
079 import java.io.IOException;
080 import java.io.InputStream;
081
082 import java.util.ArrayList;
083 import java.util.Date;
084 import java.util.HashMap;
085 import java.util.HashSet;
086 import java.util.List;
087 import java.util.Locale;
088 import java.util.Map;
089 import java.util.Set;
090
091 import org.apache.commons.lang.time.StopWatch;
092
093
105 public class LayoutImporter {
106
107 public void importLayouts(
108 long userId, long groupId, boolean privateLayout,
109 Map<String, String[]> parameterMap, File file)
110 throws Exception {
111
112 boolean deleteMissingLayouts = MapUtil.getBoolean(
113 parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
114 Boolean.TRUE.booleanValue());
115 boolean deletePortletData = MapUtil.getBoolean(
116 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
117 boolean importCategories = MapUtil.getBoolean(
118 parameterMap, PortletDataHandlerKeys.CATEGORIES);
119 boolean importPermissions = MapUtil.getBoolean(
120 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
121 boolean importUserPermissions = MapUtil.getBoolean(
122 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
123 boolean importPortletData = MapUtil.getBoolean(
124 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
125 boolean importPortletSetup = MapUtil.getBoolean(
126 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
127 boolean importPortletArchivedSetups = MapUtil.getBoolean(
128 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
129 boolean importPortletUserPreferences = MapUtil.getBoolean(
130 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
131 boolean importTheme = MapUtil.getBoolean(
132 parameterMap, PortletDataHandlerKeys.THEME);
133 String layoutsImportMode = MapUtil.getString(
134 parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
135 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_ID);
136 String portletsMergeMode = MapUtil.getString(
137 parameterMap, PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
138 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
139 String userIdStrategy = MapUtil.getString(
140 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
141
142 if (_log.isDebugEnabled()) {
143 _log.debug("Delete portlet data " + deletePortletData);
144 _log.debug("Import categories " + importCategories);
145 _log.debug("Import permissions " + importPermissions);
146 _log.debug("Import user permissions " + importUserPermissions);
147 _log.debug("Import portlet data " + importPortletData);
148 _log.debug("Import portlet setup " + importPortletSetup);
149 _log.debug(
150 "Import portlet archived setups " +
151 importPortletArchivedSetups);
152 _log.debug(
153 "Import portlet user preferences " +
154 importPortletUserPreferences);
155 _log.debug("Import theme " + importTheme);
156 }
157
158 StopWatch stopWatch = null;
159
160 if (_log.isInfoEnabled()) {
161 stopWatch = new StopWatch();
162
163 stopWatch.start();
164 }
165
166 LayoutCache layoutCache = new LayoutCache();
167
168 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
169 groupId, privateLayout);
170
171 long companyId = layoutSet.getCompanyId();
172
173 User user = UserUtil.findByPrimaryKey(userId);
174
175 UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
176 user, userIdStrategy);
177
178 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
179
180 PortletDataContext context = new PortletDataContextImpl(
181 companyId, groupId, parameterMap, new HashSet<String>(), strategy,
182 zipReader);
183
184 context.setPortetDataContextListener(
185 new PortletDataContextListenerImpl(context));
186
187 context.setPrivateLayout(privateLayout);
188
189
190
191 Element rootElement = null;
192 InputStream themeZip = null;
193
194
195
196 String xml = context.getZipEntryAsString("/manifest.xml");
197
198 if (xml == null) {
199 throw new LARFileException("manifest.xml not found in the LAR");
200 }
201
202 try {
203 Document document = SAXReaderUtil.read(xml);
204
205 rootElement = document.getRootElement();
206 }
207 catch (Exception e) {
208 throw new LARFileException(e);
209 }
210
211
212
213 Element headerElement = rootElement.element("header");
214
215 int buildNumber = ReleaseInfo.getBuildNumber();
216
217 int importBuildNumber = GetterUtil.getInteger(
218 headerElement.attributeValue("build-number"));
219
220 if (buildNumber != importBuildNumber) {
221 throw new LayoutImportException(
222 "LAR build number " + importBuildNumber + " does not match " +
223 "portal build number " + buildNumber);
224 }
225
226
227
228 String larType = headerElement.attributeValue("type");
229
230 if (!larType.equals("layout-set")) {
231 throw new LARTypeException(
232 "Invalid type of LAR file (" + larType + ")");
233 }
234
235
236
237 long sourceGroupId = GetterUtil.getLong(
238 headerElement.attributeValue("group-id"));
239
240 context.setSourceGroupId(sourceGroupId);
241
242
243
244 if (importTheme) {
245 themeZip = context.getZipEntryAsInputStream("theme.zip");
246 }
247
248
249
250 String themeId = headerElement.attributeValue("theme-id");
251 String colorSchemeId = headerElement.attributeValue("color-scheme-id");
252
253 boolean useThemeZip = false;
254
255 if (themeZip != null) {
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
272 boolean wapTheme = false;
273
274 LayoutSetLocalServiceUtil.updateLookAndFeel(
275 groupId, privateLayout, themeId, colorSchemeId, StringPool.BLANK,
276 wapTheme);
277
278
279
280
281 if (importPermissions) {
282 _permissionImporter.readPortletDataPermissions(context);
283 }
284
285 if (importCategories) {
286 _portletImporter.readCategories(context);
287 }
288
289 _portletImporter.readComments(context, rootElement);
290 _portletImporter.readLocks(context, rootElement);
291 _portletImporter.readRatings(context, rootElement);
292 _portletImporter.readTags(context, rootElement);
293
294
295
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, Layout> newLayoutsMap =
304 (Map<Long, Layout>)context.getNewPrimaryKeysMap(Layout.class);
305
306 Element layoutsElement = rootElement.element("layouts");
307
308 List<Element> layoutElements = layoutsElement.elements("layout");
309
310 if (_log.isDebugEnabled()) {
311 if (layoutElements.size() > 0) {
312 _log.debug("Importing layouts");
313 }
314 }
315
316 for (Element layoutElement : layoutElements) {
317 importLayout(
318 context, user, layoutCache, previousLayouts, newLayouts,
319 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
320 colorSchemeId, layoutsImportMode, privateLayout,
321 importPermissions, importUserPermissions, useThemeZip,
322 rootElement, layoutElement);
323 }
324
325 Element portletsElement = rootElement.element("portlets");
326
327 List<Element> portletElements = portletsElement.elements("portlet");
328
329
330
331 if (deletePortletData) {
332 if (_log.isDebugEnabled()) {
333 if (portletElements.size() > 0) {
334 _log.debug("Deleting portlet data");
335 }
336 }
337
338 for (Element portletElement : portletElements) {
339 String portletId = portletElement.attributeValue("portlet-id");
340 long layoutId = GetterUtil.getLong(
341 portletElement.attributeValue("layout-id"));
342 long plid = newLayoutsMap.get(layoutId).getPlid();
343
344 context.setPlid(plid);
345
346 _portletImporter.deletePortletData(context, portletId, plid);
347 }
348 }
349
350
351
352 if (_log.isDebugEnabled()) {
353 if (portletElements.size() > 0) {
354 _log.debug("Importing portlets");
355 }
356 }
357
358 for (Element portletElement : portletElements) {
359 String portletPath = portletElement.attributeValue("path");
360 String portletId = portletElement.attributeValue("portlet-id");
361 long layoutId = GetterUtil.getLong(
362 portletElement.attributeValue("layout-id"));
363 long plid = newLayoutsMap.get(layoutId).getPlid();
364 long oldPlid = GetterUtil.getLong(
365 portletElement.attributeValue("old-plid"));
366
367 Portlet portlet = PortletLocalServiceUtil.getPortletById(
368 context.getCompanyId(), portletId);
369
370 if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
371 continue;
372 }
373
374 Layout layout = null;
375
376 try {
377 layout = LayoutUtil.findByPrimaryKey(plid);
378 }
379 catch (NoSuchLayoutException nsle) {
380 continue;
381 }
382
383 context.setPlid(plid);
384 context.setOldPlid(oldPlid);
385
386 Document portletDocument = SAXReaderUtil.read(
387 context.getZipEntryAsString(portletPath));
388
389 portletElement = portletDocument.getRootElement();
390
391
392
393
394
395
396
397
398 _portletImporter.importPortletPreferences(
399 context, layoutSet.getCompanyId(), layout.getGroupId(),
400 layout, null, portletElement, importPortletSetup,
401 importPortletArchivedSetups, importPortletUserPreferences,
402 false);
403
404
405
406 String scopeLayoutUuid = GetterUtil.getString(
407 portletElement.attributeValue("scope-layout-uuid"));
408
409 context.setScopeLayoutUuid(scopeLayoutUuid);
410
411
412
413 Element portletDataElement = portletElement.element("portlet-data");
414
415 if (importPortletData && (portletDataElement != null)) {
416 _portletImporter.importPortletData(
417 context, portletId, plid, portletDataElement);
418 }
419
420
421
422 if (importPermissions) {
423 _permissionImporter.importPortletPermissions(
424 layoutCache, companyId, groupId, userId, layout,
425 portletElement, portletId, importUserPermissions);
426 }
427
428
429
430 _portletImporter.importPortletPreferences(
431 context, layoutSet.getCompanyId(), groupId, null, null,
432 portletElement, importPortletSetup, importPortletArchivedSetups,
433 importPortletUserPreferences, false);
434 }
435
436
437
438 if (deleteMissingLayouts) {
439 deleteMissingLayouts(
440 groupId, privateLayout, newLayoutIds, previousLayouts);
441 }
442
443
444
445 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
446
447 if (_log.isInfoEnabled()) {
448 _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
449 }
450
451
452
453 for (Layout layout : newLayouts) {
454 UnicodeProperties typeSettingsProperties =
455 layout.getTypeSettingsProperties();
456
457 String articleId = typeSettingsProperties.getProperty("article-id");
458
459 if (Validator.isNotNull(articleId)) {
460 Map<String, String> articleIds =
461 (Map<String, String>)context.getNewPrimaryKeysMap(
462 JournalArticle.class);
463
464 typeSettingsProperties.setProperty(
465 "article-id",
466 MapUtil.getString(articleIds, articleId, articleId));
467
468 LayoutUtil.update(layout, false);
469 }
470 }
471
472 zipReader.close();
473 }
474
475 protected String[] appendPortletIds(
476 String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
477
478 for (String portletId : newPortletIds) {
479 if (ArrayUtil.contains(portletIds, portletId)) {
480 continue;
481 }
482
483 if (portletsMergeMode.equals(
484 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
485
486 portletIds = ArrayUtil.append(portletIds, portletId);
487 }
488 else {
489 portletIds = ArrayUtil.append(
490 new String[] {portletId}, portletIds);
491 }
492 }
493
494 return portletIds;
495 }
496
497 protected void deleteMissingLayouts(
498 long groupId, boolean privateLayout, Set<Long> newLayoutIds,
499 List<Layout> previousLayouts)
500 throws Exception {
501
502
503
504 if (_log.isDebugEnabled()) {
505 if (newLayoutIds.size() > 0) {
506 _log.debug("Delete missing layouts");
507 }
508 }
509
510 for (Layout layout : previousLayouts) {
511 if (!newLayoutIds.contains(layout.getLayoutId())) {
512 try {
513 LayoutLocalServiceUtil.deleteLayout(layout, false);
514 }
515 catch (NoSuchLayoutException nsle) {
516 }
517 }
518 }
519
520
521
522 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
523 }
524
525 protected void fixTypeSettings(Layout layout) throws Exception {
526 if (!layout.isTypeURL()) {
527 return;
528 }
529
530 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
531
532 String url = GetterUtil.getString(typeSettings.getProperty("url"));
533
534 String friendlyURLPrivateGroupPath =
535 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
536 String friendlyURLPrivateUserPath =
537 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
538 String friendlyURLPublicPath =
539 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
540
541 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
542 !url.startsWith(friendlyURLPrivateUserPath) &&
543 !url.startsWith(friendlyURLPublicPath)) {
544
545 return;
546 }
547
548 int x = url.indexOf(CharPool.SLASH, 1);
549
550 if (x == -1) {
551 return;
552 }
553
554 int y = url.indexOf(CharPool.SLASH, x + 1);
555
556 if (y == -1) {
557 return;
558 }
559
560 String friendlyURL = url.substring(x, y);
561
562 if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
563 return;
564 }
565
566 typeSettings.setProperty(
567 "url",
568 url.substring(0, x) + layout.getGroup().getFriendlyURL() +
569 url.substring(y));
570 }
571
572 protected AssetVocabulary getAssetVocabulary(
573 PortletDataContext context, String vocabularyUuid,
574 String vocabularyName, String userUuid,
575 ServiceContext serviceContext)
576 throws Exception {
577
578 AssetVocabulary assetVocabulary = null;
579
580 try {
581 if (context.getDataStrategy().equals(
582 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
583
584 AssetVocabulary existingAssetVocabulary =
585 AssetVocabularyUtil.fetchByUUID_G(
586 vocabularyUuid, context.getGroupId());
587
588 if (existingAssetVocabulary == null) {
589 Map<Locale, String> titleMap =
590 new HashMap<Locale, String>();
591
592 titleMap.put(LocaleUtil.getDefault(), vocabularyName);
593
594 serviceContext.setUuid(vocabularyUuid);
595
596 assetVocabulary =
597 AssetVocabularyLocalServiceUtil.addVocabulary(
598 context.getUserId(userUuid), StringPool.BLANK,
599 titleMap, null, StringPool.BLANK, serviceContext);
600 }
601 else {
602 assetVocabulary =
603 AssetVocabularyLocalServiceUtil.updateVocabulary(
604 existingAssetVocabulary.getVocabularyId(),
605 existingAssetVocabulary.getTitle(),
606 existingAssetVocabulary.getTitleMap(),
607 existingAssetVocabulary.getDescriptionMap(),
608 existingAssetVocabulary.getSettings(),
609 serviceContext);
610 }
611 }
612 else {
613 Map<Locale, String> titleMap = new HashMap<Locale, String>();
614
615 titleMap.put(LocaleUtil.getDefault(), vocabularyName);
616
617 assetVocabulary = AssetVocabularyLocalServiceUtil.addVocabulary(
618 context.getUserId(userUuid), StringPool.BLANK, titleMap,
619 null, StringPool.BLANK, serviceContext);
620 }
621 }
622 catch (DuplicateVocabularyException dve) {
623 assetVocabulary =
624 AssetVocabularyLocalServiceUtil.getGroupVocabulary(
625 context.getGroupId(), vocabularyName);
626 }
627
628 return assetVocabulary;
629 }
630
631 protected void importLayout(
632 PortletDataContext context, User user, LayoutCache layoutCache,
633 List<Layout> previousLayouts, List<Layout> newLayouts,
634 Map<Long, Layout> newLayoutsMap, Set<Long> newLayoutIds,
635 String portletsMergeMode, String themeId, String colorSchemeId,
636 String layoutsImportMode, boolean privateLayout,
637 boolean importPermissions, boolean importUserPermissions,
638 boolean useThemeZip, Element rootElement, Element layoutElement)
639 throws Exception {
640
641 long groupId = context.getGroupId();
642
643 String layoutUuid = GetterUtil.getString(
644 layoutElement.attributeValue("layout-uuid"));
645
646 long layoutId = GetterUtil.getInteger(
647 layoutElement.attributeValue("layout-id"));
648
649 long oldLayoutId = layoutId;
650
651 boolean deleteLayout = GetterUtil.getBoolean(
652 layoutElement.attributeValue("delete"));
653
654 if (deleteLayout) {
655 try {
656 Layout layout =
657 LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
658 layoutUuid, groupId);
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 {" + layoutUuid + ", " +
669 groupId + "}");
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 {
717
718
719
720
721 existingLayout = LayoutUtil.fetchByUUID_G(
722 layout.getUuid(), groupId);
723
724 if (existingLayout == null) {
725 existingLayout = LayoutUtil.fetchByG_P_F(
726 groupId, privateLayout, friendlyURL);
727 }
728
729 if (existingLayout == null) {
730 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
731 groupId, privateLayout);
732 }
733 }
734
735 if (_log.isDebugEnabled()) {
736 if (existingLayout == 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.setUuid(layout.getUuid());
756 importedLayout.setGroupId(groupId);
757 importedLayout.setPrivateLayout(privateLayout);
758 importedLayout.setLayoutId(layoutId);
759
760 if (layout.isIconImage()) {
761 long iconImageId = CounterLocalServiceUtil.increment();
762
763 importedLayout.setIconImageId(iconImageId);
764 }
765 }
766 else {
767 importedLayout = existingLayout;
768 }
769
770 newLayoutsMap.put(oldLayoutId, importedLayout);
771
772 long parentLayoutId = layout.getParentLayoutId();
773
774 Node parentLayoutNode = rootElement.selectSingleNode(
775 "./layouts/layout[@layout-id='" + parentLayoutId + "']");
776
777 String parentLayoutUuid = GetterUtil.getString(
778 layoutElement.attributeValue("parent-layout-uuid"));
779
780 if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
781 (parentLayoutNode != null)) {
782
783 importLayout(
784 context, user, layoutCache, previousLayouts, newLayouts,
785 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
786 colorSchemeId, layoutsImportMode, privateLayout,
787 importPermissions, importUserPermissions, useThemeZip,
788 rootElement, (Element)parentLayoutNode);
789
790 Layout parentLayout = newLayoutsMap.get(parentLayoutId);
791
792 parentLayoutId = parentLayout.getLayoutId();
793 }
794 else if (Validator.isNotNull(parentLayoutUuid)) {
795 Layout parentLayout =
796 LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
797 parentLayoutUuid, groupId);
798
799 parentLayoutId = parentLayout.getLayoutId();
800 }
801
802 if (_log.isDebugEnabled()) {
803 _log.debug(
804 "Importing layout with layout id " + layoutId +
805 " and parent layout id " + parentLayoutId);
806 }
807
808 importedLayout.setCompanyId(user.getCompanyId());
809 importedLayout.setParentLayoutId(parentLayoutId);
810 importedLayout.setName(layout.getName());
811 importedLayout.setTitle(layout.getTitle());
812 importedLayout.setDescription(layout.getDescription());
813 importedLayout.setType(layout.getType());
814
815 if (layout.isTypePortlet() &&
816 Validator.isNotNull(layout.getTypeSettings()) &&
817 !portletsMergeMode.equals(
818 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
819
820 mergePortlets(
821 importedLayout, layout.getTypeSettings(), portletsMergeMode);
822 }
823 else if (layout.isTypeLinkToLayout()) {
824 UnicodeProperties typeSettingsProperties =
825 layout.getTypeSettingsProperties();
826
827 long linkToLayoutId = GetterUtil.getLong(
828 typeSettingsProperties.getProperty(
829 "linkToLayoutId", StringPool.BLANK));
830
831 if (linkToLayoutId > 0) {
832 Node linkedLayoutNode = rootElement.selectSingleNode(
833 "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
834
835 importLayout(
836 context, user, layoutCache, previousLayouts, newLayouts,
837 newLayoutsMap, newLayoutIds, portletsMergeMode, themeId,
838 colorSchemeId, layoutsImportMode, privateLayout,
839 importPermissions, importUserPermissions, useThemeZip,
840 rootElement, (Element)linkedLayoutNode);
841
842 Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
843
844 typeSettingsProperties.setProperty(
845 "linkToLayoutId",
846 String.valueOf(linkedLayout.getLayoutId()));
847 }
848
849 importedLayout.setTypeSettings(layout.getTypeSettings());
850 }
851 else {
852 importedLayout.setTypeSettings(layout.getTypeSettings());
853 }
854
855 importedLayout.setHidden(layout.isHidden());
856 importedLayout.setFriendlyURL(friendlyURL);
857
858 if (useThemeZip) {
859 importedLayout.setThemeId(StringPool.BLANK);
860 importedLayout.setColorSchemeId(StringPool.BLANK);
861 }
862 else {
863 importedLayout.setThemeId(layout.getThemeId());
864 importedLayout.setColorSchemeId(layout.getColorSchemeId());
865 }
866
867 importedLayout.setWapThemeId(layout.getWapThemeId());
868 importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
869 importedLayout.setCss(layout.getCss());
870 importedLayout.setPriority(layout.getPriority());
871
872 fixTypeSettings(importedLayout);
873
874 if (layout.isIconImage()) {
875 String iconImagePath = layoutElement.elementText("icon-image-path");
876
877 byte[] iconBytes = context.getZipEntryAsByteArray(iconImagePath);
878
879 if ((iconBytes != null) && (iconBytes.length > 0)) {
880 importedLayout.setIconImage(true);
881
882 ImageLocalServiceUtil.updateImage(
883 importedLayout.getIconImageId(), iconBytes);
884 }
885 }
886 else {
887 ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
888 }
889
890 LayoutUtil.update(importedLayout, false);
891
892 context.setPlid(importedLayout.getPlid());
893 context.setOldPlid(layout.getPlid());
894
895 newLayoutIds.add(importedLayout.getLayoutId());
896
897 newLayouts.add(importedLayout);
898
899
900
901 if (importPermissions) {
902 _permissionImporter.importLayoutPermissions(
903 layoutCache, context.getCompanyId(), groupId, user.getUserId(),
904 importedLayout, layoutElement, rootElement,
905 importUserPermissions);
906 }
907
908 _portletImporter.importPortletData(
909 context, PortletKeys.LAYOUT_CONFIGURATION, null, layoutElement);
910 }
911
912 protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
913 throws Exception {
914
915 ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
916
917 if (themeLoader == null) {
918 _log.error("No theme loaders are deployed");
919
920 return null;
921 }
922
923 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
924
925 String lookAndFeelXML = zipReader.getEntryAsString(
926 "liferay-look-and-feel.xml");
927
928 String themeId = String.valueOf(layoutSet.getGroupId());
929
930 if (layoutSet.isPrivateLayout()) {
931 themeId += "-private";
932 }
933 else {
934 themeId += "-public";
935 }
936
937 if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
938 Date now = new Date();
939
940 themeId += "-" + Time.getShortTimestamp(now);
941 }
942
943 String themeName = themeId;
944
945 lookAndFeelXML = StringUtil.replace(
946 lookAndFeelXML,
947 new String[] {
948 "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
949 },
950 new String[] {
951 String.valueOf(layoutSet.getGroupId()), themeId, themeName
952 }
953 );
954
955 FileUtil.deltree(
956 themeLoader.getFileStorage() + StringPool.SLASH + themeId);
957
958 List<String> zipEntries = zipReader.getEntries();
959
960 for (String zipEntry : zipEntries) {
961 String key = zipEntry;
962
963 if (key.contains(StringPool.SLASH)) {
964 key = key.substring(key.lastIndexOf(CharPool.SLASH));
965 }
966
967 if (key.equals("liferay-look-and-feel.xml")) {
968 FileUtil.write(
969 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
970 StringPool.SLASH + key,
971 lookAndFeelXML.getBytes());
972 }
973 else {
974 InputStream is = zipReader.getEntryAsInputStream(zipEntry);
975
976 FileUtil.write(
977 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
978 StringPool.SLASH + key,
979 is);
980 }
981 }
982
983 themeLoader.loadThemes();
984
985 ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
986 _loadThemesMethodHandler, true);
987
988 clusterRequest.setFireAndForget(true);
989
990 ClusterExecutorUtil.execute(clusterRequest);
991
992 themeId +=
993 PortletConstants.WAR_SEPARATOR +
994 themeLoader.getServletContextName();
995
996 return PortalUtil.getJsSafePortletId(themeId);
997 }
998
999 protected void mergePortlets(
1000 Layout layout, String newTypeSettings, String portletsMergeMode) {
1001
1002 try {
1003 UnicodeProperties previousProperties =
1004 layout.getTypeSettingsProperties();
1005 LayoutTypePortlet previousLayoutType =
1006 (LayoutTypePortlet)layout.getLayoutType();
1007 List<String> previousColumns =
1008 previousLayoutType.getLayoutTemplate().getColumns();
1009
1010 UnicodeProperties newProperties = new UnicodeProperties(true);
1011
1012 newProperties.load(newTypeSettings);
1013
1014 String layoutTemplateId = newProperties.getProperty(
1015 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1016
1017 LayoutTemplate newLayoutTemplate =
1018 LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1019 layoutTemplateId, false, null);
1020
1021 String[] lostPortletIds = new String[0];
1022
1023 for (String columnId : newLayoutTemplate.getColumns()) {
1024 String columnValue = newProperties.getProperty(columnId);
1025
1026 String[] portletIds = StringUtil.split(columnValue);
1027
1028 if (!previousColumns.contains(columnId)) {
1029 lostPortletIds = ArrayUtil.append(
1030 lostPortletIds, portletIds);
1031 }
1032 else {
1033 String[] previousPortletIds = StringUtil.split(
1034 previousProperties.getProperty(columnId));
1035
1036 portletIds = appendPortletIds(
1037 previousPortletIds, portletIds, portletsMergeMode);
1038
1039 previousProperties.setProperty(
1040 columnId, StringUtil.merge(portletIds));
1041 }
1042 }
1043
1044
1045
1046 String columnId = previousColumns.get(0);
1047
1048 String[] portletIds = StringUtil.split(
1049 previousProperties.getProperty(columnId));
1050
1051 appendPortletIds(portletIds, lostPortletIds, portletsMergeMode);
1052
1053 previousProperties.setProperty(
1054 columnId, StringUtil.merge(portletIds));
1055
1056 layout.setTypeSettings(previousProperties.toString());
1057 }
1058 catch (IOException ioe) {
1059 layout.setTypeSettings(newTypeSettings);
1060 }
1061 }
1062
1063 private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1064
1065 private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1066 new MethodKey(ThemeLoaderFactory.class.getName(), "loadThemes"));
1067
1068 private PermissionImporter _permissionImporter = new PermissionImporter();
1069 private PortletImporter _portletImporter = new PortletImporter();
1070
1071 }