001
014
015 package com.liferay.portlet.layoutsadmin.lar;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.NoSuchLayoutException;
019 import com.liferay.portal.kernel.dao.orm.QueryUtil;
020 import com.liferay.portal.kernel.exception.PortalException;
021 import com.liferay.portal.kernel.json.JSONFactoryUtil;
022 import com.liferay.portal.kernel.json.JSONObject;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.spring.osgi.OSGiBeanProperties;
026 import com.liferay.portal.kernel.util.ArrayUtil;
027 import com.liferay.portal.kernel.util.CharPool;
028 import com.liferay.portal.kernel.util.Constants;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.ListUtil;
031 import com.liferay.portal.kernel.util.LocaleUtil;
032 import com.liferay.portal.kernel.util.MapUtil;
033 import com.liferay.portal.kernel.util.StringBundler;
034 import com.liferay.portal.kernel.util.StringPool;
035 import com.liferay.portal.kernel.util.StringUtil;
036 import com.liferay.portal.kernel.util.UnicodeProperties;
037 import com.liferay.portal.kernel.util.Validator;
038 import com.liferay.portal.kernel.xml.Element;
039 import com.liferay.portal.model.Group;
040 import com.liferay.portal.model.Image;
041 import com.liferay.portal.model.Layout;
042 import com.liferay.portal.model.LayoutBranch;
043 import com.liferay.portal.model.LayoutConstants;
044 import com.liferay.portal.model.LayoutFriendlyURL;
045 import com.liferay.portal.model.LayoutPrototype;
046 import com.liferay.portal.model.LayoutRevision;
047 import com.liferay.portal.model.LayoutSet;
048 import com.liferay.portal.model.LayoutStagingHandler;
049 import com.liferay.portal.model.LayoutTemplate;
050 import com.liferay.portal.model.LayoutTypePortlet;
051 import com.liferay.portal.model.LayoutTypePortletConstants;
052 import com.liferay.portal.model.adapter.StagedTheme;
053 import com.liferay.portal.model.adapter.impl.StagedThemeImpl;
054 import com.liferay.portal.service.GroupLocalServiceUtil;
055 import com.liferay.portal.service.ImageLocalServiceUtil;
056 import com.liferay.portal.service.LayoutFriendlyURLLocalServiceUtil;
057 import com.liferay.portal.service.LayoutLocalServiceUtil;
058 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
059 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
060 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
061 import com.liferay.portal.service.PortletLocalServiceUtil;
062 import com.liferay.portal.service.ResourceLocalServiceUtil;
063 import com.liferay.portal.service.ServiceContext;
064 import com.liferay.portal.service.ServiceContextThreadLocal;
065 import com.liferay.portal.service.impl.LayoutLocalServiceHelper;
066 import com.liferay.portal.util.PropsValues;
067 import com.liferay.portlet.exportimport.lar.BaseStagedModelDataHandler;
068 import com.liferay.portlet.exportimport.lar.ExportImportPathUtil;
069 import com.liferay.portlet.exportimport.lar.PortletDataContext;
070 import com.liferay.portlet.exportimport.lar.PortletDataException;
071 import com.liferay.portlet.exportimport.lar.PortletDataHandlerKeys;
072 import com.liferay.portlet.exportimport.lar.StagedModelDataHandlerUtil;
073 import com.liferay.portlet.exportimport.lar.StagedModelModifiedDateComparator;
074 import com.liferay.portlet.exportimport.staging.LayoutStagingUtil;
075 import com.liferay.portlet.exportimport.staging.StagingUtil;
076 import com.liferay.portlet.sites.util.SitesUtil;
077
078 import java.io.IOException;
079
080 import java.util.Date;
081 import java.util.HashMap;
082 import java.util.List;
083 import java.util.Locale;
084 import java.util.Map;
085
086
089 @OSGiBeanProperties
090 public class LayoutStagedModelDataHandler
091 extends BaseStagedModelDataHandler<Layout> {
092
093 public static final String[] CLASS_NAMES = {Layout.class.getName()};
094
095 @Override
096 public void deleteStagedModel(Layout layout) {
097 LayoutLocalServiceUtil.deleteLayout(layout);
098 }
099
100 @Override
101 public void deleteStagedModel(
102 String uuid, long groupId, String className, String extraData)
103 throws PortalException {
104
105 JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject(
106 extraData);
107
108 boolean privateLayout = extraDataJSONObject.getBoolean("privateLayout");
109
110 Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
111 uuid, groupId, privateLayout);
112
113 if (layout != null) {
114 deleteStagedModel(layout);
115 }
116 }
117
118 @Override
119 public List<Layout> fetchStagedModelsByUuidAndCompanyId(
120 String uuid, long companyId) {
121
122 return LayoutLocalServiceUtil.getLayoutsByUuidAndCompanyId(
123 uuid, companyId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
124 new StagedModelModifiedDateComparator<Layout>());
125 }
126
127 @Override
128 public String[] getClassNames() {
129 return CLASS_NAMES;
130 }
131
132 @Override
133 public String getDisplayName(Layout layout) {
134 return layout.getNameCurrentValue();
135 }
136
137 @Override
138 public Map<String, String> getReferenceAttributes(
139 PortletDataContext portletDataContext, Layout layout) {
140
141 Map<String, String> referenceAttributes = new HashMap<>();
142
143 referenceAttributes.put(
144 "private-layout", String.valueOf(layout.isPrivateLayout()));
145 referenceAttributes.put(
146 "layout-id", String.valueOf(layout.getLayoutId()));
147
148 return referenceAttributes;
149 }
150
151 @Override
152 public void importMissingReference(
153 PortletDataContext portletDataContext, Element referenceElement)
154 throws PortletDataException {
155
156 importMissingGroupReference(portletDataContext, referenceElement);
157
158 String uuid = referenceElement.attributeValue("uuid");
159
160 Map<Long, Long> groupIds =
161 (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
162 Group.class);
163
164 long groupId = GetterUtil.getLong(
165 referenceElement.attributeValue("group-id"));
166
167 groupId = MapUtil.getLong(groupIds, groupId);
168
169 boolean privateLayout = GetterUtil.getBoolean(
170 referenceElement.attributeValue("private-layout"));
171
172 Layout existingLayout = null;
173
174 existingLayout = fetchMissingReference(uuid, groupId, privateLayout);
175
176 Map<Long, Layout> layouts =
177 (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
178 Layout.class + ".layout");
179
180 long layoutId = GetterUtil.getLong(
181 referenceElement.attributeValue("layout-id"));
182
183 layouts.put(layoutId, existingLayout);
184
185 Map<Long, Long> layoutPlids =
186 (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
187 Layout.class);
188
189 long plid = GetterUtil.getLong(
190 referenceElement.attributeValue("class-pk"));
191
192 layoutPlids.put(plid, existingLayout.getPlid());
193 }
194
195 public void setLayoutLocalServiceHelper(
196 LayoutLocalServiceHelper layoutLocalServiceHelper) {
197
198 _layoutLocalServiceHelper = layoutLocalServiceHelper;
199 }
200
201 @Override
202 public boolean validateReference(
203 PortletDataContext portletDataContext, Element referenceElement) {
204
205 validateMissingGroupReference(portletDataContext, referenceElement);
206
207 String uuid = referenceElement.attributeValue("uuid");
208
209 Map<Long, Long> groupIds =
210 (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
211 Group.class);
212
213 long groupId = GetterUtil.getLong(
214 referenceElement.attributeValue("group-id"));
215
216 groupId = MapUtil.getLong(groupIds, groupId);
217
218 boolean privateLayout = GetterUtil.getBoolean(
219 referenceElement.attributeValue("private-layout"));
220
221 Layout existingLayout = fetchMissingReference(
222 uuid, groupId, privateLayout);
223
224 if (existingLayout == null) {
225 return false;
226 }
227
228 return true;
229 }
230
231 protected String[] appendPortletIds(
232 String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
233
234 for (String portletId : newPortletIds) {
235 if (ArrayUtil.contains(portletIds, portletId)) {
236 continue;
237 }
238
239 if (portletsMergeMode.equals(
240 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
241
242 portletIds = ArrayUtil.append(portletIds, portletId);
243 }
244 else {
245 portletIds = ArrayUtil.append(
246 new String[] {portletId}, portletIds);
247 }
248 }
249
250 return portletIds;
251 }
252
253 @Override
254 protected void doExportStagedModel(
255 PortletDataContext portletDataContext, Layout layout)
256 throws Exception {
257
258 Element layoutElement = portletDataContext.getExportDataElement(layout);
259
260 populateElementLayoutMetadata(layoutElement, layout);
261
262 layoutElement.addAttribute(Constants.ACTION, Constants.ADD);
263
264 portletDataContext.setPlid(layout.getPlid());
265
266 long parentLayoutId = layout.getParentLayoutId();
267
268 if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
269 Layout parentLayout = LayoutLocalServiceUtil.fetchLayout(
270 layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
271
272 if (parentLayout != null) {
273 StagedModelDataHandlerUtil.exportReferenceStagedModel(
274 portletDataContext, layout, parentLayout,
275 PortletDataContext.REFERENCE_TYPE_PARENT);
276
277 layoutElement.addAttribute(
278 "parent-layout-uuid", parentLayout.getUuid());
279 }
280 }
281
282 List<LayoutFriendlyURL> layoutFriendlyURLs =
283 LayoutFriendlyURLLocalServiceUtil.getLayoutFriendlyURLs(
284 layout.getPlid());
285
286 for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
287 StagedModelDataHandlerUtil.exportReferenceStagedModel(
288 portletDataContext, layout, layoutFriendlyURL,
289 PortletDataContext.REFERENCE_TYPE_DEPENDENCY);
290 }
291
292 if (layout.isIconImage()) {
293 exportLayoutIconImage(portletDataContext, layout, layoutElement);
294 }
295
296 if (layout.isTypeLinkToLayout()) {
297 exportLinkedLayout(portletDataContext, layout, layoutElement);
298 }
299
300 fixExportTypeSettings(layout);
301
302 exportTheme(portletDataContext, layout);
303
304 portletDataContext.addClassedModel(
305 layoutElement, ExportImportPathUtil.getModelPath(layout), layout);
306 }
307
308 @Override
309 protected void doImportStagedModel(
310 PortletDataContext portletDataContext, Layout layout)
311 throws Exception {
312
313 long groupId = portletDataContext.getGroupId();
314 long userId = portletDataContext.getUserId(layout.getUserUuid());
315
316 Element layoutElement =
317 portletDataContext.getImportDataStagedModelElement(layout);
318
319 String layoutUuid = GetterUtil.getString(
320 layoutElement.attributeValue("layout-uuid"));
321
322 long layoutId = GetterUtil.getInteger(
323 layoutElement.attributeValue("layout-id"));
324
325 long oldLayoutId = layoutId;
326
327 boolean privateLayout = portletDataContext.isPrivateLayout();
328
329 String action = layoutElement.attributeValue(Constants.ACTION);
330
331 if (action.equals(Constants.DELETE)) {
332 Layout deletingLayout =
333 LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
334 layoutUuid, groupId, privateLayout);
335
336 LayoutLocalServiceUtil.deleteLayout(
337 deletingLayout, false,
338 ServiceContextThreadLocal.getServiceContext());
339
340 return;
341 }
342
343 Map<Long, Layout> layouts =
344 (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
345 Layout.class + ".layout");
346
347 Layout existingLayout = null;
348 Layout importedLayout = null;
349
350 String friendlyURL = layout.getFriendlyURL();
351
352 String layoutsImportMode = MapUtil.getString(
353 portletDataContext.getParameterMap(),
354 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
355 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
356
357 if (layoutsImportMode.equals(
358 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
359
360 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
361 groupId, privateLayout);
362 friendlyURL = StringPool.SLASH + layoutId;
363 }
364 else if (layoutsImportMode.equals(
365 PortletDataHandlerKeys.
366 LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
367
368 Locale locale = LocaleUtil.getSiteDefault();
369
370 String localizedName = layout.getName(locale);
371
372 List<Layout> previousLayouts = LayoutLocalServiceUtil.getLayouts(
373 groupId, privateLayout);
374
375 for (Layout curLayout : previousLayouts) {
376 if (localizedName.equals(curLayout.getName(locale)) ||
377 friendlyURL.equals(curLayout.getFriendlyURL())) {
378
379 existingLayout = curLayout;
380
381 break;
382 }
383 }
384
385 if (existingLayout == null) {
386 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
387 groupId, privateLayout);
388
389 friendlyURL = getFriendlyURL(friendlyURL, layoutId);
390 }
391 }
392 else if (layoutsImportMode.equals(
393 PortletDataHandlerKeys.
394 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
395
396 existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
397 layout.getUuid(), groupId, privateLayout);
398
399 if (SitesUtil.isLayoutModifiedSinceLastMerge(existingLayout)) {
400 layouts.put(oldLayoutId, existingLayout);
401
402 return;
403 }
404
405 LayoutFriendlyURL layoutFriendlyURL =
406 LayoutFriendlyURLLocalServiceUtil.fetchFirstLayoutFriendlyURL(
407 groupId, privateLayout, friendlyURL);
408
409 if ((layoutFriendlyURL != null) && (existingLayout == null)) {
410 Layout mergeFailFriendlyURLLayout =
411 LayoutLocalServiceUtil.getLayout(
412 layoutFriendlyURL.getPlid());
413
414 SitesUtil.addMergeFailFriendlyURLLayout(
415 mergeFailFriendlyURLLayout);
416
417 if (!_log.isWarnEnabled()) {
418 return;
419 }
420
421 StringBundler sb = new StringBundler(6);
422
423 sb.append("Layout with layout ID ");
424 sb.append(layout.getLayoutId());
425 sb.append(" cannot be propagated because the friendly URL ");
426 sb.append("conflicts with the friendly URL of layout with ");
427 sb.append("layout ID ");
428 sb.append(mergeFailFriendlyURLLayout.getLayoutId());
429
430 _log.warn(sb.toString());
431
432 return;
433 }
434 }
435 else {
436
437
438
439
440 existingLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
441 layout.getUuid(), groupId, privateLayout);
442
443 if (existingLayout == null) {
444 existingLayout =
445 LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
446 groupId, privateLayout, friendlyURL);
447 }
448
449 if (existingLayout == null) {
450 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
451 groupId, privateLayout);
452
453 friendlyURL = getFriendlyURL(friendlyURL, layoutId);
454 }
455 }
456
457 if (_log.isDebugEnabled()) {
458 StringBundler sb = new StringBundler(7);
459
460 sb.append("Layout with {groupId=");
461 sb.append(groupId);
462 sb.append(",privateLayout=");
463 sb.append(privateLayout);
464 sb.append(",layoutId=");
465 sb.append(layoutId);
466
467 if (existingLayout == null) {
468 sb.append("} does not exist");
469
470 _log.debug(sb.toString());
471 }
472 else {
473 sb.append("} exists");
474
475 _log.debug(sb.toString());
476 }
477 }
478
479 if (existingLayout == null) {
480 long plid = CounterLocalServiceUtil.increment();
481
482 importedLayout = LayoutLocalServiceUtil.createLayout(plid);
483
484 if (layoutsImportMode.equals(
485 PortletDataHandlerKeys.
486 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
487
488 importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
489
490 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
491 groupId, privateLayout);
492
493 friendlyURL = getFriendlyURL(friendlyURL, layoutId);
494 }
495 else {
496 importedLayout.setCreateDate(layout.getCreateDate());
497 importedLayout.setModifiedDate(layout.getModifiedDate());
498 importedLayout.setLayoutPrototypeUuid(
499 layout.getLayoutPrototypeUuid());
500 importedLayout.setLayoutPrototypeLinkEnabled(
501 layout.isLayoutPrototypeLinkEnabled());
502 importedLayout.setSourcePrototypeLayoutUuid(
503 layout.getSourcePrototypeLayoutUuid());
504 }
505
506 importedLayout.setUuid(layout.getUuid());
507 importedLayout.setGroupId(groupId);
508 importedLayout.setUserId(userId);
509 importedLayout.setPrivateLayout(privateLayout);
510 importedLayout.setLayoutId(layoutId);
511
512 initNewLayoutPermissions(
513 portletDataContext.getCompanyId(), groupId, userId, layout,
514 importedLayout, privateLayout);
515
516 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
517 groupId, privateLayout);
518
519 importedLayout.setLayoutSet(layoutSet);
520 }
521 else {
522 importedLayout = existingLayout;
523 }
524
525 portletDataContext.setPlid(importedLayout.getPlid());
526 portletDataContext.setOldPlid(layout.getPlid());
527
528 long parentLayoutId = layout.getParentLayoutId();
529
530 String parentLayoutUuid = GetterUtil.getString(
531 layoutElement.attributeValue("parent-layout-uuid"));
532
533 Element parentLayoutElement =
534 portletDataContext.getReferenceDataElement(
535 layout, Layout.class, layout.getGroupId(), parentLayoutUuid);
536
537 if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
538 (parentLayoutElement != null)) {
539
540 StagedModelDataHandlerUtil.importStagedModel(
541 portletDataContext, parentLayoutElement);
542
543 Layout importedParentLayout = layouts.get(parentLayoutId);
544
545 parentLayoutId = importedParentLayout.getLayoutId();
546 }
547
548 if (_log.isDebugEnabled()) {
549 StringBundler sb = new StringBundler(4);
550
551 sb.append("Importing layout with layout id ");
552 sb.append(layoutId);
553 sb.append(" and parent layout id ");
554 sb.append(parentLayoutId);
555
556 _log.debug(sb.toString());
557 }
558
559 importedLayout.setCompanyId(portletDataContext.getCompanyId());
560
561 if (layout.getLayoutPrototypeUuid() != null) {
562 importedLayout.setModifiedDate(new Date());
563 }
564
565 importedLayout.setParentLayoutId(parentLayoutId);
566 importedLayout.setName(layout.getName());
567 importedLayout.setTitle(layout.getTitle());
568 importedLayout.setDescription(layout.getDescription());
569 importedLayout.setKeywords(layout.getKeywords());
570 importedLayout.setRobots(layout.getRobots());
571 importedLayout.setType(layout.getType());
572
573 String portletsMergeMode = MapUtil.getString(
574 portletDataContext.getParameterMap(),
575 PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
576 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
577
578 if (layout.isTypePortlet() &&
579 Validator.isNotNull(layout.getTypeSettings()) &&
580 !portletsMergeMode.equals(
581 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
582
583 mergePortlets(
584 importedLayout, layout.getTypeSettings(), portletsMergeMode);
585 }
586 else if (layout.isTypeLinkToLayout()) {
587 importLinkedLayout(
588 portletDataContext, layout, importedLayout, layoutElement,
589 layouts);
590 }
591 else {
592 updateTypeSettings(importedLayout, layout);
593 }
594
595 importedLayout.setHidden(layout.isHidden());
596 importedLayout.setFriendlyURL(
597 getUniqueFriendlyURL(
598 portletDataContext, importedLayout, friendlyURL));
599
600 if (layout.getIconImageId() > 0) {
601 importLayoutIconImage(
602 portletDataContext, importedLayout, layoutElement);
603 }
604 else if (importedLayout.getIconImageId() > 0) {
605 ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
606 }
607
608 if (existingLayout == null) {
609 int priority = _layoutLocalServiceHelper.getNextPriority(
610 groupId, privateLayout, parentLayoutId, null, -1);
611
612 importedLayout.setPriority(priority);
613 }
614
615 importedLayout.setLayoutPrototypeUuid(layout.getLayoutPrototypeUuid());
616 importedLayout.setLayoutPrototypeLinkEnabled(
617 layout.isLayoutPrototypeLinkEnabled());
618
619 ServiceContext serviceContext = portletDataContext.createServiceContext(
620 layout);
621
622 importedLayout.setExpandoBridgeAttributes(serviceContext);
623
624 StagingUtil.updateLastImportSettings(
625 layoutElement, importedLayout, portletDataContext);
626
627 fixImportTypeSettings(importedLayout);
628
629 importTheme(portletDataContext, layout, importedLayout);
630
631 LayoutLocalServiceUtil.updateLayout(importedLayout);
632
633 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
634
635 Map<Long, Long> layoutPlids =
636 (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
637 Layout.class);
638
639 layoutPlids.put(layout.getPlid(), importedLayout.getPlid());
640
641 layouts.put(oldLayoutId, importedLayout);
642
643 importAssets(portletDataContext, layout, importedLayout);
644
645 importLayoutFriendlyURLs(portletDataContext, layout);
646
647 portletDataContext.importClassedModel(layout, importedLayout);
648 }
649
650 protected void exportLayoutIconImage(
651 PortletDataContext portletDataContext, Layout layout,
652 Element layoutElement)
653 throws Exception {
654
655 Image image = ImageLocalServiceUtil.getImage(layout.getIconImageId());
656
657 if (image != null) {
658 String iconPath = ExportImportPathUtil.getModelPath(
659 portletDataContext.getScopeGroupId(), Image.class.getName(),
660 image.getImageId());
661
662 Element iconImagePathElement = layoutElement.addElement(
663 "icon-image-path");
664
665 iconImagePathElement.addText(iconPath);
666
667 portletDataContext.addZipEntry(iconPath, image.getTextObj());
668 }
669 }
670
671 protected void exportLinkedLayout(
672 PortletDataContext portletDataContext, Layout layout,
673 Element layoutElement)
674 throws Exception {
675
676 UnicodeProperties typeSettingsProperties =
677 layout.getTypeSettingsProperties();
678
679 long linkToLayoutId = GetterUtil.getLong(
680 typeSettingsProperties.getProperty(
681 "linkToLayoutId", StringPool.BLANK));
682
683 if (linkToLayoutId > 0) {
684 try {
685 Layout linkedToLayout = LayoutLocalServiceUtil.getLayout(
686 portletDataContext.getScopeGroupId(),
687 layout.isPrivateLayout(), linkToLayoutId);
688
689 StagedModelDataHandlerUtil.exportReferenceStagedModel(
690 portletDataContext, layout, linkedToLayout,
691 PortletDataContext.REFERENCE_TYPE_STRONG);
692
693 layoutElement.addAttribute(
694 "linked-to-layout-uuid", linkedToLayout.getUuid());
695 }
696 catch (NoSuchLayoutException nsle) {
697 }
698 }
699 }
700
701 protected void exportTheme(
702 PortletDataContext portletDataContext, Layout layout)
703 throws Exception {
704
705 boolean exportThemeSettings = MapUtil.getBoolean(
706 portletDataContext.getParameterMap(),
707 PortletDataHandlerKeys.THEME_REFERENCE);
708
709 if (_log.isDebugEnabled()) {
710 _log.debug("Export theme settings " + exportThemeSettings);
711 }
712
713 if (exportThemeSettings &&
714 !portletDataContext.isPerformDirectBinaryImport() &&
715 !layout.isInheritLookAndFeel()) {
716
717 StagedTheme stagedTheme = new StagedThemeImpl(layout.getTheme());
718
719 Element layoutElement = portletDataContext.getExportDataElement(
720 layout);
721
722 portletDataContext.addReferenceElement(
723 layout, layoutElement, stagedTheme,
724 PortletDataContext.REFERENCE_TYPE_DEPENDENCY, true);
725 }
726 }
727
728 protected Object[] extractFriendlyURLInfo(Layout layout) {
729 if (!layout.isTypeURL()) {
730 return null;
731 }
732
733 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
734
735 String url = GetterUtil.getString(typeSettings.getProperty("url"));
736
737 String friendlyURLPrivateGroupPath =
738 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
739 String friendlyURLPrivateUserPath =
740 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
741 String friendlyURLPublicPath =
742 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
743
744 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
745 !url.startsWith(friendlyURLPrivateUserPath) &&
746 !url.startsWith(friendlyURLPublicPath)) {
747
748 return null;
749 }
750
751 int x = url.indexOf(CharPool.SLASH, 1);
752
753 if (x == -1) {
754 return null;
755 }
756
757 int y = url.indexOf(CharPool.SLASH, x + 1);
758
759 if (y == -1) {
760 return null;
761 }
762
763 return new Object[] {url.substring(x, y), url, x, y};
764 }
765
766 protected Layout fetchMissingReference(
767 String uuid, long groupId, boolean privateLayout) {
768
769
770
771 Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
772 uuid, groupId, privateLayout);
773
774 if (layout != null) {
775 return layout;
776 }
777
778 try {
779
780
781
782 Group originalGroup = GroupLocalServiceUtil.getGroup(groupId);
783
784 Group group = originalGroup.getParentGroup();
785
786 while (group != null) {
787 layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
788 uuid, group.getGroupId(), privateLayout);
789
790 if (layout != null) {
791 break;
792 }
793
794 group = group.getParentGroup();
795 }
796
797 if (layout == null) {
798 List<Layout> layouts = fetchStagedModelsByUuidAndCompanyId(
799 uuid, originalGroup.getCompanyId());
800
801 if (ListUtil.isEmpty(layouts)) {
802 return null;
803 }
804
805 layout = layouts.get(0);
806 }
807
808 return layout;
809 }
810 catch (Exception e) {
811 if (_log.isDebugEnabled()) {
812 _log.debug(e, e);
813 }
814 else if (_log.isWarnEnabled()) {
815 _log.warn(
816 "Unable to fetch missing reference layout from group " +
817 groupId);
818 }
819
820 return null;
821 }
822 }
823
824 protected void fixExportTypeSettings(Layout layout) throws Exception {
825 Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
826
827 if (friendlyURLInfo == null) {
828 return;
829 }
830
831 String friendlyURL = (String)friendlyURLInfo[0];
832
833 Group group = layout.getGroup();
834
835 String groupFriendlyURL = group.getFriendlyURL();
836
837 if (!friendlyURL.equals(groupFriendlyURL)) {
838 return;
839 }
840
841 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
842
843 String url = (String)friendlyURLInfo[1];
844
845 int x = (Integer)friendlyURLInfo[2];
846 int y = (Integer)friendlyURLInfo[3];
847
848 typeSettings.setProperty(
849 "url",
850 url.substring(0, x) + _SAME_GROUP_FRIENDLY_URL + url.substring(y));
851 }
852
853 protected void fixImportTypeSettings(Layout layout) throws Exception {
854 Object[] friendlyURLInfo = extractFriendlyURLInfo(layout);
855
856 if (friendlyURLInfo == null) {
857 return;
858 }
859
860 String friendlyURL = (String)friendlyURLInfo[0];
861
862 if (!friendlyURL.equals(_SAME_GROUP_FRIENDLY_URL)) {
863 return;
864 }
865
866 Group group = layout.getGroup();
867
868 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
869
870 String url = (String)friendlyURLInfo[1];
871
872 int x = (Integer)friendlyURLInfo[2];
873 int y = (Integer)friendlyURLInfo[3];
874
875 typeSettings.setProperty(
876 "url",
877 url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
878 }
879
880 protected String getFriendlyURL(String friendlyURL, long layoutId) {
881 if (!Validator.isNumber(friendlyURL.substring(1))) {
882 return friendlyURL;
883 }
884
885 return StringPool.SLASH + layoutId;
886 }
887
888 protected String getUniqueFriendlyURL(
889 PortletDataContext portletDataContext, Layout existingLayout,
890 String friendlyURL) {
891
892 for (int i = 1;; i++) {
893 Layout duplicateFriendlyURLLayout =
894 LayoutLocalServiceUtil.fetchLayoutByFriendlyURL(
895 portletDataContext.getGroupId(),
896 portletDataContext.isPrivateLayout(), friendlyURL);
897
898 if ((duplicateFriendlyURLLayout == null) ||
899 (duplicateFriendlyURLLayout.getPlid() ==
900 existingLayout.getPlid())) {
901
902 break;
903 }
904
905 friendlyURL = friendlyURL + i;
906 }
907
908 return friendlyURL;
909 }
910
911 protected void importAssets(
912 PortletDataContext portletDataContext, Layout layout,
913 Layout importedLayout)
914 throws Exception {
915
916 long userId = portletDataContext.getUserId(layout.getUserUuid());
917
918 long[] assetCategoryIds = portletDataContext.getAssetCategoryIds(
919 Layout.class, layout.getPlid());
920 String[] assetTagNames = portletDataContext.getAssetTagNames(
921 Layout.class, layout.getPlid());
922
923 LayoutLocalServiceUtil.updateAsset(
924 userId, importedLayout, assetCategoryIds, assetTagNames);
925 }
926
927 protected void importLayoutFriendlyURLs(
928 PortletDataContext portletDataContext, Layout layout)
929 throws Exception {
930
931 List<Element> layoutFriendlyURLElements =
932 portletDataContext.getReferenceDataElements(
933 layout, LayoutFriendlyURL.class);
934
935 for (Element layoutFriendlyURLElement : layoutFriendlyURLElements) {
936 String layoutFriendlyURLPath =
937 layoutFriendlyURLElement.attributeValue("path");
938
939 LayoutFriendlyURL layoutFriendlyURL =
940 (LayoutFriendlyURL)portletDataContext.getZipEntryAsObject(
941 layoutFriendlyURLPath);
942
943 StagedModelDataHandlerUtil.importStagedModel(
944 portletDataContext, layoutFriendlyURL);
945 }
946 }
947
948 protected void importLayoutIconImage(
949 PortletDataContext portletDataContext, Layout importedLayout,
950 Element layoutElement)
951 throws Exception {
952
953 String iconImagePath = layoutElement.elementText("icon-image-path");
954
955 byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
956 iconImagePath);
957
958 if (ArrayUtil.isNotEmpty(iconBytes)) {
959 if (importedLayout.getIconImageId() == 0) {
960 long iconImageId = CounterLocalServiceUtil.increment();
961
962 importedLayout.setIconImageId(iconImageId);
963 }
964
965 ImageLocalServiceUtil.updateImage(
966 importedLayout.getIconImageId(), iconBytes);
967 }
968 }
969
970 protected void importLinkedLayout(
971 PortletDataContext portletDataContext, Layout layout,
972 Layout importedLayout, Element layoutElement,
973 Map<Long, Layout> layouts)
974 throws Exception {
975
976 UnicodeProperties typeSettingsProperties =
977 layout.getTypeSettingsProperties();
978
979 long linkToLayoutId = GetterUtil.getLong(
980 typeSettingsProperties.getProperty(
981 "linkToLayoutId", StringPool.BLANK));
982
983 String linkedToLayoutUuid = layoutElement.attributeValue(
984 "linked-to-layout-uuid");
985
986 if (Validator.isNull(linkedToLayoutUuid)) {
987 return;
988 }
989
990 if (linkToLayoutId <= 0) {
991 updateTypeSettings(importedLayout, layout);
992
993 return;
994 }
995
996 Element linkedToLayoutElement =
997 portletDataContext.getReferenceDataElement(
998 layout, Layout.class, layout.getGroupId(), linkedToLayoutUuid);
999
1000 if (linkedToLayoutElement != null) {
1001 String linkedToLayoutPath = linkedToLayoutElement.attributeValue(
1002 "path");
1003
1004 Layout linkedToLayout =
1005 (Layout)portletDataContext.getZipEntryAsObject(
1006 linkedToLayoutPath);
1007
1008 StagedModelDataHandlerUtil.importStagedModel(
1009 portletDataContext, linkedToLayout);
1010
1011 Layout importedLinkedLayout = layouts.get(linkToLayoutId);
1012
1013 typeSettingsProperties.setProperty(
1014 "privateLayout",
1015 String.valueOf(importedLinkedLayout.isPrivateLayout()));
1016 typeSettingsProperties.setProperty(
1017 "linkToLayoutId",
1018 String.valueOf(importedLinkedLayout.getLayoutId()));
1019 }
1020 else {
1021 if (_log.isWarnEnabled()) {
1022 StringBundler sb = new StringBundler(6);
1023
1024 sb.append("Unable to link layout with friendly URL ");
1025 sb.append(layout.getFriendlyURL());
1026 sb.append(" and layout id ");
1027 sb.append(layout.getLayoutId());
1028 sb.append(" to layout with layout id ");
1029 sb.append(linkToLayoutId);
1030
1031 _log.warn(sb.toString());
1032 }
1033 }
1034
1035 updateTypeSettings(importedLayout, layout);
1036 }
1037
1038 @Override
1039 protected void importReferenceStagedModels(
1040 PortletDataContext portletDataContext, Layout layout) {
1041 }
1042
1043 protected void importTheme(
1044 PortletDataContext portletDataContext, Layout layout,
1045 Layout importedLayout)
1046 throws Exception {
1047
1048 boolean importThemeSettings = MapUtil.getBoolean(
1049 portletDataContext.getParameterMap(),
1050 PortletDataHandlerKeys.THEME_REFERENCE);
1051
1052 if (_log.isDebugEnabled()) {
1053 _log.debug("Import theme settings " + importThemeSettings);
1054 }
1055
1056 if (importThemeSettings) {
1057 importedLayout.setColorSchemeId(layout.getColorSchemeId());
1058 importedLayout.setCss(layout.getCss());
1059 importedLayout.setThemeId(layout.getThemeId());
1060 importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
1061 importedLayout.setWapThemeId(layout.getWapThemeId());
1062 }
1063 else {
1064 importedLayout.setColorSchemeId(StringPool.BLANK);
1065 importedLayout.setCss(StringPool.BLANK);
1066 importedLayout.setThemeId(StringPool.BLANK);
1067 importedLayout.setWapColorSchemeId(StringPool.BLANK);
1068 importedLayout.setWapThemeId(StringPool.BLANK);
1069 }
1070 }
1071
1072 protected void initNewLayoutPermissions(
1073 long companyId, long groupId, long userId, Layout layout,
1074 Layout importedLayout, boolean privateLayout)
1075 throws Exception {
1076
1077 boolean addGroupPermissions = true;
1078
1079 Group group = importedLayout.getGroup();
1080
1081 if (privateLayout && group.isUser()) {
1082 addGroupPermissions = false;
1083 }
1084
1085 boolean addGuestPermissions = false;
1086
1087 if (!privateLayout || layout.isTypeControlPanel()) {
1088 addGuestPermissions = true;
1089 }
1090
1091 ResourceLocalServiceUtil.addResources(
1092 companyId, groupId, userId, Layout.class.getName(),
1093 importedLayout.getPlid(), false, addGroupPermissions,
1094 addGuestPermissions);
1095 }
1096
1097 protected void mergePortlets(
1098 Layout layout, String newTypeSettings, String portletsMergeMode) {
1099
1100 try {
1101 UnicodeProperties previousTypeSettingsProperties =
1102 layout.getTypeSettingsProperties();
1103
1104 LayoutTypePortlet previousLayoutType =
1105 (LayoutTypePortlet)layout.getLayoutType();
1106
1107 LayoutTemplate previousLayoutTemplate =
1108 previousLayoutType.getLayoutTemplate();
1109
1110 List<String> previousColumns = previousLayoutTemplate.getColumns();
1111
1112 UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1113 true);
1114
1115 newTypeSettingsProperties.load(newTypeSettings);
1116
1117 String layoutTemplateId = newTypeSettingsProperties.getProperty(
1118 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1119
1120 previousTypeSettingsProperties.setProperty(
1121 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1122 layoutTemplateId);
1123
1124 String nestedColumnIds = newTypeSettingsProperties.getProperty(
1125 LayoutTypePortletConstants.NESTED_COLUMN_IDS);
1126
1127 if (Validator.isNotNull(nestedColumnIds)) {
1128 previousTypeSettingsProperties.setProperty(
1129 LayoutTypePortletConstants.NESTED_COLUMN_IDS,
1130 nestedColumnIds);
1131
1132 String[] nestedColumnIdsArray = StringUtil.split(
1133 nestedColumnIds);
1134
1135 for (String nestedColumnId : nestedColumnIdsArray) {
1136 String nestedColumnValue =
1137 newTypeSettingsProperties.getProperty(nestedColumnId);
1138
1139 previousTypeSettingsProperties.setProperty(
1140 nestedColumnId, nestedColumnValue);
1141 }
1142 }
1143
1144 LayoutTemplate newLayoutTemplate =
1145 LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1146 layoutTemplateId, false, null);
1147
1148 String[] newPortletIds = new String[0];
1149
1150 for (String columnId : newLayoutTemplate.getColumns()) {
1151 String columnValue = newTypeSettingsProperties.getProperty(
1152 columnId);
1153
1154 String[] portletIds = StringUtil.split(columnValue);
1155
1156 if (!previousColumns.contains(columnId)) {
1157 newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1158 }
1159 else {
1160 String[] previousPortletIds = StringUtil.split(
1161 previousTypeSettingsProperties.getProperty(columnId));
1162
1163 portletIds = appendPortletIds(
1164 previousPortletIds, portletIds, portletsMergeMode);
1165
1166 previousTypeSettingsProperties.setProperty(
1167 columnId, StringUtil.merge(portletIds));
1168 }
1169 }
1170
1171
1172
1173 String columnId = previousColumns.get(0);
1174
1175 String[] portletIds = StringUtil.split(
1176 previousTypeSettingsProperties.getProperty(columnId));
1177
1178 appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1179
1180 previousTypeSettingsProperties.setProperty(
1181 columnId, StringUtil.merge(portletIds));
1182
1183 layout.setTypeSettings(previousTypeSettingsProperties.toString());
1184 }
1185 catch (IOException ioe) {
1186 layout.setTypeSettings(newTypeSettings);
1187 }
1188 }
1189
1190 protected void populateElementLayoutMetadata(
1191 Element layoutElement, Layout layout)
1192 throws Exception {
1193
1194 LayoutStagingHandler layoutStagingHandler =
1195 LayoutStagingUtil.getLayoutStagingHandler(layout);
1196
1197 if (layoutStagingHandler != null) {
1198 LayoutRevision layoutRevision =
1199 layoutStagingHandler.getLayoutRevision();
1200
1201 if (layoutRevision != null) {
1202 layoutElement.addAttribute(
1203 "layout-revision-id",
1204 String.valueOf(layoutRevision.getLayoutRevisionId()));
1205 layoutElement.addAttribute(
1206 "layout-branch-id",
1207 String.valueOf(layoutRevision.getLayoutBranchId()));
1208
1209 LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
1210
1211 layoutElement.addAttribute(
1212 "layout-branch-name",
1213 String.valueOf(layoutBranch.getName()));
1214 }
1215 }
1216
1217 layoutElement.addAttribute("layout-uuid", layout.getUuid());
1218 layoutElement.addAttribute(
1219 "layout-id", String.valueOf(layout.getLayoutId()));
1220 layoutElement.addAttribute(
1221 "layout-priority", String.valueOf(layout.getPriority()));
1222
1223 String layoutPrototypeUuid = layout.getLayoutPrototypeUuid();
1224
1225 if (Validator.isNotNull(layoutPrototypeUuid)) {
1226 LayoutPrototype layoutPrototype =
1227 LayoutPrototypeLocalServiceUtil.
1228 getLayoutPrototypeByUuidAndCompanyId(
1229 layoutPrototypeUuid, layout.getCompanyId());
1230
1231 layoutElement.addAttribute(
1232 "layout-prototype-uuid", layoutPrototypeUuid);
1233 layoutElement.addAttribute(
1234 "layout-prototype-name",
1235 layoutPrototype.getName(LocaleUtil.getDefault()));
1236 }
1237 }
1238
1239 protected void updateTypeSettings(Layout importedLayout, Layout layout)
1240 throws PortalException {
1241
1242 long groupId = layout.getGroupId();
1243
1244 try {
1245 LayoutTypePortlet importedLayoutType =
1246 (LayoutTypePortlet)importedLayout.getLayoutType();
1247
1248 List<String> importedPortletIds =
1249 importedLayoutType.getPortletIds();
1250
1251 layout.setGroupId(importedLayout.getGroupId());
1252
1253 LayoutTypePortlet layoutTypePortlet =
1254 (LayoutTypePortlet)layout.getLayoutType();
1255
1256 importedPortletIds.removeAll(layoutTypePortlet.getPortletIds());
1257
1258 if (!importedPortletIds.isEmpty()) {
1259 PortletLocalServiceUtil.deletePortlets(
1260 importedLayout.getCompanyId(),
1261 importedPortletIds.toArray(
1262 new String[importedPortletIds.size()]),
1263 importedLayout.getPlid());
1264 }
1265
1266 importedLayout.setTypeSettingsProperties(
1267 layoutTypePortlet.getTypeSettingsProperties());
1268 }
1269 finally {
1270 layout.setGroupId(groupId);
1271 }
1272 }
1273
1274 private static final String _SAME_GROUP_FRIENDLY_URL =
1275 "/[$SAME_GROUP_FRIENDLY_URL$]";
1276
1277 private static final Log _log = LogFactoryUtil.getLog(
1278 LayoutStagedModelDataHandler.class);
1279
1280 private static LayoutLocalServiceHelper _layoutLocalServiceHelper;
1281
1282 }