001
014
015 package com.liferay.portlet.dynamicdatamapping.lar;
016
017 import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
018 import com.liferay.portal.kernel.dao.orm.DynamicQuery;
019 import com.liferay.portal.kernel.exception.PortalException;
020 import com.liferay.portal.kernel.lar.BasePortletDataHandler;
021 import com.liferay.portal.kernel.lar.ExportImportPathUtil;
022 import com.liferay.portal.kernel.lar.PortletDataContext;
023 import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
024 import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.repository.model.FileEntry;
028 import com.liferay.portal.kernel.util.ArrayUtil;
029 import com.liferay.portal.kernel.util.CharPool;
030 import com.liferay.portal.kernel.util.GetterUtil;
031 import com.liferay.portal.kernel.util.HttpUtil;
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.Validator;
037 import com.liferay.portal.kernel.xml.Element;
038 import com.liferay.portal.model.Group;
039 import com.liferay.portal.model.Layout;
040 import com.liferay.portal.model.RepositoryEntry;
041 import com.liferay.portal.repository.liferayrepository.model.LiferayFileEntry;
042 import com.liferay.portal.service.GroupLocalServiceUtil;
043 import com.liferay.portal.service.LayoutLocalServiceUtil;
044 import com.liferay.portal.util.PortalUtil;
045 import com.liferay.portal.util.PortletKeys;
046 import com.liferay.portal.util.PropsValues;
047 import com.liferay.portlet.documentlibrary.model.DLFileEntry;
048 import com.liferay.portlet.documentlibrary.service.DLAppLocalServiceUtil;
049 import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
050 import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
051 import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
052 import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
053 import com.liferay.portlet.dynamicdatamapping.service.DDMTemplateLocalServiceUtil;
054 import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMStructureActionableDynamicQuery;
055 import com.liferay.portlet.dynamicdatamapping.service.persistence.DDMTemplateActionableDynamicQuery;
056
057 import java.util.ArrayList;
058 import java.util.HashMap;
059 import java.util.List;
060 import java.util.Map;
061 import java.util.regex.Matcher;
062 import java.util.regex.Pattern;
063
064 import javax.portlet.PortletPreferences;
065
066
070 public class DDMPortletDataHandler extends BasePortletDataHandler {
071
072 public static final String NAMESPACE = "dynamic_data_mapping";
073
074 public static String exportReferencedContent(
075 PortletDataContext portletDataContext,
076 Element dlFileEntryTypesElement, Element dlFoldersElement,
077 Element dlFileEntriesElement, Element dlFileRanksElement,
078 Element dlRepositoriesElement, Element dlRepositoryEntriesElement,
079 Element entityElement, String content)
080 throws Exception {
081
082 content = exportDLFileEntries(
083 portletDataContext, dlFileEntryTypesElement, dlFoldersElement,
084 dlFileEntriesElement, dlFileRanksElement, dlRepositoriesElement,
085 dlRepositoryEntriesElement, entityElement, content, false);
086 content = exportLayoutFriendlyURLs(portletDataContext, content);
087 content = exportLinksToLayout(portletDataContext, content);
088
089 String entityElementName = entityElement.getName();
090
091 if (!entityElementName.equals("article")) {
092 content = StringUtil.replace(
093 content, StringPool.AMPERSAND_ENCODED, StringPool.AMPERSAND);
094 }
095
096 return content;
097 }
098
099 public DDMPortletDataHandler() {
100 setAlwaysExportable(true);
101 setDataLocalized(true);
102 setExportControls(
103 new PortletDataHandlerBoolean(NAMESPACE, "structures", true, true),
104 new PortletDataHandlerBoolean(NAMESPACE, "templates"));
105 }
106
107 protected static String exportDLFileEntries(
108 PortletDataContext portletDataContext,
109 Element dlFileEntryTypesElement, Element dlFoldersElement,
110 Element dlFileEntriesElement, Element dlFileRanksElement,
111 Element dlRepositoriesElement, Element dlRepositoryEntriesElement,
112 Element entityElement, String content, boolean checkDateRange)
113 throws Exception {
114
115 Group group = GroupLocalServiceUtil.getGroup(
116 portletDataContext.getGroupId());
117
118 if (group.isStagingGroup()) {
119 group = group.getLiveGroup();
120 }
121
122 if (group.isStaged() && !group.isStagedRemotely() &&
123 !group.isStagedPortlet(PortletKeys.DOCUMENT_LIBRARY)) {
124
125 return content;
126 }
127
128 StringBuilder sb = new StringBuilder(content);
129
130 int beginPos = content.length();
131 int currentLocation = -1;
132
133 boolean legacyURL = true;
134
135 while (true) {
136 String contextPath = PortalUtil.getPathContext();
137
138 currentLocation = content.lastIndexOf(
139 contextPath.concat("/c/document_library/get_file?"), beginPos);
140
141 if (currentLocation == -1) {
142 currentLocation = content.lastIndexOf(
143 contextPath.concat("/image/image_gallery?"), beginPos);
144 }
145
146 if (currentLocation == -1) {
147 currentLocation = content.lastIndexOf(
148 contextPath.concat("/documents/"), beginPos);
149
150 legacyURL = false;
151 }
152
153 if (currentLocation == -1) {
154 return sb.toString();
155 }
156
157 beginPos = currentLocation + contextPath.length();
158
159 int endPos1 = content.indexOf(CharPool.APOSTROPHE, beginPos);
160 int endPos2 = content.indexOf(CharPool.CLOSE_BRACKET, beginPos);
161 int endPos3 = content.indexOf(CharPool.CLOSE_CURLY_BRACE, beginPos);
162 int endPos4 = content.indexOf(CharPool.CLOSE_PARENTHESIS, beginPos);
163 int endPos5 = content.indexOf(CharPool.LESS_THAN, beginPos);
164 int endPos6 = content.indexOf(CharPool.QUESTION, beginPos);
165 int endPos7 = content.indexOf(CharPool.QUOTE, beginPos);
166 int endPos8 = content.indexOf(CharPool.SPACE, beginPos);
167
168 int endPos = endPos1;
169
170 if ((endPos == -1) || ((endPos2 != -1) && (endPos2 < endPos))) {
171 endPos = endPos2;
172 }
173
174 if ((endPos == -1) || ((endPos3 != -1) && (endPos3 < endPos))) {
175 endPos = endPos3;
176 }
177
178 if ((endPos == -1) || ((endPos4 != -1) && (endPos4 < endPos))) {
179 endPos = endPos4;
180 }
181
182 if ((endPos == -1) || ((endPos5 != -1) && (endPos5 < endPos))) {
183 endPos = endPos5;
184 }
185
186 if ((endPos == -1) ||
187 ((endPos6 != -1) && (endPos6 < endPos) && !legacyURL)) {
188
189 endPos = endPos6;
190 }
191
192 if ((endPos == -1) || ((endPos7 != -1) && (endPos7 < endPos))) {
193 endPos = endPos7;
194 }
195
196 if ((endPos == -1) || ((endPos8 != -1) && (endPos8 < endPos))) {
197 endPos = endPos8;
198 }
199
200 if ((beginPos == -1) || (endPos == -1)) {
201 break;
202 }
203
204 try {
205 String oldParameters = content.substring(beginPos, endPos);
206
207 while (oldParameters.contains(StringPool.AMPERSAND_ENCODED)) {
208 oldParameters = oldParameters.replace(
209 StringPool.AMPERSAND_ENCODED, StringPool.AMPERSAND);
210 }
211
212 Map<String, String[]> map = new HashMap<String, String[]>();
213
214 if (oldParameters.startsWith("/documents/")) {
215 String[] pathArray = oldParameters.split(StringPool.SLASH);
216
217 map.put("groupId", new String[] {pathArray[2]});
218
219 if (pathArray.length == 4) {
220 map.put("uuid", new String[] {pathArray[3]});
221 }
222 else if (pathArray.length == 5) {
223 map.put("folderId", new String[] {pathArray[3]});
224
225 String title = HttpUtil.decodeURL(pathArray[4]);
226
227 int pos = title.indexOf(StringPool.QUESTION);
228
229 if (pos != -1) {
230 title = title.substring(0, pos);
231 }
232
233 map.put("title", new String[] {title});
234 }
235 else if (pathArray.length > 5) {
236 String uuid = pathArray[5];
237
238 int pos = uuid.indexOf(StringPool.QUESTION);
239
240 if (pos != -1) {
241 uuid = uuid.substring(0, pos);
242 }
243
244 map.put("uuid", new String[] {uuid});
245 }
246 }
247 else {
248 oldParameters = oldParameters.substring(
249 oldParameters.indexOf(CharPool.QUESTION) + 1);
250
251 map = HttpUtil.parameterMapFromString(oldParameters);
252 }
253
254 FileEntry fileEntry = null;
255
256 String uuid = MapUtil.getString(map, "uuid");
257
258 if (Validator.isNotNull(uuid)) {
259 String groupIdString = MapUtil.getString(map, "groupId");
260
261 long groupId = GetterUtil.getLong(groupIdString);
262
263 if (groupIdString.equals("@group_id@")) {
264 groupId = portletDataContext.getScopeGroupId();
265 }
266
267 fileEntry =
268 DLAppLocalServiceUtil.getFileEntryByUuidAndGroupId(
269 uuid, groupId);
270 }
271 else {
272 String folderIdString = MapUtil.getString(map, "folderId");
273
274 if (Validator.isNotNull(folderIdString)) {
275 long folderId = GetterUtil.getLong(folderIdString);
276 String name = MapUtil.getString(map, "name");
277 String title = MapUtil.getString(map, "title");
278
279 String groupIdString = MapUtil.getString(
280 map, "groupId");
281
282 long groupId = GetterUtil.getLong(groupIdString);
283
284 if (groupIdString.equals("@group_id@")) {
285 groupId = portletDataContext.getScopeGroupId();
286 }
287
288 if (Validator.isNotNull(title)) {
289 fileEntry = DLAppLocalServiceUtil.getFileEntry(
290 groupId, folderId, title);
291 }
292 else {
293 DLFileEntry dlFileEntry =
294 DLFileEntryLocalServiceUtil.getFileEntryByName(
295 groupId, folderId, name);
296
297 fileEntry = new LiferayFileEntry(dlFileEntry);
298 }
299 }
300 else if (map.containsKey("image_id") ||
301 map.containsKey("img_id") ||
302 map.containsKey("i_id")) {
303
304 long imageId = MapUtil.getLong(map, "image_id");
305
306 if (imageId <= 0) {
307 imageId = MapUtil.getLong(map, "img_id");
308
309 if (imageId <= 0) {
310 imageId = MapUtil.getLong(map, "i_id");
311 }
312 }
313
314 DLFileEntry dlFileEntry =
315 DLFileEntryLocalServiceUtil.
316 fetchFileEntryByAnyImageId(imageId);
317
318 if (dlFileEntry != null) {
319 fileEntry = new LiferayFileEntry(dlFileEntry);
320 }
321 }
322 }
323
324 if (fileEntry == null) {
325 beginPos--;
326
327 continue;
328 }
329
330 beginPos = currentLocation;
331
332 StagedModelDataHandlerUtil.exportStagedModel(
333 portletDataContext, fileEntry);
334
335 Element dlReferenceElement = entityElement.addElement(
336 "dl-reference");
337
338 dlReferenceElement.addAttribute(
339 "default-repository",
340 String.valueOf(fileEntry.isDefaultRepository()));
341
342 String path = null;
343
344 if (fileEntry.isDefaultRepository()) {
345 path = ExportImportPathUtil.getModelPath(
346 (DLFileEntry)fileEntry.getModel());
347
348 }
349 else {
350 path = ExportImportPathUtil.getModelPath(
351 (RepositoryEntry)fileEntry.getModel());
352 }
353
354 dlReferenceElement.addAttribute("path", path);
355
356 String dlReference = "[$dl-reference=" + path + "$]";
357
358 sb.replace(beginPos, endPos, dlReference);
359 }
360 catch (Exception e) {
361 if (_log.isDebugEnabled()) {
362 _log.debug(e, e);
363 }
364 else if (_log.isWarnEnabled()) {
365 _log.warn(e.getMessage());
366 }
367 }
368
369 beginPos--;
370 }
371
372 return sb.toString();
373 }
374
375 protected static String exportLayoutFriendlyURLs(
376 PortletDataContext portletDataContext, String content) {
377
378 Group group = null;
379
380 try {
381 group = GroupLocalServiceUtil.getGroup(
382 portletDataContext.getScopeGroupId());
383 }
384 catch (Exception e) {
385 if (_log.isWarnEnabled()) {
386 _log.warn(e);
387 }
388
389 return content;
390 }
391
392 StringBuilder sb = new StringBuilder(content);
393
394 String privateGroupServletMapping =
395 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
396 String privateUserServletMapping =
397 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
398 String publicServletMapping =
399 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
400
401 String portalContextPath = PortalUtil.getPathContext();
402
403 if (Validator.isNotNull(portalContextPath)) {
404 privateGroupServletMapping = portalContextPath.concat(
405 privateGroupServletMapping);
406 privateUserServletMapping = portalContextPath.concat(
407 privateUserServletMapping);
408 publicServletMapping = portalContextPath.concat(
409 publicServletMapping);
410 }
411
412 String href = "href=";
413
414 int beginPos = content.length();
415
416 while (true) {
417 int hrefLength = href.length();
418
419 beginPos = content.lastIndexOf(href, beginPos);
420
421 if (beginPos == -1) {
422 break;
423 }
424
425 char c = content.charAt(beginPos + hrefLength);
426
427 if ((c == CharPool.APOSTROPHE) || (c == CharPool.QUOTE)) {
428 hrefLength++;
429 }
430
431 int endPos1 = content.indexOf(
432 CharPool.APOSTROPHE, beginPos + hrefLength);
433 int endPos2 = content.indexOf(
434 CharPool.CLOSE_BRACKET, beginPos + hrefLength);
435 int endPos3 = content.indexOf(
436 CharPool.CLOSE_CURLY_BRACE, beginPos + hrefLength);
437 int endPos4 = content.indexOf(
438 CharPool.CLOSE_PARENTHESIS, beginPos + hrefLength);
439 int endPos5 = content.indexOf(
440 CharPool.LESS_THAN, beginPos + hrefLength);
441 int endPos6 = content.indexOf(
442 CharPool.QUESTION, beginPos + hrefLength);
443 int endPos7 = content.indexOf(
444 CharPool.QUOTE, beginPos + hrefLength);
445 int endPos8 = content.indexOf(
446 CharPool.SPACE, beginPos + hrefLength);
447
448 int endPos = endPos1;
449
450 if ((endPos == -1) || ((endPos2 != -1) && (endPos2 < endPos))) {
451 endPos = endPos2;
452 }
453
454 if ((endPos == -1) || ((endPos3 != -1) && (endPos3 < endPos))) {
455 endPos = endPos3;
456 }
457
458 if ((endPos == -1) || ((endPos4 != -1) && (endPos4 < endPos))) {
459 endPos = endPos4;
460 }
461
462 if ((endPos == -1) || ((endPos5 != -1) && (endPos5 < endPos))) {
463 endPos = endPos5;
464 }
465
466 if ((endPos == -1) || ((endPos6 != -1) && (endPos6 < endPos))) {
467 endPos = endPos6;
468 }
469
470 if ((endPos == -1) || ((endPos7 != -1) && (endPos7 < endPos))) {
471 endPos = endPos7;
472 }
473
474 if ((endPos == -1) || ((endPos8 != -1) && (endPos8 < endPos))) {
475 endPos = endPos8;
476 }
477
478 if (endPos == -1) {
479 beginPos--;
480
481 continue;
482 }
483
484 String url = content.substring(beginPos + hrefLength, endPos);
485
486 if (!url.startsWith(privateGroupServletMapping) &&
487 !url.startsWith(privateUserServletMapping) &&
488 !url.startsWith(publicServletMapping)) {
489
490 beginPos--;
491
492 continue;
493 }
494
495 int contextLength = 0;
496
497 if (Validator.isNotNull(portalContextPath)) {
498 contextLength = portalContextPath.length();
499 }
500
501 int beginGroupPos = content.indexOf(
502 CharPool.SLASH, beginPos + hrefLength + contextLength + 1);
503
504 if (beginGroupPos == -1) {
505 beginPos--;
506
507 continue;
508 }
509
510 int endGroupPos = content.indexOf(
511 CharPool.SLASH, beginGroupPos + 1);
512
513 if (endGroupPos == -1) {
514 beginPos--;
515
516 continue;
517 }
518
519 String groupFriendlyURL = content.substring(
520 beginGroupPos, endGroupPos);
521
522 if (groupFriendlyURL.equals(group.getFriendlyURL())) {
523 sb.replace(
524 beginGroupPos, endGroupPos,
525 "@data_handler_group_friendly_url@");
526 }
527
528 String dataHandlerServletMapping = StringPool.BLANK;
529
530 if (url.startsWith(privateGroupServletMapping)) {
531 dataHandlerServletMapping =
532 "@data_handler_private_group_servlet_mapping@";
533 }
534 else if (url.startsWith(privateUserServletMapping)) {
535 dataHandlerServletMapping =
536 "@data_handler_private_user_servlet_mapping@";
537 }
538 else {
539 dataHandlerServletMapping =
540 "@data_handler_public_servlet_mapping@";
541 }
542
543 sb.replace(
544 beginPos + hrefLength, beginGroupPos,
545 dataHandlerServletMapping);
546
547 beginPos--;
548 }
549
550 return sb.toString();
551 }
552
553 protected static String exportLinksToLayout(
554 PortletDataContext portletDataContext, String content)
555 throws Exception {
556
557 List<String> oldLinksToLayout = new ArrayList<String>();
558 List<String> newLinksToLayout = new ArrayList<String>();
559
560 Matcher matcher = _exportLinksToLayoutPattern.matcher(content);
561
562 while (matcher.find()) {
563 long layoutId = GetterUtil.getLong(matcher.group(1));
564
565 String type = matcher.group(2);
566
567 boolean privateLayout = type.startsWith("private");
568
569 try {
570 Layout layout = LayoutLocalServiceUtil.getLayout(
571 portletDataContext.getScopeGroupId(), privateLayout,
572 layoutId);
573
574 String oldLinkToLayout = matcher.group(0);
575
576 StringBundler sb = new StringBundler(5);
577
578 sb.append(type);
579 sb.append(StringPool.AT);
580 sb.append(layout.getUuid());
581 sb.append(StringPool.AT);
582 sb.append(layout.getFriendlyURL());
583
584 String newLinkToLayout = StringUtil.replace(
585 oldLinkToLayout, type, sb.toString());
586
587 oldLinksToLayout.add(oldLinkToLayout);
588 newLinksToLayout.add(newLinkToLayout);
589 }
590 catch (Exception e) {
591 if (_log.isDebugEnabled() || _log.isWarnEnabled()) {
592 String message =
593 "Unable to get layout with ID " + layoutId +
594 " in group " + portletDataContext.getScopeGroupId();
595
596 if (_log.isWarnEnabled()) {
597 _log.warn(message);
598 }
599 else {
600 _log.debug(message, e);
601 }
602 }
603 }
604 }
605
606 content = StringUtil.replace(
607 content, ArrayUtil.toStringArray(oldLinksToLayout.toArray()),
608 ArrayUtil.toStringArray(newLinksToLayout.toArray()));
609
610 return content;
611 }
612
613 @Override
614 protected PortletPreferences doDeleteData(
615 PortletDataContext portletDataContext, String portletId,
616 PortletPreferences portletPreferences)
617 throws Exception {
618
619 if (portletDataContext.addPrimaryKey(
620 DDMPortletDataHandler.class, "deleteData")) {
621
622 return portletPreferences;
623 }
624
625 DDMTemplateLocalServiceUtil.deleteTemplates(
626 portletDataContext.getScopeGroupId());
627
628 DDMStructureLocalServiceUtil.deleteStructures(
629 portletDataContext.getScopeGroupId());
630
631 return portletPreferences;
632 }
633
634 @Override
635 protected String doExportData(
636 final PortletDataContext portletDataContext, String portletId,
637 PortletPreferences portletPreferences)
638 throws Exception {
639
640 portletDataContext.addPermissions(
641 "com.liferay.portlet.dynamicdatamapping",
642 portletDataContext.getScopeGroupId());
643
644 Element rootElement = addExportDataRootElement(portletDataContext);
645
646 rootElement.addAttribute(
647 "group-id", String.valueOf(portletDataContext.getScopeGroupId()));
648
649 ActionableDynamicQuery structureActionableDynamicQuery =
650 new DDMStructureActionableDynamicQuery() {
651
652 @Override
653 protected void addCriteria(DynamicQuery dynamicQuery) {
654 portletDataContext.addDateRangeCriteria(
655 dynamicQuery, "modifiedDate");
656 }
657
658 @Override
659 protected void performAction(Object object) throws PortalException {
660 DDMStructure structure = (DDMStructure)object;
661
662 StagedModelDataHandlerUtil.exportStagedModel(
663 portletDataContext, structure);
664 }
665
666 };
667
668 structureActionableDynamicQuery.setGroupId(
669 portletDataContext.getScopeGroupId());
670
671 structureActionableDynamicQuery.performActions();
672
673 ActionableDynamicQuery templateActionableDynamicQuery =
674 new DDMTemplateActionableDynamicQuery() {
675
676 @Override
677 protected void addCriteria(DynamicQuery dynamicQuery) {
678 portletDataContext.addDateRangeCriteria(
679 dynamicQuery, "modifiedDate");
680 }
681
682 @Override
683 protected void performAction(Object object) throws PortalException {
684 DDMTemplate template = (DDMTemplate)object;
685
686 StagedModelDataHandlerUtil.exportStagedModel(
687 portletDataContext, template);
688 }
689
690 };
691
692 templateActionableDynamicQuery.setGroupId(
693 portletDataContext.getScopeGroupId());
694
695 templateActionableDynamicQuery.performActions();
696
697 return getExportDataRootElementString(rootElement);
698 }
699
700 @Override
701 protected PortletPreferences doImportData(
702 PortletDataContext portletDataContext, String portletId,
703 PortletPreferences portletPreferences, String data)
704 throws Exception {
705
706 portletDataContext.importPermissions(
707 "com.liferay.portlet.dynamicdatamapping",
708 portletDataContext.getSourceGroupId(),
709 portletDataContext.getScopeGroupId());
710
711 Element structuresElement =
712 portletDataContext.getImportDataGroupElement(DDMStructure.class);
713
714 List<Element> structureElements = structuresElement.elements();
715
716 for (Element structureElement : structureElements) {
717 StagedModelDataHandlerUtil.importStagedModel(
718 portletDataContext, structureElement);
719 }
720
721 if (portletDataContext.getBooleanParameter(NAMESPACE, "templates")) {
722 Element templatesElement =
723 portletDataContext.getImportDataGroupElement(DDMTemplate.class);
724
725 List<Element> templateElements = templatesElement.elements();
726
727 for (Element templateElement : templateElements) {
728 StagedModelDataHandlerUtil.importStagedModel(
729 portletDataContext, templateElement);
730 }
731 }
732
733 return portletPreferences;
734 }
735
736 private static Log _log = LogFactoryUtil.getLog(
737 DDMPortletDataHandler.class);
738
739 private static Pattern _exportLinksToLayoutPattern = Pattern.compile(
740 "\\[([0-9]+)@(public|private\\-[a-z]*)\\]");
741
742 }