001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.catalog;
016:
017: import java.io.File;
018: import java.io.IOException;
019: import java.net.MalformedURLException;
020: import java.net.URL;
021:
022: import org.geotools.data.DataUtilities;
023:
024: /**
025: * Utilities for dealing with the catalog's use of URLs as identifiers
026: *
027: * @author Jesse
028: * @since 1.1.0
029: */
030: public class URLUtils {
031:
032: /**
033: * Primarily for testing the comparison of URLS. it is not a simple thing because different platforms can sometimes
034: * create ones with a dangling / or with / vs \ some times file:/// or file:/.
035: *
036: * @param url1 first url to compare
037: * @param url2 second url
038: * @param stripRef if the reference should be ignored. For example searching for the IService
039: * of a IGeoResource. The Service ID would not have a reference but the IGeoResource would so
040: * ignore the reference in this case.
041: * @return true if they refer to the same resource.
042: */
043: public static boolean urlEquals(URL url1, URL url2, boolean stripRef) {
044: if (url1 == null) {
045: if (url2 == null)
046: return true;
047: return false;
048: }
049: if (url2 == null) {
050: return false;
051: }
052: boolean sameProtocol = url2.getProtocol().equalsIgnoreCase(
053: url1.getProtocol());
054: boolean sameHost = ((url2.getHost() == null || "".equals(url2.getHost())) || (url2.getHost() != null && url2.getHost().equalsIgnoreCase(url1.getHost()))); //$NON-NLS-1$
055: boolean samePath = ((url2.getPath() == null || "".equals(url2.getPath())) || (url2.getPath() != null && url2.getPath().equalsIgnoreCase(url1.getPath()))); //$NON-NLS-1$
056: boolean sameQuery = ((url2.getQuery() == null || "".equals(url2.getQuery())) || (url2.getQuery() != null && url2.getQuery().equalsIgnoreCase(url1.getQuery()))); //$NON-NLS-1$
057: boolean sameAuthority = ((url2.getAuthority() == null || "".equals(url2.getAuthority())) || (url2.getAuthority() != null && url2.getAuthority().equalsIgnoreCase(url1.getAuthority()))); //$NON-NLS-1$
058: boolean sameRef = !stripRef
059: && ((url2.getRef() == null || "".equals(url2.getRef())) || (url2.getRef() != null && url2.getRef().equalsIgnoreCase(url1.getRef()))); //$NON-NLS-1$
060: if (sameProtocol && sameHost && samePath && sameQuery
061: && sameAuthority && sameRef)
062: return true;
063:
064: String string1 = URLUtils.urlToString(url1, stripRef);
065: String string2 = URLUtils.urlToString(url2, stripRef);
066: if (stripRef)
067: return string1.startsWith(string2)
068: || string2.startsWith(string1);
069: return string1.equalsIgnoreCase(string2);
070: }
071:
072: /**
073: * Provides a standard way of converting to string.
074: *
075: * @param url1 url to convert to string
076: * @param ignoreRef wether to ignore te reference in the string.
077: * @return the url in string form. Always uses / and file:/. (rather than file:///).
078: */
079: public static String urlToString(URL url1, boolean ignoreRef) {
080: String string = url1.toExternalForm();
081: if (ignoreRef) {
082: if (string.contains("#")) //$NON-NLS-1$
083: string = string.substring(0, string.lastIndexOf('#'));
084: }
085: string = string.replaceAll("\\\\", "/"); //$NON-NLS-1$//$NON-NLS-2$
086: if (string.endsWith("/")) //$NON-NLS-1$
087: string = string.substring(0, string.length() - 1);
088: string = string.replaceAll("/+", "/"); //$NON-NLS-1$ //$NON-NLS-2$
089: return string;
090: }
091:
092: /**
093: * Converts the URL to a URL indicating the relative path from the reference file to the location indicated
094: * by the destination URL. If it is not possible to to make a relative path then the destination URL will be returned unchanged.
095: * <p>
096: * Examples:
097: * <ul>
098: * <li>reference = c:\foo\bar
099: * <p>destination = file:/c:\booger\data<p>
100: * <p>return = file:/..\..\booger\data</p></li>
101: * <li>reference = c:\foo\bar
102: * <p>destination = file:/d:\booger\data<p>
103: * <p>return = file:/d:\booger\data</p></li>
104: * <li>reference = c:\foo\bar
105: * <p>destination = http://booger.com\data<p>
106: * <p>return = http://booger.com\data</p></li>
107: * </ul>
108: * </p>
109: *
110: * @param reference the "from" file. The file that the relative path will start at. <b>MUST BE A FILE</b>
111: * @param destination the URL to transform to a relative path
112: * @return the relative path from reference to destination
113: */
114: public static URL toRelativePath(File reference, URL destination) {
115: if (!destination.getProtocol().equalsIgnoreCase("file") //$NON-NLS-1$
116: || destination.getQuery() != null
117: || destination.getRef() != null)
118: return destination;
119:
120: String from = reference.getAbsolutePath();
121: String to = urlToString(destination, false).substring(5);
122:
123: if (from.equals(to))
124: try {
125: return new URL("file:/./"); //$NON-NLS-1$
126: } catch (MalformedURLException e1) {
127: throw new RuntimeException(e1);
128: }
129:
130: int endOfMatch = 0;
131: int lastSlash = 0;
132: for (int i = 0; i < from.length(); i++) {
133: char fromChar = from.charAt(i);
134: char toChar = to.charAt(i);
135:
136: endOfMatch = i;
137: if (fromChar != toChar) {
138: break;
139: }
140: if (fromChar == '/')
141: lastSlash = i;
142:
143: }
144:
145: if (endOfMatch == 0)
146: return destination;
147:
148: String substring = from.substring(lastSlash + 1);
149: int slashes = substring.split("/").length - 1; //$NON-NLS-1$
150:
151: StringBuilder result = new StringBuilder();
152:
153: for (int i = 0; i < slashes; i++) {
154: result.append("../"); //$NON-NLS-1$
155: }
156:
157: try {
158: return new URL(
159: "file:/" + result.toString() + to.substring(lastSlash + 1)); //$NON-NLS-1$
160: } catch (MalformedURLException e) {
161: return destination;
162: }
163: }
164:
165: /**
166: * Creates a URL from the string. If the String is a relative URL (and is a file) the returned
167: * URL will be resolved to the Absolute path with respect to the reference parameter.
168: *
169: * <p>
170: * <ul>
171: * <li>reference = c:\foo\bar
172: * <p>destination = file:/..\..\booger\data</p>
173: * <p> return = file:/c:\booger\data<p>
174: * </li>
175: * </ul></p>
176: *
177: * @param reference the base of any relative path. <b>MUST BE A FILE</b>
178: * @param url the url in string form.
179: *
180: * @return the URL created from the string
181: */
182: public static URL constructURL(File reference, String url)
183: throws MalformedURLException {
184: if (!url.startsWith("file:/") || url.contains("?") //$NON-NLS-1$ //$NON-NLS-2$
185: || url.contains("#")) { //$NON-NLS-1$
186: return new URL(url);
187: }
188:
189: String substring = url.substring(6);
190: try {
191: if (substring.charAt(0) == reference.getCanonicalPath()
192: .charAt(0))
193: return new URL(url);
194: } catch (IOException e1) {
195: return new URL(url);
196: }
197:
198: File file = new File(reference.getParentFile(), substring);
199:
200: try {
201: return file.getCanonicalFile().toURL();
202: } catch (IOException e) {
203: return new URL(url);
204: }
205: }
206:
207: /**
208: * Takes a URL and converts it to a File. The attempts to deal with
209: * Windows UNC format specific problems, specifically files located
210: * on network shares and different drives.
211: *
212: * If the URL.getAuthority() returns null or is empty, then only the
213: * url's path property is used to construct the file. Otherwise, the
214: * authority is prefixed before the path.
215: *
216: * It is assumed that url.getProtocol returns "file".
217: *
218: * Authority is the drive or network share the file is located on.
219: * Such as "C:", "E:", "\\fooServer"
220: *
221: * @param url
222: * @return
223: */
224: public static File urlToFile(URL url) {
225: return DataUtilities.urlToFile(url);
226: }
227: }
|