001: /*
002: * Copyright (C) The MX4J Contributors.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the MX4J License version 1.0.
006: * See the terms of the MX4J License in the documentation provided with this software.
007: */
008:
009: package mx4j.remote;
010:
011: import java.io.BufferedReader;
012: import java.io.IOException;
013: import java.io.InputStream;
014: import java.io.InputStreamReader;
015: import java.net.MalformedURLException;
016: import java.net.URL;
017: import java.security.AccessController;
018: import java.security.PrivilegedActionException;
019: import java.security.PrivilegedExceptionAction;
020: import java.util.ArrayList;
021: import java.util.Collections;
022: import java.util.Enumeration;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.StringTokenizer;
026:
027: import javax.management.MBeanServer;
028: import javax.management.remote.JMXConnector;
029: import javax.management.remote.JMXConnectorFactory;
030: import javax.management.remote.JMXConnectorProvider;
031: import javax.management.remote.JMXConnectorServer;
032: import javax.management.remote.JMXConnectorServerFactory;
033: import javax.management.remote.JMXConnectorServerProvider;
034: import javax.management.remote.JMXProviderException;
035: import javax.management.remote.JMXServiceURL;
036:
037: import mx4j.log.Logger;
038:
039: /**
040: * @version $Revision: 1.8 $
041: */
042: public class ProviderFactory extends ProviderHelper {
043: public static JMXConnector newJMXConnector(JMXServiceURL url,
044: Map env) throws IOException {
045: // Yes, throw NPE if url is null (spec compliant)
046: String protocol = normalizeProtocol(url.getProtocol());
047: String providerPackages = findProviderPackageList(env,
048: JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES);
049: ClassLoader classLoader = findProviderClassLoader(env,
050: JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
051: List providers = loadProviders(JMXConnectorProvider.class,
052: providerPackages, protocol,
053: MX4JRemoteConstants.CLIENT_PROVIDER_CLASS, classLoader);
054: for (int i = 0; i < providers.size(); i++) {
055: JMXConnectorProvider provider = (JMXConnectorProvider) providers
056: .get(i);
057: try {
058: return provider.newJMXConnector(url, Collections
059: .unmodifiableMap(env));
060: } catch (JMXProviderException x) {
061: throw x;
062: } catch (IOException x) {
063: continue;
064: }
065: }
066: throw new MalformedURLException(
067: "Could not find provider for protocol " + protocol);
068: }
069:
070: public static JMXConnectorServer newJMXConnectorServer(
071: JMXServiceURL url, Map env, MBeanServer server)
072: throws IOException {
073: // Yes, throw NPE if url is null (spec compliant)
074: String protocol = normalizeProtocol(url.getProtocol());
075: String providerPackages = findProviderPackageList(env,
076: JMXConnectorServerFactory.PROTOCOL_PROVIDER_PACKAGES);
077: ClassLoader classLoader = findProviderClassLoader(
078: env,
079: JMXConnectorServerFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
080: List providers = loadProviders(
081: JMXConnectorServerProvider.class, providerPackages,
082: protocol, MX4JRemoteConstants.SERVER_PROVIDER_CLASS,
083: classLoader);
084: for (int i = 0; i < providers.size(); i++) {
085: JMXConnectorServerProvider provider = (JMXConnectorServerProvider) providers
086: .get(i);
087: try {
088: return provider.newJMXConnectorServer(url, Collections
089: .unmodifiableMap(env), server);
090: } catch (JMXProviderException x) {
091: throw x;
092: } catch (IOException x) {
093: continue;
094: }
095: }
096: throw new MalformedURLException(
097: "Could not find provider for protocol " + protocol);
098: }
099:
100: /**
101: * public static JMXConnectorProvider newJMXConnectorProvider(JMXServiceURL url, Map env) throws IOException
102: * {
103: * // Yes, throw NPE if url is null (spec compliant)
104: * String protocol = normalizeProtocol(url.getProtocol());
105: * String providerPackages = findProviderPackageList(env, JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES);
106: * ClassLoader classLoader = findProviderClassLoader(env, JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
107: * JMXConnectorProvider provider = (JMXConnectorProvider)loadProvider(JMXConnectorProvider.class, providerPackages, protocol, MX4JRemoteConstants.CLIENT_PROVIDER_CLASS, classLoader);
108: * return provider;
109: * }
110: * <p/>
111: * public static JMXConnectorServerProvider newJMXConnectorServerProvider(JMXServiceURL url, Map env) throws IOException
112: * {
113: * // Yes, throw NPE if url is null (spec compliant)
114: * String protocol = normalizeProtocol(url.getProtocol());
115: * String providerPackages = findProviderPackageList(env, JMXConnectorServerFactory.PROTOCOL_PROVIDER_PACKAGES);
116: * ClassLoader classLoader = findProviderClassLoader(env, JMXConnectorServerFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
117: * JMXConnectorServerProvider provider = (JMXConnectorServerProvider)loadProvider(JMXConnectorServerProvider.class, providerPackages, protocol, MX4JRemoteConstants.SERVER_PROVIDER_CLASS, classLoader);
118: * return provider;
119: * }
120: */
121: private static String findEnvironmentProviderPackageList(
122: Map environment, String key) throws JMXProviderException {
123: String providerPackages = null;
124: if (environment != null) {
125: Logger logger = getLogger();
126: Object pkgs = environment.get(key);
127: if (logger.isEnabledFor(Logger.DEBUG))
128: logger.debug("Provider packages in the environment: "
129: + pkgs);
130: if (pkgs != null && !(pkgs instanceof String))
131: throw new JMXProviderException(
132: "Provider package list must be a string");
133: providerPackages = (String) pkgs;
134: }
135: return providerPackages;
136: }
137:
138: private static String findProviderPackageList(Map environment,
139: final String providerPkgsKey) throws JMXProviderException {
140: // 1. Look in the environment
141: // 2. Look for system property
142: // 3. Use implementation's provider
143:
144: String providerPackages = findEnvironmentProviderPackageList(
145: environment, providerPkgsKey);
146:
147: if (providerPackages == null) {
148: providerPackages = findSystemPackageList(providerPkgsKey);
149: }
150:
151: if (providerPackages != null
152: && providerPackages.trim().length() == 0)
153: throw new JMXProviderException(
154: "Provider package list cannot be an empty string");
155:
156: if (providerPackages == null)
157: providerPackages = MX4JRemoteConstants.PROVIDER_PACKAGES;
158: else
159: providerPackages += MX4JRemoteConstants.PROVIDER_PACKAGES_SEPARATOR
160: + MX4JRemoteConstants.PROVIDER_PACKAGES;
161:
162: Logger logger = getLogger();
163: if (logger.isEnabledFor(Logger.DEBUG))
164: logger.debug("Provider packages list is: "
165: + providerPackages);
166:
167: return providerPackages;
168: }
169:
170: private static ClassLoader findProviderClassLoader(Map environment,
171: String providerLoaderKey) {
172: Logger logger = getLogger();
173:
174: ClassLoader classLoader = null;
175: if (environment != null) {
176: Object loader = environment.get(providerLoaderKey);
177: if (logger.isEnabledFor(Logger.DEBUG))
178: logger
179: .debug("Provider classloader in the environment: "
180: + loader);
181: if (loader != null && !(loader instanceof ClassLoader))
182: throw new IllegalArgumentException(
183: "Provider classloader is not a ClassLoader");
184: classLoader = (ClassLoader) loader;
185: }
186:
187: if (classLoader == null) {
188: classLoader = Thread.currentThread()
189: .getContextClassLoader();
190: if (logger.isEnabledFor(Logger.DEBUG))
191: logger
192: .debug("Provider classloader in the environment: "
193: + classLoader);
194: }
195:
196: // Add the classloader as required by the spec
197: environment.put(
198: JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER,
199: classLoader);
200: if (logger.isEnabledFor(Logger.TRACE))
201: logger
202: .trace("Provider classloader added to the environment");
203:
204: return classLoader;
205: }
206:
207: private static List loadProviders(Class providerType,
208: String packages, String protocol, String className,
209: ClassLoader loader) throws JMXProviderException {
210: Logger logger = getLogger();
211: List result = new ArrayList();
212:
213: StringTokenizer tokenizer = new StringTokenizer(packages,
214: MX4JRemoteConstants.PROVIDER_PACKAGES_SEPARATOR);
215: while (tokenizer.hasMoreTokens()) {
216: String pkg = tokenizer.nextToken().trim();
217: if (logger.isEnabledFor(Logger.DEBUG))
218: logger.debug("Provider package: " + pkg);
219:
220: // The spec states the package cannot be empty
221: if (pkg.length() == 0)
222: throw new JMXProviderException(
223: "Empty package list not allowed: " + packages);
224:
225: String providerClassName = constructClassName(pkg,
226: protocol, className);
227:
228: Class providerClass = null;
229: try {
230: providerClass = loadClass(providerClassName, loader);
231: } catch (ClassNotFoundException x) {
232: if (logger.isEnabledFor(Logger.DEBUG))
233: logger
234: .debug("Provider class "
235: + providerClassName
236: + " not found, "
237: + (tokenizer.hasMoreTokens() ? "continuing with next package"
238: : "no more packages to try"));
239: continue;
240: } catch (Exception x) {
241: if (logger.isEnabledFor(Logger.TRACE))
242: logger.trace("Cannot load provider class "
243: + providerClassName, x);
244: throw new JMXProviderException(
245: "Cannot load provider class "
246: + providerClassName, x);
247: }
248:
249: try {
250: Object provider = providerClass.newInstance();
251: result.add(provider);
252: } catch (Exception x) {
253: if (logger.isEnabledFor(Logger.TRACE))
254: logger.trace("Cannot instantiate provider class "
255: + providerClassName, x);
256: throw new JMXProviderException(
257: "Cannot instantiate provider class "
258: + providerClassName, x);
259: }
260: }
261:
262: try {
263: List serviceProviders = fromServiceProviders(providerType,
264: protocol, className, loader);
265: result.addAll(serviceProviders);
266: } catch (IOException x) {
267: if (logger.isEnabledFor(Logger.DEBUG))
268: logger.debug("Error retrieving service providers", x);
269: }
270:
271: if (logger.isEnabledFor(Logger.DEBUG))
272: logger.debug("Providers found are: " + result);
273: return result;
274: }
275:
276: private static List fromServiceProviders(Class providerType,
277: String protocol, String className, ClassLoader loader)
278: throws IOException {
279: String services = "META-INF/services/";
280:
281: Logger logger = getLogger();
282: if (logger.isEnabledFor(Logger.DEBUG))
283: logger.debug("Loading providers from " + services);
284:
285: if (loader == null)
286: loader = Thread.currentThread().getContextClassLoader();
287: if (loader == null)
288: loader = ClassLoader.getSystemClassLoader();
289: Enumeration providerURLs = loader.getResources(services
290: + providerType.getName());
291: List providers = new ArrayList();
292: while (providerURLs.hasMoreElements()) {
293: final URL providerURL = (URL) providerURLs.nextElement();
294:
295: InputStream stream = null;
296: try {
297: stream = (InputStream) AccessController
298: .doPrivileged(new PrivilegedExceptionAction() {
299: public Object run() throws Exception {
300: return providerURL.openStream();
301: }
302: });
303: } catch (PrivilegedActionException x) {
304: Exception xx = x.getException();
305: if (xx instanceof IOException)
306: throw (IOException) xx;
307: throw new IOException(xx.toString());
308: }
309:
310: BufferedReader reader = null;
311: try {
312: if (logger.isEnabledFor(Logger.DEBUG))
313: logger
314: .debug("Reading provider from "
315: + providerURL);
316: reader = new BufferedReader(new InputStreamReader(
317: stream, "UTF-8"));
318: String line = null;
319: while ((line = reader.readLine()) != null) {
320: int comment = line.indexOf('#');
321: if (comment >= 0)
322: line = line.substring(0, comment);
323: line = line.trim();
324: if (line.length() == 0)
325: continue;
326: if (logger.isEnabledFor(Logger.DEBUG))
327: logger.debug("Found provider '" + line
328: + "' in " + providerURL);
329: try {
330: Class providerClass = loader.loadClass(line);
331: if (providerType
332: .isAssignableFrom(providerClass)) {
333: Object providerInstance = providerClass
334: .newInstance();
335: providers.add(providerInstance);
336: }
337: } catch (Exception ignored) {
338: // Skip this line and continue
339: }
340: }
341: } finally {
342: if (reader != null)
343: reader.close();
344: }
345: }
346:
347: return providers;
348: }
349: }
|