KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > wsif > util > WSIFPluggableProviders


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2002 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "WSIF" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 2001, 2002, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57 package org.apache.wsif.util;
58
59 import java.io.BufferedReader JavaDoc;
60 import java.io.IOException JavaDoc;
61 import java.io.InputStreamReader JavaDoc;
62 import java.net.URL JavaDoc;
63 import java.security.AccessController JavaDoc;
64 import java.security.PrivilegedAction JavaDoc;
65 import java.util.ArrayList JavaDoc;
66 import java.util.Enumeration JavaDoc;
67 import java.util.HashMap JavaDoc;
68 import java.util.Iterator JavaDoc;
69
70 import org.apache.wsif.WSIFConstants;
71 import org.apache.wsif.WSIFException;
72 import org.apache.wsif.logging.MessageLogger;
73 import org.apache.wsif.logging.Trc;
74 import org.apache.wsif.spi.WSIFProvider;
75
76 /**
77  * Utility methods for pluggable provider support.
78  * <p>
79  * A WSIF provider is a class that implements the
80  * org.apache.wsif.spi.Provider interface. A Provider is
81  * the logic that supports any particular WSDL binding extension.
82  * <p>
83  * WSIF providers are packaged in JAR files, and use the J2SE 1.3
84  * JAR file extensions to support service providers.
85  * A WSIF Provider JAR will contain the following file:
86  * <p>
87  * META-INF/services/com.ibm.wsif.spi.WSIFProvider
88  * <p>
89  * This file will contain a list of the class names of the Provider
90  * classes in the JAR (which must implement com.ibm.wsif.spi.WSIFProvider).
91  * When the first request for a provider is made all the providers
92  * defined in the META-INF/services files will be instantiated. This can
93  * be prevented from happening by using the <code>setAutoLoadProviders<\code>
94  * method. When this is done providers must be manually defined by using the
95  * <code>overrideDefaultProvider<\code> method.
96  * <p>
97  * It is possible to have multiple providers supporting the same binding
98  * namespace. When this occurs the provider used is chosen in the following
99  * 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 JavaDoc 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 JavaDoc defaultNSProviders;
124
125     private static final String JavaDoc PLUGABLE_PROVIDER_FILENAME =
126         "META-INF/services/org.apache.wsif.spi.WSIFProvider";
127
128     /**
129      * Gets a WSIFProvider for a particular bindng namespace URI.
130      * @param namespaceURI the URI of the binding namespace
131      * that the WSIFProvider must support
132      * @return a WSIFProvider supporting the requested binding
133      * namespace, or null if no providers are available.
134      */

135     public static WSIFProvider getProvider(String JavaDoc namespaceURI) {
136         Trc.entry(null, namespaceURI);
137         WSIFProvider provider;
138
139         // the defaultNSProviders Hashtable URIs end with a '/'
140
if (!namespaceURI.endsWith("/")) {
141             namespaceURI += "/";
142         }
143
144         if (defaultNSProviders == null) {
145             defaultNSProviders = new HashMap JavaDoc();
146         } else {
147             provider = (WSIFProvider) defaultNSProviders.get(namespaceURI);
148             if (provider != null) {
149                 return provider;
150             }
151         }
152         ArrayList JavaDoc 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 JavaDoc providerNamespaceURI,
177         WSIFProvider provider) {
178         Trc.entry(null, providerNamespaceURI, provider);
179
180         if (defaultNSProviders == null) {
181             defaultNSProviders = new HashMap JavaDoc();
182         }
183
184         // the defaultNSProviders HashMap URIs end with a '/'
185
if (!providerNamespaceURI.endsWith("/")) {
186             providerNamespaceURI += "/";
187         }
188
189         if (provider == null) {
190             WSIFProvider p =
191                 (WSIFProvider) defaultNSProviders.get(providerNamespaceURI);
192             if (defaultNSProviders != null) {
193                 defaultNSProviders.remove(providerNamespaceURI);
194             }
195         } else {
196             defaultNSProviders.put(providerNamespaceURI, provider);
197             issueChosenProviderMsg(providerNamespaceURI, provider);
198         }
199
200         Trc.exit();
201     }
202
203     /**
204      * Tests if a provider is available for the given namespace.
205      * @param ns1 the WSDL binding namespace URI
206      * @return true if a provider is available for the given
207      * binding namespace, otherwise false.
208      */

209     public static boolean isProviderAvailable(String JavaDoc ns1) {
210         return isProviderAvailable(ns1, ns1);
211     }
212
213     /**
214      * Tests if a provider is available for the given namespaces.
215      * @param ns1 the WSDL binding namespace URI
216      * @param ns2 the WSDL port addresses namespace URI
217      * @return true if a provider is available for the given
218      * namespaces, otherwise false.
219      */

220     public static boolean isProviderAvailable(String JavaDoc ns1, String JavaDoc ns2) {
221         boolean supported = false;
222         ArrayList JavaDoc ps = getSupportingProviders(ns1, false);
223         if (ps.size() > 0) {
224             if (ns2 == null || ns2.length() < 1 || ns2.equals(ns1)) {
225                 supported = true;
226             } else {
227                 String JavaDoc[] supportedNS;
228                 for (int i = 0; i < ps.size() && !supported; i++) {
229                  supportedNS = ((WSIFProvider)ps.get(i)).getAddressNamespaceURIs();
230                  for (int j=0; j<supportedNS.length && !supported; j++) {
231                         if (ns2.equals(supportedNS[j])) {
232                             supported = true;
233                         }
234                     }
235                 }
236             }
237         }
238         return supported;
239     }
240
241     /**
242      * This sets if the WSIFProviders will be automatically loaded.
243      * If this is set to false any providers required msut be explicitly
244      * defined by using the <code>overrideDefaultProvider<\code> method.
245      * Changing the state of the auto loading of providers clears any providers
246      * that have already been loaded or choosen as a default provider.
247      * @param b true means all the WSIFProviders will be loaded automatically,
248      * false means all WSIFProviders must be manually set with the
249      * setDynamicWSIFProvider method
250      */

251     public static void setAutoLoadProviders(boolean b) {
252         Trc.entry(null, b);
253         if (autoLoadProviders != b) {
254             providersFromSPIFiles = null;
255             defaultNSProviders = null;
256             autoLoadProviders = b;
257         }
258         Trc.exit();
259     }
260
261     /**
262      * Tests if providers are set to be automatically loaded.
263      * @return true if providers will be loaded automatically,
264      * otherwise false.
265      */

266     public static boolean isAutoLoadProviders() {
267         Trc.entry(null);
268         Trc.exit(autoLoadProviders);
269         return autoLoadProviders;
270     }
271
272     /**
273      * Gets all the available WSIFProvider that support a particular
274      * namespace URI.
275      * @param namesapceURI the namespace the WSIFProvider must support.
276      * @param issueMessage Flag to inicate whether or not to log when multiple
277      * providers are found for the same namespace.
278      * @return an array of WSIFProvider. The array will have a length
279      * of zero if no WSIFProvider are available for the requested namespace.
280      */

281     private static ArrayList JavaDoc getSupportingProviders(
282         String JavaDoc namespaceURI,
283         boolean issueMessage) {
284
285         Trc.entry(null, namespaceURI, new Boolean JavaDoc(issueMessage));
286         if (providersFromSPIFiles == null) {
287             providersFromSPIFiles = getAllDynamicWSIFProviders();
288         }
289         ArrayList JavaDoc supportingProviders = new ArrayList JavaDoc();
290         String JavaDoc[] uris;
291         WSIFProvider p;
292         for (Iterator JavaDoc 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 && namespaceURI.equals(uris[j])) {
297                     Trc.event(
298                         null,
299                         "Adding provider " + p + " for namespace " + uris[j]);
300                     supportingProviders.add(p);
301                 }
302             }
303         }
304         if (defaultNSProviders != null) {
305             if (defaultNSProviders.get(namespaceURI) != null) {
306                 Trc.event(
307                     null,
308                     "Adding default provider "
309                         + defaultNSProviders.get(namespaceURI)
310                         + " for namespace "
311                         + namespaceURI);
312                 supportingProviders.add(defaultNSProviders.get(namespaceURI));
313             }
314         }
315
316         if (supportingProviders.size() > 1 && issueMessage) {
317             issueMultipleProvidersMsg(namespaceURI, supportingProviders);
318         }
319
320         Trc.exit(supportingProviders);
321         return supportingProviders;
322     }
323
324     /**
325      * Gets all the available WSIFProviders.
326      * WSIFProviders are located using the J2SE 1.3 JAR file extensions
327      * to support service providers.
328      * @return an array of WSIFProvider.
329      */

330     private static ArrayList JavaDoc getAllDynamicWSIFProviders() {
331         Trc.entry(null);
332         if (!autoLoadProviders) {
333             return new ArrayList JavaDoc();
334         }
335
336         ArrayList JavaDoc al =
337             (ArrayList JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
338             public Object JavaDoc run() {
339                 return findPlugableProviders();
340             }
341         });
342         Trc.exit(al);
343         return al;
344     }
345
346     private static ArrayList JavaDoc findPlugableProviders() {
347         Object JavaDoc o;
348         ArrayList JavaDoc classNames = new ArrayList JavaDoc();
349         ArrayList JavaDoc providers = new ArrayList JavaDoc();
350
351         // find all the class names mentioned in all the META-INF files
352
ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
353
354         try {
355             for (Enumeration JavaDoc e = loader.getResources(PLUGABLE_PROVIDER_FILENAME); e.hasMoreElements();) {
356                 readMETAINFClassNames((URL JavaDoc) e.nextElement(), classNames);
357             }
358         } catch (Exception JavaDoc ex) {
359             Trc.exception(ex);
360             MessageLogger.log("WSIF.0003W", ex.getMessage());
361             return providers;
362         }
363
364         // instantiate a provider for each of the named classes
365
for (Iterator JavaDoc i = classNames.iterator(); i.hasNext();) {
366             try {
367                 o = Class.forName((String JavaDoc) i.next(), true, loader).newInstance();
368                 if (o instanceof org.apache.wsif.spi.WSIFProvider) {
369                     WSIFProvider p = (org.apache.wsif.spi.WSIFProvider) o;
370                     if (p.getBindingNamespaceURIs().length > 0) {
371                         Trc.event(null, "Registering provider: " + p);
372                         providers.add(p);
373                     } else {
374                         WSIFException ex =
375                             new WSIFException(
376                                 "Disabled WSIFProvider found:"
377                                     + p.getClass().getName());
378                         Trc.ignoredException(ex);
379                     }
380                 } else {
381                     MessageLogger.log(
382                         "WSIF.0003W",
383                         "The provider class specified,"
384                             + ((o == null) ? null : o.getClass().getName())
385                             + ", does not implement org.apache.wsif.spi.WSIFProvider");
386                 }
387             } catch (ClassNotFoundException JavaDoc ex) {
388                 Trc.exception(ex);
389                 MessageLogger.log("WSIF.0003W", ex.getMessage());
390             } catch (Exception JavaDoc ex) {
391                 Trc.exception(ex);
392                 MessageLogger.log("WSIF.0003W", ex.getMessage());
393             }
394         }
395
396         return providers;
397     }
398
399     private static void readMETAINFClassNames(URL JavaDoc u, ArrayList JavaDoc classNames) {
400         Trc.entry(null, u);
401         Trc.event(
402             null,
403             "Reading provider class names from URL: " + u.toString());
404         BufferedReader JavaDoc in = null;
405         String JavaDoc inputLine;
406         int i;
407         try {
408             in = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(u.openStream()));
409             while ((inputLine = in.readLine()) != null) {
410                 i = inputLine.indexOf('#');
411                 if (i >= 0) {
412                     inputLine = inputLine.substring(0, i);
413                 }
414                 inputLine = inputLine.trim();
415                 if (inputLine.length() > 0) {
416                     Trc.event(null, "Found provider class name: " + inputLine);
417                     if (!classNames.contains(inputLine)) {
418                         classNames.add(inputLine);
419                     }
420                 }
421             }
422         } catch (IOException JavaDoc ex) {
423             Trc.exception(ex);
424             MessageLogger.log("WSIF.0003W", ex.getMessage());
425         } finally {
426             if (in != null) {
427                 try {
428                     in.close();
429                 } catch (IOException JavaDoc ex) {
430                     Trc.exception(ex);
431                     MessageLogger.log("WSIF.0003W", ex.getMessage());
432                 }
433             }
434         }
435         Trc.exit();
436     }
437
438     /**
439      * Chooses a particular WSIFProvider. If the passed array of providers
440      * contains more than one element then a choice is made based on a WSIF
441      * properties file default setting.
442      * @param providers an array of WSIFProvider
443      * @return a WSIFProvider. Returns null if the input array is null or
444      * has a length of zero, the first element if the array contains
445      * only one element, or an element based on the property file setting.
446      */

447     private static WSIFProvider chooseProvider(
448         ArrayList JavaDoc providers,
449         String JavaDoc uri) {
450         if (providers == null || providers.size() < 1) {
451             return null;
452         } else if (providers.size() == 1) {
453             return (WSIFProvider) providers.get(0);
454         }
455
456         int i = providers.size() - 1;
457         while (i > 0
458             && !isDefaultProvider((WSIFProvider) providers.get(i), uri)) {
459             i--;
460         }
461         WSIFProvider p = (WSIFProvider) providers.get(i);
462         issueChosenProviderMsg(uri, p);
463
464         return p;
465     }
466
467     /**
468      * Tests if a class name is defined in the WSIF properties file as being the
469      * default WSIF provider for the namespace URI.
470      * @param className the class name to test
471      * @param uri the namespace URI
472      * @return true if className is defined as the default WSIFprovider,
473      * otherwise false.
474      */

475     private static boolean isDefaultProvider(
476         WSIFProvider provider,
477         String JavaDoc uri) {
478         String JavaDoc className = provider.getClass().getName();
479         String JavaDoc defaultURI;
480         try {
481             String JavaDoc key = WSIFConstants.WSIF_PROP_PROVIDER_PFX1 + className;
482             int n = Integer.parseInt(WSIFProperties.getProperty(key));
483             for (int i = 1; i <= n; i++) {
484                 key =
485                     WSIFConstants.WSIF_PROP_PROVIDER_PFX2 + i + "." + className;
486                 defaultURI = WSIFProperties.getProperty(key);
487                 if (uri != null && uri.equals(defaultURI)) {
488                     return true;
489                 }
490             }
491         } catch (NumberFormatException JavaDoc e) { // ignore any error
492
Trc.ignoredException(e);
493         } // ignore any error
494
return false;
495     }
496
497     /**
498      * Issues a MessageLoger warning saying multiple providers
499      * exist with support for the same namespaceURI.
500      * @param uri the namespaceURI with multiple WSIFProviders
501      * @param providers an array of the providers supporting the namespaceURI
502      */

503     private static void issueMultipleProvidersMsg(
504         String JavaDoc uri,
505         ArrayList JavaDoc providers) {
506         String JavaDoc providerNames = providers.get(0).getClass().getName();
507         for (int i = 1; i < providers.size(); i++) {
508             providerNames += ", " + providers.get(i).getClass().getName();
509         }
510         MessageLogger.log("WSIF.0006W", uri, providerNames);
511     }
512
513     /**
514      * Issues a MessageLoger information message saying which provider has
515      * been chosen to support a namespaceURI when multiple providers are available.
516      * @param uri the namespaceURI with multiple WSIFProviders
517      * @param providers an array of the providers supporting the namespaceURI
518      */

519     private static void issueChosenProviderMsg(
520         String JavaDoc uri,
521         WSIFProvider provider) {
522
523         MessageLogger.log(
524             "WSIF.0007I",
525             provider == null ? "null" : provider.getClass().getName(),
526             uri);
527     }
528
529 }
530
Popular Tags