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,
105 Session jcrSession,
106 AccessManager aManager)
107 throws RepositoryException {
108 this.userId = userId;
109 this.jcrSession = jcrSession;
110 this.rootNode = jcrSession.getRootNode();
111 this.workspace = jcrSession.getWorkspace();
112 this.workspaceName = this.workspace.getName();
113 this.repositoryName = ContentRepository.getParentRepositoryName(this.workspaceName);
114 this.accessManager = aManager;
115 }
116
117
118
119
120 private void reInitialize() {
121 WorkspaceAccessUtil util = WorkspaceAccessUtil.getInstance();
122 try {
123 this.jcrSession = util.createRepositorySession(util.getDefaultCredentials(), this.repositoryName, this.workspaceName);
124 this.queryManager = util.createQueryManager(this.jcrSession, this);
125 this.rootNode = this.jcrSession.getRootNode();
126 this.workspace = this.jcrSession.getWorkspace();
127 } catch (RepositoryException re) {
128 log.error("Failed to load HierarchyManager from persistent storage", re);
129 }
130 }
131
132
133
134
135
136 protected void setAccessManager(AccessManager accessManager) {
137 this.accessManager = accessManager;
138 }
139
140
141
142
143
144 public AccessManager getAccessManager() {
145 return this.accessManager;
146 }
147
148
149
150
151
152 protected void setQueryManager(QueryManager queryManager) {
153 this.queryManager = queryManager;
154 }
155
156 public QueryManager getQueryManager() {
157 if (null == this.queryManager) {
158 WorkspaceAccessUtil util = WorkspaceAccessUtil.getInstance();
159 try {
160 this.queryManager = util.createQueryManager(this.jcrSession, this);
161 } catch (RepositoryException e) {
162 reInitialize();
163 }
164 }
165 return this.queryManager;
166 }
167
168 private Node getRootNode() {
169 if (null == this.rootNode) {
170 reInitialize();
171 }
172 return this.rootNode;
173 }
174
175 private Session getJcrSession() {
176 if (null == this.jcrSession) {
177 reInitialize();
178 }
179 return this.jcrSession;
180 }
181
182
183
184
185
186
187
188
189
190
191
192 public Content createContent(String path, String label, String contentType) throws PathNotFoundException,
193 RepositoryException, AccessDeniedException {
194 Content content = new DefaultContent(this.getRootNode(), this.getNodePath(path, label), contentType, this);
195 setMetaData(content.getMetaData());
196 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_CREATE, workspaceName, content.getItemType(), content.getHandle());
197 return content;
198 }
199
200 private String getNodePath(String parent, String label) {
201 if (StringUtils.isEmpty(parent) || (parent.equals("/"))) {
202 return label;
203 }
204 if (!parent.endsWith("/")) {
205 parent = parent + "/";
206 }
207 return getNodePath(parent + label);
208 }
209
210 private String getNodePath(String path) {
211 if (path != null && path.startsWith("/")) {
212 return path.replaceFirst("/", StringUtils.EMPTY);
213 }
214 return path;
215 }
216
217
218
219
220
221 protected void setMetaData(MetaData md) throws RepositoryException, AccessDeniedException {
222 md.setCreationDate();
223 md.setModificationDate();
224 md.setAuthorId(this.userId);
225 md.setTitle(StringUtils.EMPTY);
226 }
227
228
229
230
231
232
233
234
235 public Content getContent(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
236 if (path.equals("/")) {
237 return this.getRoot();
238 }
239 return (new DefaultContent(this.getRootNode(), getNodePath(path), this));
240 }
241
242
243
244
245
246
247
248
249
250
251 public Content getContent(String path, boolean create, ItemType type) throws AccessDeniedException,
252 RepositoryException {
253 Content node;
254 try {
255 node = getContent(path);
256 }
257 catch (PathNotFoundException e) {
258 if (create) {
259 node = this.createContent(StringUtils.substringBeforeLast(path, "/"), StringUtils.substringAfterLast(
260 path,
261 "/"), type.toString());
262 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_CREATE, workspaceName, node.getItemType(), node.getHandle());
263 }
264 else {
265 throw e;
266 }
267 }
268 return node;
269 }
270
271
272
273
274
275
276
277
278
279 public NodeData getNodeData(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
280 if (StringUtils.isEmpty(path)) {
281 return null;
282 }
283 final String nodePath = StringUtils.substringBeforeLast(path, "/");
284 final String nodeDataName = StringUtils.substringAfterLast(path, "/");
285 return getContent(nodePath).getNodeData(nodeDataName);
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299 public Content getPage(String path, String templateName) throws PathNotFoundException, RepositoryException,
300 AccessDeniedException {
301 Content page = getContent(path);
302 if (page.getTemplate().equals(templateName)) {
303 return page;
304 }
305 Content pageToBeFound = null;
306 try {
307 if (page.hasChildren()) {
308 Collection<Content> children = page.getChildren(ItemType.CONTENT.getSystemName());
309 for (Content child : children) {
310 if (child.getTemplate().equals(templateName)) {
311 return child;
312 }
313 if (child.hasChildren()) {
314 pageToBeFound = getPage(child.getHandle(), templateName);
315 }
316 if (pageToBeFound != null) {
317 return pageToBeFound;
318 }
319 }
320 }
321 }
322 catch (Exception e) {
323 log.error("Failed to get - " + path + " : " + e.getMessage(), e);
324 }
325 return pageToBeFound;
326 }
327
328
329
330
331
332
333
334
335 public void delete(String path) throws PathNotFoundException, RepositoryException, AccessDeniedException {
336 Access.isGranted(this.accessManager, path, Permission.REMOVE);
337 ItemType type = null;
338 if (this.isNodeData(path)) {
339 this.getNodeData(makeRelative(path)).delete();
340 }
341 else {
342 Node aNode = this.getRootNode().getNode(makeRelative(path));
343 if (aNode.hasProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE)) {
344 type = new ItemType(aNode.getProperty(ItemType.JCR_FROZEN_PRIMARY_TYPE).getString());
345 }
346 type = new ItemType(aNode.getProperty(ItemType.JCR_PRIMARY_TYPE).getString());
347 aNode.remove();
348 }
349 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_DELETE, workspaceName, type, path);
350 }
351
352 private String makeRelative(String path) {
353 return StringUtils.stripStart(path, "/");
354 }
355
356
357
358
359 public Content getRoot() throws RepositoryException, AccessDeniedException {
360 return (new DefaultContent(this.getRootNode(), this));
361 }
362
363
364
365
366
367
368
369
370 public boolean isPage(String path) throws AccessDeniedException {
371 Access.isGranted(this.accessManager, path, Permission.READ);
372
373 String nodePath = getNodePath(path);
374 if (StringUtils.isEmpty(nodePath)) {
375 return false;
376 }
377
378 try {
379 Node n = this.getRootNode().getNode(nodePath);
380 return (n.isNodeType(ItemType.CONTENT.getSystemName()));
381 }
382 catch (RepositoryException re) {
383
384 }
385 return false;
386 }
387
388
389
390
391
392
393 public boolean isExist(String path) {
394 try {
395 Access.isGranted(this.accessManager, path, Permission.READ);
396 } catch (AccessDeniedException e) {
397 log.error(e.getMessage());
398 return false;
399 }
400 try {
401 return this.getJcrSession().itemExists(path);
402 }
403 catch (RepositoryException re) {
404 log.error("Exception caught", re);
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 public boolean isNodeType(String path, String type) {
423 try {
424 Node n = this.getRootNode().getNode(getNodePath(path));
425 return n.isNodeType(type);
426 }
427 catch (RepositoryException re) {
428 log.error(re.getMessage());
429 log.debug(re.getMessage(), re);
430 }
431 return false;
432 }
433
434
435
436
437
438 public boolean isNodeType(String path, ItemType type) {
439 return isNodeType(path, type.getSystemName());
440 }
441
442
443
444
445
446
447 public boolean isNodeData(String path) throws AccessDeniedException {
448 Access.isGranted(this.accessManager, path, Permission.READ);
449 boolean result = false;
450 String nodePath = getNodePath(path);
451 if (StringUtils.isEmpty(nodePath)) {
452 return false;
453 }
454 try {
455 result = this.getRootNode().hasProperty(nodePath);
456 if (!result) {
457
458 result = this.getRootNode().hasProperty(nodePath + "/" + ItemType.JCR_DATA);
459 }
460 }
461 catch (RepositoryException e) {
462
463 }
464 return result;
465 }
466
467
468
469
470
471
472 public Content getContentByUUID(String uuid) throws ItemNotFoundException, RepositoryException,
473 AccessDeniedException {
474 return new DefaultContent(this.getJcrSession().getNodeByUUID(uuid), this);
475 }
476
477
478
479
480 public Workspace getWorkspace() {
481 if (null == this.workspace) {
482 reInitialize();
483 }
484 return this.workspace;
485 }
486
487
488
489
490
491
492
493
494 public void moveTo(String source, String destination) throws PathNotFoundException, RepositoryException,
495 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,
510 AccessDeniedException {
511 Access.isGranted(this.accessManager, source, Permission.READ);
512 Access.isGranted(this.accessManager, destination, Permission.WRITE);
513 this.getWorkspace().copy(source, destination);
514 AuditLoggingUtil.log( AuditLoggingUtil.ACTION_COPY, workspaceName, source, destination);
515 }
516
517
518
519
520
521 public void save() throws RepositoryException {
522 try {
523 this.getJcrSession().save();
524 }
525 catch (RepositoryException re) {
526 log.error(re.getMessage(), re);
527 throw re;
528 }
529 }
530
531
532
533
534 public boolean hasPendingChanges() throws RepositoryException {
535 return this.getJcrSession().hasPendingChanges();
536 }
537
538
539
540
541
542
543
544 public void refresh(boolean keepChanges) throws RepositoryException {
545 this.getJcrSession().refresh(keepChanges);
546 }
547
548 public String getName() {
549 return this.workspaceName;
550 }
551
552 }