1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.chemistry.opencmis.jcr;
21
22 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
23 import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import javax.jcr.Node;
28 import javax.jcr.RepositoryException;
29
30 /**
31 * Utility class for mapping JCR paths to CMIS paths
32 */
33 public class PathManager {
34 private static final Log log = LogFactory.getLog(PathManager.class);
35
36 /**
37 * Identifier of the root folder
38 */
39 public static final String CMIS_ROOT_ID = "[root]";
40
41 /**
42 * Root path
43 */
44 public static final String CMIS_ROOT_PATH = "/";
45
46 private final String jcrRootPath;
47
48 /**
49 * Create a new <code>PathManager</code> instance for the given JCR root path.
50 * @param jcrRootPath
51 */
52 public PathManager(String jcrRootPath) {
53 this.jcrRootPath = normalize(jcrRootPath);
54 }
55
56 /**
57 * @return the JCR root path
58 */
59 public String getJcrRootPath() {
60 return jcrRootPath;
61 }
62
63 /**
64 * Determines whether a JCR <code>Node</code> is the root node wrt. to this
65 * <code>PathManager</code> instance. That is, whether the path of the node is
66 * equal to this instance's JCR root path.
67 *
68 * @param node
69 * @return <code>true</code> iff <code>node</code> is the root node wrt. to
70 * this <code>PathManager</code> instance.
71 */
72 public boolean isRoot(Node node) {
73 try {
74 return node.getPath().equals(jcrRootPath);
75 }
76 catch (RepositoryException e) {
77 log.debug(e.getMessage(), e);
78 throw new CmisRuntimeException(e.getMessage(), e);
79 }
80 }
81
82 /**
83 * Determine the CMIS path given a JCR <code>Node</code>.
84 *
85 * @param node
86 * @return
87 * @throws IllegalArgumentException when <code>node</code> is not part of the hierarchy
88 */
89 public String getPath(Node node) {
90 try {
91 if (jcrRootPath.length() > node.getPath().length()) {
92 throw new IllegalArgumentException("Node is not part of the hierarchy: " + node.getPath());
93 }
94
95 String path = node.getPath().substring(jcrRootPath.length());
96 return path.startsWith("/") ? path : '/' + path;
97 }
98 catch (RepositoryException e) {
99 log.debug(e.getMessage(), e);
100 throw new CmisRuntimeException(e.getMessage(), e);
101 }
102 }
103
104 /**
105 * @param cmisPath
106 * @return <code>true</code> iff <code>cmisPath</code> equals {@link PathManager#CMIS_ROOT_PATH}
107 */
108 public static boolean isRoot(String cmisPath) {
109 return CMIS_ROOT_PATH.equals(cmisPath);
110 }
111
112 /**
113 * @param cmisPath
114 * @return <code>true</code> iff <code>cmisPath</code>
115 */
116 public static boolean isAbsolute(String cmisPath) {
117 return cmisPath.startsWith(CMIS_ROOT_PATH);
118 }
119
120 /**
121 * Create a CMIS path from a parent path and a child element
122 * @param cmisPath parent path
123 * @param child child element
124 * @return
125 */
126 public static String createCmisPath(String cmisPath, String child) {
127 return cmisPath.length() > 0 && cmisPath.charAt(cmisPath.length() - 1) == '/'
128 ? cmisPath + child
129 : cmisPath + '/' + child;
130 }
131
132 /**
133 * Relativize an CMIS path wrt. to a prefix.
134 * @param prefix
135 * @param cmisPath
136 * @return a string <code>r</code> such that <code>prefix</code> + <code>r</code> = <code>cmisPath</code>
137 * @throws IllegalArgumentException if <code>prefix</code> is not a prefix of <code>cmisPath</code>
138 */
139 public static String relativize(String prefix, String cmisPath) {
140 if (cmisPath.startsWith(prefix)) {
141 return cmisPath.substring(prefix.length());
142 }
143 else {
144 throw new IllegalArgumentException(prefix + " is not a prefix of " + cmisPath);
145 }
146 }
147
148 //------------------------------------------< private >---
149
150 private static String normalize(String path) {
151 if (path == null || path.length() == 0) {
152 return "/";
153 }
154
155 if (!path.startsWith("/")) {
156 throw new CmisInvalidArgumentException("Root path must be absolute. Got: " + path);
157 }
158
159 while (path.length() > 1 && path.endsWith("/")) {
160 path = path.substring(0, path.length() - 1);
161 }
162 return path;
163 }
164 }