src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 418
43240b8b995b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.xml.internal.ws.policy.privateutil;
aoqi@0 27
aoqi@0 28 import com.sun.xml.internal.ws.policy.PolicyException;
aoqi@0 29 import java.io.Closeable;
aoqi@0 30 import java.io.IOException;
aoqi@0 31 import java.io.UnsupportedEncodingException;
aoqi@0 32 import java.lang.reflect.InvocationTargetException;
aoqi@0 33 import java.lang.reflect.Method;
aoqi@0 34 import java.net.URL;
aoqi@0 35 import java.util.ArrayList;
aoqi@0 36 import java.util.Arrays;
aoqi@0 37 import java.util.Collection;
aoqi@0 38 import java.util.Comparator;
aoqi@0 39 import java.util.LinkedList;
aoqi@0 40 import java.util.List;
aoqi@0 41 import java.util.Queue;
aoqi@0 42 import javax.xml.namespace.QName;
aoqi@0 43 import javax.xml.stream.XMLStreamException;
aoqi@0 44 import javax.xml.stream.XMLStreamReader;
aoqi@0 45
aoqi@0 46 /**
aoqi@0 47 * This is a wrapper class for various utilities that may be reused within Policy API implementation.
aoqi@0 48 * The class is not part of public Policy API. Do not use it from your client code!
aoqi@0 49 *
aoqi@0 50 * @author Marek Potociar
aoqi@0 51 */
aoqi@0 52 public final class PolicyUtils {
aoqi@0 53 private PolicyUtils() { }
aoqi@0 54
aoqi@0 55 public static class Commons {
aoqi@0 56 /**
aoqi@0 57 * Method returns the name of the method that is on the {@code methodIndexInStack}
aoqi@0 58 * position in the call stack of the current {@link Thread}.
aoqi@0 59 *
aoqi@0 60 * @param methodIndexInStack index to the call stack to get the method name for.
aoqi@0 61 * @return the name of the method that is on the {@code methodIndexInStack}
aoqi@0 62 * position in the call stack of the current {@link Thread}.
aoqi@0 63 */
aoqi@0 64 public static String getStackMethodName(final int methodIndexInStack) {
aoqi@0 65 final String methodName;
aoqi@0 66
aoqi@0 67 final StackTraceElement[] stack = Thread.currentThread().getStackTrace();
aoqi@0 68 if (stack.length > methodIndexInStack + 1) {
aoqi@0 69 methodName = stack[methodIndexInStack].getMethodName();
aoqi@0 70 } else {
aoqi@0 71 methodName = "UNKNOWN METHOD";
aoqi@0 72 }
aoqi@0 73
aoqi@0 74 return methodName;
aoqi@0 75 }
aoqi@0 76
aoqi@0 77 /**
aoqi@0 78 * Function returns the name of the caller method for the method executing this
aoqi@0 79 * function.
aoqi@0 80 *
aoqi@0 81 * @return caller method name from the call stack of the current {@link Thread}.
aoqi@0 82 */
aoqi@0 83 public static String getCallerMethodName() {
aoqi@0 84 String result = getStackMethodName(5);
aoqi@0 85 if (result.equals("invoke0")) {
aoqi@0 86 // We are likely running on Mac OS X, which returns a shorter stack trace
aoqi@0 87 result = getStackMethodName(4);
aoqi@0 88 }
aoqi@0 89 return result;
aoqi@0 90 }
aoqi@0 91 }
aoqi@0 92
aoqi@0 93 public static class IO {
aoqi@0 94 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyUtils.IO.class);
aoqi@0 95
aoqi@0 96 /**
aoqi@0 97 * If the {@code resource} is not {@code null}, this method will try to close the
aoqi@0 98 * {@code resource} instance and log warning about any unexpected
aoqi@0 99 * {@link IOException} that may occur.
aoqi@0 100 *
aoqi@0 101 * @param resource resource to be closed
aoqi@0 102 */
aoqi@0 103 public static void closeResource(Closeable resource) {
aoqi@0 104 if (resource != null) {
aoqi@0 105 try {
aoqi@0 106 resource.close();
aoqi@0 107 } catch (IOException e) {
aoqi@0 108 LOGGER.warning(LocalizationMessages.WSP_0023_UNEXPECTED_ERROR_WHILE_CLOSING_RESOURCE(resource.toString()), e);
aoqi@0 109 }
aoqi@0 110 }
aoqi@0 111 }
aoqi@0 112
aoqi@0 113 /**
aoqi@0 114 * If the {@code reader} is not {@code null}, this method will try to close the
aoqi@0 115 * {@code reader} instance and log warning about any unexpected
aoqi@0 116 * {@link IOException} that may occur.
aoqi@0 117 *
aoqi@0 118 * @param reader resource to be closed
aoqi@0 119 */
aoqi@0 120 public static void closeResource(XMLStreamReader reader) {
aoqi@0 121 if (reader != null) {
aoqi@0 122 try {
aoqi@0 123 reader.close();
aoqi@0 124 } catch (XMLStreamException e) {
aoqi@0 125 LOGGER.warning(LocalizationMessages.WSP_0023_UNEXPECTED_ERROR_WHILE_CLOSING_RESOURCE(reader.toString()), e);
aoqi@0 126 }
aoqi@0 127 }
aoqi@0 128 }
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 /**
aoqi@0 132 * Text utilities wrapper.
aoqi@0 133 */
aoqi@0 134 public static class Text {
aoqi@0 135 /**
aoqi@0 136 * System-specific line separator character retrieved from the Java system property
aoqi@0 137 * <code>line.separator</code>
aoqi@0 138 */
aoqi@0 139 public final static String NEW_LINE = System.getProperty("line.separator");
aoqi@0 140
aoqi@0 141 /**
aoqi@0 142 * Method creates indent string consisting of as many {@code TAB} characters as specified by {@code indentLevel} parameter
aoqi@0 143 *
aoqi@0 144 * @param indentLevel indentation level
aoqi@0 145 * @return indentation string as specified by indentation level
aoqi@0 146 *
aoqi@0 147 */
aoqi@0 148 public static String createIndent(final int indentLevel) {
aoqi@0 149 final char[] charData = new char[indentLevel * 4];
aoqi@0 150 Arrays.fill(charData, ' ');
aoqi@0 151 return String.valueOf(charData);
aoqi@0 152 }
aoqi@0 153 }
aoqi@0 154
aoqi@0 155 public static class Comparison {
aoqi@0 156 /**
aoqi@0 157 * The comparator comapres QName objects according to their publicly accessible attributes, in the following
aoqi@0 158 * order of attributes:
aoqi@0 159 *
aoqi@0 160 * 1. namespace (not null String)
aoqi@0 161 * 2. local name (not null String)
aoqi@0 162 */
aoqi@0 163 public static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
aoqi@0 164 public int compare(final QName qn1, final QName qn2) {
aoqi@0 165 if (qn1 == qn2 || qn1.equals(qn2)) {
aoqi@0 166 return 0;
aoqi@0 167 }
aoqi@0 168
aoqi@0 169 int result;
aoqi@0 170
aoqi@0 171 result = qn1.getNamespaceURI().compareTo(qn2.getNamespaceURI());
aoqi@0 172 if (result != 0) {
aoqi@0 173 return result;
aoqi@0 174 }
aoqi@0 175
aoqi@0 176 return qn1.getLocalPart().compareTo(qn2.getLocalPart());
aoqi@0 177 }
aoqi@0 178 };
aoqi@0 179
aoqi@0 180 /**
aoqi@0 181 * Compares two boolean values in the following way: {@code false < true}
aoqi@0 182 *
aoqi@0 183 * @return {@code -1} if {@code b1 < b2}, {@code 0} if {@code b1 == b2}, {@code 1} if {@code b1 > b2}
aoqi@0 184 */
aoqi@0 185 public static int compareBoolean(final boolean b1, final boolean b2) {
aoqi@0 186 final int i1 = (b1) ? 1 : 0;
aoqi@0 187 final int i2 = (b2) ? 1 : 0;
aoqi@0 188
aoqi@0 189 return i1 - i2;
aoqi@0 190 }
aoqi@0 191
aoqi@0 192 /**
aoqi@0 193 * Compares two String values, that may possibly be null in the following way: {@code null < "string value"}
aoqi@0 194 *
aoqi@0 195 * @return {@code -1} if {@code s1 < s2}, {@code 0} if {@code s1 == s2}, {@code 1} if {@code s1 > s2}
aoqi@0 196 */
aoqi@0 197 public static int compareNullableStrings(final String s1, final String s2) {
aoqi@0 198 return ((s1 == null) ? ((s2 == null) ? 0 : -1) : ((s2 == null) ? 1 : s1.compareTo(s2)));
aoqi@0 199 }
aoqi@0 200 }
aoqi@0 201
aoqi@0 202 public static class Collections {
aoqi@0 203 /**
aoqi@0 204 * TODO javadocs
aoqi@0 205 *
aoqi@0 206 * @param initialBase the combination base that will be present in each combination. May be {@code null} or empty.
aoqi@0 207 * @param options options that should be combined. May be {@code null} or empty.
aoqi@0 208 * @param ignoreEmptyOption flag identifies whether empty options should be ignored or whether the method should halt
aoqi@0 209 * processing and return {@code null} when an empty option is encountered
aoqi@0 210 * @return TODO
aoqi@0 211 */
aoqi@0 212 public static <E, T extends Collection<? extends E>, U extends Collection<? extends E>> Collection<Collection<E>> combine(final U initialBase, final Collection<T> options, final boolean ignoreEmptyOption) {
aoqi@0 213 List<Collection<E>> combinations = null;
aoqi@0 214 if (options == null || options.isEmpty()) {
aoqi@0 215 // no combination creation needed
aoqi@0 216 if (initialBase != null) {
aoqi@0 217 combinations = new ArrayList<Collection<E>>(1);
aoqi@0 218 combinations.add(new ArrayList<E>(initialBase));
aoqi@0 219 }
aoqi@0 220 return combinations;
aoqi@0 221 }
aoqi@0 222
aoqi@0 223 // creating defensive and modifiable copy of the base
aoqi@0 224 final Collection<E> base = new LinkedList<E>();
aoqi@0 225 if (initialBase != null && !initialBase.isEmpty()) {
aoqi@0 226 base.addAll(initialBase);
aoqi@0 227 }
aoqi@0 228 /**
aoqi@0 229 * now we iterate over all options and build up an option processing queue:
aoqi@0 230 * 1. if ignoreEmptyOption flag is not set and we found an empty option, we are going to stop processing and return null. Otherwise we
aoqi@0 231 * ignore the empty option.
aoqi@0 232 * 2. if the option has one child only, we add the child directly to the base.
aoqi@0 233 * 3. if there are more children in examined node, we add it to the queue for further processing and precoumpute the final size of
aoqi@0 234 * resulting collection of combinations.
aoqi@0 235 */
aoqi@0 236 int finalCombinationsSize = 1;
aoqi@0 237 final Queue<T> optionProcessingQueue = new LinkedList<T>();
aoqi@0 238 for (T option : options) {
aoqi@0 239 final int optionSize = option.size();
aoqi@0 240
aoqi@0 241 if (optionSize == 0) {
aoqi@0 242 if (!ignoreEmptyOption) {
aoqi@0 243 return null;
aoqi@0 244 }
aoqi@0 245 } else if (optionSize == 1) {
aoqi@0 246 base.addAll(option);
aoqi@0 247 } else {
aoqi@0 248 optionProcessingQueue.offer(option);
aoqi@0 249 finalCombinationsSize *= optionSize;
aoqi@0 250 }
aoqi@0 251 }
aoqi@0 252
aoqi@0 253 // creating final combinations
aoqi@0 254 combinations = new ArrayList<Collection<E>>(finalCombinationsSize);
aoqi@0 255 combinations.add(base);
aoqi@0 256 if (finalCombinationsSize > 1) {
aoqi@0 257 T processedOption;
aoqi@0 258 while ((processedOption = optionProcessingQueue.poll()) != null) {
aoqi@0 259 final int actualSemiCombinationCollectionSize = combinations.size();
aoqi@0 260 final int newSemiCombinationCollectionSize = actualSemiCombinationCollectionSize * processedOption.size();
aoqi@0 261
aoqi@0 262 int semiCombinationIndex = 0;
aoqi@0 263 for (E optionElement : processedOption) {
aoqi@0 264 for (int i = 0; i < actualSemiCombinationCollectionSize; i++) {
aoqi@0 265 final Collection<E> semiCombination = combinations.get(semiCombinationIndex); // unfinished combination
aoqi@0 266
aoqi@0 267 if (semiCombinationIndex + actualSemiCombinationCollectionSize < newSemiCombinationCollectionSize) {
aoqi@0 268 // this is not the last optionElement => we create a new combination copy for the next child
aoqi@0 269 combinations.add(new LinkedList<E>(semiCombination));
aoqi@0 270 }
aoqi@0 271
aoqi@0 272 semiCombination.add(optionElement);
aoqi@0 273 semiCombinationIndex++;
aoqi@0 274 }
aoqi@0 275 }
aoqi@0 276 }
aoqi@0 277 }
aoqi@0 278 return combinations;
aoqi@0 279 }
aoqi@0 280 }
aoqi@0 281
aoqi@0 282 /**
aoqi@0 283 * Reflection utilities wrapper
aoqi@0 284 */
aoqi@0 285 static class Reflection {
aoqi@0 286 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyUtils.Reflection.class);
aoqi@0 287
aoqi@0 288 /**
aoqi@0 289 * Reflectively invokes specified method on the specified target
aoqi@0 290 */
aoqi@0 291 static <T> T invoke(final Object target, final String methodName,
aoqi@0 292 final Class<T> resultClass, final Object... parameters) throws RuntimePolicyUtilsException {
aoqi@0 293 Class[] parameterTypes;
aoqi@0 294 if (parameters != null && parameters.length > 0) {
aoqi@0 295 parameterTypes = new Class[parameters.length];
aoqi@0 296 int i = 0;
aoqi@0 297 for (Object parameter : parameters) {
aoqi@0 298 parameterTypes[i++] = parameter.getClass();
aoqi@0 299 }
aoqi@0 300 } else {
aoqi@0 301 parameterTypes = null;
aoqi@0 302 }
aoqi@0 303
aoqi@0 304 return invoke(target, methodName, resultClass, parameters, parameterTypes);
aoqi@0 305 }
aoqi@0 306
aoqi@0 307 /**
aoqi@0 308 * Reflectively invokes specified method on the specified target
aoqi@0 309 */
aoqi@0 310 public static <T> T invoke(final Object target, final String methodName, final Class<T> resultClass,
aoqi@0 311 final Object[] parameters, final Class[] parameterTypes) throws RuntimePolicyUtilsException {
aoqi@0 312 try {
aoqi@0 313 final Method method = target.getClass().getMethod(methodName, parameterTypes);
aoqi@0 314 final Object result = MethodUtil.invoke(target, method,parameters);
aoqi@0 315
aoqi@0 316 return resultClass.cast(result);
aoqi@0 317 } catch (IllegalArgumentException e) {
aoqi@0 318 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(createExceptionMessage(target, parameters, methodName), e));
aoqi@0 319 } catch (InvocationTargetException e) {
aoqi@0 320 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(createExceptionMessage(target, parameters, methodName), e));
aoqi@0 321 } catch (IllegalAccessException e) {
aoqi@0 322 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(createExceptionMessage(target, parameters, methodName), e.getCause()));
aoqi@0 323 } catch (SecurityException e) {
aoqi@0 324 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(createExceptionMessage(target, parameters, methodName), e));
aoqi@0 325 } catch (NoSuchMethodException e) {
aoqi@0 326 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(createExceptionMessage(target, parameters, methodName), e));
aoqi@0 327 }
aoqi@0 328 }
aoqi@0 329
aoqi@0 330 private static String createExceptionMessage(final Object target, final Object[] parameters, final String methodName) {
aoqi@0 331 return LocalizationMessages.WSP_0061_METHOD_INVOCATION_FAILED(target.getClass().getName(), methodName,
aoqi@0 332 parameters == null ? null : Arrays.asList(parameters).toString());
aoqi@0 333 }
aoqi@0 334 }
aoqi@0 335
aoqi@0 336 public static class ConfigFile {
aoqi@0 337 /**
aoqi@0 338 * Generates a config file resource name from provided config file identifier.
aoqi@0 339 * The generated file name can be transformed into a URL instance using
aoqi@0 340 * {@link #loadFromContext(String, Object)} or {@link #loadFromClasspath(String)}
aoqi@0 341 * method.
aoqi@0 342 *
aoqi@0 343 * @param configFileIdentifier the string used to generate the config file URL that will be parsed. Each WSIT config
aoqi@0 344 * file is in form of <code>wsit-<i>{configFileIdentifier}</i>.xml</code>. Must not be {@code null}.
aoqi@0 345 * @return generated config file resource name
aoqi@0 346 * @throw PolicyException If configFileIdentifier is null.
aoqi@0 347 */
aoqi@0 348 public static String generateFullName(final String configFileIdentifier) throws PolicyException {
aoqi@0 349 if (configFileIdentifier != null) {
aoqi@0 350 final StringBuffer buffer = new StringBuffer("wsit-");
aoqi@0 351 buffer.append(configFileIdentifier).append(".xml");
aoqi@0 352 return buffer.toString();
aoqi@0 353 } else {
aoqi@0 354 throw new PolicyException(LocalizationMessages.WSP_0080_IMPLEMENTATION_EXPECTED_NOT_NULL());
aoqi@0 355 }
aoqi@0 356 }
aoqi@0 357
aoqi@0 358 /**
aoqi@0 359 * Returns a URL pointing to the given config file. The file name is
aoqi@0 360 * looked up as a resource from a ServletContext.
aoqi@0 361 *
aoqi@0 362 * May return null if the file can not be found.
aoqi@0 363 *
aoqi@0 364 * @param configFileName The name of the file resource
aoqi@0 365 * @param context A ServletContext object. May not be null.
aoqi@0 366 */
aoqi@0 367 public static URL loadFromContext(final String configFileName, final Object context) {
aoqi@0 368 return Reflection.invoke(context, "getResource", URL.class, configFileName);
aoqi@0 369 }
aoqi@0 370
aoqi@0 371 /**
aoqi@0 372 * Returns a URL pointing to the given config file. The file is looked up as
aoqi@0 373 * a resource on the classpath.
aoqi@0 374 *
aoqi@0 375 * May return null if the file can not be found.
aoqi@0 376 *
aoqi@0 377 * @param configFileName the name of the file resource. May not be {@code null}.
aoqi@0 378 */
aoqi@0 379 public static URL loadFromClasspath(final String configFileName) {
aoqi@0 380 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
aoqi@0 381 if (cl == null) {
aoqi@0 382 return ClassLoader.getSystemResource(configFileName);
aoqi@0 383 } else {
aoqi@0 384 return cl.getResource(configFileName);
aoqi@0 385 }
aoqi@0 386 }
aoqi@0 387 }
aoqi@0 388
aoqi@0 389 /**
aoqi@0 390 * Wrapper for ServiceFinder class which is not part of the Java SE yet.
aoqi@0 391 */
aoqi@0 392 public static class ServiceProvider {
aoqi@0 393 /**
aoqi@0 394 * Locates and incrementally instantiates the available providers of a
aoqi@0 395 * given service using the given class loader.
aoqi@0 396 * <p/>
aoqi@0 397 * <p> This method transforms the name of the given service class into a
aoqi@0 398 * provider-configuration filename as described above and then uses the
aoqi@0 399 * <tt>getResources</tt> method of the given class loader to find all
aoqi@0 400 * available files with that name. These files are then read and parsed to
aoqi@0 401 * produce a list of provider-class names. Eventually each provider class is
aoqi@0 402 * instantiated and array of those instances is returned.
aoqi@0 403 * <p/>
aoqi@0 404 * <p> Because it is possible for extensions to be installed into a running
aoqi@0 405 * Java virtual machine, this method may return different results each time
aoqi@0 406 * it is invoked. <p>
aoqi@0 407 *
aoqi@0 408 * @param serviceClass The service's abstract service class. Must not be {@code null}.
aoqi@0 409 * @param loader The class loader to be used to load provider-configuration files
aoqi@0 410 * and instantiate provider classes, or <tt>null</tt> if the system
aoqi@0 411 * class loader (or, failing that the bootstrap class loader) is to
aoqi@0 412 * be used
aoqi@0 413 * @throws NullPointerException in case {@code service} input parameter is {@code null}.
aoqi@0 414 * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
aoqi@0 415 * or names a provider class that cannot be found and instantiated
aoqi@0 416 * @see #load(Class)
aoqi@0 417 */
aoqi@0 418 public static <T> T[] load(final Class<T> serviceClass, final ClassLoader loader) {
aoqi@0 419 return ServiceFinder.find(serviceClass, loader).toArray();
aoqi@0 420 }
aoqi@0 421
aoqi@0 422 /**
aoqi@0 423 * Locates and incrementally instantiates the available providers of a
aoqi@0 424 * given service using the context class loader. This convenience method
aoqi@0 425 * is equivalent to
aoqi@0 426 * <p/>
aoqi@0 427 * <pre>
aoqi@0 428 * ClassLoader cl = Thread.currentThread().getContextClassLoader();
aoqi@0 429 * return PolicyUtils.ServiceProvider.load(service, cl);
aoqi@0 430 * </pre>
aoqi@0 431 *
aoqi@0 432 * @param serviceClass The service's abstract service class. Must not be {@code null}.
aoqi@0 433 *
aoqi@0 434 * @throws NullPointerException in case {@code service} input parameter is {@code null}.
aoqi@0 435 * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
aoqi@0 436 * or names a provider class that cannot be found and instantiated
aoqi@0 437 * @see #load(Class, ClassLoader)
aoqi@0 438 */
aoqi@0 439 public static <T> T[] load(final Class<T> serviceClass) {
aoqi@0 440 return ServiceFinder.find(serviceClass).toArray();
aoqi@0 441 }
aoqi@0 442 }
aoqi@0 443
aoqi@0 444 public static class Rfc2396 {
aoqi@0 445
aoqi@0 446 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyUtils.Reflection.class);
aoqi@0 447
aoqi@0 448 // converts "hello%20world" into "hello world"
aoqi@0 449 public static String unquote(final String quoted) {
aoqi@0 450 if (null == quoted) {
aoqi@0 451 return null;
aoqi@0 452 }
aoqi@0 453 final byte[] unquoted = new byte[quoted.length()]; // result cannot be longer than original string
aoqi@0 454 int newLength = 0;
aoqi@0 455 char c;
aoqi@0 456 int hi, lo;
aoqi@0 457 for (int i=0; i < quoted.length(); i++) { // iterarate over all chars in the input
aoqi@0 458 c = quoted.charAt(i);
aoqi@0 459 if ('%' == c) { // next escape sequence found
aoqi@0 460 if ((i + 2) >= quoted.length()) {
aoqi@0 461 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(LocalizationMessages.WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted)), false);
aoqi@0 462 }
aoqi@0 463 hi = Character.digit(quoted.charAt(++i), 16);
aoqi@0 464 lo = Character.digit(quoted.charAt(++i), 16);
aoqi@0 465 if ((0 > hi) || (0 > lo)) {
aoqi@0 466 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(LocalizationMessages.WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted)), false);
aoqi@0 467 }
aoqi@0 468 unquoted[newLength++] = (byte) (hi * 16 + lo);
aoqi@0 469 } else { // regular character found
aoqi@0 470 unquoted[newLength++] = (byte) c;
aoqi@0 471 }
aoqi@0 472 }
aoqi@0 473 try {
aoqi@0 474 return new String(unquoted, 0, newLength, "utf-8");
aoqi@0 475 } catch (UnsupportedEncodingException uee) {
aoqi@0 476 throw LOGGER.logSevereException(new RuntimePolicyUtilsException(LocalizationMessages.WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted), uee));
aoqi@0 477 }
aoqi@0 478 }
aoqi@0 479 }
aoqi@0 480 }

mercurial