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