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