001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.description.builder;
020:
021: import org.apache.axis2.jaxws.ExceptionFactory;
022: import org.apache.axis2.jaxws.util.ClassLoaderUtils;
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: /**
027: *
028: */
029: class DescriptionBuilderUtils {
030:
031: private static final Log log = LogFactory
032: .getLog(DescriptionBuilderUtils.class);
033:
034: static String JAXWS_HOLDER_CLASS = "javax.xml.ws.Holder";
035:
036: private static final String INT_PRIMITIVE = "int";
037: private static final String INT_PRIMITIVE_ENCODING = "I";
038: private static final String BYTE_PRIMITIVE = "byte";
039: private static final String BYTE_PRIMITIVE_ENCODING = "B";
040: private static final String CHAR_PRIMITIVE = "char";
041: private static final String CHAR_PRIMITIVE_ENCODING = "C";
042: private static final String SHORT_PRIMITIVE = "short";
043: private static final String SHORT_PRIMITIVE_ENCODING = "S";
044: private static final String BOOLEAN_PRIMITIVE = "boolean";
045: private static final String BOOLEAN_PRIMITIVE_ENCODING = "Z";
046: private static final String LONG_PRIMITIVE = "long";
047: private static final String LONG_PRIMITIVE_ENCODING = "J";
048: private static final String FLOAT_PRIMITIVE = "float";
049: private static final String FLOAT_PRIMITIVE_ENCODING = "F";
050: private static final String DOUBLE_PRIMITIVE = "double";
051: private static final String DOUBLE_PRIMITIVE_ENCODING = "D";
052: private static final String VOID_PRIMITIVE = "void";
053: // REVIEW: This may not be the correct encoding for Void
054: private static final String VOID_PRIMITIVE_ENCODING = "V";
055:
056: /**
057: * Returns a string representing the outermost generic raw type class, or null if the argument
058: * is not a generic. For example if the string "javax.xml.ws.Holder<my.package.MyObject>" is
059: * passed in, the string "javax.xml.ws.Holder" will be returned.
060: * <p/>
061: * Note that generic arrays are supported. For example, for "Holder<List<String>[][]", the
062: * returned value will be "List[][]".
063: *
064: * @param inputType
065: * @return A string representing the generic raw type or null if there is no generic.
066: */
067: static String getRawType(String inputType) {
068: String returnRawType = null;
069: int leftBracket = inputType.indexOf("<");
070: int rightBracket = inputType.lastIndexOf(">");
071: if (leftBracket > 0 && rightBracket > 0
072: && rightBracket > leftBracket) {
073: String part1 = inputType.substring(0, leftBracket);
074: if ((rightBracket + 1) == inputType.length()) {
075: // There is nothing after the closing ">" we need to append to the raw type
076: returnRawType = part1;
077: } else {
078: // Skip over the closing ">" then append the rest of the string to the raw type
079: // This would be an array declaration for example.
080: String part2 = inputType.substring(rightBracket + 1)
081: .trim();
082: returnRawType = part1 + part2;
083: }
084: }
085: return returnRawType;
086: }
087:
088: /**
089: * Return the actual type in a JAX-WS holder declaration. For example, for the argument
090: * "javax.xml.ws.Holder<my.package.MyObject>", return "my.package.MyObject". If the actual type
091: * itself is a generic, then that raw type will be returned. For example,
092: * "javax.xml.ws.Holder<java.util.List<my.package.MyObject>>" will return "java.util.List".
093: * <p/>
094: * Note that Holders of Arrays and of Generic Arrays are also supported. For example, for
095: * "javax.xml.ws.Holder<String[]>", return "String[]". For an array of a generic, the array of
096: * the raw type is returned. For example, for "javax.xml.ws.Holder<List<String>[][]>", return
097: * "List[][]".
098: * <p/>
099: * Important note! The JAX-WS Holder generic only supports a single actual type, i.e. the
100: * generic is javax.xml.ws.Holder<T>. This method is not general purpose; it does not support
101: * generics with multiple types such as Generic<K,V> at the outermost level.
102: *
103: * @param holderInputString
104: * @return return the actual argument class name for a JAX-WS Holder; returns null if the
105: * argument is not a JAX-WS Holder
106: */
107: static String getHolderActualType(String holderInputString) {
108: String returnString = null;
109: if (DescriptionBuilderUtils.isHolderType(holderInputString)) {
110: int leftBracket = holderInputString.indexOf("<");
111: int rightBracket = holderInputString.lastIndexOf(">");
112: if (leftBracket > 0 && rightBracket > leftBracket + 1) {
113: // Get everything between the outermost "<" and ">"
114: String actualType = holderInputString.substring(
115: leftBracket + 1, rightBracket).trim();
116: // If the holder contained a generic, then get the generic raw type (e.g. "List" for
117: // Holder<List<String>>).
118: String rawType = getRawType(actualType);
119: if (rawType != null) {
120: returnString = rawType;
121: } else {
122: return returnString = actualType;
123: }
124: }
125: }
126: return returnString;
127: }
128:
129: /**
130: * Check if the input String is a JAX-WS Holder. For example "javax.xml.ws.Holder<my.package.MyObject>".
131: *
132: * @param checkType
133: * @return true if it is a JAX-WS Holder type; false otherwise.
134: */
135: static boolean isHolderType(String checkType) {
136: boolean isHolder = false;
137: if (checkType != null) {
138: if (checkType.startsWith(JAXWS_HOLDER_CLASS)) {
139: isHolder = checkType.length() == JAXWS_HOLDER_CLASS
140: .length()
141: || checkType
142: .charAt(JAXWS_HOLDER_CLASS.length()) == '<';
143: }
144: }
145: return isHolder;
146: }
147:
148: /**
149: * Answers if the String representing the class contains an array declaration. For example
150: * "Foo[][]" would return true, as would "int[]".
151: *
152: * @param className
153: * @return
154: */
155: static boolean isClassAnArray(String className) {
156: if (className != null && className.indexOf("[") > 0) {
157: return true;
158: } else {
159: return false;
160: }
161: }
162:
163: /**
164: * For an class name that is an array, return the non-array declaration portion. For example
165: * "my.package.Foo[][]" would return "my.package.Foo". Returns null if the argument does not
166: * contain an array declaration.
167: *
168: * @param fullClassName
169: * @return
170: */
171: static String getBaseArrayClassName(String fullClassName) {
172: String baseArrayClassName = null;
173: if (fullClassName != null) {
174: int firstArrayDimension = fullClassName.indexOf("[");
175: if (firstArrayDimension > 0) {
176: baseArrayClassName = fullClassName.substring(0,
177: firstArrayDimension);
178: }
179: }
180: return baseArrayClassName;
181: }
182:
183: /**
184: * Return a prefix suitable for passing to Class.forName(String) for an array. Each array
185: * dimension represented by "[]" will be represented by a single "[".
186: *
187: * @param arrayClassName
188: * @return
189: */
190: static String getArrayDimensionPrefix(String arrayClassName) {
191: StringBuffer arrayDimPrefix = new StringBuffer();
192:
193: if (arrayClassName != null) {
194: int arrayDimIndex = arrayClassName.indexOf("[]");
195: while (arrayDimIndex > 0) {
196: arrayDimPrefix.append("[");
197: // Skip over this "[]" and see if there are any more.
198: int startNext = arrayDimIndex + 2;
199: arrayDimIndex = arrayClassName.indexOf("[]", startNext);
200: }
201: }
202:
203: if (arrayDimPrefix.length() > 0)
204: return arrayDimPrefix.toString();
205: else
206: return null;
207: }
208:
209: /**
210: * For primitives, return the appropriate primitive class. Note that arrays of primitives are
211: * handled differently, like arrays of objects. Only non-array primitives are processed by this
212: * method. This method understands both the typical primitive declaration (e.g. "int") and the
213: * encoding used as for arrays (e.g. "I").
214: *
215: * @param classType
216: * @return
217: */
218: static Class getPrimitiveClass(String classType) {
219:
220: Class paramClass = null;
221:
222: if (INT_PRIMITIVE.equals(classType)
223: || INT_PRIMITIVE_ENCODING.equals(classType)) {
224: paramClass = int.class;
225: } else if (BYTE_PRIMITIVE.equals(classType)
226: || BYTE_PRIMITIVE_ENCODING.equals(classType)) {
227: paramClass = byte.class;
228: } else if (CHAR_PRIMITIVE.equals(classType)
229: || CHAR_PRIMITIVE_ENCODING.equals(classType)) {
230: paramClass = char.class;
231: } else if (SHORT_PRIMITIVE.equals(classType)
232: || SHORT_PRIMITIVE_ENCODING.equals(classType)) {
233: paramClass = short.class;
234: } else if (BOOLEAN_PRIMITIVE.equals(classType)
235: || BOOLEAN_PRIMITIVE_ENCODING.equals(classType)) {
236: paramClass = boolean.class;
237: } else if (LONG_PRIMITIVE.equals(classType)
238: || LONG_PRIMITIVE_ENCODING.equals(classType)) {
239: paramClass = long.class;
240: } else if (FLOAT_PRIMITIVE.equals(classType)
241: || FLOAT_PRIMITIVE_ENCODING.equals(classType)) {
242: paramClass = float.class;
243: } else if (DOUBLE_PRIMITIVE.equals(classType)
244: || DOUBLE_PRIMITIVE_ENCODING.equals(classType)) {
245: paramClass = double.class;
246: } else if (VOID_PRIMITIVE.equals(classType)
247: || VOID_PRIMITIVE_ENCODING.equals(classType)) {
248: paramClass = void.class;
249: }
250: return paramClass;
251: }
252:
253: /**
254: * Returns the encoding used to represent a Class for an array of a primitive type. For
255: * example, an array of boolean is represented by "Z". This is as described in the javadoc for
256: * Class.getName(). If the argument is not a primitive type, a null will be returned.
257: * <p/>
258: * Note that arrays of voids are not allowed; a null will be returned.
259: *
260: * @param primitiveType
261: * @return
262: */
263: static String getPrimitiveTypeArrayEncoding(String primitiveType) {
264: String encoding = null;
265:
266: if (BOOLEAN_PRIMITIVE.equals(primitiveType)) {
267: encoding = BOOLEAN_PRIMITIVE_ENCODING;
268: } else if (BYTE_PRIMITIVE.equals(primitiveType)) {
269: encoding = BYTE_PRIMITIVE_ENCODING;
270: } else if (CHAR_PRIMITIVE.equals(primitiveType)) {
271: encoding = CHAR_PRIMITIVE_ENCODING;
272: } else if (DOUBLE_PRIMITIVE.equals(primitiveType)) {
273: encoding = DOUBLE_PRIMITIVE_ENCODING;
274: } else if (FLOAT_PRIMITIVE.equals(primitiveType)) {
275: encoding = FLOAT_PRIMITIVE_ENCODING;
276: } else if (INT_PRIMITIVE.equals(primitiveType)) {
277: encoding = INT_PRIMITIVE_ENCODING;
278: } else if (LONG_PRIMITIVE.equals(primitiveType)) {
279: encoding = LONG_PRIMITIVE_ENCODING;
280: } else if (SHORT_PRIMITIVE.equals(primitiveType)) {
281: encoding = SHORT_PRIMITIVE_ENCODING;
282: }
283: return encoding;
284: }
285:
286: /**
287: * If the parameter represents and array, then the returned string is in a format that a
288: * Class.forName(String) can be done on it. This format is described by Class.getName(). If the
289: * parameter does not represent an array, the parememter is returned unmodified.
290: * <p/>
291: * Note that arrays of primitives are processed as well as arrays of objects.
292: *
293: * @param classToLoad
294: * @return
295: */
296: static String reparseIfArray(String classToLoad) {
297:
298: String reparsedClassName = classToLoad;
299: if (isClassAnArray(classToLoad)) {
300: String baseType = getBaseArrayClassName(classToLoad);
301: String dimensionPrefix = getArrayDimensionPrefix(classToLoad);
302: if (getPrimitiveTypeArrayEncoding(baseType) != null) {
303: reparsedClassName = dimensionPrefix
304: + getPrimitiveTypeArrayEncoding(baseType);
305: } else {
306: reparsedClassName = dimensionPrefix + "L" + baseType
307: + ";";
308: }
309: }
310: return reparsedClassName;
311: }
312:
313: /**
314: * Load a class represented in a Description Builder Composite. If a classloader is specified,
315: * it will be used; otherwise the default classloader is used.
316: *
317: * @param classToLoad
318: * @param classLoader
319: * @return
320: */
321: static Class loadClassFromComposite(String classToLoad,
322: ClassLoader classLoader) {
323: Class returnClass = null;
324:
325: // If this is an array, then create a string version as described by Class.getName.
326: // For example, "Foo[][]" becomes "[[LFoo". Note that arrays of primitives must also be parsed.
327: classToLoad = DescriptionBuilderUtils
328: .reparseIfArray(classToLoad);
329:
330: if (classLoader != null) {
331: // Use the specified classloader to load the class.
332: try {
333: returnClass = ClassLoaderUtils.forName(classToLoad,
334: false, classLoader);
335: }
336: //Catch Throwable as ClassLoader can throw an NoClassDefFoundError that
337: //does not extend Exception, so lets catch everything that extends Throwable
338: //rather than just Exception.
339: catch (Throwable ex) {
340: throw ExceptionFactory
341: .makeWebServiceException("DescriptionBuilderUtils: Class not found for parameter: "
342: + classToLoad
343: + " using classloader: "
344: + classLoader);
345: }
346: } else {
347: //Use the thread context class loader to load the class.
348: try {
349: returnClass = ClassLoaderUtils
350: .forName(classToLoad, false, ClassLoaderUtils
351: .getContextClassLoader());
352: } catch (Throwable ex) {
353: //Use the default classloader to load the class.
354: try {
355: returnClass = ClassLoaderUtils.forName(classToLoad);
356: }
357: //Catch Throwable as ClassLoader can throw an NoClassDefFoundError that
358: //does not extend Exception
359: catch (Throwable ex2) {
360: throw ExceptionFactory
361: .makeWebServiceException("DescriptionBuilderUtils: Class not found using default classloader for parameter: "
362: + classToLoad);
363: }
364: }
365: }
366: return returnClass;
367: }
368:
369: }
|