/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.axis2.jaxws.util; | |
import org.apache.axis2.java.security.AccessController; | |
import org.apache.axis2.jaxws.ExceptionFactory; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import java.io.IOException; | |
import java.security.PrivilegedActionException; | |
import java.security.PrivilegedExceptionAction; | |
import java.util.Properties; | |
import java.util.StringTokenizer; | |
public class WSToolingUtils { | |
private static final Log log = LogFactory.getLog(WSToolingUtils.class); | |
/** | |
* A handy function to check for empty or null string | |
* | |
* @param str | |
* @return boolean | |
* | |
*/ | |
public static boolean hasValue(String str) { | |
return ((str != null) && (str.length() > 0)); | |
} | |
/** | |
* Retrieves the major version number of the WsGen class that we're using | |
* | |
* @return String | |
* | |
*/ | |
public static String getWsGenVersion() throws ClassNotFoundException, IOException { | |
Class clazz = null; | |
try { | |
clazz = forName("com.sun.tools.ws.WsGen", false, | |
getContextClassLoader(null)); | |
} catch (ClassNotFoundException e1) { | |
try { | |
clazz = forName("com.sun.tools.internal.ws.WsGen", false, | |
getContextClassLoader(null)); | |
} catch (ClassNotFoundException e2) { | |
if (log.isDebugEnabled()) { | |
log.debug("Exception thrown from getWsGenVersion: " + e2.getMessage(), e2); | |
} | |
throw (ClassNotFoundException) e2; | |
} | |
} | |
Properties p = new Properties(); | |
try { | |
p.load(clazz.getResourceAsStream("version.properties")); | |
} catch (IOException ioex) { | |
if (log.isDebugEnabled()) { | |
log.debug("Exception thrown from getWsGenVersion: " + ioex.getMessage(), ioex); | |
} | |
throw (IOException) ioex.getCause(); | |
} | |
return (p.getProperty("major-version")); | |
} | |
/** | |
* @return ClassLoader | |
*/ | |
private static ClassLoader getContextClassLoader(final ClassLoader classLoader) { | |
ClassLoader cl; | |
try { | |
cl = (ClassLoader) AccessController.doPrivileged( | |
new PrivilegedExceptionAction() { | |
public Object run() throws ClassNotFoundException { | |
return classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader(); | |
} | |
} | |
); | |
} catch (PrivilegedActionException e) { | |
if (log.isDebugEnabled()) { | |
log.debug("Exception thrown from AccessController: " + e.getMessage(), e); | |
} | |
throw ExceptionFactory.makeWebServiceException(e.getException()); | |
} | |
return cl; | |
} | |
/** | |
* Return the class for this name | |
* | |
* @return Class | |
*/ | |
private static Class forName(final String className, final boolean initialize, | |
final ClassLoader classloader) throws ClassNotFoundException { | |
Class cl = null; | |
try { | |
cl = (Class) AccessController.doPrivileged( | |
new PrivilegedExceptionAction() { | |
public Object run() throws ClassNotFoundException { | |
return Class.forName(className, initialize, classloader); | |
} | |
} | |
); | |
} catch (PrivilegedActionException e) { | |
if (log.isDebugEnabled()) { | |
log.debug("Exception thrown from AccessController: " + e.getMessage(), e); | |
} | |
throw (ClassNotFoundException) e.getException(); | |
} | |
return cl; | |
} | |
/** | |
* Answer if the input version number is 2.1.6 or later. Version 2.1.6 is the Sun RI version that changed | |
* the WebMethod annotation semantics. | |
* | |
* @param wsGenVersion A version number separated by "." Up to the first 3 values will be checked. | |
* @return true if the version number is 2.1.6 or later, false otherwise. | |
*/ | |
public static boolean isValidVersion(String wsGenVersion) { | |
if(log.isDebugEnabled()){ | |
log.debug("Start isValidVersion(String)"); | |
} | |
if (log.isDebugEnabled()) { | |
log.debug("isValidVersion: Determining if WsGen version: " +wsGenVersion | |
+" is appropriate version for using new SUN RI behavior"); | |
} | |
if(wsGenVersion == null){ | |
return false; | |
} | |
/* | |
* This algorithm is improvement over the old algorithm we had to validate the | |
* version. In this algorithm we don't assume that the format will be x.x.x. | |
* This algorithm looks for versionNumbers in a String token delimited by a | |
* ".", the idea is to look for the first digit in each token and compare that | |
* with the version validation requirements. | |
* we return false if version is less that 2.1.6. | |
* possible input version strings could be "JAX-WS RI 2.2-b05-", "2.1.6" "2.1.0" etc. | |
*/ | |
// Minimum version required is 2.1.6 | |
final int minimumVersionRequired[] = {2, 1, 6}; | |
String version = wsGenVersion.trim(); | |
StringTokenizer st = new StringTokenizer(version, "."); | |
if(st.countTokens() <= 0){ | |
if(log.isDebugEnabled()){ | |
log.debug("No Tokens to validate the tooling version, Input version String is invalid."); | |
} | |
return false; | |
} | |
// Check up to as many version values as we have values in the minimum required version | |
boolean lastCheckEqual = false; | |
int tokenCnt = 0; | |
for( ; tokenCnt < minimumVersionRequired.length && st.hasMoreTokens(); tokenCnt++) { | |
String token = st.nextToken(); | |
if(token == null){ | |
return false; | |
} | |
int versionNumber = getIntegerValue(token); | |
int minimumVersionNumber = minimumVersionRequired[tokenCnt]; | |
if (versionNumber < minimumVersionNumber) { | |
// The version number is too low, so it is invalid | |
if(log.isDebugEnabled()){ | |
log.debug("Validation failed on tokenCnt = " + tokenCnt); | |
log.debug("Input VersionNumber =" + versionNumber); | |
log.debug("Minimum Version Number required = " + minimumVersionNumber); | |
} | |
return false; | |
} else if (versionNumber > minimumVersionNumber) { | |
// The version number is higher than required, so it passes validation. | |
if(log.isDebugEnabled()){ | |
log.debug("Validation passed on tokenCnt = " + tokenCnt); | |
log.debug("Input VersionNumber = " + versionNumber); | |
log.debug("Minimum Version Number required = " + minimumVersionNumber); | |
} | |
return true; | |
} else { | |
// The version number sub-value matches exactly, so we need to check the next sub-value.s | |
if(log.isDebugEnabled()){ | |
log.debug("Validation unresolved on tokenCnt = " + tokenCnt); | |
log.debug("Input VersionNumber = " + versionNumber); | |
log.debug("Minimum Version Number required = " + minimumVersionNumber); | |
} | |
lastCheckEqual = true; | |
continue; | |
} | |
} | |
if(log.isDebugEnabled()){ | |
log.debug("Exit isValidVersion(String)"); | |
} | |
// If the version numbers we checked so far were equal to the minimum version BUT it was shorter | |
// in length, then return false. For example if the input is "2.1", that is actually "2.1.0" | |
// which would be less than "2.1.6". | |
if (lastCheckEqual && tokenCnt < minimumVersionRequired.length) { | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Parse the input string and return an integer value based on it. It will look for the first numeric value | |
* in the string then use all digits up to the next non-numeric value or end of the string as the basis for | |
* the value. For example "JAX-WS RI 27" will return the value 27. | |
* @param s - String containing the integer to be returned. | |
* @return a value or -1 if not integer value was found in the token. | |
*/ | |
private static int getIntegerValue(String s){ | |
int returnValue = -1; | |
// Build up a buffer containing any digits up to the first non-numeric character. | |
StringBuffer valueString = new StringBuffer(); | |
for(int i = 0; i < s.length(); i++){ | |
char ch = s.charAt(i); | |
if(Character.isDigit(ch)){ | |
valueString.append(Character.getNumericValue(ch)); | |
} else if (valueString.length() > 0){ | |
// We've found some numbers then encountered the first non-numeric value, so | |
// exit the loop and use those numbers as the value | |
break; | |
} | |
} | |
// If there were any numeric values found in the string, convert them to the integer return value | |
if (valueString.length() > 0) { | |
returnValue = Integer.valueOf(valueString.toString()); | |
} | |
return returnValue; | |
} | |
} |