001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001, ThoughtWorks, Inc.
004: * 200 E. Randolph, 25th Floor
005: * Chicago, IL 60601 USA
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * + Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * + Redistributions in binary form must reproduce the above
016: * copyright notice, this list of conditions and the following
017: * disclaimer in the documentation and/or other materials provided
018: * with the distribution.
019: *
020: * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
021: * names of its contributors may be used to endorse or promote
022: * products derived from this software without specific prior
023: * written permission.
024: *
025: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
026: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
027: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
028: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
030: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
031: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
032: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
033: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
034: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036: ********************************************************************************/package net.sourceforge.cruisecontrol.launch.util;
037:
038: import java.io.File;
039: import java.io.FilenameFilter;
040: import java.net.MalformedURLException;
041: import java.net.URL;
042: import java.text.CharacterIterator;
043: import java.text.StringCharacterIterator;
044: import java.util.Locale;
045:
046: /**
047: * The Locator is a utility class which is used to find certain items
048: * in the environment.
049: *
050: * @since Ant 1.6
051: */
052: public final class Locator {
053: /**
054: * Not instantiable
055: */
056: private Locator() {
057: }
058:
059: /**
060: * Find the directory or jar file the class has been loaded from.
061: *
062: * @param c the class whose location is required.
063: * @return the file or jar with the class or null if we cannot
064: * determine the location.
065: *
066: * @since Ant 1.6
067: */
068: public static File getClassSource(Class c) {
069: String classResource = c.getName().replace('.', '/') + ".class";
070: return getResourceSource(c.getClassLoader(), classResource);
071: }
072:
073: /**
074: * Find the directory or jar a given resource has been loaded from.
075: *
076: * @param c the classloader to be consulted for the source.
077: * @param resource the resource whose location is required.
078: *
079: * @return the file with the resource source or null if
080: * we cannot determine the location.
081: *
082: * @since Ant 1.6
083: */
084: public static File getResourceSource(ClassLoader c, String resource) {
085: if (c == null) {
086: c = Locator.class.getClassLoader();
087: }
088: URL url = null;
089: if (c == null) {
090: url = ClassLoader.getSystemResource(resource);
091: } else {
092: url = c.getResource(resource);
093: }
094: if (url != null) {
095: String u = url.toString();
096: if (u.startsWith("jar:file:")) {
097: int pling = u.indexOf("!");
098: String jarName = u.substring(4, pling);
099: return new File(fromURI(jarName));
100: } else if (u.startsWith("file:")) {
101: int tail = u.indexOf(resource);
102: String dirName = u.substring(0, tail);
103: return new File(fromURI(dirName));
104: }
105: }
106: return null;
107: }
108:
109: /**
110: * Constructs a file path from a <code>file:</code> URI.
111: *
112: * <p>Will be an absolute path if the given URI is absolute.</p>
113: *
114: * <p>Swallows '%' that are not followed by two characters,
115: * doesn't deal with non-ASCII characters.</p>
116: *
117: * @param uri the URI designating a file in the local filesystem.
118: * @return the local file system path for the file.
119: * @since Ant 1.6
120: */
121: public static String fromURI(String uri) {
122: URL url = null;
123: try {
124: url = new URL(uri);
125: } catch (MalformedURLException emYouEarlEx) {
126: // Ignore malformed exception
127: }
128: if (url == null || !("file".equals(url.getProtocol()))) {
129: throw new IllegalArgumentException(
130: "Can only handle valid file: URIs");
131: }
132: StringBuffer buf = new StringBuffer(url.getHost());
133: if (buf.length() > 0) {
134: buf.insert(0, File.separatorChar).insert(0,
135: File.separatorChar);
136: }
137: String file = url.getFile();
138: int queryPos = file.indexOf('?');
139: buf.append((queryPos < 0) ? file : file.substring(0, queryPos));
140:
141: uri = buf.toString().replace('/', File.separatorChar);
142:
143: if (File.pathSeparatorChar == ';' && uri.startsWith("\\")
144: && uri.length() > 2
145: && Character.isLetter(uri.charAt(1))
146: && uri.lastIndexOf(':') > -1) {
147: uri = uri.substring(1);
148: }
149: String path = decodeUri(uri);
150: return path;
151: }
152:
153: /**
154: * Decodes an Uri with % characters.
155: * @param uri String with the uri possibly containing % characters.
156: * @return The decoded Uri
157: */
158: private static String decodeUri(String uri) {
159: if (uri.indexOf('%') == -1) {
160: return uri;
161: }
162: StringBuffer sb = new StringBuffer();
163: CharacterIterator iter = new StringCharacterIterator(uri);
164: for (char c = iter.first(); c != CharacterIterator.DONE; c = iter
165: .next()) {
166: if (c == '%') {
167: char c1 = iter.next();
168: if (c1 != CharacterIterator.DONE) {
169: int i1 = Character.digit(c1, 16);
170: char c2 = iter.next();
171: if (c2 != CharacterIterator.DONE) {
172: int i2 = Character.digit(c2, 16);
173: sb.append((char) ((i1 << 4) + i2));
174: }
175: }
176: } else {
177: sb.append(c);
178: }
179: }
180: String path = sb.toString();
181: return path;
182: }
183:
184: /**
185: * Get the File necessary to load the Sun compiler tools. If the classes
186: * are available to this class, then no additional URL is required and
187: * null is returned. This may be because the classes are explicitly in the
188: * class path or provided by the JVM directly.
189: *
190: * @return the tools jar as a File if required, null otherwise.
191: */
192: public static File getToolsJar() {
193: // firstly check if the tools jar is already in the classpath
194: boolean toolsJarAvailable = false;
195: try {
196: // just check whether this throws an exception
197: Class.forName("com.sun.tools.javac.Main");
198: toolsJarAvailable = true;
199: } catch (Exception e) {
200: try {
201: Class.forName("sun.tools.javac.Main");
202: toolsJarAvailable = true;
203: } catch (Exception e2) {
204: // ignore
205: }
206: }
207: if (toolsJarAvailable) {
208: return null;
209: }
210: // couldn't find compiler - try to find tools.jar
211: // based on java.home setting
212: String javaHome = System.getProperty("java.home");
213: if (javaHome.toLowerCase(Locale.US).endsWith("jre")) {
214: javaHome = javaHome.substring(0, javaHome.length() - 4);
215: }
216: File toolsJar = new File(javaHome + "/lib/tools.jar");
217: if (!toolsJar.exists()) {
218: System.out.println("Unable to locate tools.jar. "
219: + "Expected to find it in " + toolsJar.getPath());
220: return null;
221: }
222: return toolsJar;
223: }
224:
225: /**
226: * Get an array of URLs representing all of the jar files in the
227: * given location. If the location is a file, it is returned as the only
228: * element of the array. If the location is a directory, it is scanned for
229: * jar files.
230: *
231: * @param location the location to scan for Jars.
232: *
233: * @return an array of URLs for all jars in the given location.
234: *
235: * @exception MalformedURLException if the URLs for the jars cannot be
236: * formed.
237: */
238: public static URL[] getLocationURLs(File location)
239: throws MalformedURLException {
240: return getLocationURLs(location, new String[] { ".jar" });
241: }
242:
243: /**
244: * Get an array of URLs representing all of the files of a given set of
245: * extensions in the given location. If the location is a file, it is
246: * returned as the only element of the array. If the location is a
247: * directory, it is scanned for matching files.
248: *
249: * @param location
250: * the location to scan for files.
251: * @param extensions
252: * an array of extension that are to match in the directory
253: * search.
254: *
255: * @return an array of URLs of matching files.
256: * @exception MalformedURLException
257: * if the URLs for the files cannot be formed.
258: */
259: public static URL[] getLocationURLs(File location,
260: final String[] extensions) throws MalformedURLException {
261:
262: URL[] urls = new URL[0];
263:
264: if (!location.exists()) {
265: return urls;
266: }
267: if (!location.isDirectory()) {
268: urls = new URL[1];
269: String path = location.getPath();
270: for (int i = 0; i < extensions.length; ++i) {
271: if (path.toLowerCase().endsWith(extensions[i])) {
272: urls[0] = location.toURI().toURL();
273: break;
274: }
275: }
276: return urls;
277: }
278: File[] matches = location.listFiles(new FilenameFilter() {
279: public boolean accept(File dir, String name) {
280: for (int i = 0; i < extensions.length; ++i) {
281: if (name.toLowerCase().endsWith(extensions[i])) {
282: return true;
283: }
284: }
285: return false;
286: }
287: });
288: urls = new URL[matches.length];
289: for (int i = 0; i < matches.length; ++i) {
290: urls[i] = matches[i].toURI().toURL();
291: }
292: return urls;
293: }
294: }
|