View Javadoc

1   /*
2    * Copyright 2007 Hippo
3    *
4    * Licensed under the Apache License, Version 2.0 (the  "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" 
12   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
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     // Regular expression matching two or more consecutive slashes
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         // rule number 1
122         if (path == null || path.length() == 0) {
123             path = "/";
124         }
125 
126         // rule number 2
127         path = multipleSlashes.matcher(path).replaceAll("/");
128 
129         // rule number 3
130         if (!path.startsWith("/")) {
131             path = "/" + path;
132         }
133 
134         // rule number 4
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 }