/* * 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; } }