/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.util;
import java.lang.reflect.*;
import java.util.Vector;
import java.util.StringTokenizer;
import java.util.Set;
import java.util.HashSet;
import java.util.Hashtable;
import com.sun.enterprise.deployment.FieldDescriptor;
/**
* Datatype management utility methods
*/
public class TypeUtil {
// map a decimal digit to its (real!) character
private static final char[] digits = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
// Map of primitive class name and its associated Class object
private static Hashtable primitiveClasses_;
static {
primitiveClasses_ = new Hashtable();
primitiveClasses_.put(Character.TYPE.getName(), Character.TYPE);
primitiveClasses_.put(Boolean.TYPE.getName(), Boolean.TYPE);
primitiveClasses_.put(Byte.TYPE.getName(), Byte.TYPE);
primitiveClasses_.put(Integer.TYPE.getName(), Integer.TYPE);
primitiveClasses_.put(Long.TYPE.getName(), Long.TYPE);
primitiveClasses_.put(Short.TYPE.getName(), Short.TYPE);
primitiveClasses_.put(Float.TYPE.getName(), Float.TYPE);
primitiveClasses_.put(Double.TYPE.getName(), Double.TYPE);
}
/**
* Place a character representation of src into the buffer.
* No formatting (e.g. localization) is done.
*
* @param src - the integer to convert. Must not be Integer.MIN_VALUE.
* @param buf - the buf to put the result in
* @param offset - the offset in buf to place the first digit
* @return the number of bytes added to buf
* @exception IllegalArgumentException if src is Integer.MIN_VALUE.
*/
public static int intGetChars(
int src,
char buf[],
int offset
) {
int power = 1000000000; // magnitude of highest digit this can handle
int this_digit;
boolean have_emitted = false;
int init_offset = offset;
// special case src is zero
if (src == 0) {
buf[offset] = digits[0];
return 1;
}
else if (src < 0) {
if (src == Integer.MIN_VALUE)
throw new IllegalArgumentException();
// emit the negation sign and continue as if positive
buf[offset++] = '-';
src = Math.abs(src);
}
// iterate until there are no more digits to emit
while (power > 0) {
this_digit = src / power;
if (this_digit != 0 || have_emitted) {
// emit this digit
have_emitted = true;
buf[offset++] = digits[this_digit];
}
src = src % power;
power = power / 10;
}
return offset - init_offset;
}
// map a digit to its single byte character
private static final byte[] charval = {
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',(byte) '6',(byte) '7',(byte) '8',(byte) '9'
};
/**
* Place a byte representation of src into the byte array buf.
* No commas or any other formatting is done to the integer.
* @param src - the integer to convert. Must not be Integer.MIN_VALUE.
* @param buf - the buf to put the result in
* @param offset - the offset in buf to place the first digit
* @return the number of bytes added to buf
* @exception IllegalArgumentException if src is Integer.MIN_VALUE.
*/
public static int intGetBytes(
int src,
byte buf[],
int offset
) {
int power = 1000000000; // magnitude of highest digit this can handle
int this_digit;
boolean have_emitted = false;
int init_offset = offset;
// special case src is zero
if (src == 0) {
buf[offset] = charval[0];
return 1;
}
else if (src < 0) {
if (src == Integer.MIN_VALUE)
throw new IllegalArgumentException();
// emit the negation sign and continue as if positive
buf[offset++] = (byte) '-';
src = Math.abs(src);
}
// iterate until there are no more digits to emit
while (power > 0) {
this_digit = src / power;
if (this_digit != 0 || have_emitted) {
// emit this digit
have_emitted = true;
buf[offset++] = charval[this_digit];
}
src = src % power;
power = power / 10;
}
return offset - init_offset;
}
/**
* Work around a performance bug in String.hashCode() for strings longer
* than sixteen characters, by calculating a (slower) hash on all the
* characters in the string. Not needed starting in the JDK 1.2 release.
*/
public static int hashCode(String s)
{
int length = s.length();
int h = 1;
for (int i = 0; i < length; i++)
h = (h * 37) + (int) s.charAt(i);
return h;
}
/**
* Word-wrap a string into an array of strings. Space is the only
* separator character recognized.
*/
public static String[] wordWrap(String msg, int widthInChars) {
int width = widthInChars;
int nextBreak =0;
int lastBreak = 0;
int length = msg.length();
int lengthLeft = length;
boolean breakFound = true;
Vector v = new Vector();
int nextNewline = msg.indexOf("\n");
while (lengthLeft > width || nextNewline != -1) {
// Find a convenient word break, always respecting explicit line
// breaks.
nextBreak = nextNewline;
// If no newline, look for a space.
if (nextBreak == -1 ||
nextBreak <= lastBreak ||
nextBreak > lastBreak + width) {
nextBreak = msg.lastIndexOf(" ", lastBreak + width);
}
// No space, break it at the wrap width.
if (nextBreak == -1 || nextBreak <= lastBreak) {
nextBreak = lastBreak + width - 1;
breakFound = false;
if (nextBreak > length) {
break;
}
}
// Save the substring and adjust indexes.
String substr = msg.substring(lastBreak, nextBreak);
v.addElement(substr);
lengthLeft -= substr.length();
lastBreak = nextBreak;
if (breakFound) {
++lastBreak;
}
breakFound = true;
nextNewline = msg.indexOf("\n", lastBreak);
}
v.addElement(msg.substring(lastBreak));
String[] lines = new String[v.size()];
v.copyInto(lines);
return lines;
}
/**
* Convert an array of strings to a single line with elements separated
* by the given separator. Similar to Tcl's <code>join</code>.
* @param from the array of strings to convert
* @param separator the string to insert between each element
*/
public static String arrayToString(String[] from, String separator) {
StringBuffer sb = new StringBuffer(100);
String sep = "";
for (int i = 0; i < from.length; i++) {
sb.append(sep);
sb.append(from[i]);
sep = separator;
}
return sb.toString();
}
/**
* Convert a string of delimited strings to an array of strings.
* Similar to AWK's and Tcl's <code>split</code>.
* @param from the string to convert
* @param separator the delimiter
*/
public static String[] stringToArray(String from, String separator) {
if (from == null) {
return null;
}
if (separator == null) {
separator = " ";
}
StringTokenizer toks = new StringTokenizer(from, separator);
String[] result = new String[toks.countTokens()];
int i = 0;
while (toks.hasMoreTokens()) {
result[i++] = toks.nextToken().trim();
}
return result;
}
/**
* Truncate a float to the required number of significant digits.
*/
public static String truncateFloat(float f, int digits) {
double factor = Math.pow(10, digits);
f = (float)(Math.round(f * factor) / factor);
return Float.toString(f);
}
/**
* Add commas to a number for "123,456.7" style formatting.
* @deprecated Use standard java.* APIs which create the correct
* localized number format.
*/
public static String addCommas(float f) {
String floatStr = truncateFloat(f, 0);
return addCommas(floatStr);
}
/**
* Add commas to a number for "123,456.7" style formatting.
* @deprecated Use standard java.* APIs which create the correct
* localized number format.
*/
public static String addCommas(String numStr) {
int dotIndex = numStr.lastIndexOf('.');
String n;
String fraction = "";
if (dotIndex >= 0) {
fraction = numStr.substring(dotIndex);
n = numStr.substring(0, dotIndex);
} else {
n = numStr;
}
String val = "";
int lastIndex = 0;
for (int i = n.length(); i > 0; i -= 3) {
String comma;
if (i > 3) {
comma = ",";
} else {
comma = "";
}
int start = Math.max(i - 3, 0);
val = comma + n.substring(start, i) + val;
lastIndex = start;
}
val = n.substring(0, lastIndex) + val + fraction;
return val;
}
/**
* Test if a class is a subclass of another.
* @deprecated Use <em>sup.isAssignableFrom(sub)</em>
*/
public static boolean isSubclassOf(Class sub, Class sup) {
if (sub == sup) {
return true;
}
Class superclass = sub.getSuperclass();
while (superclass != null && superclass != sup) {
superclass = superclass.getSuperclass();
}
return (superclass != null);
}
/**
* Get all super-interfaces of a class, excluding the
* given base interface.
* Returns a set of strings containing class names.
*/
public static Set getSuperInterfaces(ClassLoader cl, String className, String baseClassName) throws ClassNotFoundException {
Set allSuper = new HashSet();
if( !className.equals(baseClassName) ) {
Class theClass = cl.loadClass(className);
Class[] superInterfaces = theClass.getInterfaces();
for(int superIndex = 0; superIndex < superInterfaces.length; superIndex++) {
Class currentClass = superInterfaces[superIndex];
String currentClassName = currentClass.getName();
if( !currentClassName.equals(baseClassName) ) {
allSuper.add(currentClassName);
allSuper.addAll(getSuperInterfaces(cl, currentClassName, baseClassName));
}
} // End for -- each super interface
}
return allSuper;
}
public static Method getMethod(Class declaringClass, ClassLoader loader,
String name, String[] paramClassNames)
throws Exception
{
Class[] parameterTypes=null;
if (paramClassNames!=null) {
parameterTypes = new Class[paramClassNames.length];
for(int pIndex = 0; pIndex < parameterTypes.length; pIndex++) {
String next = paramClassNames[pIndex];
if( primitiveClasses_.containsKey(next) ) {
parameterTypes[pIndex] =
(Class) primitiveClasses_.get(next);
} else {
parameterTypes[pIndex] = Class.forName(next, true, loader);
}
}
}
return declaringClass.getMethod(name, parameterTypes);
}
public static Method getDeclaredMethod(Class declaringClass, ClassLoader loader,
String name, String[] paramClassNames)
throws Exception
{
Class[] parameterTypes=null;
if (paramClassNames!=null) {
parameterTypes = new Class[paramClassNames.length];
for(int pIndex = 0; pIndex < parameterTypes.length; pIndex++) {
String next = paramClassNames[pIndex];
if( primitiveClasses_.containsKey(next) ) {
parameterTypes[pIndex] =
(Class) primitiveClasses_.get(next);
} else {
parameterTypes[pIndex] = Class.forName(next, true, loader);
}
}
}
return declaringClass.getDeclaredMethod(name, parameterTypes);
}
/**
* Compares the signatures of two methods to see if they
* have the same numer of parameters and same parameter types.
*
* Note that this equality check does NOT cover :
* 1) declaring class 2) exceptions 3) method name
* 4) return type
*
*/
public static boolean sameParamTypes(Method m1, Method m2) {
boolean same = false;
Class[] pm1 = m1.getParameterTypes();
Class[] pm2 = m2.getParameterTypes();
if( (pm1.length == pm2.length) ) {
same = true;
for(int i = 0; i < pm1.length; i++) {
if( pm1[i] != pm2[i] ) {
same = false;
break;
}
}
}
return same;
}
/**
* Compares the signatures of two methods to see if they
* have the same method name, parameters, and return type.
*
* Note that this equality check does NOT cover :
* 1) declaring class 2) exceptions
*
*/
public static boolean sameMethodSignature(Method m1, Method m2) {
boolean same = false;
Class[] pm1 = m1.getParameterTypes();
Class[] pm2 = m2.getParameterTypes();
if( (m1.getName().equals(m2.getName())) &&
(m1.getReturnType() == m2.getReturnType()) ) {
same = sameParamTypes(m1, m2);
}
return same;
}
public static Vector getPossibleCmpCmrFields(ClassLoader cl,
String className)
throws Exception {
Vector fieldDescriptors = new Vector();
Class theClass = cl.loadClass(className);
// Start with all *public* methods
Method[] methods = theClass.getMethods();
// Find all accessors that could be cmp fields. This list
// will contain all cmr field accessors as well, since there
// is no good way to distinguish between the two purely based
// on method signature.
for(int mIndex = 0; mIndex < methods.length; mIndex++) {
Method next = methods[mIndex];
String nextName = next.getName();
int nextModifiers = next.getModifiers();
if( Modifier.isAbstract(nextModifiers) ) {
if( nextName.startsWith("get") &&
nextName.length() > 3 ) {
String field =
nextName.substring(3,4).toLowerCase() +
nextName.substring(4);
fieldDescriptors.add(new FieldDescriptor(field));
}
}
}
return fieldDescriptors;
}
/**
* Convert a java beans setter method to its property name.
*/
public static String setterMethodToPropertyName(String setterMethodName) {
if( (setterMethodName == null) ||
(setterMethodName.length() <= 3) ||
!setterMethodName.startsWith("set") ) {
throw new IllegalArgumentException("Invalid setter method name " +
setterMethodName);
}
return ( setterMethodName.substring(3, 4).toLowerCase() +
setterMethodName.substring(4) );
}
/**
* Convert a java beans property name to a setter method name
*/
public static String propertyNameToSetterMethod(String propertyName) {
if( (propertyName == null) ||
(propertyName.length() == 0) ) {
throw new IllegalArgumentException("Invalid property name " +
propertyName);
}
return ( "set" + propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1) );
}
}
|