001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.portal.LARFileException;
018 import com.liferay.portal.LARTypeException;
019 import com.liferay.portal.LayoutImportException;
020 import com.liferay.portal.LayoutPrototypeException;
021 import com.liferay.portal.LocaleException;
022 import com.liferay.portal.MissingReferenceException;
023 import com.liferay.portal.NoSuchLayoutException;
024 import com.liferay.portal.NoSuchLayoutPrototypeException;
025 import com.liferay.portal.NoSuchLayoutSetPrototypeException;
026 import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
027 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
028 import com.liferay.portal.kernel.cluster.ClusterRequest;
029 import com.liferay.portal.kernel.language.LanguageUtil;
030 import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
031 import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
032 import com.liferay.portal.kernel.lar.ManifestSummary;
033 import com.liferay.portal.kernel.lar.MissingReference;
034 import com.liferay.portal.kernel.lar.MissingReferences;
035 import com.liferay.portal.kernel.lar.PortletDataContext;
036 import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
037 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
038 import com.liferay.portal.kernel.lar.PortletDataHandlerStatusMessageSenderUtil;
039 import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
040 import com.liferay.portal.kernel.lar.UserIdStrategy;
041 import com.liferay.portal.kernel.log.Log;
042 import com.liferay.portal.kernel.log.LogFactoryUtil;
043 import com.liferay.portal.kernel.search.Indexer;
044 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
045 import com.liferay.portal.kernel.util.ArrayUtil;
046 import com.liferay.portal.kernel.util.ColorSchemeFactoryUtil;
047 import com.liferay.portal.kernel.util.Constants;
048 import com.liferay.portal.kernel.util.FileUtil;
049 import com.liferay.portal.kernel.util.GetterUtil;
050 import com.liferay.portal.kernel.util.LocaleUtil;
051 import com.liferay.portal.kernel.util.MapUtil;
052 import com.liferay.portal.kernel.util.MethodHandler;
053 import com.liferay.portal.kernel.util.MethodKey;
054 import com.liferay.portal.kernel.util.ReleaseInfo;
055 import com.liferay.portal.kernel.util.StringPool;
056 import com.liferay.portal.kernel.util.StringUtil;
057 import com.liferay.portal.kernel.util.Time;
058 import com.liferay.portal.kernel.util.Tuple;
059 import com.liferay.portal.kernel.util.UnicodeProperties;
060 import com.liferay.portal.kernel.util.Validator;
061 import com.liferay.portal.kernel.xml.Attribute;
062 import com.liferay.portal.kernel.xml.Document;
063 import com.liferay.portal.kernel.xml.Element;
064 import com.liferay.portal.kernel.xml.SAXReaderUtil;
065 import com.liferay.portal.kernel.zip.ZipReader;
066 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
067 import com.liferay.portal.model.Group;
068 import com.liferay.portal.model.Layout;
069 import com.liferay.portal.model.LayoutConstants;
070 import com.liferay.portal.model.LayoutPrototype;
071 import com.liferay.portal.model.LayoutSet;
072 import com.liferay.portal.model.LayoutSetPrototype;
073 import com.liferay.portal.model.Portlet;
074 import com.liferay.portal.model.PortletConstants;
075 import com.liferay.portal.model.User;
076 import com.liferay.portal.security.permission.PermissionCacheUtil;
077 import com.liferay.portal.service.GroupLocalServiceUtil;
078 import com.liferay.portal.service.LayoutLocalServiceUtil;
079 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
080 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
081 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
082 import com.liferay.portal.service.PortletLocalServiceUtil;
083 import com.liferay.portal.service.ServiceContext;
084 import com.liferay.portal.service.ServiceContextThreadLocal;
085 import com.liferay.portal.service.persistence.LayoutUtil;
086 import com.liferay.portal.service.persistence.UserUtil;
087 import com.liferay.portal.servlet.filters.cache.CacheUtil;
088 import com.liferay.portal.theme.ThemeLoader;
089 import com.liferay.portal.theme.ThemeLoaderFactory;
090 import com.liferay.portal.util.PortalUtil;
091 import com.liferay.portal.util.PropsValues;
092 import com.liferay.portlet.journal.model.JournalArticle;
093 import com.liferay.portlet.journalcontent.util.JournalContentUtil;
094 import com.liferay.portlet.sites.util.Sites;
095
096 import java.io.File;
097 import java.io.InputStream;
098
099 import java.util.ArrayList;
100 import java.util.Date;
101 import java.util.List;
102 import java.util.Locale;
103 import java.util.Map;
104
105 import org.apache.commons.lang.time.StopWatch;
106
107
120 public class LayoutImporter {
121
122 public void importLayouts(
123 long userId, long groupId, boolean privateLayout,
124 Map<String, String[]> parameterMap, File file)
125 throws Exception {
126
127 try {
128 ExportImportThreadLocal.setLayoutImportInProcess(true);
129
130 doImportLayouts(userId, groupId, privateLayout, parameterMap, file);
131 }
132 finally {
133 ExportImportThreadLocal.setLayoutImportInProcess(false);
134
135 CacheUtil.clearCache();
136 JournalContentUtil.clearCache();
137 PermissionCacheUtil.clearCache();
138 }
139 }
140
141 public MissingReferences validateFile(
142 long userId, long groupId, boolean privateLayout,
143 Map<String, String[]> parameterMap, File file)
144 throws Exception {
145
146 try {
147 ExportImportThreadLocal.setLayoutValidationInProcess(true);
148
149 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
150 groupId, privateLayout);
151
152 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
153
154 PortletDataContext portletDataContext =
155 PortletDataContextFactoryUtil.createImportPortletDataContext(
156 layoutSet.getCompanyId(), groupId, parameterMap, null,
157 zipReader);
158
159 validateFile(portletDataContext);
160
161 MissingReferences missingReferences =
162 ExportImportHelperUtil.validateMissingReferences(
163 userId, groupId, parameterMap, file);
164
165 Map<String, MissingReference> dependencyMissingReferences =
166 missingReferences.getDependencyMissingReferences();
167
168 if (!dependencyMissingReferences.isEmpty()) {
169 throw new MissingReferenceException(missingReferences);
170 }
171
172 return missingReferences;
173 }
174 finally {
175 ExportImportThreadLocal.setLayoutValidationInProcess(false);
176 }
177 }
178
179 protected void deleteMissingLayouts(
180 List<String> sourceLayoutUuids, List<Layout> previousLayouts,
181 ServiceContext serviceContext)
182 throws Exception {
183
184 if (_log.isDebugEnabled() && !sourceLayoutUuids.isEmpty()) {
185 _log.debug("Delete missing layouts");
186 }
187
188 for (Layout layout : previousLayouts) {
189 if (!sourceLayoutUuids.contains(layout.getUuid())) {
190 try {
191 LayoutLocalServiceUtil.deleteLayout(
192 layout, false, serviceContext);
193 }
194 catch (NoSuchLayoutException nsle) {
195 }
196 }
197 }
198 }
199
200 protected void doImportLayouts(
201 long userId, long groupId, boolean privateLayout,
202 Map<String, String[]> parameterMap, File file)
203 throws Exception {
204
205 boolean deleteMissingLayouts = MapUtil.getBoolean(
206 parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
207 Boolean.TRUE.booleanValue());
208 boolean deletePortletData = MapUtil.getBoolean(
209 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
210 boolean importCategories = MapUtil.getBoolean(
211 parameterMap, PortletDataHandlerKeys.CATEGORIES);
212 boolean importPermissions = MapUtil.getBoolean(
213 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
214 boolean importTheme = MapUtil.getBoolean(
215 parameterMap, PortletDataHandlerKeys.THEME);
216 boolean importThemeSettings = MapUtil.getBoolean(
217 parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
218 boolean importLogo = MapUtil.getBoolean(
219 parameterMap, PortletDataHandlerKeys.LOGO);
220 boolean importLayoutSetSettings = MapUtil.getBoolean(
221 parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
222
223 boolean layoutSetPrototypeLinkEnabled = MapUtil.getBoolean(
224 parameterMap,
225 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, true);
226
227 Group group = GroupLocalServiceUtil.getGroup(groupId);
228
229 if (group.isLayoutSetPrototype()) {
230 layoutSetPrototypeLinkEnabled = false;
231 }
232
233 String layoutsImportMode = MapUtil.getString(
234 parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
235 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
236 String userIdStrategy = MapUtil.getString(
237 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
238
239 if (_log.isDebugEnabled()) {
240 _log.debug("Delete portlet data " + deletePortletData);
241 _log.debug("Import categories " + importCategories);
242 _log.debug("Import permissions " + importPermissions);
243 _log.debug("Import theme " + importTheme);
244 }
245
246 StopWatch stopWatch = null;
247
248 if (_log.isInfoEnabled()) {
249 stopWatch = new StopWatch();
250
251 stopWatch.start();
252 }
253
254 LayoutCache layoutCache = new LayoutCache();
255
256 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
257 groupId, privateLayout);
258
259 long companyId = layoutSet.getCompanyId();
260
261 User user = UserUtil.findByPrimaryKey(userId);
262
263 UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
264 user, userIdStrategy);
265
266 if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
267 ManifestSummary manifestSummary =
268 ExportImportHelperUtil.getManifestSummary(
269 userId, groupId, parameterMap, file);
270
271 PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
272 "layout", manifestSummary);
273 }
274
275 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
276
277 PortletDataContext portletDataContext =
278 PortletDataContextFactoryUtil.createImportPortletDataContext(
279 companyId, groupId, parameterMap, strategy, zipReader);
280
281 portletDataContext.setPortetDataContextListener(
282 new PortletDataContextListenerImpl(portletDataContext));
283
284 portletDataContext.setPrivateLayout(privateLayout);
285
286
287
288 InputStream themeZip = null;
289
290 validateFile(portletDataContext);
291
292
293
294 long sourceCompanyId = GetterUtil.getLong(
295 _headerElement.attributeValue("company-id"));
296
297 portletDataContext.setSourceCompanyId(sourceCompanyId);
298
299
300
301 long sourceCompanyGroupId = GetterUtil.getLong(
302 _headerElement.attributeValue("company-group-id"));
303
304 portletDataContext.setSourceCompanyGroupId(sourceCompanyGroupId);
305
306
307
308 long sourceGroupId = GetterUtil.getLong(
309 _headerElement.attributeValue("group-id"));
310
311 portletDataContext.setSourceGroupId(sourceGroupId);
312
313
314
315 long sourceUserPersonalSiteGroupId = GetterUtil.getLong(
316 _headerElement.attributeValue("user-personal-site-group-id"));
317
318 portletDataContext.setSourceUserPersonalSiteGroupId(
319 sourceUserPersonalSiteGroupId);
320
321
322
323 String layoutSetPrototypeUuid = _layoutsElement.attributeValue(
324 "layout-set-prototype-uuid");
325
326 String larType = _headerElement.attributeValue("type");
327
328 if (group.isLayoutPrototype() && larType.equals("layout-prototype")) {
329 deleteMissingLayouts = false;
330
331 LayoutPrototype layoutPrototype =
332 LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
333 group.getClassPK());
334
335 String layoutPrototypeUuid = GetterUtil.getString(
336 _headerElement.attributeValue("type-uuid"));
337
338 LayoutPrototype existingLayoutPrototype = null;
339
340 if (Validator.isNotNull(layoutPrototypeUuid)) {
341 try {
342 existingLayoutPrototype =
343 LayoutPrototypeLocalServiceUtil.
344 getLayoutPrototypeByUuidAndCompanyId(
345 layoutPrototypeUuid, companyId);
346 }
347 catch (NoSuchLayoutPrototypeException nslpe) {
348 }
349 }
350
351 if (existingLayoutPrototype == null) {
352 List<Layout> layouts =
353 LayoutLocalServiceUtil.getLayoutsByLayoutPrototypeUuid(
354 layoutPrototype.getUuid());
355
356 layoutPrototype.setUuid(layoutPrototypeUuid);
357
358 LayoutPrototypeLocalServiceUtil.updateLayoutPrototype(
359 layoutPrototype);
360
361 for (Layout layout : layouts) {
362 layout.setLayoutPrototypeUuid(layoutPrototypeUuid);
363
364 LayoutLocalServiceUtil.updateLayout(layout);
365 }
366 }
367 }
368 else if (group.isLayoutSetPrototype() &&
369 larType.equals("layout-set-prototype")) {
370
371 LayoutSetPrototype layoutSetPrototype =
372 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
373 group.getClassPK());
374
375 String importedLayoutSetPrototypeUuid = GetterUtil.getString(
376 _headerElement.attributeValue("type-uuid"));
377
378 LayoutSetPrototype existingLayoutSetPrototype = null;
379
380 if (Validator.isNotNull(importedLayoutSetPrototypeUuid)) {
381 try {
382 existingLayoutSetPrototype =
383 LayoutSetPrototypeLocalServiceUtil.
384 getLayoutSetPrototypeByUuidAndCompanyId(
385 importedLayoutSetPrototypeUuid, companyId);
386 }
387 catch (NoSuchLayoutSetPrototypeException nslspe) {
388 }
389 }
390
391 if (existingLayoutSetPrototype == null) {
392 layoutSetPrototype.setUuid(importedLayoutSetPrototypeUuid);
393
394 LayoutSetPrototypeLocalServiceUtil.updateLayoutSetPrototype(
395 layoutSetPrototype);
396 }
397 }
398 else if (larType.equals("layout-set-prototype")) {
399 layoutSetPrototypeUuid = GetterUtil.getString(
400 _headerElement.attributeValue("type-uuid"));
401 }
402
403 ServiceContext serviceContext =
404 ServiceContextThreadLocal.getServiceContext();
405
406 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
407 layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
408 layoutSet.setLayoutSetPrototypeLinkEnabled(
409 layoutSetPrototypeLinkEnabled);
410
411 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
412 }
413
414
415
416 if (importTheme) {
417 themeZip = portletDataContext.getZipEntryAsInputStream("theme.zip");
418 }
419
420
421
422 String themeId = layoutSet.getThemeId();
423 String colorSchemeId = layoutSet.getColorSchemeId();
424
425 if (importThemeSettings) {
426 Attribute themeIdAttribute = _headerElement.attribute("theme-id");
427
428 if (themeIdAttribute != null) {
429 themeId = themeIdAttribute.getValue();
430 }
431
432 Attribute colorSchemeIdAttribute = _headerElement.attribute(
433 "color-scheme-id");
434
435 if (colorSchemeIdAttribute != null) {
436 colorSchemeId = colorSchemeIdAttribute.getValue();
437 }
438 }
439
440 if (importLogo) {
441 String logoPath = _headerElement.attributeValue("logo-path");
442
443 byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
444 logoPath);
445
446 if (ArrayUtil.isNotEmpty(iconBytes)) {
447 File logo = null;
448
449 try {
450 logo = FileUtil.createTempFile(iconBytes);
451
452 LayoutSetLocalServiceUtil.updateLogo(
453 groupId, privateLayout, true, logo);
454 }
455 finally {
456 FileUtil.delete(logo);
457 }
458 }
459 else {
460 LayoutSetLocalServiceUtil.updateLogo(
461 groupId, privateLayout, false, (File)null);
462 }
463 }
464
465 if (importLayoutSetSettings) {
466 String settings = GetterUtil.getString(
467 _headerElement.elementText("settings"));
468
469 LayoutSetLocalServiceUtil.updateSettings(
470 groupId, privateLayout, settings);
471 }
472
473 String css = GetterUtil.getString(_headerElement.elementText("css"));
474
475 if (themeZip != null) {
476 String importThemeId = importTheme(layoutSet, themeZip);
477
478 if (importThemeId != null) {
479 themeId = importThemeId;
480 colorSchemeId =
481 ColorSchemeFactoryUtil.getDefaultRegularColorSchemeId();
482 }
483
484 if (_log.isDebugEnabled()) {
485 _log.debug(
486 "Importing theme takes " + stopWatch.getTime() + " ms");
487 }
488 }
489
490 boolean wapTheme = false;
491
492 LayoutSetLocalServiceUtil.updateLookAndFeel(
493 groupId, privateLayout, themeId, colorSchemeId, css, wapTheme);
494
495
496
497
498
499 if (importPermissions) {
500 _permissionImporter.readPortletDataPermissions(portletDataContext);
501 }
502
503 _portletImporter.readAssetCategories(portletDataContext);
504 _portletImporter.readAssetTags(portletDataContext);
505 _portletImporter.readComments(portletDataContext);
506 _portletImporter.readExpandoTables(portletDataContext);
507 _portletImporter.readLocks(portletDataContext);
508 _portletImporter.readRatingsEntries(portletDataContext);
509
510
511
512 List<Layout> previousLayouts = LayoutUtil.findByG_P(
513 groupId, privateLayout);
514
515
516
517 if (Validator.isNotNull(layoutSetPrototypeUuid) &&
518 layoutSetPrototypeLinkEnabled) {
519
520 LayoutSetPrototype layoutSetPrototype =
521 LayoutSetPrototypeLocalServiceUtil.
522 getLayoutSetPrototypeByUuidAndCompanyId(
523 layoutSetPrototypeUuid, companyId);
524
525 for (Layout layout : previousLayouts) {
526 String sourcePrototypeLayoutUuid =
527 layout.getSourcePrototypeLayoutUuid();
528
529 if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
530 continue;
531 }
532
533 Layout sourcePrototypeLayout = LayoutUtil.fetchByUUID_G_P(
534 sourcePrototypeLayoutUuid, layoutSetPrototype.getGroupId(),
535 true);
536
537 if (sourcePrototypeLayout == null) {
538 LayoutLocalServiceUtil.deleteLayout(
539 layout, false, serviceContext);
540 }
541 }
542 }
543
544 List<String> sourceLayoutsUuids = new ArrayList<String>();
545 List<Layout> newLayouts = new ArrayList<Layout>();
546
547 if (_log.isDebugEnabled()) {
548 if (_layoutElements.size() > 0) {
549 _log.debug("Importing layouts");
550 }
551 }
552
553 for (Element layoutElement : _layoutElements) {
554 importLayout(
555 portletDataContext, sourceLayoutsUuids, newLayouts,
556 layoutElement);
557 }
558
559 Element portletsElement = _rootElement.element("portlets");
560
561 List<Element> portletElements = portletsElement.elements("portlet");
562
563
564
565 Map<Long, Layout> newLayoutsMap =
566 (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
567 Layout.class + ".layout");
568
569 if (deletePortletData) {
570 if (_log.isDebugEnabled()) {
571 if (portletElements.size() > 0) {
572 _log.debug("Deleting portlet data");
573 }
574 }
575
576 for (Element portletElement : portletElements) {
577 String portletId = portletElement.attributeValue("portlet-id");
578 long layoutId = GetterUtil.getLong(
579 portletElement.attributeValue("layout-id"));
580
581 Layout layout = newLayoutsMap.get(layoutId);
582
583 long plid = layout.getPlid();
584
585 portletDataContext.setPlid(plid);
586
587 _portletImporter.deletePortletData(
588 portletDataContext, portletId, plid);
589 }
590 }
591
592
593
594 if (_log.isDebugEnabled()) {
595 if (portletElements.size() > 0) {
596 _log.debug("Importing portlets");
597 }
598 }
599
600 for (Element portletElement : portletElements) {
601 String portletPath = portletElement.attributeValue("path");
602 String portletId = portletElement.attributeValue("portlet-id");
603 long layoutId = GetterUtil.getLong(
604 portletElement.attributeValue("layout-id"));
605 long oldPlid = GetterUtil.getLong(
606 portletElement.attributeValue("old-plid"));
607
608 Portlet portlet = PortletLocalServiceUtil.getPortletById(
609 portletDataContext.getCompanyId(), portletId);
610
611 if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
612 continue;
613 }
614
615 Layout layout = newLayoutsMap.get(layoutId);
616
617 long plid = LayoutConstants.DEFAULT_PLID;
618
619 if (layout != null) {
620 plid = layout.getPlid();
621 }
622
623 layout = LayoutUtil.fetchByPrimaryKey(plid);
624
625 if ((layout == null) && !group.isCompany()) {
626 continue;
627 }
628
629 portletDataContext.setPlid(plid);
630 portletDataContext.setOldPlid(oldPlid);
631
632 Document portletDocument = SAXReaderUtil.read(
633 portletDataContext.getZipEntryAsString(portletPath));
634
635 portletElement = portletDocument.getRootElement();
636
637
638
639
640
641
642 _portletImporter.setPortletScope(
643 portletDataContext, portletElement);
644
645 long portletPreferencesGroupId = groupId;
646
647 Element portletDataElement = portletElement.element("portlet-data");
648
649 boolean[] importPortletControls = getImportPortletControls(
650 companyId, portletId, parameterMap, portletDataElement);
651
652 try {
653 if ((layout != null) && !group.isCompany()) {
654 portletPreferencesGroupId = layout.getGroupId();
655 }
656
657
658
659 _portletImporter.importPortletPreferences(
660 portletDataContext, layoutSet.getCompanyId(),
661 portletPreferencesGroupId, layout, null, portletElement,
662 importPortletControls[2], importPortletControls[0],
663 importPortletControls[3], false, importPortletControls[1]);
664
665
666
667 if (importPortletControls[1]) {
668 _portletImporter.importPortletData(
669 portletDataContext, portletId, plid,
670 portletDataElement);
671 }
672 }
673 finally {
674 _portletImporter.resetPortletScope(
675 portletDataContext, portletPreferencesGroupId);
676 }
677
678
679
680 if (importPermissions) {
681 _permissionImporter.importPortletPermissions(
682 layoutCache, companyId, groupId, userId, layout,
683 portletElement, portletId);
684 }
685
686
687
688 _portletImporter.importPortletPreferences(
689 portletDataContext, layoutSet.getCompanyId(), groupId, null,
690 null, portletElement, importPortletControls[2],
691 importPortletControls[0], importPortletControls[3], false,
692 importPortletControls[1]);
693 }
694
695 if (importPermissions) {
696 if (userId > 0) {
697 Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
698 User.class);
699
700 indexer.reindex(userId);
701 }
702 }
703
704
705
706 _portletImporter.readAssetLinks(portletDataContext);
707
708
709
710 if (deleteMissingLayouts) {
711 deleteMissingLayouts(
712 sourceLayoutsUuids, previousLayouts, serviceContext);
713 }
714
715
716
717 layoutSet = LayoutSetLocalServiceUtil.updatePageCount(
718 groupId, privateLayout);
719
720
721
722 GroupLocalServiceUtil.updateSite(groupId, true);
723
724
725
726
727 long lastMergeTime = System.currentTimeMillis();
728
729 for (Layout layout : newLayouts) {
730 boolean modifiedTypeSettingsProperties = false;
731
732 UnicodeProperties typeSettingsProperties =
733 layout.getTypeSettingsProperties();
734
735
736
737 String articleId = typeSettingsProperties.getProperty("article-id");
738
739 if (Validator.isNotNull(articleId)) {
740 Map<String, String> articleIds =
741 (Map<String, String>)portletDataContext.
742 getNewPrimaryKeysMap(
743 JournalArticle.class + ".articleId");
744
745 typeSettingsProperties.setProperty(
746 "article-id",
747 MapUtil.getString(articleIds, articleId, articleId));
748
749 modifiedTypeSettingsProperties = true;
750 }
751
752
753
754 if (layoutsImportMode.equals(
755 PortletDataHandlerKeys.
756 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
757
758 typeSettingsProperties.setProperty(
759 Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
760
761 modifiedTypeSettingsProperties = true;
762 }
763
764 if (modifiedTypeSettingsProperties) {
765 LayoutUtil.update(layout);
766 }
767 }
768
769
770
771 if (layoutsImportMode.equals(
772 PortletDataHandlerKeys.
773 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
774
775 UnicodeProperties settingsProperties =
776 layoutSet.getSettingsProperties();
777
778 String mergeFailFriendlyURLLayouts =
779 settingsProperties.getProperty(
780 Sites.MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
781
782 if (Validator.isNull(mergeFailFriendlyURLLayouts)) {
783 settingsProperties.setProperty(
784 Sites.LAST_MERGE_TIME, String.valueOf(lastMergeTime));
785
786 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
787 }
788 }
789
790
791
792 _deletionSystemEventImporter.importDeletionSystemEvents(
793 portletDataContext);
794
795 if (_log.isInfoEnabled()) {
796 _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
797 }
798
799 zipReader.close();
800 }
801
802 protected boolean[] getImportPortletControls(
803 long companyId, String portletId,
804 Map<String, String[]> parameterMap, Element portletDataElement)
805 throws Exception {
806
807 boolean importPortletConfiguration = MapUtil.getBoolean(
808 parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION);
809 boolean importPortletConfigurationAll = MapUtil.getBoolean(
810 parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL);
811 boolean importPortletData = MapUtil.getBoolean(
812 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
813 boolean importPortletDataAll = MapUtil.getBoolean(
814 parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
815
816 if (_log.isDebugEnabled()) {
817 _log.debug("Import portlet data " + importPortletData);
818 _log.debug("Import all portlet data " + importPortletDataAll);
819 _log.debug(
820 "Import portlet configuration " + importPortletConfiguration);
821 }
822
823 boolean importCurPortletData = importPortletData;
824
825 String rootPortletId =
826 ExportImportHelperUtil.getExportableRootPortletId(
827 companyId, portletId);
828
829 if (portletDataElement == null) {
830 importCurPortletData = false;
831 }
832 else if (importPortletDataAll) {
833 importCurPortletData = true;
834 }
835 else if (rootPortletId != null) {
836 importCurPortletData =
837 importPortletData &&
838 MapUtil.getBoolean(
839 parameterMap,
840 PortletDataHandlerKeys.PORTLET_DATA +
841 StringPool.UNDERLINE + rootPortletId);
842 }
843
844 boolean importCurPortletArchivedSetups = importPortletConfiguration;
845 boolean importCurPortletSetup = importPortletConfiguration;
846 boolean importCurPortletUserPreferences = importPortletConfiguration;
847
848 if (importPortletConfigurationAll) {
849 importCurPortletArchivedSetups =
850 MapUtil.getBoolean(
851 parameterMap,
852 PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS_ALL);
853 importCurPortletSetup =
854 MapUtil.getBoolean(
855 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
856 importCurPortletUserPreferences =
857 MapUtil.getBoolean(
858 parameterMap,
859 PortletDataHandlerKeys.PORTLET_USER_PREFERENCES_ALL);
860 }
861 else if (rootPortletId != null) {
862 boolean importCurPortletConfiguration =
863 importPortletConfiguration &&
864 MapUtil.getBoolean(
865 parameterMap,
866 PortletDataHandlerKeys.PORTLET_CONFIGURATION +
867 StringPool.UNDERLINE + rootPortletId);
868
869 importCurPortletArchivedSetups =
870 importCurPortletConfiguration &&
871 MapUtil.getBoolean(
872 parameterMap,
873 PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS +
874 StringPool.UNDERLINE + rootPortletId);
875 importCurPortletSetup =
876 importCurPortletConfiguration &&
877 MapUtil.getBoolean(
878 parameterMap,
879 PortletDataHandlerKeys.PORTLET_SETUP +
880 StringPool.UNDERLINE + rootPortletId);
881 importCurPortletUserPreferences =
882 importCurPortletConfiguration &&
883 MapUtil.getBoolean(
884 parameterMap,
885 PortletDataHandlerKeys.PORTLET_USER_PREFERENCES +
886 StringPool.UNDERLINE + rootPortletId);
887 }
888
889 return new boolean[] {
890 importCurPortletArchivedSetups, importCurPortletData,
891 importCurPortletSetup, importCurPortletUserPreferences};
892 }
893
894 protected void importLayout(
895 PortletDataContext portletDataContext,
896 List<String> sourceLayoutsUuids, List<Layout> newLayouts,
897 Element layoutElement)
898 throws Exception {
899
900 String action = layoutElement.attributeValue("action");
901
902 if (!action.equals(Constants.SKIP)) {
903 StagedModelDataHandlerUtil.importStagedModel(
904 portletDataContext, layoutElement);
905
906 List<Layout> portletDataContextNewLayouts =
907 portletDataContext.getNewLayouts();
908
909 newLayouts.addAll(portletDataContextNewLayouts);
910
911 portletDataContextNewLayouts.clear();
912 }
913
914 if (!action.equals(Constants.DELETE)) {
915 sourceLayoutsUuids.add(layoutElement.attributeValue("uuid"));
916 }
917 }
918
919 protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
920 throws Exception {
921
922 ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
923
924 if (themeLoader == null) {
925 _log.error("No theme loaders are deployed");
926
927 return null;
928 }
929
930 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
931
932 String lookAndFeelXML = zipReader.getEntryAsString(
933 "liferay-look-and-feel.xml");
934
935 String themeId = String.valueOf(layoutSet.getGroupId());
936
937 if (layoutSet.isPrivateLayout()) {
938 themeId += "-private";
939 }
940 else {
941 themeId += "-public";
942 }
943
944 if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
945 Date now = new Date();
946
947 themeId += "-" + Time.getShortTimestamp(now);
948 }
949
950 String themeName = themeId;
951
952 lookAndFeelXML = StringUtil.replace(
953 lookAndFeelXML,
954 new String[] {
955 "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
956 },
957 new String[] {
958 String.valueOf(layoutSet.getGroupId()), themeId, themeName
959 }
960 );
961
962 FileUtil.deltree(
963 themeLoader.getFileStorage() + StringPool.SLASH + themeId);
964
965 List<String> zipEntries = zipReader.getEntries();
966
967 for (String zipEntry : zipEntries) {
968 String key = zipEntry;
969
970 if (key.equals("liferay-look-and-feel.xml")) {
971 FileUtil.write(
972 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
973 StringPool.SLASH + key,
974 lookAndFeelXML.getBytes());
975 }
976 else {
977 InputStream is = zipReader.getEntryAsInputStream(zipEntry);
978
979 FileUtil.write(
980 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
981 StringPool.SLASH + key,
982 is);
983 }
984 }
985
986 themeLoader.loadThemes();
987
988 ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
989 _loadThemesMethodHandler, true);
990
991 clusterRequest.setFireAndForget(true);
992
993 ClusterExecutorUtil.execute(clusterRequest);
994
995 themeId +=
996 PortletConstants.WAR_SEPARATOR +
997 themeLoader.getServletContextName();
998
999 return PortalUtil.getJsSafePortletId(themeId);
1000 }
1001
1002 protected void readXML(PortletDataContext portletDataContext)
1003 throws Exception {
1004
1005 if ((_rootElement != null) && (_headerElement != null) &&
1006 (_layoutsElement != null) && (_layoutElements != null)) {
1007
1008 return;
1009 }
1010
1011 String xml = portletDataContext.getZipEntryAsString("/manifest.xml");
1012
1013 if (xml == null) {
1014 throw new LARFileException("manifest.xml not found in the LAR");
1015 }
1016
1017 try {
1018 Document document = SAXReaderUtil.read(xml);
1019
1020 _rootElement = document.getRootElement();
1021
1022 portletDataContext.setImportDataRootElement(_rootElement);
1023 }
1024 catch (Exception e) {
1025 throw new LARFileException(e);
1026 }
1027
1028 _headerElement = _rootElement.element("header");
1029
1030 _layoutsElement = portletDataContext.getImportDataGroupElement(
1031 Layout.class);
1032
1033 _layoutElements = _layoutsElement.elements();
1034 }
1035
1036 protected void validateFile(PortletDataContext portletDataContext)
1037 throws Exception {
1038
1039
1040
1041 readXML(portletDataContext);
1042
1043 int buildNumber = ReleaseInfo.getBuildNumber();
1044
1045 int importBuildNumber = GetterUtil.getInteger(
1046 _headerElement.attributeValue("build-number"));
1047
1048 if (buildNumber != importBuildNumber) {
1049 throw new LayoutImportException(
1050 "LAR build number " + importBuildNumber + " does not match " +
1051 "portal build number " + buildNumber);
1052 }
1053
1054
1055
1056 String larType = _headerElement.attributeValue("type");
1057
1058 if (!larType.equals("layout-prototype") &&
1059 !larType.equals("layout-set") &&
1060 !larType.equals("layout-set-prototype")) {
1061
1062 throw new LARTypeException(larType);
1063 }
1064
1065
1066
1067 Locale[] sourceAvailableLocales = LocaleUtil.fromLanguageIds(
1068 StringUtil.split(
1069 _headerElement.attributeValue("available-locales")));
1070
1071 Locale[] targetAvailableLocales = LanguageUtil.getAvailableLocales(
1072 portletDataContext.getScopeGroupId());
1073
1074 for (Locale sourceAvailableLocale : sourceAvailableLocales) {
1075 if (!ArrayUtil.contains(
1076 targetAvailableLocales, sourceAvailableLocale)) {
1077
1078 LocaleException le = new LocaleException(
1079 LocaleException.TYPE_EXPORT_IMPORT);
1080
1081 le.setSourceAvailableLocales(sourceAvailableLocales);
1082 le.setTargetAvailableLocales(targetAvailableLocales);
1083
1084 throw le;
1085 }
1086 }
1087
1088
1089
1090 validateLayoutPrototypes(
1091 portletDataContext.getCompanyId(), _layoutsElement,
1092 _layoutElements);
1093 }
1094
1095 protected void validateLayoutPrototypes(
1096 long companyId, Element layoutsElement,
1097 List<Element> layoutElements)
1098 throws Exception {
1099
1100 List<Tuple> missingLayoutPrototypes = new ArrayList<Tuple>();
1101
1102 String layoutSetPrototypeUuid = layoutsElement.attributeValue(
1103 "layout-set-prototype-uuid");
1104
1105 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
1106 try {
1107 LayoutSetPrototypeLocalServiceUtil.
1108 getLayoutSetPrototypeByUuidAndCompanyId(
1109 layoutSetPrototypeUuid, companyId);
1110 }
1111 catch (NoSuchLayoutSetPrototypeException nlspe) {
1112 String layoutSetPrototypeName = layoutsElement.attributeValue(
1113 "layout-set-prototype-name");
1114
1115 missingLayoutPrototypes.add(
1116 new Tuple(
1117 LayoutSetPrototype.class.getName(),
1118 layoutSetPrototypeUuid, layoutSetPrototypeName));
1119 }
1120 }
1121
1122 for (Element layoutElement : layoutElements) {
1123 String action = layoutElement.attributeValue("action");
1124
1125 if (action.equals(Constants.SKIP)) {
1126 continue;
1127 }
1128
1129 String layoutPrototypeUuid = GetterUtil.getString(
1130 layoutElement.attributeValue("layout-prototype-uuid"));
1131
1132 if (Validator.isNotNull(layoutPrototypeUuid)) {
1133 try {
1134 LayoutPrototypeLocalServiceUtil.
1135 getLayoutPrototypeByUuidAndCompanyId(
1136 layoutPrototypeUuid, companyId);
1137 }
1138 catch (NoSuchLayoutPrototypeException nslpe) {
1139 String layoutPrototypeName = GetterUtil.getString(
1140 layoutElement.attributeValue("layout-prototype-name"));
1141
1142 missingLayoutPrototypes.add(
1143 new Tuple(
1144 LayoutPrototype.class.getName(),
1145 layoutPrototypeUuid, layoutPrototypeName));
1146 }
1147 }
1148 }
1149
1150 if (!missingLayoutPrototypes.isEmpty()) {
1151 throw new LayoutPrototypeException(missingLayoutPrototypes);
1152 }
1153 }
1154
1155 private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1156
1157 private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1158 new MethodKey(ThemeLoaderFactory.class, "loadThemes"));
1159
1160 private DeletionSystemEventImporter _deletionSystemEventImporter =
1161 new DeletionSystemEventImporter();
1162 private Element _headerElement;
1163 private List<Element> _layoutElements;
1164 private Element _layoutsElement;
1165 private PermissionImporter _permissionImporter = new PermissionImporter();
1166 private PortletImporter _portletImporter = new PortletImporter();
1167 private Element _rootElement;
1168
1169 }