001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.policy.privateutil;
038:
039: import java.io.Closeable;
040: import java.io.IOException;
041: import java.io.UnsupportedEncodingException;
042: import java.lang.reflect.InvocationTargetException;
043: import java.lang.reflect.Method;
044: import java.net.URL;
045: import java.util.ArrayList;
046: import java.util.Arrays;
047: import java.util.Collection;
048: import java.util.Comparator;
049: import java.util.LinkedList;
050: import java.util.List;
051: import java.util.Queue;
052: import javax.xml.namespace.QName;
053: import javax.xml.stream.XMLStreamException;
054: import javax.xml.stream.XMLStreamReader;
055:
056: /**
057: * This is a wrapper class for various utilities that may be reused within Policy API implementation.
058: * The class is not part of public Policy API. Do not use it from your client code!
059: *
060: * @author Marek Potociar
061: */
062: public final class PolicyUtils {
063: private PolicyUtils() {
064: }
065:
066: public static class Commons {
067: private static final LinkedList<StackTraceElement> stackTraceElements = new LinkedList<StackTraceElement>();
068:
069: /**
070: * Method returns the name of the method that is on the {@code methodIndexInStack}
071: * position in the call stack of the current {@link Thread}.
072: *
073: * @param methodIndexInStack index to the call stack to get the method name for.
074: * @return the name of the method that is on the {@code methodIndexInStack}
075: * position in the call stack of the current {@link Thread}.
076: */
077: public static String getStackMethodName(
078: final int methodIndexInStack) {
079: final String methodName;
080:
081: final StackTraceElement[] stack = Thread.currentThread()
082: .getStackTrace();
083: if (stack.length > methodIndexInStack + 1) {
084: methodName = stack[methodIndexInStack].getMethodName();
085: } else {
086: methodName = "UNKNOWN METHOD";
087: }
088:
089: return methodName;
090: }
091:
092: /**
093: * Function returns the name of the caller method for the method executing this
094: * function.
095: *
096: * @return caller method name from the call stack of the current {@link Thread}.
097: */
098: public static String getCallerMethodName() {
099: return getStackMethodName(5);
100: }
101: }
102:
103: public static class IO {
104: private static final PolicyLogger LOGGER = PolicyLogger
105: .getLogger(PolicyUtils.IO.class);
106:
107: /**
108: * If the {@code resource} is not {@code null}, this method will try to close the
109: * {@code resource} instance and log warning about any unexpected
110: * {@link IOException} that may occur.
111: *
112: * @param resource resource to be closed
113: */
114: public static void closeResource(Closeable resource) {
115: if (resource != null) {
116: try {
117: resource.close();
118: } catch (IOException e) {
119: LOGGER
120: .warning(
121: LocalizationMessages
122: .WSP_0023_UNEXPECTED_ERROR_WHILE_CLOSING_RESOURCE(resource
123: .toString()), e);
124: }
125: }
126: }
127:
128: /**
129: * If the {@code reader} is not {@code null}, this method will try to close the
130: * {@code reader} instance and log warning about any unexpected
131: * {@link IOException} that may occur.
132: *
133: * @param reader resource to be closed
134: */
135: public static void closeResource(XMLStreamReader reader) {
136: if (reader != null) {
137: try {
138: reader.close();
139: } catch (XMLStreamException e) {
140: LOGGER
141: .warning(
142: LocalizationMessages
143: .WSP_0023_UNEXPECTED_ERROR_WHILE_CLOSING_RESOURCE(reader
144: .toString()), e);
145: }
146: }
147: }
148: }
149:
150: /**
151: * Text utilities wrapper.
152: */
153: public static class Text {
154: /**
155: * System-specific line separator character retrieved from the Java system property
156: * <code>line.separator</code>
157: */
158: public final static String NEW_LINE = System
159: .getProperty("line.separator");
160:
161: /**
162: * Method creates indent string consisting of as many {@code TAB} characters as specified by {@code indentLevel} parameter
163: *
164: * @param indentLevel indentation level
165: * @return indentation string as specified by indentation level
166: *
167: */
168: public static String createIndent(final int indentLevel) {
169: final char[] charData = new char[indentLevel * 4];
170: Arrays.fill(charData, ' ');
171: return String.valueOf(charData);
172: }
173: }
174:
175: public static class Comparison {
176: /**
177: * The comparator comapres QName objects according to their publicly accessible attributes, in the following
178: * order of attributes:
179: *
180: * 1. namespace (not null String)
181: * 2. local name (not null String)
182: */
183: public static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
184: public int compare(final QName qn1, final QName qn2) {
185: if (qn1 == qn2 || qn1.equals(qn2)) {
186: return 0;
187: }
188:
189: int result;
190:
191: result = qn1.getNamespaceURI().compareTo(
192: qn2.getNamespaceURI());
193: if (result != 0) {
194: return result;
195: }
196:
197: return qn1.getLocalPart().compareTo(qn2.getLocalPart());
198: }
199: };
200:
201: /**
202: * Compares two boolean values in the following way: {@code false < true}
203: *
204: * @return {@code -1} if {@code b1 < b2}, {@code 0} if {@code b1 == b2}, {@code 1} if {@code b1 > b2}
205: */
206: public static int compareBoolean(final boolean b1,
207: final boolean b2) {
208: final int i1 = (b1) ? 1 : 0;
209: final int i2 = (b2) ? 1 : 0;
210:
211: return i1 - i2;
212: }
213:
214: /**
215: * Compares two String values, that may possibly be null in the following way: {@code null < "string value"}
216: *
217: * @return {@code -1} if {@code s1 < s2}, {@code 0} if {@code s1 == s2}, {@code 1} if {@code s1 > s2}
218: */
219: public static int compareNullableStrings(final String s1,
220: final String s2) {
221: return ((s1 == null) ? ((s2 == null) ? 0 : -1)
222: : ((s2 == null) ? 1 : s1.compareTo(s2)));
223: }
224: }
225:
226: public static class Collections {
227: /**
228: * TODO javadocs
229: *
230: * @param initialBase the combination base that will be present in each combination. May be {@code null} or empty.
231: * @param options options that should be combined. May be {@code null} or empty.
232: * @param ignoreEmptyOption flag identifies whether empty options should be ignored or whether the method should halt
233: * processing and return {@code null} when an empty option is encountered
234: * @return TODO
235: */
236: public static <E, T extends Collection<? extends E>, U extends Collection<? extends E>> Collection<Collection<E>> combine(
237: final U initialBase, final Collection<T> options,
238: final boolean ignoreEmptyOption) {
239: List<Collection<E>> combinations = null;
240: if (options == null || options.isEmpty()) {
241: // no combination creation needed
242: if (initialBase != null) {
243: combinations = new ArrayList<Collection<E>>(1);
244: combinations.add(new ArrayList<E>(initialBase));
245: }
246: return combinations;
247: }
248:
249: // creating defensive and modifiable copy of the base
250: final Collection<E> base = new LinkedList<E>();
251: if (initialBase != null && !initialBase.isEmpty()) {
252: base.addAll(initialBase);
253: }
254: /**
255: * now we iterate over all options and build up an option processing queue:
256: * 1. if ignoreEmptyOption flag is not set and we found an empty option, we are going to stop processing and return null. Otherwise we
257: * ignore the empty option.
258: * 2. if the option has one child only, we add the child directly to the base.
259: * 3. if there are more children in examined node, we add it to the queue for further processing and precoumpute the final size of
260: * resulting collection of combinations.
261: */
262: int finalCombinationsSize = 1;
263: final Queue<T> optionProcessingQueue = new LinkedList<T>();
264: for (T option : options) {
265: final int optionSize = option.size();
266:
267: if (optionSize == 0) {
268: if (!ignoreEmptyOption) {
269: return null;
270: }
271: } else if (optionSize == 1) {
272: base.addAll(option);
273: } else {
274: optionProcessingQueue.offer(option);
275: finalCombinationsSize *= optionSize;
276: }
277: }
278:
279: // creating final combinations
280: combinations = new ArrayList<Collection<E>>(
281: finalCombinationsSize);
282: combinations.add(base);
283: if (finalCombinationsSize > 1) {
284: T processedOption;
285: while ((processedOption = optionProcessingQueue.poll()) != null) {
286: final int actualSemiCombinationCollectionSize = combinations
287: .size();
288: final int newSemiCombinationCollectionSize = actualSemiCombinationCollectionSize
289: * processedOption.size();
290:
291: int semiCombinationIndex = 0;
292: for (E optionElement : processedOption) {
293: for (int i = 0; i < actualSemiCombinationCollectionSize; i++) {
294: final Collection<E> semiCombination = combinations
295: .get(semiCombinationIndex); // unfinished combination
296:
297: if (semiCombinationIndex
298: + actualSemiCombinationCollectionSize < newSemiCombinationCollectionSize) {
299: // this is not the last optionElement => we create a new combination copy for the next child
300: combinations.add(new LinkedList<E>(
301: semiCombination));
302: }
303:
304: semiCombination.add(optionElement);
305: semiCombinationIndex++;
306: }
307: }
308: }
309: }
310: return combinations;
311: }
312: }
313:
314: /**
315: * Reflection utilities wrapper
316: */
317: public static class Reflection {
318: private static final PolicyLogger LOGGER = PolicyLogger
319: .getLogger(PolicyUtils.Reflection.class);
320:
321: /**
322: * Reflectively invokes specified method on the specified target
323: */
324: public static <T> T invoke(final Object target,
325: final String methodName, final Class<T> resultClass,
326: final Object... parameters)
327: throws RuntimePolicyUtilsException {
328: Class[] parameterTypes;
329: if (parameters != null && parameters.length > 0) {
330: parameterTypes = new Class[parameters.length];
331: int i = 0;
332: for (Object parameter : parameters) {
333: parameterTypes[i++] = parameter.getClass();
334: }
335: } else {
336: parameterTypes = null;
337: }
338:
339: return invoke(target, methodName, resultClass, parameters,
340: parameterTypes);
341: }
342:
343: /**
344: * Reflectively invokes specified method on the specified target
345: */
346: public static <T> T invoke(final Object target,
347: final String methodName, final Class<T> resultClass,
348: final Object[] parameters, final Class[] parameterTypes)
349: throws RuntimePolicyUtilsException {
350: try {
351: final Method method = target.getClass().getMethod(
352: methodName, parameterTypes);
353: final Object result = method.invoke(target, parameters);
354:
355: return resultClass.cast(result);
356: } catch (IllegalArgumentException e) {
357: throw LOGGER
358: .logSevereException(new RuntimePolicyUtilsException(
359: createExceptionMessage(target,
360: parameters, methodName), e));
361: } catch (InvocationTargetException e) {
362: throw LOGGER
363: .logSevereException(new RuntimePolicyUtilsException(
364: createExceptionMessage(target,
365: parameters, methodName), e));
366: } catch (IllegalAccessException e) {
367: throw LOGGER
368: .logSevereException(new RuntimePolicyUtilsException(
369: createExceptionMessage(target,
370: parameters, methodName), e
371: .getCause()));
372: } catch (SecurityException e) {
373: throw LOGGER
374: .logSevereException(new RuntimePolicyUtilsException(
375: createExceptionMessage(target,
376: parameters, methodName), e));
377: } catch (NoSuchMethodException e) {
378: throw LOGGER
379: .logSevereException(new RuntimePolicyUtilsException(
380: createExceptionMessage(target,
381: parameters, methodName), e));
382: }
383: }
384:
385: private static String createExceptionMessage(
386: final Object target, final Object[] parameters,
387: final String methodName) {
388: return LocalizationMessages
389: .WSP_0061_METHOD_INVOCATION_FAILED(target
390: .getClass().getName(), methodName, Arrays
391: .asList(parameters).toString());
392: }
393: }
394:
395: public static class ConfigFile {
396: /**
397: * Generates a config file resource name from provided config file identifier.
398: * The generated file name can be transformed into a URL instance using
399: * {@link #loadFromContext(String, Object)} or {@link #loadFromClasspath(String)}
400: * method.
401: *
402: * @param configFileIdentifier the string used to generate the config file URL that will be parsed. Each WSIT config
403: * file is in form of <code>wsit-<i>{configFileIdentifier}</i>.xml</code>. Must not be {@code null}.
404: * @return generated config file resource name
405: */
406: public static String generateFullName(
407: final String configFileIdentifier) {
408: if (configFileIdentifier != null) {
409: final StringBuffer buffer = new StringBuffer("wsit-");
410: buffer.append(configFileIdentifier).append(".xml");
411: return buffer.toString();
412: } else {
413: return "wsit.xml"; //TODO: throw exception instead
414: }
415: }
416:
417: /**
418: * Returns a URL pointing to the given config file. The file name is
419: * looked up as a resource from a ServletContext.
420: *
421: * May return null if the file can not be found.
422: *
423: * @param configFileName The name of the file resource
424: * @param context A ServletContext object. May not be null.
425: */
426: public static URL loadFromContext(final String configFileName,
427: final Object context) {
428: return Reflection.invoke(context, "getResource", URL.class,
429: configFileName);
430: }
431:
432: /**
433: * Returns a URL pointing to the given config file. The file is looked up as
434: * a resource on the classpath.
435: *
436: * May return null if the file can not be found.
437: *
438: * @param configFileName the name of the file resource. May not be {@code null}.
439: */
440: public static URL loadFromClasspath(final String configFileName) {
441: final ClassLoader cl = Thread.currentThread()
442: .getContextClassLoader();
443: if (cl == null) {
444: return ClassLoader.getSystemResource(configFileName);
445: } else {
446: return cl.getResource(configFileName);
447: }
448: }
449: }
450:
451: /**
452: * Wrapper for ServiceFinder class which is not part of the Java SE yet.
453: */
454: public static class ServiceProvider {
455: /**
456: * Locates and incrementally instantiates the available providers of a
457: * given service using the given class loader.
458: * <p/>
459: * <p> This method transforms the name of the given service class into a
460: * provider-configuration filename as described above and then uses the
461: * <tt>getResources</tt> method of the given class loader to find all
462: * available files with that name. These files are then read and parsed to
463: * produce a list of provider-class names. Eventually each provider class is
464: * instantiated and array of those instances is returned.
465: * <p/>
466: * <p> Because it is possible for extensions to be installed into a running
467: * Java virtual machine, this method may return different results each time
468: * it is invoked. <p>
469: *
470: * @param serviceClass The service's abstract service class. Must not be {@code null}.
471: * @param loader The class loader to be used to load provider-configuration files
472: * and instantiate provider classes, or <tt>null</tt> if the system
473: * class loader (or, failing that the bootstrap class loader) is to
474: * be used
475: * @throws NullPointerException in case {@code service} input parameter is {@code null}.
476: * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
477: * or names a provider class that cannot be found and instantiated
478: * @see #load(Class)
479: */
480: public static <T> T[] load(final Class<T> serviceClass,
481: final ClassLoader loader) {
482: return ServiceFinder.find(serviceClass, loader).toArray();
483: }
484:
485: /**
486: * Locates and incrementally instantiates the available providers of a
487: * given service using the context class loader. This convenience method
488: * is equivalent to
489: * <p/>
490: * <pre>
491: * ClassLoader cl = Thread.currentThread().getContextClassLoader();
492: * return PolicyUtils.ServiceProvider.load(service, cl);
493: * </pre>
494: *
495: * @param serviceClass The service's abstract service class. Must not be {@code null}.
496: *
497: * @throws NullPointerException in case {@code service} input parameter is {@code null}.
498: * @throws ServiceConfigurationError If a provider-configuration file violates the specified format
499: * or names a provider class that cannot be found and instantiated
500: * @see #load(Class, ClassLoader)
501: */
502: public static <T> T[] load(final Class<T> serviceClass) {
503: return ServiceFinder.find(serviceClass).toArray();
504: }
505: }
506:
507: public static class Rfc2396 {
508:
509: private static final PolicyLogger LOGGER = PolicyLogger
510: .getLogger(PolicyUtils.Reflection.class);
511:
512: // converts "hello%20world" into "hello world"
513: public static String unquote(final String quoted) {
514: if (null == quoted) {
515: return null;
516: }
517: final byte[] unquoted = new byte[quoted.length()]; // result cannot be longer than original string
518: int newLength = 0;
519: char c;
520: int hi, lo;
521: for (int i = 0; i < quoted.length(); i++) { // iterarate over all chars in the input
522: c = quoted.charAt(i);
523: if ('%' == c) { // next escape sequence found
524: if ((i + 2) > quoted.length()) {
525: throw LOGGER
526: .logSevereException(
527: new RuntimePolicyUtilsException(
528: LocalizationMessages
529: .WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted)),
530: false);
531: }
532: hi = Character.digit(quoted.charAt(++i), 16);
533: lo = Character.digit(quoted.charAt(++i), 16);
534: if ((0 > hi) || (0 > lo)) {
535: throw LOGGER
536: .logSevereException(
537: new RuntimePolicyUtilsException(
538: LocalizationMessages
539: .WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted)),
540: false);
541: }
542: unquoted[newLength++] = (byte) (hi * 16 + lo);
543: } else { // regular character found
544: unquoted[newLength++] = (byte) c;
545: }
546: }
547: try {
548: return new String(unquoted, 0, newLength, "utf-8");
549: } catch (UnsupportedEncodingException uee) {
550: throw LOGGER
551: .logSevereException(new RuntimePolicyUtilsException(
552: LocalizationMessages
553: .WSP_0079_ERROR_WHILE_RFC_2396_UNESCAPING(quoted),
554: uee));
555: }
556: }
557: }
558: }
|