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