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.cms.core;
35
36 import info.magnolia.cms.core.version.ContentVersion;
37 import info.magnolia.cms.core.version.VersionManager;
38 import info.magnolia.cms.security.AccessDeniedException;
39 import info.magnolia.cms.security.Permission;
40 import info.magnolia.cms.util.Rule;
41 import info.magnolia.context.MgnlContext;
42 import info.magnolia.context.MgnlContext.Op;
43 import info.magnolia.logging.AuditLoggingUtil;
44
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.Collections;
48 import java.util.Comparator;
49 import java.util.List;
50
51 import javax.jcr.Item;
52 import javax.jcr.ItemNotFoundException;
53 import javax.jcr.Node;
54 import javax.jcr.NodeIterator;
55 import javax.jcr.PathNotFoundException;
56 import javax.jcr.Property;
57 import javax.jcr.PropertyIterator;
58 import javax.jcr.PropertyType;
59 import javax.jcr.RepositoryException;
60 import javax.jcr.UnsupportedRepositoryOperationException;
61 import javax.jcr.lock.Lock;
62 import javax.jcr.lock.LockException;
63 import javax.jcr.nodetype.NodeType;
64 import javax.jcr.version.Version;
65 import javax.jcr.version.VersionException;
66 import javax.jcr.version.VersionHistory;
67 import javax.jcr.version.VersionIterator;
68
69 import org.apache.commons.lang.StringUtils;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73
74
75
76
77
78
79
80 public class DefaultContent extends AbstractContent {
81 private static final Logger log = LoggerFactory.getLogger(DefaultContent.class);
82
83
84
85
86 protected Node node;
87
88
89
90
91 private String path;
92
93
94
95
96 private Node rootNode;
97
98
99
100
101 private MetaData metaData;
102
103
104
105
106 protected DefaultContent() {
107 }
108
109
110
111
112
113
114
115
116
117
118
119 DefaultContent(Node rootNode, String path, HierarchyManager hierarchyManager) throws PathNotFoundException, RepositoryException, AccessDeniedException {
120 this.setHierarchyManager(hierarchyManager);
121 Access.isGranted(hierarchyManager.getAccessManager(), Path.getAbsolutePath(rootNode.getPath(), path), Permission.READ);
122 this.setPath(path);
123 this.setRootNode(rootNode);
124 this.setNode(this.rootNode.getNode(this.path));
125 }
126
127
128
129
130
131
132
133
134
135 public DefaultContent(Item elem,HierarchyManager hierarchyManager) throws RepositoryException, AccessDeniedException {
136 this.setHierarchyManager(hierarchyManager);
137 Access.isGranted(hierarchyManager.getAccessManager(), Path.getAbsolutePath(elem.getPath()), Permission.READ);
138 this.setNode((Node) elem);
139 this.setPath(this.getHandle());
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 DefaultContent(Node rootNode, String path, String contentType, HierarchyManager hierarchyManager)
155 throws PathNotFoundException,
156 RepositoryException,
157 AccessDeniedException {
158 this.setHierarchyManager(hierarchyManager);
159 Access.isGranted(hierarchyManager.getAccessManager(), Path.getAbsolutePath(rootNode.getPath(), path), Permission.WRITE);
160 this.setPath(path);
161 this.setRootNode(rootNode);
162 this.node = this.rootNode.addNode(this.path, contentType);
163
164
165
166 this.addMixin(ItemType.MIX_LOCKABLE);
167 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_CREATE, hierarchyManager.getName(), this.getItemType(), Path.getAbsolutePath(node.getPath()));
168 }
169
170
171
172
173 protected void setNode(Node node) {
174 this.node = node;
175 }
176
177
178
179
180 protected void setRootNode(Node node) {
181 this.rootNode = node;
182 }
183
184
185
186
187 protected void setPath(String path) {
188 this.path = path;
189 }
190
191 public Content getContent(String name) throws PathNotFoundException, RepositoryException, AccessDeniedException {
192 return (new DefaultContent(this.node, name, this.getHierarchyManager()));
193 }
194
195 public Content createContent(String name, String contentType) throws PathNotFoundException, RepositoryException,
196 AccessDeniedException {
197 Content content = new DefaultContent(this.node, name, contentType, this.getHierarchyManager());
198 MetaData metaData = content.getMetaData();
199 metaData.setCreationDate();
200 return content;
201 }
202
203 @Override
204 public boolean hasNodeData(String name) throws RepositoryException {
205 if (this.node.hasProperty(name)) {
206 return true;
207 }
208 else {
209 if (this.node.hasNode(name) && (this.node.getNode(name).isNodeType(ItemType.NT_RESOURCE) || (this.node.hasProperty("jcr:frozenPrimaryType") && this.node.getNode(name).getProperty("jcr:frozenPrimaryType").getValue().getString().equals(ItemType.NT_RESOURCE)))) {
210 return true;
211 }
212 }
213 return false;
214 }
215
216 @Override
217 public NodeData newNodeDataInstance(String name, int type, boolean createIfNotExisting) throws AccessDeniedException, RepositoryException {
218 try {
219 Access.isGranted(getAccessManager(), Path.getAbsolutePath(getHandle(), name), Permission.READ);
220 }
221
222 catch (AccessDeniedException e) {
223 return new NonExistingNodeData(this, name);
224 }
225
226
227 if(!hasNodeData(name) && !createIfNotExisting){
228 return new NonExistingNodeData(this, name);
229 }
230
231 if(type == PropertyType.UNDEFINED){
232 type = determineNodeDataType(name);
233 }
234
235 if(type == PropertyType.BINARY){
236 return new BinaryNodeData(this, name);
237 }
238 else{
239 return new DefaultNodeData(this, name);
240 }
241 }
242
243 protected int determineNodeDataType(String name) {
244
245 try {
246 if (this.node.hasProperty(name)) {
247 return this.node.getProperty(name).getType();
248 }
249 else {
250 if (this.node.hasNode(name) && (this.node.getNode(name).isNodeType(ItemType.NT_RESOURCE) || (this.node.getNode(name).hasProperty("jcr:frozenPrimaryType") && this.node.getNode(name).getProperty("jcr:frozenPrimaryType").getValue().getString().equals(ItemType.NT_RESOURCE)))) {
251 return PropertyType.BINARY;
252 }
253 }
254 }
255 catch (RepositoryException e) {
256 throw new IllegalStateException("Can't determine property type of [" + getHandle() + "/" + name + "]", e);
257 }
258 return PropertyType.UNDEFINED;
259 }
260
261
262 public MetaData getMetaData() {
263 if (this.metaData == null) {
264 this.metaData = new MetaData(this.node, this.getHierarchyManager().getAccessManager());
265 }
266 return this.metaData;
267 }
268
269 public String getName() {
270 try {
271 return this.node.getName();
272 }
273 catch (RepositoryException e) {
274 log.error(e.getMessage(), e);
275 }
276 return StringUtils.EMPTY;
277 }
278
279 @Override
280 public Collection<Content> getChildren(ContentFilter filter, String namePattern, Comparator<Content> orderCriteria) {
281 List<Content> children;
282 children = new ArrayList<Content>();
283
284 try {
285 final NodeIterator nodeIterator;
286 if (namePattern == null) {
287 nodeIterator = this.node.getNodes();
288 } else {
289 nodeIterator = this.node.getNodes(namePattern);
290 }
291
292 while (nodeIterator.hasNext()) {
293 Node subNode = (Node) nodeIterator.next();
294 try {
295 Content content = new DefaultContent(subNode, this.getHierarchyManager());
296 if (filter.accept(content)) {
297 children.add(content);
298 }
299 }
300 catch (PathNotFoundException e) {
301 log.error("Exception caught", e);
302 }
303 catch (AccessDeniedException e) {
304
305 }
306 }
307 }
308 catch (RepositoryException re) {
309 log.error("Exception caught", re);
310 }
311
312 if (orderCriteria != null) {
313
314 Collections.sort(children, orderCriteria);
315 }
316 return children;
317 }
318
319 public Collection<NodeData> getNodeDataCollection(String namePattern) {
320 final ArrayList<NodeData> all = new ArrayList<NodeData>();
321 try {
322 all.addAll(getPrimitiveNodeDatas(namePattern));
323 all.addAll(getBinaryNodeDatas(namePattern));
324 }
325 catch (RepositoryException e) {
326 throw new IllegalStateException("Can't read node datas of " + toString(), e);
327 }
328 return all;
329 }
330
331 protected Collection<NodeData> getPrimitiveNodeDatas(String namePattern) throws RepositoryException {
332 final Collection<NodeData> nodeDatas = new ArrayList<NodeData>();
333 final PropertyIterator propertyIterator;
334 if (namePattern == null) {
335 propertyIterator = this.node.getProperties();
336 } else {
337 propertyIterator = this.node.getProperties(namePattern);
338 }
339 while (propertyIterator.hasNext()) {
340 Property property = (Property) propertyIterator.next();
341 try {
342 if (!property.getName().startsWith("jcr:") && !property.getName().startsWith("mgnl:")) {
343 nodeDatas.add(getNodeData(property.getName()));
344 }
345 }
346 catch (PathNotFoundException e) {
347 log.error("Exception caught", e);
348 }
349 catch (AccessDeniedException e) {
350
351 }
352 }
353 return nodeDatas;
354 }
355
356
357 public boolean hasContent(String name) throws RepositoryException {
358 return this.node.hasNode(name);
359 }
360
361 public String getHandle() {
362 try {
363 return this.node.getPath();
364 }
365 catch (RepositoryException e) {
366 log.error("Failed to get handle: " + e.getMessage(), e);
367 return StringUtils.EMPTY;
368 }
369 }
370
371 public Content getParent() throws PathNotFoundException, RepositoryException, AccessDeniedException {
372 return (new DefaultContent(this.node.getParent(), this.getHierarchyManager()));
373 }
374
375 public Content getAncestor(int level) throws PathNotFoundException, RepositoryException, AccessDeniedException {
376 if (level > this.getLevel()) {
377 throw new PathNotFoundException();
378 }
379 return (new DefaultContent(this.node.getAncestor(level), this.getHierarchyManager()));
380 }
381
382 public Collection<Content> getAncestors() throws PathNotFoundException, RepositoryException {
383 List<Content> allAncestors = new ArrayList<Content>();
384 int level = this.getLevel();
385 while (level != 0) {
386 try {
387 allAncestors.add(getAncestor(--level));
388 }
389 catch (AccessDeniedException e) {
390
391 }
392 }
393 return allAncestors;
394 }
395
396 public int getLevel() throws PathNotFoundException, RepositoryException {
397 return this.node.getDepth();
398 }
399
400 public void orderBefore(String srcName, String beforeName) throws RepositoryException {
401 this.node.orderBefore(srcName, beforeName);
402 }
403
404 public int getIndex() throws RepositoryException {
405 return this.node.getIndex();
406 }
407
408 public Node getJCRNode() {
409 return this.node;
410 }
411
412 public boolean isNodeType(String type) {
413 return isNodeType(this.node, type);
414 }
415
416
417
418
419
420
421 protected boolean isNodeType(Node node, String type) {
422 try {
423 final String actualType = node.getProperty(ItemType.JCR_PRIMARY_TYPE).getString();
424
425 if (ItemType.NT_FROZENNODE.equals(actualType) && !(ItemType.NT_FROZENNODE.equals(type))) {
426 final Property p = node.getProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE);
427 final String s = p.getString();
428 return s.equalsIgnoreCase(type);
429 } else {
430 return node.isNodeType(type);
431 }
432 }
433 catch (RepositoryException re) {
434 log.error(re.getMessage());
435 log.debug(re.getMessage(), re);
436 return false;
437 }
438 }
439
440 public NodeType getNodeType() throws RepositoryException {
441 return this.node.getPrimaryNodeType();
442 }
443
444 public String getNodeTypeName() throws RepositoryException {
445
446 if (this.node.hasProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE)) {
447 return this.node.getProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE).getString();
448 }
449 return this.node.getProperty(ItemType.JCR_PRIMARY_TYPE).getString();
450 }
451
452 public ItemType getItemType() throws RepositoryException {
453 return new ItemType(getNodeTypeName());
454 }
455
456 public void restore(String versionName, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException {
457 Access.isGranted(this.getHierarchyManager().getAccessManager(), this.getHandle(), Permission.WRITE);
458 Version version = this.getVersionHistory().getVersion(versionName);
459 this.restore(version, removeExisting);
460 }
461
462 public void restore(Version version, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException {
463 Access.isGranted(this.getHierarchyManager().getAccessManager(), this.getHandle(), Permission.WRITE);
464 VersionManager.getInstance().restore(this, version, removeExisting);
465 }
466
467 public void restore(Version version, String relPath, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException {
468 throw new UnsupportedRepositoryOperationException("Not implemented in 3.0 Beta");
469 }
470
471 public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException, UnsupportedRepositoryOperationException, RepositoryException {
472 this.node.restoreByLabel(versionLabel, removeExisting);
473 throw new UnsupportedRepositoryOperationException("Not implemented in 3.0 Beta");
474 }
475
476 public Version addVersion() throws UnsupportedRepositoryOperationException, RepositoryException {
477 return VersionManager.getInstance().addVersion(this);
478 }
479
480 public Version addVersion(Rule rule) throws UnsupportedRepositoryOperationException, RepositoryException {
481 return VersionManager.getInstance().addVersion(this, rule);
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 protected boolean isCheckedOut() throws RepositoryException {
499 return this.node.isCheckedOut();
500 }
501
502 public boolean isModified() {
503 return this.node.isModified();
504 }
505
506 public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException {
507 return VersionManager.getInstance().getVersionHistory(this);
508 }
509
510 public VersionIterator getAllVersions() throws UnsupportedRepositoryOperationException, RepositoryException {
511 return VersionManager.getInstance().getAllVersions(this);
512 }
513
514 public ContentVersion getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException {
515 return new ContentVersion(VersionManager.getInstance().getBaseVersion(this), this);
516 }
517
518 public ContentVersion getVersionedContent(Version version) throws RepositoryException {
519 return new ContentVersion(version, this);
520 }
521
522 public ContentVersion getVersionedContent(String versionName) throws RepositoryException {
523 return new ContentVersion(VersionManager.getInstance().getVersion(this, versionName), this);
524 }
525
526 public void removeVersionHistory() throws AccessDeniedException, RepositoryException {
527 Access.isGranted(this.getHierarchyManager().getAccessManager(), Path.getAbsolutePath(node.getPath()), Permission.WRITE);
528 VersionManager.getInstance().removeVersionHistory(this.node.getUUID());
529 }
530
531 public void save() throws RepositoryException {
532 this.node.save();
533 }
534
535 public void delete() throws RepositoryException {
536 final String nodePath = Path.getAbsolutePath(this.node.getPath());
537 log.debug("removing {} from {}", this.node.getPath(), getHierarchyManager().getName());
538 Access.isGranted(getHierarchyManager().getAccessManager(), nodePath, Permission.REMOVE);
539 final ItemType nodeType = this.getItemType();
540 if (!getHierarchyManager().getName().equals("mgnlVersion")) {
541 MgnlContext.doInSystemContext(new Op<Void, RepositoryException>() {
542 public Void exec() throws RepositoryException {
543 try {
544 final String uuid = node.getUUID();
545
546
547 HierarchyManager hm = MgnlContext.getHierarchyManager("mgnlVersion");
548 Node versionedNode = hm.getContentByUUID(uuid).getJCRNode();
549 log.debug("Located versioned node {}({})", uuid, nodePath);
550
551 VersionHistory history = versionedNode.getVersionHistory();
552
553 log.debug("Removing versioned node {}({})", uuid, nodePath);
554 versionedNode.remove();
555 hm.save();
556
557 VersionIterator iter = history.getAllVersions();
558
559 iter.nextVersion();
560 while (iter.hasNext()) {
561 Version version = iter.nextVersion();
562 log.debug("removing version {}", version.getName());
563 history.removeVersion(version.getName());
564 }
565
566 } catch (ItemNotFoundException e) {
567
568 } catch (UnsupportedRepositoryOperationException e) {
569
570 }
571 return null;
572 }
573 });
574 }
575 this.node.remove();
576 AuditLoggingUtil.log(AuditLoggingUtil.ACTION_DELETE, getHierarchyManager().getName(), nodeType, nodePath);
577 }
578
579
580 public void refresh(boolean keepChanges) throws RepositoryException {
581 this.node.refresh(keepChanges);
582 }
583
584 public String getUUID() {
585 try {
586 return this.node.getUUID();
587 }
588 catch (UnsupportedOperationException e) {
589 log.error(e.getMessage());
590 }
591 catch (RepositoryException re) {
592 log.error("Exception caught", re);
593 }
594 return StringUtils.EMPTY;
595 }
596
597 public void addMixin(String type) throws RepositoryException {
598 Access.isGranted(this.getHierarchyManager().getAccessManager(), Path.getAbsolutePath(this.node.getPath()), Permission.SET);
599
600 if (!this.node.canAddMixin(type)) {
601 log.debug("Node - " + this.node.getPath() + " does not allow mixin type - " + type);
602 }
603 try {
604 this.node.addMixin(type);
605 } catch (Exception e) {
606 log.error("Failed to add mixin type - " + type + " to a node " + this.node.getPath());
607 }
608 }
609
610 public void removeMixin(String type) throws RepositoryException {
611 Access.isGranted(this.getHierarchyManager().getAccessManager(), Path.getAbsolutePath(this.node.getPath()), Permission.SET);
612 this.node.removeMixin(type);
613 }
614
615 public NodeType[] getMixinNodeTypes() throws RepositoryException {
616 return this.node.getMixinNodeTypes();
617 }
618
619 public Lock lock(boolean isDeep, boolean isSessionScoped) throws LockException, RepositoryException {
620 return this.node.lock(isDeep, isSessionScoped);
621 }
622
623 public Lock lock(boolean isDeep, boolean isSessionScoped, long yieldFor) throws LockException, RepositoryException {
624 long finalTime = System.currentTimeMillis() + yieldFor;
625 LockException lockException = null;
626 while (System.currentTimeMillis() <= finalTime) {
627 try {
628 return this.node.lock(isDeep, isSessionScoped);
629 }
630 catch (LockException e) {
631
632 lockException = e;
633 }
634 Thread.yield();
635 }
636
637 throw lockException;
638 }
639
640 public Lock getLock() throws LockException, RepositoryException {
641 return this.node.getLock();
642 }
643
644 public void unlock() throws LockException, RepositoryException {
645 this.node.unlock();
646 }
647
648 public boolean holdsLock() throws RepositoryException {
649 return this.node.holdsLock();
650 }
651
652 public boolean isLocked() throws RepositoryException {
653 return this.node.isLocked();
654 }
655
656 public boolean hasMetaData() {
657 try {
658 return this.node.hasNode("MetaData");
659 }
660 catch (RepositoryException re) {
661 log.debug(re.getMessage(), re);
662 }
663 return false;
664 }
665
666 public boolean hasMixin(String mixinName) throws RepositoryException {
667 if (StringUtils.isBlank(mixinName)) {
668 throw new IllegalArgumentException("Mixin name can't be empty.");
669 }
670 for (NodeType type : getMixinNodeTypes()) {
671 if (mixinName.equals(type.getName())) {
672 return true;
673 }
674 }
675 return false;
676 }
677 }