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