1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package nl.hippo.client.webdav;
17
18 import java.util.regex.Pattern;
19
20 import nl.hippo.client.api.content.DocumentPath;
21
22 import org.apache.commons.lang.builder.HashCodeBuilder;
23 import org.apache.commons.lang.builder.ToStringBuilder;
24 import org.apache.commons.lang.builder.ToStringStyle;
25
26 /**
27 * Represents a path in the repository.
28 *
29 * <p>
30 * <b>methods</b>
31 * <ul>
32 * <li>getNamespace() => returns hippo.client.namespace from WebdavConfig</li>
33 * <li>getFilesPath() => returns hippo.client.filespath from WebdavConfig</li>
34 * <li>getRootPath() => returns getNameSpace() + getFilesPath() or getPrefixPath() + getFilesPath()</li>
35 * <li>getRelativePath() => returns the relative documentpath (getFullPath() - getRootPath())</li>
36 * <li>getFullPath() => returns getRootPath() + getRelativePath()</li>
37 * </ul>
38 * </p>
39 *
40 * <p>
41 * <b>slashes</b>
42 * <ul>
43 * <li>getNamespace() -> without any slashes</li>
44 * <li>All other methods -> starts with slash and ends without slash</li>
45 * </ul>
46 *
47 * These rules are guaranteed even if the configuration isn't completely clean,
48 * ie "namespace = /default/"
49 * </p>
50 */
51 public class DocumentPathImpl implements DocumentPath {
52
53 private static final long serialVersionUID = 1L;
54
55 private String contextroot;
56 private String namespace;
57 private String filesPath;
58 private String fullPath;
59 private String rootPath;
60 private String relativePath;
61
62 public DocumentPathImpl(String namespace, String contextroot, String filesPath, String path, boolean isRelative) {
63 this(namespace, contextroot, filesPath, new String[] { path }, isRelative);
64 }
65
66 public DocumentPathImpl(String namespace, String contextroot, String filesPath, String[] pathElems,
67 boolean isRelative) {
68 if (namespace == null) {
69 throw new IllegalArgumentException("namespace may not be null");
70 }
71 if (pathElems == null) {
72 throw new IllegalArgumentException("pathElems may not be null");
73 }
74
75 if(contextroot != null) {
76 this.contextroot = contextroot.equals("/") ? "" : fixPath(contextroot);
77 } else {
78 this.contextroot = null;
79 }
80 this.namespace = namespace.replaceAll("/+", "");
81 this.filesPath = fixPath(filesPath);
82 if (this.contextroot != null) {
83 this.rootPath = fixPath(this.contextroot + this.filesPath);
84 } else {
85 this.rootPath = fixPath(this.namespace + this.filesPath);
86 }
87
88 StringBuffer buf = new StringBuffer();
89 for (int i = 0; i < pathElems.length; i++) {
90 buf.append(fixPath(pathElems[i]));
91 }
92 String path = fixPath(buf.toString());
93
94 if (isRelative) {
95 this.fullPath = rootPath + path;
96 this.relativePath = path;
97
98 } else {
99 this.fullPath = path;
100 if (!fullPath.startsWith(rootPath)) {
101 throw new IllegalArgumentException("Absolute path '" + fullPath
102 + "' cannot be constructed if root path is configured as '" + rootPath + "'");
103 }
104 this.relativePath = fullPath.substring(rootPath.length(), fullPath.length());
105 }
106 }
107
108
109 private static final Pattern multipleSlashes = Pattern.compile("/{2,}");
110
111 /**
112 * Ensure that:
113 * <ol>
114 * <li>path is '/' rather than null or an empty String</li>
115 * <li>there are only single '/' occurences</li>
116 * <li>path starts with one and only one '/'</li>
117 * <li>path ends without a '/'</li>
118 * </ol>
119 */
120 private String fixPath(String path) {
121
122 if (path == null || path.length() == 0) {
123 path = "/";
124 }
125
126
127 path = multipleSlashes.matcher(path).replaceAll("/");
128
129
130 if (!path.startsWith("/")) {
131 path = "/" + path;
132 }
133
134
135 if (path.endsWith("/")) {
136 path = path.substring(0, path.length() - 1);
137 }
138
139 return path;
140 }
141
142 public String getContextRoot() {
143 return contextroot;
144 }
145
146 public String getNamespace() {
147 return namespace;
148 }
149
150 public String getFilesPath() {
151 return filesPath;
152 }
153
154 public String getRootPath() {
155 return rootPath;
156 }
157
158 public String getRelativePath() {
159 return relativePath;
160 }
161
162 public String getFullPath() {
163 return fullPath;
164 }
165
166 public DocumentPath createAbsolutePath(String absolute) {
167 return createAbsolutePath(new String[] { absolute });
168 }
169
170 public DocumentPath createAbsolutePath(String[] pathElems) {
171 return new DocumentPathImpl(this.namespace, this.contextroot, this.filesPath, pathElems, false);
172 }
173
174 public DocumentPath createRelativePath(String relative) {
175 return createRelativePath(new String[] { relative });
176 }
177
178 public DocumentPath createRelativePath(String[] pathElems) {
179 return new DocumentPathImpl(this.namespace, this.contextroot, this.filesPath, pathElems, true);
180 }
181
182 public String toString() {
183 ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("namespace",
184 namespace).append("contextroot", (contextroot != null ? contextroot : "")).append("filesPath",
185 filesPath).append("fullPath", fullPath).append("rootPath", rootPath).append("relativePath",
186 relativePath);
187 return builder.toString();
188 }
189
190 public boolean equals(Object obj) {
191 boolean eq;
192 if (obj == null) {
193 eq = false;
194 } else if (!(obj instanceof DocumentPathImpl)) {
195 eq = false;
196 } else if (this == obj) {
197 eq = true;
198 } else {
199 DocumentPathImpl rhs = (DocumentPathImpl) obj;
200 eq = ((contextroot == null && rhs.contextroot == null) || (contextroot != null && rhs.contextroot != null && contextroot
201 .equals(rhs.contextroot)))
202 && (namespace.equals(rhs.namespace) && filesPath.equals(rhs.filesPath) && fullPath
203 .equals(rhs.fullPath));
204 }
205 return eq;
206 }
207
208 public int hashCode() {
209 int hash;
210 if (contextroot != null) {
211 hash = new HashCodeBuilder(23, 77).append(namespace).append(contextroot).append(filesPath).append(fullPath)
212 .append(rootPath).append(relativePath).toHashCode();
213 } else {
214 hash = new HashCodeBuilder(23, 77).append(namespace).append(filesPath).append(fullPath).append(rootPath)
215 .append(relativePath).toHashCode();
216 }
217 return hash;
218 }
219
220 }