1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.jcr.wrapper;
35
36 import info.magnolia.cms.security.JCRSessionOp;
37 import info.magnolia.context.Context;
38 import info.magnolia.context.MgnlContext;
39 import info.magnolia.context.SystemContext;
40 import info.magnolia.jcr.decoration.ContentDecorator;
41 import info.magnolia.jcr.decoration.ContentDecoratorPropertyWrapper;
42 import info.magnolia.jcr.decoration.ContentDecoratorSessionWrapper;
43 import info.magnolia.jcr.decoration.ContentDecoratorWorkspaceWrapper;
44 import info.magnolia.jcr.util.NodeTypes;
45 import info.magnolia.jcr.util.NodeTypes.LastModified;
46 import info.magnolia.jcr.util.NodeUtil;
47 import info.magnolia.repository.RepositoryConstants;
48
49 import java.io.InputStream;
50 import java.math.BigDecimal;
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.LinkedList;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Stack;
57
58 import javax.jcr.AccessDeniedException;
59 import javax.jcr.Binary;
60 import javax.jcr.InvalidItemStateException;
61 import javax.jcr.ItemExistsException;
62 import javax.jcr.NoSuchWorkspaceException;
63 import javax.jcr.Node;
64 import javax.jcr.NodeIterator;
65 import javax.jcr.PathNotFoundException;
66 import javax.jcr.Property;
67 import javax.jcr.ReferentialIntegrityException;
68 import javax.jcr.RepositoryException;
69 import javax.jcr.Session;
70 import javax.jcr.Value;
71 import javax.jcr.ValueFormatException;
72 import javax.jcr.Workspace;
73 import javax.jcr.lock.LockException;
74 import javax.jcr.nodetype.ConstraintViolationException;
75 import javax.jcr.nodetype.NoSuchNodeTypeException;
76 import javax.jcr.version.VersionException;
77
78 import org.apache.commons.lang3.StringUtils;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 import com.google.common.collect.ImmutableList;
83 import com.google.common.collect.ImmutableMap;
84
85
86
87
88
89
90 public class MgnlPropertySettingContentDecorator extends PropertyAndChildWrappingContentDecorator implements ContentDecorator {
91
92
93
94
95
96 private class DirtyOp {
97
98 private String path;
99 private String userName;
100 private Calendar updateDate;
101
102 public DirtyOp(String path, String userName, Calendar updateDate) {
103 this.path = path;
104 this.userName = userName;
105 this.updateDate = updateDate;
106 }
107
108 public String getPath() {
109 return path;
110 }
111
112 public void setPath(String path) {
113 this.path = path;
114 }
115
116 public String getUserName() {
117 return userName;
118 }
119
120 public Calendar getUpdateDate() {
121 return updateDate;
122 }
123
124 }
125
126 private static final Logger log = LoggerFactory.getLogger(MgnlPropertySettingContentDecorator.class);
127
128
129
130
131 private static final ImmutableList<String> SPECIAL_PROPERTY_NAMES = ImmutableList.of(
132 NodeTypes.MGNL_PREFIX + "variantTitle",
133 NodeTypes.MGNL_PREFIX + "variationOf",
134 NodeTypes.MGNL_PREFIX + "assignedSegments",
135 NodeTypes.Renderable.TEMPLATE
136 );
137
138
139
140
141
142 private static Map<String, String> PARENT_NODE_MAPPINGS = ImmutableMap.of(RepositoryConstants.WEBSITE, NodeTypes.Page.NAME,
143 RepositoryConstants.USERS, NodeTypes.User.NAME);
144
145 protected List<DirtyOp> dirtyOps = new LinkedList<>();
146
147
148
149
150
151 final class ChangeLastUpdateDateOp extends MgnlContext.RepositoryOp {
152 private final String workspaceName;
153 private final String userName;
154 private final String destAbsPath;
155 private final Calendar updateDate;
156 private final boolean recursiveDown;
157
158 ChangeLastUpdateDateOp(String workspaceName, String userName, String destAbsPath, Calendar updateDate, boolean recursiveDown) {
159 this.workspaceName = workspaceName;
160 this.userName = userName;
161 this.destAbsPath = destAbsPath;
162 this.updateDate = updateDate;
163 this.recursiveDown = recursiveDown;
164 }
165
166 @Override
167 public void doExec() throws RepositoryException {
168 Session sysSession = MgnlContext.getJCRSession(workspaceName);
169
170
171 if (!sysSession.itemExists(destAbsPath)) {
172
173 if (log.isDebugEnabled()) {
174 log.warn("Can't update mgnl:lastModified. Path {}:{} doesn't exist anymore.", workspaceName, destAbsPath);
175 }
176 return;
177 }
178 String srcAbsPath = sysSession.getNode(destAbsPath).getPath();
179
180 Stack<Node> nodes = resolveNodesToModify(destAbsPath, sysSession);
181 Node node;
182 if (!nodes.isEmpty()) {
183 node = nodes.pop();
184 } else {
185
186 node = sysSession.getNode(destAbsPath);
187 }
188
189 if (node.isNodeType(NodeTypes.MetaData.NAME)) {
190
191 return;
192 }
193
194
195 if (node.getDepth() == 0) {
196 return;
197 }
198
199
200 if (node instanceof DelegateNodeWrapper) {
201 node = ((DelegateNodeWrapper) node).deepUnwrap(MgnlPropertySettingNodeWrapper.class);
202 }
203
204 log.debug("LUD on {} from {}:{}", node.getPath(), node.getSession().toString(), Thread.currentThread().getName());
205 if (node.isNodeType(LastModified.NAME)) {
206 String resolvedPath = node.getPath();
207 if (!destAbsPath.equals(srcAbsPath)) {
208
209 if (!resolvedPath.equals(srcAbsPath) && !resolvedPath.equals(destAbsPath)) {
210
211 if (srcAbsPath.startsWith(resolvedPath)) {
212 String hunk = StringUtils.substringAfter(srcAbsPath, resolvedPath);
213 if (destAbsPath.endsWith(hunk)) {
214 resolvedPath = StringUtils.substringBefore(destAbsPath, hunk);
215 }
216 } else {
217 resolvedPath = destAbsPath;
218 }
219 }
220 }
221
222 dirtyOps.add(new DirtyOp(resolvedPath, userName, updateDate));
223 }
224
225
226 while (!nodes.isEmpty()) {
227 Node child = nodes.pop();
228 if (child.isNodeType(LastModified.NAME)) {
229 dirtyOps.add(new DirtyOp(child.getPath(), userName, updateDate));
230 }
231 }
232
233 if (recursiveDown) {
234
235 List<NodeIterator> iters = new ArrayList<>();
236 iters.add(node.getNodes());
237 while (!iters.isEmpty()) {
238 List<NodeIterator> tmp = updateChildren(node.getPath(), destAbsPath, iters, updateDate);
239 iters.clear();
240 iters.addAll(tmp);
241 }
242 }
243
244
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259 private Stack<Node> resolveNodesToModify(String destAbsPath, Session sysSession) throws RepositoryException {
260 Stack<Node> nodeStack = new Stack<>();
261
262 String parentNodeType = PARENT_NODE_MAPPINGS.get(workspaceName);
263 Node node = sysSession.getNode(destAbsPath);
264 if (parentNodeType == null) {
265 return nodeStack;
266 }
267 while (node != null && !parentNodeType.equals(node.getPrimaryNodeType().getName()) && node.getDepth() > 0) {
268 nodeStack.add(node);
269 node = node.getParent();
270 }
271 nodeStack.add(node);
272 return nodeStack;
273 }
274
275 private List<NodeIterator> updateChildren(String srcAbsPath, String destAbsPath, List<NodeIterator> iters, Calendar updateDate) {
276 List<NodeIterator> tmp = new ArrayList<>();
277 for (NodeIterator iter : iters) {
278 while (iter.hasNext()) {
279 Node node = iter.nextNode();
280 try {
281 if (skipTypeInWorkspace(workspaceName, node.getPrimaryNodeType().getName())) {
282
283 continue;
284 }
285 if (node.isNodeType(NodeTypes.MetaData.NAME)) {
286
287 continue;
288 }
289 if (node.isNodeType(LastModified.NAME)) {
290 dirtyOps.add(new DirtyOp(destAbsPath + StringUtils.removeStart(node.getPath(), srcAbsPath), userName, updateDate));
291 }
292 tmp.add(node.getNodes());
293 } catch (RepositoryException e) {
294 log.error("Failed to update last modified date of {} with {}", node, e.getMessage(), e);
295 }
296 }
297 }
298 return tmp;
299 }
300
301 private boolean skipTypeInWorkspace(String workspaceName, String name) {
302 if (RepositoryConstants.USER_ROLES.equals(workspaceName)) {
303 return !(NodeTypes.Role.NAME.equals(name) || NodeTypes.Folder.NAME.equals(name));
304 }
305 if (RepositoryConstants.WEBSITE.equals(workspaceName)) {
306 return !NodeTypes.Page.NAME.equals(name);
307 }
308 return false;
309 }
310
311 }
312
313
314
315
316 public class LastUpdatePropertyWrapper extends ContentDecoratorPropertyWrapper<MgnlPropertySettingContentDecorator> implements Property {
317
318 public LastUpdatePropertyWrapper(Property property, MgnlPropertySettingContentDecorator contentDecorator) {
319 super(property, contentDecorator);
320 }
321
322 @Override
323 public void setValue(BigDecimal value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
324 String parentPath = this.getParent().getPath();
325 String propertyName = this.getName();
326 super.setValue(value);
327 updateLastModifiedProperty(propertyName, parentPath);
328 }
329
330 @Override
331 public void setValue(Binary value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
332 String parentPath = this.getParent().getPath();
333 String propertyName = this.getName();
334 super.setValue(value);
335 updateLastModifiedProperty(propertyName, parentPath);
336 }
337
338 @Override
339 public void setValue(boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
340 String parentPath = this.getParent().getPath();
341 String propertyName = this.getName();
342 super.setValue(value);
343 updateLastModifiedProperty(propertyName, parentPath);
344 }
345
346 @Override
347 public void setValue(Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
348 String parentPath = this.getParent().getPath();
349 String propertyName = this.getName();
350 super.setValue(value);
351 updateLastModifiedProperty(propertyName, parentPath);
352 }
353
354 @Override
355 public void setValue(double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
356 String parentPath = this.getParent().getPath();
357 String propertyName = this.getName();
358 super.setValue(value);
359 updateLastModifiedProperty(propertyName, parentPath);
360 }
361
362 @Override
363 public void setValue(InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
364 String parentPath = this.getParent().getPath();
365 String propertyName = this.getName();
366 super.setValue(value);
367 updateLastModifiedProperty(propertyName, parentPath);
368 }
369
370 @Override
371 public void setValue(long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
372 String parentPath = this.getParent().getPath();
373 String propertyName = this.getName();
374 super.setValue(value);
375 updateLastModifiedProperty(propertyName, parentPath);
376 }
377
378 @Override
379 public void setValue(Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
380 String parentPath = this.getParent().getPath();
381 String propertyName = this.getName();
382 super.setValue(value);
383 updateLastModifiedProperty(propertyName, parentPath);
384 }
385
386 @Override
387 public void setValue(String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
388 String parentPath = this.getParent().getPath();
389 String propertyName = this.getName();
390 super.setValue(value);
391 updateLastModifiedProperty(propertyName, parentPath);
392 }
393
394 @Override
395 public void setValue(String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
396 String parentPath = this.getParent().getPath();
397 String propertyName = this.getName();
398 super.setValue(values);
399 updateLastModifiedProperty(propertyName, parentPath);
400 }
401
402 @Override
403 public void setValue(Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
404 String parentPath = this.getParent().getPath();
405 String propertyName = this.getName();
406 super.setValue(value);
407 updateLastModifiedProperty(propertyName, parentPath);
408 }
409
410 @Override
411 public void setValue(Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
412 String parentPath = this.getParent().getPath();
413 String propertyName = this.getName();
414 super.setValue(values);
415 updateLastModifiedProperty(propertyName, parentPath);
416 }
417
418 @Override
419 public void remove() throws VersionException, LockException, ConstraintViolationException, AccessDeniedException, RepositoryException {
420 String parentPath = this.getParent().getPath();
421 String propertyName = this.getName();
422 super.remove();
423
424 updateLastModifiedProperty(propertyName, parentPath);
425 }
426
427 private void updateLastModifiedProperty(String propertyName, String parentPath) throws RepositoryException {
428 getContentDecorator().updateLastModifiedProperty(getSession().getWorkspace().getName(), propertyName, parentPath);
429 }
430 }
431
432
433
434
435
436
437 @Deprecated
438 public class LastUpdateWorkspaceWrapper extends MgnlPropertySettingWorkspaceWrapper {
439
440 protected LastUpdateWorkspaceWrapper(final Workspace workspace, final ContentDecorator contentDecorator) {
441 super(workspace, contentDecorator);
442 }
443 }
444
445
446
447
448 public class MgnlPropertySettingWorkspaceWrapper extends ContentDecoratorWorkspaceWrapper implements Workspace {
449
450 protected MgnlPropertySettingWorkspaceWrapper(final Workspace workspace, final ContentDecorator contentDecorator) {
451 super(workspace, contentDecorator);
452 }
453
454 @Override
455 public void move(String srcAbsPath, String destAbsPath) throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException {
456 super.move(srcAbsPath, destAbsPath);
457 updateLastModified(super.getWrappedWorkspace().getSession(), destAbsPath, true);
458 }
459
460 @Override
461 public void copy(String srcAbsPath, String destAbsPath) throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException {
462 super.copy(srcAbsPath, destAbsPath);
463 final String workspaceName = super.getWrappedWorkspace().getName();
464 setCreatedDate(workspaceName, destAbsPath, true);
465 final String user = getCurrentUserName();
466 NodeUtil.visit(getSession().getNode(destAbsPath), node -> updateActivationStatus(node, user));
467 getSession().save();
468 }
469
470 @Override
471 public void copy(String srcWorkspace, String srcAbsPath, String destAbsPath) throws NoSuchWorkspaceException, ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException {
472 super.copy(srcWorkspace, srcAbsPath, destAbsPath);
473 final String workspaceName = super.getWrappedWorkspace().getName();
474 setCreatedDate(workspaceName, destAbsPath, true);
475 final String user = getCurrentUserName();
476 NodeUtil.visit(getSession().getNode(destAbsPath), node -> updateActivationStatus(node, user));
477 getSession().save();
478 }
479
480 @Override
481 public void clone(String srcWorkspace, String srcAbsPath, String destAbsPath, boolean removeExisting) throws NoSuchWorkspaceException, ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException, LockException, RepositoryException {
482 super.clone(srcWorkspace, srcAbsPath, destAbsPath, removeExisting);
483
484 }
485
486 }
487
488
489
490
491
492
493 @Deprecated
494 public class LastUpdateSessionWrapper extends MgnlPropertySettingSessionWrapper {
495 public LastUpdateSessionWrapper(final Session session, final MgnlPropertySettingContentDecorator contentDecorator) {
496 super(session, contentDecorator);
497 }
498 }
499
500
501
502
503 public class MgnlPropertySettingSessionWrapper extends ContentDecoratorSessionWrapper<MgnlPropertySettingContentDecorator> implements Session {
504
505 public MgnlPropertySettingSessionWrapper(Session session, MgnlPropertySettingContentDecorator contentDecorator) {
506 super(session, contentDecorator);
507 }
508
509 @Override
510 public void move(final String srcAbsPath, final String destAbsPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException {
511 super.move(srcAbsPath, destAbsPath);
512
513 boolean onSourcePath = MgnlContext.doInSystemContext(new JCRSessionOp<Boolean>(super.getWrappedSession().getWorkspace().getName()) {
514 @Override
515 public Boolean exec(Session session) throws RepositoryException {
516 return session.itemExists(srcAbsPath);
517 }
518 });
519 String aPath = onSourcePath ? srcAbsPath : destAbsPath;
520 updateLastModified(super.getWrappedSession(), aPath, true);
521 if (onSourcePath) {
522 for (DirtyOp op : dirtyOps) {
523 if (op.getPath().equals(srcAbsPath) || op.getPath().startsWith(srcAbsPath + "/")) {
524 op.setPath(destAbsPath + StringUtils.substringAfter(op.getPath(), srcAbsPath));
525 }
526 }
527 }
528 }
529
530 @Override
531 public void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException, ConstraintViolationException, InvalidItemStateException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException {
532 String workspaceName = wrapped.getWorkspace().getName();
533 try {
534 log.debug("saving session: {}::{}::sys:{}::{}", wrapped.toString(), workspaceName, MgnlContext.isSystemInstance(), Thread.currentThread().getName());
535 super.save();
536 } catch (InvalidItemStateException e) {
537 log.error("Failed to update LUD for session: {}::{}", wrapped.toString(), workspaceName, e);
538 throw e;
539 }
540 if (!dirtyOps.isEmpty()) {
541 Session sysSession = MgnlContext.getSystemContext().getJCRSession(workspaceName);
542 if (sysSession instanceof DelegateSessionWrapper) {
543 sysSession = ((DelegateSessionWrapper) sysSession).deepUnwrap(MgnlPropertySettingSessionWrapper.class);
544 }
545 applyPendingChanges(sysSession);
546 sysSession.save();
547 }
548 }
549
550 protected void applyPendingChanges(Session session) throws RepositoryException, PathNotFoundException {
551 while (!dirtyOps.isEmpty()) {
552 DirtyOp dirty = dirtyOps.remove(0);
553 if (session.nodeExists(dirty.getPath())) {
554 log.debug("Updating {} with {}", dirty.getPath(), dirty.getUpdateDate());
555 LastModified.update(session.getNode(dirty.getPath()), dirty.getUserName(), dirty.getUpdateDate());
556 } else {
557
558 if (log.isDebugEnabled()) {
559 log.warn("wanted to update {}:{} modified by:{} at {} but it's gone now.", session.getWorkspace().getName(), dirty.getPath(), dirty.getUserName(), dirty.getUpdateDate());
560 }
561 }
562 }
563 }
564
565 }
566
567 @Override
568 public Session wrapSession(Session session) {
569 return new MgnlPropertySettingSessionWrapper(session, this);
570 }
571
572 @Override
573 public Workspace wrapWorkspace(Workspace workspace) {
574 return new MgnlPropertySettingWorkspaceWrapper(workspace, this);
575 }
576
577 @Override
578 public Node wrapNode(Node node) {
579 return new MgnlPropertySettingNodeWrapper(node, this);
580 }
581
582 @Override
583 public Property wrapProperty(Property property) {
584 return new LastUpdatePropertyWrapper(property, this);
585 }
586
587 void updateLastModified(final Session session, final String destAbsPath, final boolean recursiveDown) throws RepositoryException, PathNotFoundException {
588 this.updateLastModified(session.getWorkspace().getName(), destAbsPath, recursiveDown);
589 }
590
591 void updateLastModified(final String workspaceName, final String destAbsPath, final boolean recursiveDown) throws RepositoryException, PathNotFoundException {
592
593 if ("/".equals(destAbsPath) && !recursiveDown) {
594
595 return;
596 }
597
598 final Calendar updateDate = Calendar.getInstance();
599
600
601 MgnlContext.doInSystemContext(new ChangeLastUpdateDateOp(workspaceName, getCurrentUserName(), destAbsPath, updateDate, recursiveDown));
602
603 }
604
605 void updateLastModified(String workspaceName, String destAbsPath) throws RepositoryException, PathNotFoundException {
606 updateLastModified(workspaceName, destAbsPath, false);
607 }
608
609 void updateLastModified(Session session, String destAbsPath) throws RepositoryException, PathNotFoundException {
610 updateLastModified(session, destAbsPath, false);
611 }
612
613 void updateLastModifiedProperty(String workspaceName, String propertyName, String parentPath) throws RepositoryException {
614 if (shouldIgnoreUpdate(propertyName)) {
615 return;
616 }
617 updateLastModified(workspaceName, parentPath);
618 }
619
620 void setCreatedDate(final String workspaceName, final String absPath) throws RepositoryException {
621 setCreatedDate(workspaceName, absPath, false);
622 }
623
624 void setCreatedDate(final String workspaceName, final String absPath, final boolean recursiveDown) throws RepositoryException {
625 final Session session = MgnlContext.getJCRSession(workspaceName);
626
627
628 if (!session.itemExists(absPath)) {
629
630 if (log.isDebugEnabled()) {
631 log.warn("Can't update {}. Path {}:{} does not exist.", NodeTypes.Created.NAME, workspaceName, absPath);
632 }
633 return;
634 }
635 Node node = session.getNode(absPath);
636
637
638 if (node == null) {
639 return;
640 }
641
642
643 if (node.getDepth() == 0) {
644 return;
645 }
646
647
648 if (node instanceof DelegateNodeWrapper) {
649 node = ((DelegateNodeWrapper) node).deepUnwrap(MgnlPropertySettingNodeWrapper.class);
650 }
651
652 final String user = getCurrentUserName();
653
654
655 final Calendar now = Calendar.getInstance();
656
657 if (node.isNodeType(NodeTypes.Created.NAME)) {
658 log.debug("Setting {} on {} from {}:{}", NodeTypes.Created.NAME, node.getPath(), node.getSession().toString(), Thread.currentThread().getName());
659 NodeTypes.Created.set(node, user, now);
660 }
661
662 if (recursiveDown) {
663
664 List<NodeIterator> iters = new ArrayList<>();
665 iters.add(node.getNodes());
666 while (!iters.isEmpty()) {
667 List<NodeIterator> tmp = updateChildren(iters, user, now);
668 iters.clear();
669 iters.addAll(tmp);
670 }
671 }
672 }
673
674 private void updateActivationStatus(Node node, String userName) throws RepositoryException {
675 if (NodeUtil.isNodeType(node, NodeTypes.Activatable.NAME)) {
676 NodeTypes.Activatable.update(node, userName, false);
677 }
678 }
679
680 private List<NodeIterator> updateChildren(final List<NodeIterator> iters, final String user, final Calendar updateDate) {
681 List<NodeIterator> tmp = new ArrayList<>();
682 for (NodeIterator iterator : iters) {
683 while (iterator.hasNext()) {
684 Node node = iterator.nextNode();
685 try {
686 if (node.isNodeType(NodeTypes.Created.NAME)) {
687 NodeTypes.Created.set(node, user, updateDate);
688 }
689 tmp.add(node.getNodes());
690 } catch (RepositoryException e) {
691 log.error("Failed to set created date of {} with {}", node, e.getMessage(), e);
692 }
693 }
694 }
695 return tmp;
696 }
697
698
699
700
701 protected boolean shouldIgnoreUpdate(final String propertyName) {
702
703 return propertyName.startsWith(NodeTypes.JCR_PREFIX) || (propertyName.startsWith(NodeTypes.MGNL_PREFIX) && !SPECIAL_PROPERTY_NAMES.contains(propertyName));
704 }
705
706 protected String getCurrentUserName() {
707 String userName = MgnlContext.getUser().getName();
708 if (MgnlContext.isSystemInstance()) {
709
710 Context ctx = ((SystemContext) MgnlContext.getInstance()).getOriginalContext();
711 if (ctx != null && ctx.getUser() != null && !userName.equals(ctx.getUser().getName())) {
712
713 return "System [" + ctx.getUser().getName() + "]";
714 }
715 }
716 return userName;
717 }
718 }