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.search.QueryManager;
37 import info.magnolia.cms.security.AccessDeniedException;
38 import info.magnolia.cms.security.AccessManager;
39 import info.magnolia.cms.security.Permission;
40 import info.magnolia.cms.util.WorkspaceAccessUtil;
41 import info.magnolia.cms.beans.config.ContentRepository;
42 import info.magnolia.logging.AuditLoggingUtil;
43
44 import java.util.Collection;
45 import java.io.ObjectStreamField;
46 import java.io.Serializable;
47
48 import javax.jcr.PathNotFoundException;
49 import javax.jcr.RepositoryException;
50 import javax.jcr.Node;
51 import javax.jcr.Session;
52 import javax.jcr.Workspace;
53 import javax.jcr.ItemNotFoundException;
54
55 import org.apache.commons.lang.StringUtils;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59
60
61
62
63
64
65
66 public class DefaultHierarchyManager implements HierarchyManager, Serializable {
67
68 private static final long serialVersionUID = 223L;
69
70
71
72
73
74 private static final ObjectStreamField[] serialPersistentFields = {
75 new ObjectStreamField("userId", String.class),
76 new ObjectStreamField("repositoryName", String.class),
77 new ObjectStreamField("workspaceName", String.class),
78 new ObjectStreamField("accessManager", AccessManager.class)
79 };
80
81 private static final Logger log = LoggerFactory.getLogger(DefaultHierarchyManager.class);
82
83 private Node rootNode;
84
85 private Workspace workspace;
86
87 private Session jcrSession;
88
89 private QueryManager queryManager;
90
91
92
93
94 private String userId;
95
96 private String repositoryName;
97
98 private String workspaceName;
99
100 private AccessManager accessManager;
101
102 protected DefaultHierarchyManager() {}
103
104 public DefaultHierarchyManager(String userId, Session jcrSession, AccessManager aManager) throws RepositoryException {
105 this.userId = userId;
106 this.jcrSession = jcrSession;
107 this.rootNode = jcrSession.getRootNode();
108 this.workspace = jcrSession.getWorkspace();
109 this.workspaceName = this.workspace.getName();
110 this.repositoryName = ContentRepository.getParentRepositoryName(this.workspaceName);
111 this.accessManager = aManager;
112 }
113
114
115
116
117 private void reInitialize() {
118 WorkspaceAccessUtil util = WorkspaceAccessUtil.getInstance();
119 try {
120 this.jcrSession = util.createRepositorySession(util.getDefaultCredentials(), this.repositoryName, this.workspaceName);
121 this.queryManager = util.createQueryManager(this.jcrSession, this);
122 this.rootNode = this.jcrSession.getRootNode();
123 this.workspace = this.jcrSession.getWorkspace();
124 } catch (RepositoryException re) {
125 log.error("Failed to load HierarchyManager from persistent storage", re);
126 }
127 }
128
129
130
131
132
133 protected void setAccessManager(AccessManager accessManager) {
134 this.accessManager = accessManager;
135 }
136
137
138
139
140
141 public AccessManager getAccessManager() {
142 return this.accessManager;
143 }
144
145
146
147
148
149 protected void setQueryManager(QueryManager queryManager) {
150 this.queryManager = queryManager;
151 }
152
153 public QueryManager getQueryManager() {
154 if (null == this.queryManager) {
155 WorkspaceAccessUtil util = WorkspaceAccessUtil.getInstance();
156 try {
157 this.queryManager = util.createQueryManager(this.jcrSession, this);
158 } catch (RepositoryException e) {
159 reInitialize();
160 }
161 }
162 return this.queryManager;
163 }
164
165 private Node getRootNode() {
166 if (null == this.rootNode) {
167 reInitialize();
168 }
169 return this.rootNode;
170 }
171
172 private Session getJcrSession() {
173 log.debug("Accessing JCR session from {}", Thread.currentThread().getName());
174 if (null == this.jcrSession) {
175 reInitialize();
176 }
177 return this.jcrSession;
178 }
179
180
181
182
183
184
185
186
187
188
189
190 public Content createContent(String path, String label, String contentType) throws PathNotFoundException, RepositoryException, AccessDeniedException {
191 Content content = new DefaultContent(this.getRootNode(), this.getNodePath(path, label), contentType, this);
192 setMetaData(content.getMetaData());
193 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_CREATE, workspaceName, content.getItemType(), content.getHandle());
194 return content;
195 }
196
197 private String getNodePath(String parent, String label) {
198 if (StringUtils.isEmpty(parent) || (parent.equals("/"))) {
199 return label;
200 }
201 if (!parent.endsWith("/")) {
202 parent = parent + "/";
203 }
204 return getNodePath(parent + label);
205 }
206
207 private String getNodePath(String path) {
208 if (path != null && path.startsWith("/")) {
209 return path.replaceFirst("/", StringUtils.EMPTY);
210 }
211 return path;
212 }
213
214
215
216
217
218 protected void setMetaData(MetaData md) throws RepositoryException, AccessDeniedException {
219 md.setCreationDate();
220 md.setModificationDate();
221 md.setAuthorId(this.userId);
222 md.setTitle(StringUtils.EMPTY);
223 }
224
225
226
227
228
229
230
231
232 public Content getContent(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
233 if (path.equals("/")) {
234 return this.getRoot();
235 }
236 return (new DefaultContent(this.getRootNode(), getNodePath(path), this));
237 }
238
239
240
241
242
243
244
245
246
247
248 public Content getContent(String path, boolean create, ItemType type) throws AccessDeniedException, RepositoryException {
249 Content node;
250 try {
251 node = getContent(path);
252 }
253 catch (PathNotFoundException e) {
254 if (create) {
255 node = this.createContent(StringUtils.substringBeforeLast(path, "/"), StringUtils.substringAfterLast( path, "/"), type.toString());
256 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_CREATE, workspaceName, node.getItemType(), node.getHandle());
257 }
258 else {
259 throw e;
260 }
261 }
262 return node;
263 }
264
265
266
267
268
269
270
271
272
273 public NodeData getNodeData(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
274 if (StringUtils.isEmpty(path)) {
275 return null;
276 }
277 final String nodePath = StringUtils.substringBeforeLast(path, "/");
278 final String nodeDataName = StringUtils.substringAfterLast(path, "/");
279 return getContent(nodePath).getNodeData(nodeDataName);
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293 @Deprecated
294 public Content getPage(String path, String templateName) throws PathNotFoundException, RepositoryException, AccessDeniedException {
295 Content page = getContent(path);
296 if (page.getTemplate().equals(templateName)) {
297 return page;
298 }
299 Content pageToBeFound = null;
300 try {
301 if (page.hasChildren()) {
302 Collection<Content> children = page.getChildren(ItemType.CONTENT.getSystemName());
303 for (Content child : children) {
304 if (child.getTemplate().equals(templateName)) {
305 return child;
306 }
307 if (child.hasChildren()) {
308 pageToBeFound = getPage(child.getHandle(), templateName);
309 }
310 if (pageToBeFound != null) {
311 return pageToBeFound;
312 }
313 }
314 }
315 }
316 catch (Exception e) {
317 log.error("Failed to get - " + path + " : " + e.getMessage(), e);
318 }
319 return pageToBeFound;
320 }
321
322
323
324
325
326
327
328
329 public void delete(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
330 Access.isGranted(this.accessManager, path, Permission.REMOVE);
331 ItemType type = null;
332 if (this.isNodeData(path)) {
333 this.getNodeData(makeRelative(path)).delete();
334 }
335 else {
336 Node aNode = this.getRootNode().getNode(makeRelative(path));
337 if (aNode.hasProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE)) {
338 type = new ItemType(aNode.getProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE).getString());
339 }
340 type = new ItemType(aNode.getProperty(ItemType.JCR_PRIMARY_TYPE).getString());
341 aNode.remove();
342 }
343 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_DELETE, workspaceName, type, path);
344 }
345
346 private String makeRelative(String path) {
347 return StringUtils.stripStart(path, "/");
348 }
349
350
351
352
353 public Content getRoot() throws RepositoryException, AccessDeniedException {
354 return (new DefaultContent(this.getRootNode(), this));
355 }
356
357
358
359
360
361
362
363
364 @Deprecated
365 public boolean isPage(String path) throws AccessDeniedException {
366 Access.isGranted(this.accessManager, path, Permission.READ);
367
368 String nodePath = getNodePath(path);
369 if (StringUtils.isEmpty(nodePath)) {
370 return false;
371 }
372
373 try {
374 Node n = this.getRootNode().getNode(nodePath);
375 return (n.isNodeType(ItemType.CONTENT.getSystemName()));
376 }
377 catch (RepositoryException re) {
378
379 }
380 return false;
381 }
382
383
384
385
386
387
388 public boolean isExist(String path) {
389 try {
390 Access.isGranted(this.accessManager, path, Permission.READ);
391 } catch (AccessDeniedException e) {
392 log.error(e.getMessage());
393 return false;
394 }
395 try {
396 return this.getJcrSession().itemExists(path);
397 } catch (RepositoryException re) {
398
399 if (re.getCause().getClass().getName().equals("org.apache.jackrabbit.spi.commons.conversion.MalformedPathException")) {
400
401 log.debug("{} is not valid jcr path.", path);
402 } else {
403 log.error("Exception caught", re);
404 }
405 return false;
406 }
407 }
408
409 public boolean isGranted(String path, long permissions) {
410 try {
411 Access.isGranted(this.accessManager, path, permissions);
412 } catch (AccessDeniedException e) {
413 return false;
414 }
415 return true;
416 }
417
418
419
420
421
422 @Deprecated
423 public boolean isNodeType(String path, String type) {
424 try {
425 Node n = this.getRootNode().getNode(getNodePath(path));
426 return n.isNodeType(type);
427 }
428 catch (RepositoryException re) {
429 log.error(re.getMessage());
430 log.debug(re.getMessage(), re);
431 }
432 return false;
433 }
434
435
436
437
438
439 @Deprecated
440 public boolean isNodeType(String path, ItemType type) {
441 return isNodeType(path, type.getSystemName());
442 }
443
444
445
446
447
448
449 public boolean isNodeData(String path) throws AccessDeniedException {
450 Access.isGranted(this.accessManager, path, Permission.READ);
451 boolean result = false;
452 String nodePath = getNodePath(path);
453 if (StringUtils.isEmpty(nodePath)) {
454 return false;
455 }
456 try {
457 result = this.getRootNode().hasProperty(nodePath);
458 if (!result) {
459
460 result = this.getRootNode().hasProperty(nodePath + "/" + ItemType.JCR_DATA);
461 }
462 }
463 catch (RepositoryException e) {
464
465 }
466 return result;
467 }
468
469
470
471
472
473
474 public Content getContentByUUID(String uuid) throws ItemNotFoundException, RepositoryException, AccessDeniedException {
475 return new DefaultContent(this.getJcrSession().getNodeByUUID(uuid), this);
476 }
477
478
479
480
481 public Workspace getWorkspace() {
482 if (null == this.workspace) {
483 reInitialize();
484 }
485 return this.workspace;
486 }
487
488
489
490
491
492
493
494
495 public void moveTo(String source, String destination) throws PathNotFoundException, RepositoryException, AccessDeniedException {
496 Access.isGranted(this.accessManager, source, Permission.REMOVE);
497 Access.isGranted(this.accessManager, destination, Permission.WRITE);
498 this.getWorkspace().move(source, destination);
499 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_MOVE, workspaceName, source, destination);
500 }
501
502
503
504
505
506
507
508
509 public void copyTo(String source, String destination) throws PathNotFoundException, RepositoryException, AccessDeniedException {
510 Access.isGranted(this.accessManager, source, Permission.READ);
511 Access.isGranted(this.accessManager, destination, Permission.WRITE);
512 this.getWorkspace().copy(source, destination);
513 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_COPY, workspaceName, source, destination);
514 }
515
516
517
518
519
520 public void save() throws RepositoryException {
521 try {
522 this.getJcrSession().save();
523 }
524 catch (RepositoryException re) {
525 log.error(re.getMessage(), re);
526 throw re;
527 }
528 }
529
530
531
532
533 public boolean hasPendingChanges() throws RepositoryException {
534 return this.getJcrSession().hasPendingChanges();
535 }
536
537
538
539
540
541
542
543 public void refresh(boolean keepChanges) throws RepositoryException {
544 this.getJcrSession().refresh(keepChanges);
545 }
546
547 public String getName() {
548 return this.workspaceName;
549 }
550
551 }