001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 2002-2003 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: URIUtils.java 5961 2006-06-03 13:02:04Z rjoachim $
044: */package org.exolab.castor.net.util;
045:
046: import java.io.*;
047: import java.net.URL;
048: import java.net.MalformedURLException;
049: import java.util.Stack;
050: import java.util.StringTokenizer;
051:
052: /**
053: * A utility class for URI handling
054: *
055: * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
056: **/
057: public class URIUtils {
058:
059: /**
060: * the File protocol
061: **/
062: private static final String FILE_PROTOCOL_PREFIX = "file:///";
063:
064: /**
065: * the path separator for an URI
066: */
067: private static final char HREF_PATH_SEP = '/';
068:
069: /**
070: * the path separate for a URL as a String
071: */
072: private static final String URL_PATH_SEP_STR = "/";
073:
074: /**
075: * The current directory designator
076: */
077: private static final String CURRENT_DIR_OP = ".";
078:
079: /**
080: * The parent directory designator
081: */
082: private static final String PARENT_DIR_OP = "..";
083:
084: /**
085: * Returns an InputStream for the file represented by the href
086: * argument
087: * @param href the href of the file to get the input stream for.
088: * @param documentBase the document base of the href argument, if it
089: * is a relative href
090: * set documentBase to null if there is none.
091: * @return an InputStream to the desired resource
092: * @throws java.io.FileNotFoundException when the file could not be
093: * found
094: * @throws java.io.IOException
095: */
096: public static InputStream getInputStream(String href,
097: String documentBase) throws java.io.FileNotFoundException,
098: java.io.IOException {
099:
100: //-- check for absolute url
101: URL url = null;
102: try {
103: url = new URL(href);
104: return url.openStream();
105: } catch (MalformedURLException muex) {
106: }
107:
108: //-- join document base + href
109: String xHref = null;
110: if ((documentBase != null) && (documentBase.length() > 0)) {
111: int idx = documentBase.lastIndexOf(HREF_PATH_SEP);
112: if (idx == (documentBase.length() - 1))
113: xHref = documentBase + href;
114: else
115: xHref = documentBase + HREF_PATH_SEP + href;
116: } else
117: xHref = href;
118:
119: //-- check for relative url
120: try {
121: url = new URL(xHref);
122: return url.openStream();
123: } catch (MalformedURLException muex) {
124: }
125:
126: // Try local files
127: File iFile = new File(href);
128: if (iFile.isAbsolute())
129: return new FileInputStream(iFile);
130:
131: iFile = new File(xHref);
132: return new FileInputStream(iFile);
133:
134: } //-- getInputStream
135:
136: /**
137: * Returns a Reader for the file represented by the href
138: * argument
139: * @param href the href of the file to get the input stream for.
140: * @param documentBase the document base of the href argument, if it
141: * is a relative href
142: * set documentBase to null if there is none.
143: * @return an InputStream to the desired resource
144: * @exception java.io.FileNotFoundException when the file could not be
145: * found
146: **/
147: public static Reader getReader(String href, String documentBase)
148: throws java.io.FileNotFoundException, java.io.IOException {
149: InputStream is = getInputStream(href, documentBase);
150: return new InputStreamReader(is);
151: } //-- getReader
152:
153: /**
154: * Returns the document base of the href argument
155: * @return the document base of the given href
156: **/
157: public static String getDocumentBase(String href) {
158:
159: String docBase = "";
160:
161: if (href == null)
162: return docBase;
163:
164: int idx = -1;
165: //-- check for URL
166: try {
167: //-- try to create a new URL and see if MalformedURLExcetion is
168: //-- ever thrown
169: new URL(href);
170: idx = href.lastIndexOf(HREF_PATH_SEP);
171: } catch (MalformedURLException muex) {
172: //-- The following contains a fix from Shane Hathaway
173: //-- to handle the case when both "\" and "/" appear in filename
174: int idx2 = href.lastIndexOf(HREF_PATH_SEP);
175: idx = href.lastIndexOf(File.separator);
176: if (idx2 > idx)
177: idx = idx2;
178: }
179:
180: if (idx >= 0)
181: docBase = href.substring(0, idx);
182:
183: return docBase;
184: } //-- getDocumentBase
185:
186: /**
187: * Returns the relative URI of the href argument
188: *
189: * @return the relative URI the given href
190: **/
191: public static String getRelativeURI(String href) {
192:
193: if (href == null)
194: return href;
195:
196: int idx = -1;
197: //-- check for URL
198: try {
199: //-- try to create a new URL and see if MalformedURLExcetion is
200: //-- ever thrown
201: new URL(href);
202: idx = href.lastIndexOf(HREF_PATH_SEP);
203: } catch (MalformedURLException muex) {
204: //-- The following contains a fix from Shane Hathaway
205: //-- to handle the case when both "\" and "/" appear in filename
206: int idx2 = href.lastIndexOf(HREF_PATH_SEP);
207: idx = href.lastIndexOf(File.separator);
208: if (idx2 > idx)
209: idx = idx2;
210: }
211:
212: if (idx >= 0)
213: return href.substring(idx + 1);
214:
215: return href;
216: } //-- getRelativeURI
217:
218: /**
219: * This method removes "." or ".." from absolute URL.
220: * I needed this method because the JDK doesn't do this
221: * automatically when creating URLs.
222: *
223: * @param absoluteURL the absolute URI to normalize
224: */
225: public static String normalize(String absoluteURL)
226: throws MalformedURLException {
227: if (absoluteURL == null)
228: return absoluteURL;
229: if (absoluteURL.indexOf('.') < 0)
230: return absoluteURL;
231:
232: //-- Note: using StringTokenizer and Stacks
233: //-- is not very efficient, this may need
234: //-- some optimizing
235: Stack tokens = new Stack();
236: StringTokenizer st = new StringTokenizer(absoluteURL,
237: URL_PATH_SEP_STR, true);
238: String last = null;
239: while (st.hasMoreTokens()) {
240: String token = st.nextToken();
241: if (URL_PATH_SEP_STR.equals(token)) {
242: if (URL_PATH_SEP_STR.equals(last)) {
243: tokens.push("");
244: }
245: } else if (PARENT_DIR_OP.equals(token)) {
246: if (tokens.empty()) {
247: //-- this should be an error
248: throw new MalformedURLException(
249: "invalid absolute URL: " + absoluteURL);
250: }
251: tokens.pop();
252: } else {
253: if (!CURRENT_DIR_OP.equals(token)) {
254: tokens.push(token);
255: }
256: }
257: last = token;
258: }
259:
260: //-- rebuild URL
261: StringBuffer buffer = new StringBuffer(absoluteURL.length());
262: for (int i = 0; i < tokens.size(); i++) {
263: if (i > 0)
264: buffer.append(HREF_PATH_SEP);
265: buffer.append(tokens.elementAt(i).toString());
266: }
267: return buffer.toString();
268: } //-- normalize
269:
270: /**
271: *
272: **/
273: public static String resolveAsString(String href,
274: String documentBase) {
275:
276: try {
277: //-- try to create a new URL and see if MalformedURLExcetion is
278: //-- ever thrown
279: new URL(href);
280: return href;
281: } catch (MalformedURLException muex) {
282: }
283:
284: //-- join document base + href
285: String absolute = null;
286: if ((documentBase != null) && (documentBase.length() > 0)) {
287: int idx = documentBase.lastIndexOf(HREF_PATH_SEP);
288: if (idx == (documentBase.length() - 1))
289: absolute = documentBase + href;
290: else
291: absolute = documentBase + HREF_PATH_SEP + href;
292:
293: } else
294: absolute = href;
295:
296: try {
297: //-- try to create a new URL and see if MalformedURLExcetion is
298: //-- ever thrown
299:
300: if (absolute.indexOf("./") >= 0) {
301: //-- normalize . or .. from URL
302: absolute = normalize(absolute);
303: }
304: new URL(absolute);
305: return absolute;
306: } catch (MalformedURLException muex) {
307: //-- check for unrecognized protocol
308: int idx = absolute.indexOf(':');
309: if (idx >= 0) {
310: String scheme = absolute.substring(0, idx);
311: //-- a bit of a hack, but good enough for now
312: String error = "unknown protocol: " + scheme;
313: if (error.equals(muex.getMessage())) {
314: return absolute;
315: }
316: }
317:
318: }
319:
320: // Try local files
321: String fileURL = absolute;
322: File iFile = new File(href);
323: boolean exists = iFile.exists();
324: fileURL = createFileURL(iFile.getAbsolutePath());
325: if (!iFile.isAbsolute()) {
326: iFile = new File(absolute);
327: if (iFile.exists() || (!exists)) {
328: fileURL = createFileURL(iFile.getAbsolutePath());
329: }
330: }
331:
332: //-- one last sanity check
333: try {
334: //-- try to create a new URL and see if MalformedURLExcetion is
335: //-- ever thrown
336: new URL(fileURL);
337: return fileURL;
338: } catch (MalformedURLException muex) {
339: }
340:
341: //-- At this point we we're unsucessful at trying to resolve
342: //-- the href + documentbase, this could be due to a custom
343: //-- protocol or typo in the URI, just return documentBase +
344: //-- href
345: return absolute;
346: } //-- resolveHref
347:
348: /**
349: * Creates a File URL for the given file name
350: *
351: * @param filename the name of the file
352: * @return the String representation of the File URL
353: **/
354: private static String createFileURL(String filename) {
355:
356: if (filename == null)
357: return FILE_PROTOCOL_PREFIX;
358: int size = filename.length() + FILE_PROTOCOL_PREFIX.length();
359: StringBuffer sb = new StringBuffer(size);
360: sb.append(FILE_PROTOCOL_PREFIX);
361: char[] chars = filename.toCharArray();
362: for (int i = 0; i < chars.length; i++) {
363: char ch = chars[i];
364: switch (ch) {
365: case '\\':
366: sb.append(HREF_PATH_SEP);
367: break;
368: default:
369: sb.append(ch);
370: break;
371:
372: }
373: }
374: return sb.toString();
375: } //-- createFileURL
376:
377: } //-- URIUtils
|