Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package javax.xml.soap;
28 import java.io.*;
29 import java.util.Properties;
32 class FactoryFinder {
34 /**
35 * Creates an instance of the specified class using the specified
36 * <code>ClassLoader</code> object.
37 *
38 * @exception SOAPException if the given class could not be found
39 * or could not be instantiated
40 */
41 private static Object newInstance(String className,
42 ClassLoader classLoader)
43 throws SOAPException
44 {
45 try {
46 Class spiClass = safeLoadClass(className, classLoader);
47 return spiClass.newInstance();
49 } catch (ClassNotFoundException x) {
50 throw new SOAPException("Provider " + className + " not found", x);
51 } catch (Exception x) {
52 throw new SOAPException("Provider " + className + " could not be instantiated: " + x, x);
53 }
54 }
56 /**
57 * Finds the implementation <code>Class</code> object for the given
58 * factory name, or null if that fails.
59 * <P>
60 * This method is package private so that this code can be shared.
61 *
62 * @return the <code>Class</code> object of the specified message factory;
63 * or <code>null</code>
64 *
65 * @param factoryId the name of the factory to find, which is
66 * a system property
67 * @exception SOAPException if there is a SOAP error
68 */
69 static Object find(String factoryId)
70 throws SOAPException
71 {
72 return find(factoryId, null, false);
73 }
75 /**
76 * Finds the implementation <code>Class</code> object for the given
77 * factory name, or if that fails, finds the <code>Class</code> object
78 * for the given fallback class name. The arguments supplied must be
79 * used in order. If using the first argument is successful, the second
80 * one will not be used.
81 * <P>
82 * This method is package private so that this code can be shared.
83 *
84 * @return the <code>Class</code> object of the specified message factory;
85 * may be <code>null</code>
86 *
87 * @param factoryId the name of the factory to find, which is
88 * a system property
89 * @param fallbackClassName the implementation class name, which is
90 * to be used only if nothing else
91 * is found; <code>null</code> to indicate that
92 * there is no fallback class name
93 * @exception SOAPException if there is a SOAP error
94 */
95 static Object find(String factoryId, String fallbackClassName)
96 throws SOAPException
97 {
98 return find(factoryId, fallbackClassName, true);
99 }
101 /**
102 * Finds the implementation <code>Class</code> object for the given
103 * factory name, or if that fails, finds the <code>Class</code> object
104 * for the given default class name, but only if <code>tryFallback</code>
105 * is <code>true</code>. The arguments supplied must be used in order
106 * If using the first argument is successful, the second one will not
107 * be used. Note the default class name may be needed even if fallback
108 * is not to be attempted, so certain error conditions can be handled.
109 * <P>
110 * This method is package private so that this code can be shared.
111 *
112 * @return the <code>Class</code> object of the specified message factory;
113 * may not be <code>null</code>
114 *
115 * @param factoryId the name of the factory to find, which is
116 * a system property
117 * @param defaultClassName the implementation class name, which is
118 * to be used only if nothing else
119 * is found; <code>null</code> to indicate
120 * that there is no default class name
121 * @param tryFallback whether to try the default class as a
122 * fallback
123 * @exception SOAPException if there is a SOAP error
124 */
125 static Object find(String factoryId, String defaultClassName,
126 boolean tryFallback) throws SOAPException {
127 ClassLoader classLoader;
128 try {
129 classLoader = Thread.currentThread().getContextClassLoader();
130 } catch (Exception x) {
131 throw new SOAPException(x.toString(), x);
132 }
134 // Use the system property first
135 try {
136 String systemProp =
137 System.getProperty( factoryId );
138 if( systemProp!=null) {
139 return newInstance(systemProp, classLoader);
140 }
141 } catch (SecurityException se) {
142 }
144 // try to read from $java.home/lib/jaxm.properties
145 try {
146 String javah=System.getProperty( "java.home" );
147 String configFile = javah + File.separator +
148 "lib" + File.separator + "jaxm.properties";
149 File f=new File( configFile );
150 if( f.exists()) {
151 Properties props=new Properties();
152 props.load( new FileInputStream(f));
153 String factoryClassName = props.getProperty(factoryId);
154 return newInstance(factoryClassName, classLoader);
155 }
156 } catch(Exception ex ) {
157 }
159 String serviceId = "META-INF/services/" + factoryId;
160 // try to find services in CLASSPATH
161 try {
162 InputStream is=null;
163 if (classLoader == null) {
164 is=ClassLoader.getSystemResourceAsStream(serviceId);
165 } else {
166 is=classLoader.getResourceAsStream(serviceId);
167 }
169 if( is!=null ) {
170 BufferedReader rd =
171 new BufferedReader(new InputStreamReader(is, "UTF-8"));
173 String factoryClassName = rd.readLine();
174 rd.close();
176 if (factoryClassName != null &&
177 ! "".equals(factoryClassName)) {
178 return newInstance(factoryClassName, classLoader);
179 }
180 }
181 } catch( Exception ex ) {
182 }
184 // If not found and fallback should not be tried, return a null result.
185 if (!tryFallback)
186 return null;
188 // We didn't find the class through the usual means so try the default
189 // (built in) factory if specified.
190 if (defaultClassName == null) {
191 throw new SOAPException(
192 "Provider for " + factoryId + " cannot be found", null);
193 }
194 return newInstance(defaultClassName, classLoader);
195 }
197 /**
198 * Loads the class, provided that the calling thread has an access to the
199 * class being loaded. If this is the specified default factory class and it
200 * is restricted by package.access we get a SecurityException and can do a
201 * Class.forName() on it so it will be loaded by the bootstrap class loader.
202 */
203 private static Class safeLoadClass(String className,
204 ClassLoader classLoader)
205 throws ClassNotFoundException {
206 try {
207 // make sure that the current thread has an access to the package of the given name.
208 SecurityManager s = System.getSecurityManager();
209 if (s != null) {
210 int i = className.lastIndexOf('.');
211 if (i != -1) {
212 s.checkPackageAccess(className.substring(0, i));
213 }
214 }
216 if (classLoader == null)
217 return Class.forName(className);
218 else
219 return classLoader.loadClass(className);
220 } catch (SecurityException se) {
221 // (only) default implementation can be loaded
222 // using bootstrap class loader:
223 if (isDefaultImplementation(className))
224 return Class.forName(className);
226 throw se;
227 }
228 }
230 private static boolean isDefaultImplementation(String className) {
231 return MessageFactory.DEFAULT_MESSAGE_FACTORY.equals(className) ||
232 SOAPFactory.DEFAULT_SOAP_FACTORY.equals(className) ||
233 SOAPConnectionFactory.DEFAULT_SOAP_CONNECTION_FACTORY.equals(className) ||
234 SAAJMetaFactory.DEFAULT_META_FACTORY_CLASS.equals(className);
235 }
236 }