| ClassUtil.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 or later
5 * as published by the Free Software Foundation. This program is distributed
6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * © CrossWire Bible Society, 2005 - 2016
18 *
19 */
20 package org.crosswire.common.util;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.zip.ZipEntry;
25 import java.util.zip.ZipFile;
26
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31 * Various Java Class Utilities.
32 *
33 * @see gnu.lgpl.License The GNU Lesser General Public License for details.
34 * @author Joe Walker
35 */
36 public final class ClassUtil {
37 /**
38 * Prevent instantiation
39 */
40 private ClassUtil() {
41 }
42
43 /**
44 * Gets the Class for the className in a way that works well for extensions.
45 * See: http://www.javageeks.com/Papers/ClassForName/ClassForName.pdf
46 *
47 * @param className
48 * the class to get
49 * @return the found Class
50 * @throws ClassNotFoundException if the class is not found
51 */
52 public static Class<?> forName(String className) throws ClassNotFoundException {
53 return Thread.currentThread().getContextClassLoader().loadClass(className);
54 }
55
56 /**
57 * This function finds the first matching filename for a Java class file
58 * from the classpath, if none is found it returns null.
59 *
60 * @param className
61 * the class to get
62 * @param classPath the lookup class path
63 * @return the filename for the class
64 */
65 public static String findClasspathEntry(String className, String classPath) {
66 String full = null;
67
68 String[] paths = StringUtil.split(classPath, File.pathSeparator);
69 for (int i = 0; i < paths.length; i++) {
70 // Search the jar
71 if (paths[i].endsWith(EXTENSION_ZIP) || paths[i].endsWith(EXTENSION_JAR)) {
72 ZipFile zip = null;
73 try {
74 String fileName = className.replace(',', '/') + EXTENSION_CLASS;
75 zip = new ZipFile(paths[i]);
76 ZipEntry entry = zip.getEntry(fileName);
77
78 if (entry != null && !entry.isDirectory()) {
79 if (full != null && !full.equals(fileName)) {
80 LOGGER.warn("Warning duplicate {} found: {} and {}", className, full, paths[i]);
81 } else {
82 full = paths[i];
83 }
84 }
85 } catch (IOException ex) {
86 // If that zip file failed, then ignore it and move on.
87 LOGGER.warn("Missing zip file for {} and {}", className, paths[i]);
88 } finally {
89 if (null != zip) {
90 try {
91 zip.close();
92 } catch (IOException ex) {
93 LOGGER.error("close", ex);
94 }
95 }
96 }
97 } else {
98 StringBuilder path = new StringBuilder(256);
99
100 // Search for the file
101 String extra = className.replace('.', File.separatorChar);
102
103 path.append(paths[i]);
104 if (paths[i].charAt(paths[i].length() - 1) != File.separatorChar) {
105 path.append(File.separatorChar);
106 }
107
108 path.append(extra);
109 path.append(EXTENSION_CLASS);
110 String fileName = path.toString();
111
112 if (new File(fileName).isFile()) {
113 if (full != null && !full.equals(fileName)) {
114 LOGGER.warn("Warning duplicate {} found: {} and {}", className, full, paths[i]);
115 } else {
116 full = paths[i];
117 }
118 }
119 }
120 }
121
122 return full;
123 }
124
125 /**
126 * This function find the first matching filename for a Java class file from
127 * the classpath, if none is found it returns null.
128 *
129 * @param className
130 * the class to get
131 * @return the filename for the class
132 */
133 public static String findClasspathEntry(String className) {
134 String classpath = System.getProperty("java.class.path", "");
135 return findClasspathEntry(className, classpath);
136 }
137
138 /**
139 * Gets the class name minus the package name for an <code>Object</code>.
140 *
141 * @param object
142 * the class to get the short name for, may be null
143 * @param valueIfNull
144 * the value to return if null
145 * @return the class name of the object without the package name, or the
146 * null value
147 */
148 public static String getShortClassName(Object object, String valueIfNull) {
149 if (object == null) {
150 return valueIfNull;
151 }
152 return getShortClassName(object.getClass().getName());
153 }
154
155 /**
156 * Gets the class name minus the package name from a <code>Class</code>.
157 *
158 * @param cls
159 * the class to get the short name for, must not be
160 * <code>null</code>
161 * @return the class name without the package name
162 * @throws IllegalArgumentException
163 * if the class is <code>null</code>
164 */
165 public static String getShortClassName(Class<?> cls) {
166 if (cls == null) {
167 throw new IllegalArgumentException("The class must not be null");
168 }
169 return getShortClassName(cls.getName());
170 }
171
172 /**
173 * Gets the class name minus the package name from a String.
174 *
175 * <p>
176 * The string passed in is assumed to be a class name - it is not checked.
177 * </p>
178 *
179 * @param className
180 * the className to get the short name for, must not be empty or
181 * <code>null</code>
182 * @return the class name of the class without the package name
183 * @throws IllegalArgumentException
184 * if the className is empty
185 */
186 public static String getShortClassName(String className) {
187 if (className == null || className.length() == 0) {
188 throw new IllegalArgumentException("The class name must not be empty");
189 }
190 char[] chars = className.toCharArray();
191 int lastDot = 0;
192 for (int i = 0; i < chars.length; i++) {
193 if (chars[i] == PACKAGE_SEPARATOR_CHAR) {
194 lastDot = i + 1;
195 } else if (chars[i] == INNER_CLASS_SEPARATOR_CHAR) {
196 chars[i] = PACKAGE_SEPARATOR_CHAR;
197 }
198 }
199 return new String(chars, lastDot, chars.length - lastDot);
200 }
201
202 /**
203 * The package separator character: <code>.</code>.
204 */
205 private static final char PACKAGE_SEPARATOR_CHAR = '.';
206
207 /**
208 * The inner class separator character: <code>$</code>.
209 */
210 private static final char INNER_CLASS_SEPARATOR_CHAR = '$';
211
212 private static final String EXTENSION_CLASS = ".class";
213 private static final String EXTENSION_JAR = ".jar";
214 private static final String EXTENSION_ZIP = ".zip";
215
216 /**
217 * The log stream
218 */
219 private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
220 }
221