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