View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.util;
8   
9   import java.net.URL;
10  import java.net.URLStreamHandler;
11  import java.net.URLStreamHandlerFactory;
12  import java.util.Collections;
13  import java.util.HashMap;
14  import java.util.Map;
15  import java.util.StringTokenizer;
16  
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  
20  /**
21   * A factory for loading URL protocol handlers. This factory is necessary to make
22   * Mule work in cases where the standard approach using system properties does not
23   * work, e.g. in application servers or with maven's surefire tests.
24   * <p>
25   * Client classes can register a subclass of {@link URLStreamHandler} for a given
26   * protocol. This implementation first checks its registered handlers before
27   * resorting to the default mechanism.
28   * <p>
29   * @see java.net.URL#URL(String, String, int, String)
30   */
31  public class MuleUrlStreamHandlerFactory extends Object implements URLStreamHandlerFactory
32  {
33      
34      private static final String HANDLER_PKGS_SYSTEM_PROPERTY = "java.protocol.handler.pkgs";
35      private static final Log log = LogFactory.getLog(MuleUrlStreamHandlerFactory.class);
36      
37      private static Map registry = Collections.synchronizedMap(new HashMap());
38  
39      /**
40       * Install an instance of this class as UrlStreamHandlerFactory. This may be done exactly
41       * once as {@link URL} will throw an {@link Error} on subsequent invocations. 
42       * <p>
43       * This method takes care that multiple invocations are possible, but the 
44       * UrlStreamHandlerFactory is installed only once.
45       */
46      public static synchronized void installUrlStreamHandlerFactory()
47      {
48          /*
49           * When running under surefire, this class will be loaded by different class loaders and
50           * will be running in multiple "main" thread objects. Thus, there is no way for this class
51           * to register a globally available variable to store the info whether our custom 
52           * UrlStreamHandlerFactory was already registered.
53           * 
54           * The only way to accomplish this is to catch the Error that is thrown by URL when
55           * trying to re-register the custom UrlStreamHandlerFactory.
56           */
57          try
58          {
59              URL.setURLStreamHandlerFactory(new MuleUrlStreamHandlerFactory());
60          }
61          catch (Error err)
62          {
63              if (log.isDebugEnabled())
64              {
65                  log.debug("Custom MuleUrlStreamHandlerFactory already registered", err);
66              }
67          }
68      }
69      
70      public static void registerHandler(String protocol, URLStreamHandler handler)
71      {
72          registry.put(protocol, handler);
73      }
74  
75      public URLStreamHandler createURLStreamHandler(String protocol)
76      {
77          URLStreamHandler handler = (URLStreamHandler) registry.get(protocol);
78          if (handler == null)
79          {
80              handler = this.defaultHandlerCreateStrategy(protocol);
81          }
82          return handler;
83      }
84  
85      private URLStreamHandler defaultHandlerCreateStrategy(String protocol)
86      {
87          String packagePrefixList = System.getProperty(HANDLER_PKGS_SYSTEM_PROPERTY, "");
88  
89          if (packagePrefixList.endsWith("|") == false)
90          {
91              packagePrefixList += "|sun.net.www.protocol";
92          }
93  
94          StringTokenizer tokenizer = new StringTokenizer(packagePrefixList, "|");
95  
96          URLStreamHandler handler = null;
97          while (handler == null && tokenizer.hasMoreTokens())
98          {
99              String packagePrefix = tokenizer.nextToken().trim();
100             String className = packagePrefix + "." + protocol + ".Handler";
101             try
102             {
103                 handler = (URLStreamHandler) ClassUtils.instanciateClass(className);
104             }
105             catch (Exception ex)
106             {
107                 // not much we can do here
108             }
109         }
110          
111         return handler;
112     }
113 }