View Javadoc

1   /**
2    * This file Copyright (c) 2003-2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.core;
35  
36  import java.io.File;
37  import java.io.IOException;
38  
39  import javax.jcr.RepositoryException;
40  import javax.jcr.Session;
41  
42  import org.apache.commons.lang.StringUtils;
43  import org.safehaus.uuid.UUIDGenerator;
44  
45  
46  /**
47   * Utility class to retrieve files or directory used by Magnolia. Examples: cache directory, tmp files, ..
48   * @author Sameer Charles
49   * @version 2.0 $Id: Path.java 49397 2011-09-20 09:57:47Z ndesmarais $
50   */
51  public final class Path {
52      /**
53       * New unlabeled nodes default name.
54       */
55      private static final String DEFAULT_UNTITLED_NODE_NAME = "untitled";
56  
57      /**
58       * Utility class, don't instantiate.
59       */
60      private Path() {
61          // unused
62      }
63  
64      /**
65       * Gets the cache directory path (cms.cache.startdir) as set with Java options while startup or in web.xml.
66       * @return Cache directory path
67       */
68      public static String getCacheDirectoryPath() {
69          return getCacheDirectory().getAbsolutePath();
70      }
71  
72      public static File getCacheDirectory() {
73          String path = SystemProperty.getProperty(SystemProperty.MAGNOLIA_CACHE_STARTDIR);
74          File dir = isAbsolute(path) ? new File(path) : new File(getAppRootDir(), path);
75          dir.mkdirs();
76          return dir;
77      }
78  
79      /**
80       * Gets the temporary directory path (cms.upload.tmpdir) as set with Java options while startup or in web.xml.
81       * @return Temporary directory path
82       */
83      public static String getTempDirectoryPath() {
84          return getTempDirectory().getAbsolutePath();
85      }
86  
87      public static File getTempDirectory() {
88          String path = SystemProperty.getProperty(SystemProperty.MAGNOLIA_UPLOAD_TMPDIR);
89          File dir = isAbsolute(path) ? new File(path) : new File(getAppRootDir(), path);
90          dir.mkdirs();
91          return dir;
92      }
93  
94      /**
95       * Gets cms.exchange.history file location as set with Java options while startup or in web.xml.
96       * @return exchange history file location
97       */
98      public static String getHistoryFilePath() {
99          return getHistoryFile().getAbsolutePath();
100     }
101 
102     public static File getHistoryFile() {
103         String path = SystemProperty.getProperty(SystemProperty.MAGNOLIA_EXCHANGE_HISTORY);
104         return isAbsolute(path) ? new File(path) : new File(getAppRootDir(), path);
105     }
106 
107     /**
108      * Gets repositories file location as set with Java options while startup or in web.xml.
109      * @return file location
110      */
111     public static String getRepositoriesConfigFilePath() {
112         return getRepositoriesConfigFile().getAbsolutePath();
113     }
114 
115     public static File getRepositoriesConfigFile() {
116         String path = SystemProperty.getProperty(SystemProperty.MAGNOLIA_REPOSITORIES_CONFIG);
117         return isAbsolute(path) ? new File(path) : new File(getAppRootDir(), path);
118     }
119 
120     /**
121      * Gets the root directory for the magnolia web application.
122      * @return magnolia root dir
123      */
124     public static File getAppRootDir() {
125         return new File(SystemProperty.getProperty(SystemProperty.MAGNOLIA_APP_ROOTDIR));
126     }
127 
128     // TODO : this should probably be in getAppRootDir()
129     private void checkAppRootDir() throws IOException {
130         String root = null;
131         // Try to get root
132         try {
133             File f = getAppRootDir();
134             if (f.isDirectory()) {
135                 root = f.getAbsolutePath();
136             }
137         }
138         catch (Exception e) {
139             // nothing
140         }
141 
142         if (root == null) {
143             throw new IOException("Invalid magnolia " + SystemProperty.MAGNOLIA_APP_ROOTDIR + " path");
144         }
145     }
146 
147     /**
148      * Gets absolute filesystem path, adds application root if path is not absolute.
149      */
150     public static String getAbsoluteFileSystemPath(String path) {
151         if (isAbsolute(path)) {
152             return path;
153         }
154         // using the file() constructor will allow relative paths in the form ../../apps
155         return new File(getAppRootDir(), path).getAbsolutePath();
156     }
157 
158     public static String getUniqueLabel(HierarchyManager hierarchyManager, String parent, String label) {
159         if (parent.equals("/")) {
160             parent = StringUtils.EMPTY;
161         }
162         while (hierarchyManager.isExist(parent + "/" + label)) {
163             label = createUniqueName(label);
164         }
165         return label;
166     }
167 
168     public static String getUniqueLabel(Session session, String parent, String label) throws RepositoryException {
169         if (parent.equals("/")) {
170             parent = StringUtils.EMPTY;
171         }
172         while (session.itemExists(parent + "/" + label)) {
173             label = createUniqueName(label);
174         }
175         return label;
176     }
177 
178     public static String getUniqueLabel(Content parent, String label) {
179         try {
180             while (parent.hasContent(label) || parent.hasNodeData(label)) {
181                 label = createUniqueName(label);
182             }
183         }
184         catch (RepositoryException e) {
185             label = UUIDGenerator.getInstance().generateRandomBasedUUID().toString();
186         }
187         return label;
188     }
189 
190     public static boolean isAbsolute(String path) {
191 
192         if (path == null) {
193             return false;
194         }
195 
196         if (path.startsWith("/") || path.startsWith(File.separator)) {
197             return true;
198         }
199 
200         // windows c:
201         if (path.length() >= 3 && Character.isLetter(path.charAt(0)) && path.charAt(1) == ':') {
202             return true;
203         }
204 
205         return false;
206     }
207 
208     /**
209      * Replace illegal characters based on system property magnolia.ut8.enabled.
210      * @param label label to validate
211      * @return validated label
212      */
213     public static String getValidatedLabel(String label)
214     {
215         String charset = StringUtils.EMPTY;
216         if ((SystemProperty.getBooleanProperty(SystemProperty.MAGNOLIA_UTF8_ENABLED)))
217         {
218             charset = "UTF-8";
219         }
220         return getValidatedLabel(label, charset);
221 
222     }
223 
224     /**
225      * If charset eq to UTF-8 replaces these characters:
226      * jackrabbit not allowed 32: [ ] 91: [[] 93: []] 42: [*] 34: ["] 46: [.] 58 [:] 92: [\] 39 :[']
227      * url not valid 59: [;] 47: [/] 63: [?] 43: [+] 37: [%] 33: [!] 35:[#] 94: [^]
228      *
229      * else replace illegal characters except [_] [0-9], [A-Z], [a-z], [-], [_].
230      * @param label label to validate
231      * @return validated label
232      */
233     public static String getValidatedLabel(String label, String charset)
234     {
235         StringBuffer s = new StringBuffer(label);
236         StringBuffer newLabel = new StringBuffer();
237 
238         for (int i = 0; i < s.length(); i++)
239         {
240             int charCode = s.charAt(i);
241             if (isCharValid(charCode, charset))
242             {
243                 newLabel.append(s.charAt(i));
244             }
245             else
246             {
247                 newLabel.append("-");
248             }
249         }
250         if (newLabel.length() == 0)
251         {
252             newLabel.append(DEFAULT_UNTITLED_NODE_NAME);
253         }
254         return newLabel.toString();
255     }
256 
257     /**
258      * @param charCode char code
259      * @param charset charset (ex. UTF-8)
260      * @return true if char can be used as a content name
261      */
262     public static boolean isCharValid(int charCode, String charset)
263     {
264         // http://www.ietf.org/rfc/rfc1738.txt
265         // safe = "$" | "-" | "_" | "." | "+"
266         // extra = "!" | "*" | "'" | "(" | ")" | ","
267         // national = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`"
268         // punctuation = "<" | ">" | "#" | "%" | <">
269         // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "="
270 
271         if ("UTF-8".equals(charset))
272         {
273             // jackrabbit not allowed 32: [ ] 91: [[] 93: []] 42: [*] 34: ["] 46: [.] 58 [:] 92: [\] 39 :[']
274             // url not valid 59: [;] 47: [/] 63: [?] 43: [+] 37: [%] 33: [!] 35:[#]
275             if (charCode != 32
276                 && charCode != '['
277                 && charCode != ']'
278                 && charCode != '*'
279                 && charCode != '"'
280                 && charCode != '.'
281                 && charCode != ':'
282                 && charCode != 92
283                 && charCode != 39
284                 && charCode != ';'
285                 && charCode != '/'
286                 && charCode != '?'
287                 && charCode != '+'
288                 && charCode != '%'
289                 && charCode != '!'
290                 && charCode != '#'
291                 && charCode != '@'
292                 && charCode != '&'
293                 && charCode != '=')
294             {
295                 return true;
296             }
297         }
298         else
299         {
300             // charCodes: 48-57: [0-9]; 65-90: [A-Z]; 97-122: [a-z]; 45: [-]; 95:[_]
301             if (((charCode >= 48) && (charCode <= 57))
302                     || ((charCode >= 65) && (charCode <= 90))
303                     || ((charCode >= 97) && (charCode <= 122))
304                     || charCode == 45
305                     || charCode == 95)
306             {
307                 return true;
308             }
309 
310         }
311         return false;
312 
313     }
314 
315     private static String createUniqueName(String baseName) {
316         int pos;
317         for (pos = baseName.length() - 1; pos >= 0; pos--) {
318             char c = baseName.charAt(pos);
319             if (c < '0' || c > '9') {
320                 break;
321             }
322         }
323         String base;
324         int cnt;
325         if (pos == -1) {
326             if (baseName.length() > 1) {
327                 pos = baseName.length() - 2;
328             }
329         }
330         if (pos == -1) {
331             base = baseName;
332             cnt = -1;
333         }
334         else {
335             pos++;
336             base = baseName.substring(0, pos);
337             if (pos == baseName.length()) {
338                 cnt = -1;
339             }
340             else {
341                 cnt = new Integer(baseName.substring(pos)).intValue();
342             }
343         }
344         return (base + ++cnt);
345     }
346 
347     public static String getAbsolutePath(String path, String label) {
348         if (StringUtils.isEmpty(path) || (path.equals("/"))) {
349             return "/" + label;
350         }
351 
352         return path + "/" + label;
353     }
354 
355     public static String getAbsolutePath(String path) {
356         if (!path.startsWith("/")) {
357             return "/" + path;
358         }
359         return path;
360     }
361 
362     /**
363      * @deprecated since 4.0 - untested and unused
364      */
365     @Deprecated
366     public static String getNodePath(String path, String label) {
367         if (StringUtils.isEmpty(path) || (path.equals("/"))) {
368             return label;
369         }
370         return getNodePath(path + "/" + label);
371     }
372 
373     /**
374      * @deprecated since 4.0 - untested and unused
375      */
376     @Deprecated
377     public static String getNodePath(String path) {
378         if (path.startsWith("/")) {
379             return path.replaceFirst("/", StringUtils.EMPTY);
380         }
381         return path;
382     }
383 
384     /**
385      * @deprecated since 4.0 - untested and unused
386      */
387     @Deprecated
388     public static String getParentPath(String path) {
389         int lastIndexOfSlash = path.lastIndexOf("/");
390         if (lastIndexOfSlash > 0) {
391             return StringUtils.substringBefore(path, "/");
392         }
393         return "/";
394     }
395 }