001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 2002 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "WSIF" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 2001, 2002, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057: package org.apache.wsif.util;
058:
059: import java.io.BufferedReader;
060: import java.io.IOException;
061: import java.io.InputStreamReader;
062: import java.net.URL;
063: import java.security.AccessController;
064: import java.security.PrivilegedAction;
065: import java.util.ArrayList;
066: import java.util.Enumeration;
067: import java.util.HashMap;
068: import java.util.Iterator;
069:
070: import org.apache.wsif.WSIFConstants;
071: import org.apache.wsif.WSIFException;
072: import org.apache.wsif.logging.MessageLogger;
073: import org.apache.wsif.logging.Trc;
074: import org.apache.wsif.spi.WSIFProvider;
075:
076: /**
077: * Utility methods for pluggable provider support.
078: * <p>
079: * A WSIF provider is a class that implements the
080: * org.apache.wsif.spi.Provider interface. A Provider is
081: * the logic that supports any particular WSDL binding extension.
082: * <p>
083: * WSIF providers are packaged in JAR files, and use the J2SE 1.3
084: * JAR file extensions to support service providers.
085: * A WSIF Provider JAR will contain the following file:
086: * <p>
087: * META-INF/services/com.ibm.wsif.spi.WSIFProvider
088: * <p>
089: * This file will contain a list of the class names of the Provider
090: * classes in the JAR (which must implement com.ibm.wsif.spi.WSIFProvider).
091: * When the first request for a provider is made all the providers
092: * defined in the META-INF/services files will be instantiated. This can
093: * be prevented from happening by using the <code>setAutoLoadProviders<\code>
094: * method. When this is done providers must be manually defined by using the
095: * <code>overrideDefaultProvider<\code> method.
096: * <p>
097: * It is possible to have multiple providers supporting the same binding
098: * namespace. When this occurs the provider used is chosen in the following
099: * order:
100: * 1 - the provider explicitly set for the namespace with the
101: * <code>overrideDefaultProvider<\code> method.
102: * 2 - the provider defined in the WSIF properties file as being the
103: * default provider for the binding namespace
104: * 3 - the provider defined first in the META-INF/services file in the
105: * jar file found first in the classpath.
106: *
107: * @author Ant Elder <antelder@apache.org>
108: */
109: public class WSIFPluggableProviders {
110:
111: // defines if providers will be loaded automatically
112: private static boolean autoLoadProviders = true;
113:
114: // all the providers found in all the SPI files from
115: // all the jar files in the classpath, in the order
116: // they were found with the 1st in the ArrayList
117: // being higher in the classpath.
118: private static ArrayList providersFromSPIFiles;
119:
120: // a mapping of providers chosen to be supporting
121: // a binding namespace. The mapping key is the
122: // namespace URI, the value is the provider
123: private static HashMap defaultNSProviders;
124:
125: private static final String PLUGABLE_PROVIDER_FILENAME = "META-INF/services/org.apache.wsif.spi.WSIFProvider";
126:
127: /**
128: * Gets a WSIFProvider for a particular bindng namespace URI.
129: * @param namespaceURI the URI of the binding namespace
130: * that the WSIFProvider must support
131: * @return a WSIFProvider supporting the requested binding
132: * namespace, or null if no providers are available.
133: */
134: public static WSIFProvider getProvider(String namespaceURI) {
135: Trc.entry(null, namespaceURI);
136: WSIFProvider provider;
137:
138: // the defaultNSProviders Hashtable URIs end with a '/'
139: if (!namespaceURI.endsWith("/")) {
140: namespaceURI += "/";
141: }
142:
143: if (defaultNSProviders == null) {
144: defaultNSProviders = new HashMap();
145: } else {
146: provider = (WSIFProvider) defaultNSProviders
147: .get(namespaceURI);
148: if (provider != null) {
149: return provider;
150: }
151: }
152: ArrayList providers = getSupportingProviders(namespaceURI, true);
153: if (providers.size() == 0) {
154: return null;
155: }
156: if (providers.size() == 1) {
157: provider = (WSIFProvider) providers.get(0);
158: } else {
159: provider = chooseProvider(providers, namespaceURI);
160: }
161: defaultNSProviders.put(namespaceURI, provider);
162: Trc.exit(provider);
163: return provider;
164: }
165:
166: /**
167: * Change the WSIFProvider used for a particular binding namespace.
168: * Calling this with a null provider removes the previously chosen
169: * provider for the binding namespace causing the next request for
170: * a provider for the namespace to use the default search order.
171: *
172: * @param providerNamespaceURI the binding namespace to be overriden
173: * @param provider the WSIFProvider to be used for the binding namespace
174: */
175: public static void overrideDefaultProvider(
176: String providerNamespaceURI, WSIFProvider provider) {
177: Trc.entry(null, providerNamespaceURI, provider);
178:
179: if (defaultNSProviders == null) {
180: defaultNSProviders = new HashMap();
181: }
182:
183: // the defaultNSProviders HashMap URIs end with a '/'
184: if (!providerNamespaceURI.endsWith("/")) {
185: providerNamespaceURI += "/";
186: }
187:
188: if (provider == null) {
189: WSIFProvider p = (WSIFProvider) defaultNSProviders
190: .get(providerNamespaceURI);
191: if (defaultNSProviders != null) {
192: defaultNSProviders.remove(providerNamespaceURI);
193: }
194: } else {
195: defaultNSProviders.put(providerNamespaceURI, provider);
196: issueChosenProviderMsg(providerNamespaceURI, provider);
197: }
198:
199: Trc.exit();
200: }
201:
202: /**
203: * Tests if a provider is available for the given namespace.
204: * @param ns1 the WSDL binding namespace URI
205: * @return true if a provider is available for the given
206: * binding namespace, otherwise false.
207: */
208: public static boolean isProviderAvailable(String ns1) {
209: return isProviderAvailable(ns1, ns1);
210: }
211:
212: /**
213: * Tests if a provider is available for the given namespaces.
214: * @param ns1 the WSDL binding namespace URI
215: * @param ns2 the WSDL port addresses namespace URI
216: * @return true if a provider is available for the given
217: * namespaces, otherwise false.
218: */
219: public static boolean isProviderAvailable(String ns1, String ns2) {
220: boolean supported = false;
221: ArrayList ps = getSupportingProviders(ns1, false);
222: if (ps.size() > 0) {
223: if (ns2 == null || ns2.length() < 1 || ns2.equals(ns1)) {
224: supported = true;
225: } else {
226: String[] supportedNS;
227: for (int i = 0; i < ps.size() && !supported; i++) {
228: supportedNS = ((WSIFProvider) ps.get(i))
229: .getAddressNamespaceURIs();
230: for (int j = 0; j < supportedNS.length
231: && !supported; j++) {
232: if (ns2.equals(supportedNS[j])) {
233: supported = true;
234: }
235: }
236: }
237: }
238: }
239: return supported;
240: }
241:
242: /**
243: * This sets if the WSIFProviders will be automatically loaded.
244: * If this is set to false any providers required msut be explicitly
245: * defined by using the <code>overrideDefaultProvider<\code> method.
246: * Changing the state of the auto loading of providers clears any providers
247: * that have already been loaded or choosen as a default provider.
248: * @param b true means all the WSIFProviders will be loaded automatically,
249: * false means all WSIFProviders must be manually set with the
250: * setDynamicWSIFProvider method
251: */
252: public static void setAutoLoadProviders(boolean b) {
253: Trc.entry(null, b);
254: if (autoLoadProviders != b) {
255: providersFromSPIFiles = null;
256: defaultNSProviders = null;
257: autoLoadProviders = b;
258: }
259: Trc.exit();
260: }
261:
262: /**
263: * Tests if providers are set to be automatically loaded.
264: * @return true if providers will be loaded automatically,
265: * otherwise false.
266: */
267: public static boolean isAutoLoadProviders() {
268: Trc.entry(null);
269: Trc.exit(autoLoadProviders);
270: return autoLoadProviders;
271: }
272:
273: /**
274: * Gets all the available WSIFProvider that support a particular
275: * namespace URI.
276: * @param namesapceURI the namespace the WSIFProvider must support.
277: * @param issueMessage Flag to inicate whether or not to log when multiple
278: * providers are found for the same namespace.
279: * @return an array of WSIFProvider. The array will have a length
280: * of zero if no WSIFProvider are available for the requested namespace.
281: */
282: private static ArrayList getSupportingProviders(
283: String namespaceURI, boolean issueMessage) {
284:
285: Trc.entry(null, namespaceURI, new Boolean(issueMessage));
286: if (providersFromSPIFiles == null) {
287: providersFromSPIFiles = getAllDynamicWSIFProviders();
288: }
289: ArrayList supportingProviders = new ArrayList();
290: String[] uris;
291: WSIFProvider p;
292: for (Iterator i = providersFromSPIFiles.iterator(); i.hasNext();) {
293: p = (WSIFProvider) i.next();
294: uris = p.getBindingNamespaceURIs();
295: for (int j = 0; j < uris.length; j++) {
296: if (namespaceURI != null
297: && namespaceURI.equals(uris[j])) {
298: Trc.event(null, "Adding provider " + p
299: + " for namespace " + uris[j]);
300: supportingProviders.add(p);
301: }
302: }
303: }
304: if (defaultNSProviders != null) {
305: if (defaultNSProviders.get(namespaceURI) != null) {
306: Trc.event(null, "Adding default provider "
307: + defaultNSProviders.get(namespaceURI)
308: + " for namespace " + namespaceURI);
309: supportingProviders.add(defaultNSProviders
310: .get(namespaceURI));
311: }
312: }
313:
314: if (supportingProviders.size() > 1 && issueMessage) {
315: issueMultipleProvidersMsg(namespaceURI, supportingProviders);
316: }
317:
318: Trc.exit(supportingProviders);
319: return supportingProviders;
320: }
321:
322: /**
323: * Gets all the available WSIFProviders.
324: * WSIFProviders are located using the J2SE 1.3 JAR file extensions
325: * to support service providers.
326: * @return an array of WSIFProvider.
327: */
328: private static ArrayList getAllDynamicWSIFProviders() {
329: Trc.entry(null);
330: if (!autoLoadProviders) {
331: return new ArrayList();
332: }
333:
334: ArrayList al = (ArrayList) AccessController
335: .doPrivileged(new PrivilegedAction() {
336: public Object run() {
337: return findPlugableProviders();
338: }
339: });
340: Trc.exit(al);
341: return al;
342: }
343:
344: private static ArrayList findPlugableProviders() {
345: Object o;
346: ArrayList classNames = new ArrayList();
347: ArrayList providers = new ArrayList();
348:
349: // find all the class names mentioned in all the META-INF files
350: ClassLoader loader = Thread.currentThread()
351: .getContextClassLoader();
352:
353: try {
354: for (Enumeration e = loader
355: .getResources(PLUGABLE_PROVIDER_FILENAME); e
356: .hasMoreElements();) {
357: readMETAINFClassNames((URL) e.nextElement(), classNames);
358: }
359: } catch (Exception ex) {
360: Trc.exception(ex);
361: MessageLogger.log("WSIF.0003W", ex.getMessage());
362: return providers;
363: }
364:
365: // instantiate a provider for each of the named classes
366: for (Iterator i = classNames.iterator(); i.hasNext();) {
367: try {
368: o = Class.forName((String) i.next(), true, loader)
369: .newInstance();
370: if (o instanceof org.apache.wsif.spi.WSIFProvider) {
371: WSIFProvider p = (org.apache.wsif.spi.WSIFProvider) o;
372: if (p.getBindingNamespaceURIs().length > 0) {
373: Trc.event(null, "Registering provider: " + p);
374: providers.add(p);
375: } else {
376: WSIFException ex = new WSIFException(
377: "Disabled WSIFProvider found:"
378: + p.getClass().getName());
379: Trc.ignoredException(ex);
380: }
381: } else {
382: MessageLogger
383: .log(
384: "WSIF.0003W",
385: "The provider class specified,"
386: + ((o == null) ? null : o
387: .getClass()
388: .getName())
389: + ", does not implement org.apache.wsif.spi.WSIFProvider");
390: }
391: } catch (ClassNotFoundException ex) {
392: Trc.exception(ex);
393: MessageLogger.log("WSIF.0003W", ex.getMessage());
394: } catch (Exception ex) {
395: Trc.exception(ex);
396: MessageLogger.log("WSIF.0003W", ex.getMessage());
397: }
398: }
399:
400: return providers;
401: }
402:
403: private static void readMETAINFClassNames(URL u,
404: ArrayList classNames) {
405: Trc.entry(null, u);
406: Trc.event(null, "Reading provider class names from URL: "
407: + u.toString());
408: BufferedReader in = null;
409: String inputLine;
410: int i;
411: try {
412: in = new BufferedReader(new InputStreamReader(u
413: .openStream()));
414: while ((inputLine = in.readLine()) != null) {
415: i = inputLine.indexOf('#');
416: if (i >= 0) {
417: inputLine = inputLine.substring(0, i);
418: }
419: inputLine = inputLine.trim();
420: if (inputLine.length() > 0) {
421: Trc.event(null, "Found provider class name: "
422: + inputLine);
423: if (!classNames.contains(inputLine)) {
424: classNames.add(inputLine);
425: }
426: }
427: }
428: } catch (IOException ex) {
429: Trc.exception(ex);
430: MessageLogger.log("WSIF.0003W", ex.getMessage());
431: } finally {
432: if (in != null) {
433: try {
434: in.close();
435: } catch (IOException ex) {
436: Trc.exception(ex);
437: MessageLogger.log("WSIF.0003W", ex.getMessage());
438: }
439: }
440: }
441: Trc.exit();
442: }
443:
444: /**
445: * Chooses a particular WSIFProvider. If the passed array of providers
446: * contains more than one element then a choice is made based on a WSIF
447: * properties file default setting.
448: * @param providers an array of WSIFProvider
449: * @return a WSIFProvider. Returns null if the input array is null or
450: * has a length of zero, the first element if the array contains
451: * only one element, or an element based on the property file setting.
452: */
453: private static WSIFProvider chooseProvider(ArrayList providers,
454: String uri) {
455: if (providers == null || providers.size() < 1) {
456: return null;
457: } else if (providers.size() == 1) {
458: return (WSIFProvider) providers.get(0);
459: }
460:
461: int i = providers.size() - 1;
462: while (i > 0
463: && !isDefaultProvider((WSIFProvider) providers.get(i),
464: uri)) {
465: i--;
466: }
467: WSIFProvider p = (WSIFProvider) providers.get(i);
468: issueChosenProviderMsg(uri, p);
469:
470: return p;
471: }
472:
473: /**
474: * Tests if a class name is defined in the WSIF properties file as being the
475: * default WSIF provider for the namespace URI.
476: * @param className the class name to test
477: * @param uri the namespace URI
478: * @return true if className is defined as the default WSIFprovider,
479: * otherwise false.
480: */
481: private static boolean isDefaultProvider(WSIFProvider provider,
482: String uri) {
483: String className = provider.getClass().getName();
484: String defaultURI;
485: try {
486: String key = WSIFConstants.WSIF_PROP_PROVIDER_PFX1
487: + className;
488: int n = Integer.parseInt(WSIFProperties.getProperty(key));
489: for (int i = 1; i <= n; i++) {
490: key = WSIFConstants.WSIF_PROP_PROVIDER_PFX2 + i + "."
491: + className;
492: defaultURI = WSIFProperties.getProperty(key);
493: if (uri != null && uri.equals(defaultURI)) {
494: return true;
495: }
496: }
497: } catch (NumberFormatException e) { // ignore any error
498: Trc.ignoredException(e);
499: } // ignore any error
500: return false;
501: }
502:
503: /**
504: * Issues a MessageLoger warning saying multiple providers
505: * exist with support for the same namespaceURI.
506: * @param uri the namespaceURI with multiple WSIFProviders
507: * @param providers an array of the providers supporting the namespaceURI
508: */
509: private static void issueMultipleProvidersMsg(String uri,
510: ArrayList providers) {
511: String providerNames = providers.get(0).getClass().getName();
512: for (int i = 1; i < providers.size(); i++) {
513: providerNames += ", "
514: + providers.get(i).getClass().getName();
515: }
516: MessageLogger.log("WSIF.0006W", uri, providerNames);
517: }
518:
519: /**
520: * Issues a MessageLoger information message saying which provider has
521: * been chosen to support a namespaceURI when multiple providers are available.
522: * @param uri the namespaceURI with multiple WSIFProviders
523: * @param providers an array of the providers supporting the namespaceURI
524: */
525: private static void issueChosenProviderMsg(String uri,
526: WSIFProvider provider) {
527:
528: MessageLogger.log("WSIF.0007I", provider == null ? "null"
529: : provider.getClass().getName(), uri);
530: }
531:
532: }
|