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