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